Skip to content

Commit d8064ec

Browse files
committed
Improve SelectNext props API
1 parent 386df2a commit d8064ec

File tree

3 files changed

+47
-22
lines changed

3 files changed

+47
-22
lines changed

src/components/input/SelectNext.tsx

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -110,26 +110,37 @@ function useShouldDropUp(
110110
export type SelectProps<T> = PresentationalProps & {
111111
value: T;
112112
onChange: (newValue: T) => void;
113-
label: ComponentChildren;
113+
buttonContent?: ComponentChildren;
114114
disabled?: boolean;
115+
116+
/**
117+
* `id` attribute for the toggle button. This is useful to associate a label
118+
* with the control.
119+
*/
120+
buttonId?: string;
121+
122+
/** @deprecated Use buttonContent instead */
123+
label?: ComponentChildren;
115124
};
116125

117126
function SelectMain<T>({
127+
buttonContent,
118128
label,
119129
value,
120130
onChange,
121131
children,
122132
disabled,
123-
classes,
124133
elementRef,
134+
classes,
135+
buttonId,
125136
}: SelectProps<T>) {
126137
const [listboxOpen, setListboxOpen] = useState(false);
127138
const closeListbox = useCallback(() => setListboxOpen(false), []);
128139
const wrapperRef = useRef<HTMLDivElement | null>(null);
129140
const listboxRef = useRef<HTMLDivElement | null>(null);
130141
const listboxId = useId();
131142
const buttonRef = useSyncedRef(elementRef);
132-
const buttonId = useId();
143+
const defaultButtonId = useId();
133144
const shouldListboxDropUp = useShouldDropUp(
134145
buttonRef,
135146
listboxRef,
@@ -168,7 +179,7 @@ function SelectMain<T>({
168179
return (
169180
<div className="relative" ref={wrapperRef}>
170181
<Button
171-
id={buttonId}
182+
id={buttonId ?? defaultButtonId}
172183
variant="custom"
173184
classes={classnames(
174185
'w-full flex border rounded',
@@ -183,12 +194,13 @@ function SelectMain<T>({
183194
onClick={() => setListboxOpen(prev => !prev)}
184195
onKeyDown={e => {
185196
if (e.key === 'ArrowDown' && !listboxOpen) {
197+
e.preventDefault();
186198
setListboxOpen(true);
187199
}
188200
}}
189201
data-testid="select-toggle-button"
190202
>
191-
{label}
203+
{buttonContent ?? label}
192204
<div className="grow" />
193205
<div className="text-grey-6">
194206
{listboxOpen ? <MenuCollapseIcon /> : <MenuExpandIcon />}
@@ -212,7 +224,7 @@ function SelectMain<T>({
212224
role="listbox"
213225
ref={listboxRef}
214226
id={listboxId}
215-
aria-labelledby={buttonId}
227+
aria-labelledby={buttonId ?? defaultButtonId}
216228
aria-orientation="vertical"
217229
data-testid="select-listbox"
218230
>

src/components/input/test/SelectNext-test.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ describe('SelectNext', () => {
1919
document.body.append(container);
2020

2121
const wrapper = mount(
22-
<SelectNext value={undefined} onChange={sinon.stub()} label="" {...props}>
22+
<SelectNext value={undefined} onChange={sinon.stub()} {...props}>
2323
{items.map(item => (
2424
<SelectNext.Option
2525
value={item}
@@ -225,12 +225,12 @@ describe('SelectNext', () => {
225225
checkAccessibility([
226226
{
227227
name: 'Closed Select listbox',
228-
content: () => createComponent({ label: 'Select' }),
228+
content: () => createComponent({ buttonContent: 'Select' }),
229229
},
230230
{
231231
name: 'Open Select listbox',
232232
content: () => {
233-
const wrapper = createComponent({ label: 'Select' });
233+
const wrapper = createComponent({ buttonContent: 'Select' });
234234
toggleListbox(wrapper);
235235

236236
return wrapper;

src/pattern-library/components/patterns/prototype/SelectNextPage.tsx

Lines changed: 26 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import { useCallback, useMemo, useState } from 'preact/hooks';
33

44
import { ArrowLeftIcon, ArrowRightIcon } from '../../../../components/icons';
55
import { IconButton, InputGroup } from '../../../../components/input';
6-
import Select from '../../../../components/input/SelectNext';
6+
import SelectNext from '../../../../components/input/SelectNext';
77
import Library from '../../Library';
88

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

2828
return (
29-
<Select
29+
<SelectNext
3030
value={value}
3131
onChange={setValue}
32-
label={
32+
buttonContent={
3333
value ? (
3434
<>
3535
{value.name}
@@ -48,7 +48,7 @@ function SelectExample({
4848
disabled={disabled}
4949
>
5050
{items.map(item => (
51-
<Select.Option value={item} key={item.id}>
51+
<SelectNext.Option value={item} key={item.id}>
5252
{() =>
5353
textOnly ? (
5454
<>{item.name}</>
@@ -62,9 +62,9 @@ function SelectExample({
6262
</>
6363
)
6464
}
65-
</Select.Option>
65+
</SelectNext.Option>
6666
))}
67-
</Select>
67+
</SelectNext>
6868
);
6969
}
7070

@@ -93,10 +93,10 @@ function InputGroupSelectExample() {
9393
disabled={selectedIndex <= 0}
9494
/>
9595
<div className="w-full">
96-
<Select
96+
<SelectNext
9797
value={selected}
9898
onChange={setSelected}
99-
label={
99+
buttonContent={
100100
selected ? (
101101
<>
102102
{selected.name}
@@ -110,7 +110,7 @@ function InputGroupSelectExample() {
110110
}
111111
>
112112
{defaultItems.map(item => (
113-
<Select.Option value={item} key={item.id}>
113+
<SelectNext.Option value={item} key={item.id}>
114114
{() => (
115115
<>
116116
{item.name}
@@ -122,9 +122,9 @@ function InputGroupSelectExample() {
122122
</div>
123123
</>
124124
)}
125-
</Select.Option>
125+
</SelectNext.Option>
126126
))}
127-
</Select>
127+
</SelectNext>
128128
</div>
129129
<IconButton
130130
icon={ArrowRightIcon}
@@ -230,7 +230,7 @@ export default function SelectNextPage() {
230230
<Library.Link href="/using-components#presentational-components-api">
231231
presentational component props
232232
</Library.Link>
233-
<Library.Example title="label">
233+
<Library.Example title="buttonContent">
234234
<Library.Info>
235235
<Library.InfoItem label="description">
236236
The content to be displayed in the toggle button.
@@ -273,6 +273,19 @@ export default function SelectNextPage() {
273273
</Library.InfoItem>
274274
</Library.Info>
275275
</Library.Example>
276+
<Library.Example title="buttonId">
277+
<Library.Info>
278+
<Library.InfoItem label="description">
279+
The toggle button{"'"}s <code>id</code>.
280+
</Library.InfoItem>
281+
<Library.InfoItem label="type">
282+
<code>string</code>
283+
</Library.InfoItem>
284+
<Library.InfoItem label="default">
285+
<code>undefined</code>
286+
</Library.InfoItem>
287+
</Library.Info>
288+
</Library.Example>
276289
</Library.Pattern>
277290

278291
<Library.Pattern title="How to use it">
@@ -288,7 +301,7 @@ export default function SelectNextPage() {
288301
<SelectNext
289302
value={value}
290303
onChange={setSelected}
291-
label={
304+
buttonContent={
292305
value ? (
293306
<>
294307
{value.name}

0 commit comments

Comments
 (0)