Skip to content

Commit b34e500

Browse files
isDisabled does not work as expected (#2479)
* first commit * second commit * preventing useMenuTrigger and useComboBox press handlers from toggling menu when isDisabled * adding tests * returning isDisabled from buttonProps in useComboBox Co-authored-by: Daniel Lu <[email protected]> Co-authored-by: Daniel Lu <[email protected]>
1 parent 1e635d5 commit b34e500

File tree

6 files changed

+70
-47
lines changed

6 files changed

+70
-47
lines changed

packages/@react-aria/combobox/src/useComboBox.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,8 @@ export function useComboBox<T>(props: AriaComboBoxProps<T>, state: ComboBoxState
7777
let formatMessage = useMessageFormatter(intlMessages);
7878
let {menuTriggerProps, menuProps} = useMenuTrigger(
7979
{
80-
type: 'listbox'
80+
type: 'listbox',
81+
isDisabled: isDisabled || isReadOnly
8182
},
8283
state,
8384
buttonRef
@@ -302,7 +303,8 @@ export function useComboBox<T>(props: AriaComboBoxProps<T>, state: ComboBoxState
302303
...triggerLabelProps,
303304
excludeFromTabOrder: true,
304305
onPress,
305-
onPressStart
306+
onPressStart,
307+
isDisabled: isDisabled || isReadOnly
306308
},
307309
inputProps: mergeProps(inputProps, {
308310
role: 'combobox',

packages/@react-aria/combobox/stories/useComboBox.stories.tsx

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,11 +25,14 @@ for (let i = 0; i < 50; i++) {
2525
lotsOfItems.push({name: 'Item ' + i});
2626
}
2727

28-
const Template = () => () => (
29-
<ComboBox label="Example" defaultItems={lotsOfItems}>
28+
const Template = () => (args) => (
29+
<ComboBox {...args} label="Example" defaultItems={lotsOfItems}>
3030
{(item: any) => <Item key={item.name}>{item.name}</Item>}
3131
</ComboBox>
3232
);
3333

3434
export const ScrollTesting = Template().bind({});
3535
ScrollTesting.args = {};
36+
37+
export const Disabled = Template().bind({});
38+
Disabled.args = {isDisabled: true};

packages/@react-aria/combobox/test/useComboBox.test.js

Lines changed: 47 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@ import {useSingleSelectListState} from '@react-stately/list';
2121
describe('useComboBox', function () {
2222
let preventDefault = jest.fn();
2323
let stopPropagation = jest.fn();
24+
let openSpy = jest.fn();
25+
let toggleSpy = jest.fn();
2426
let event = (e) => ({
2527
...e,
2628
preventDefault,
@@ -34,20 +36,31 @@ describe('useComboBox', function () {
3436
});
3537
mockLayout.collection = result.current.collection;
3638

39+
let props = {
40+
label: 'test label',
41+
popoverRef: {
42+
current: {}
43+
},
44+
buttonRef: {
45+
current: {}
46+
},
47+
inputRef: {
48+
current: {
49+
contains: jest.fn(),
50+
focus: jest.fn()
51+
}
52+
},
53+
listBoxRef: {
54+
current: {}
55+
},
56+
layout: mockLayout
57+
};
58+
3759
afterEach(() => {
3860
jest.clearAllMocks();
3961
});
4062

4163
it('should return default props for all the button group elements', function () {
42-
let props = {
43-
label: 'test label',
44-
popoverRef: React.createRef(),
45-
buttonRef: React.createRef(),
46-
inputRef: React.createRef(),
47-
listBoxRef: React.createRef(),
48-
layout: mockLayout
49-
};
50-
5164
let {result} = renderHook(() => useComboBox(props, useSingleSelectListState(defaultProps)));
5265
let {buttonProps, inputProps, listBoxProps, labelProps} = result.current;
5366

@@ -72,20 +85,6 @@ describe('useComboBox', function () {
7285
});
7386

7487
it('should prevent default on Enter if isOpen', function () {
75-
let props = {
76-
label: 'test label',
77-
popoverRef: React.createRef(),
78-
buttonRef: React.createRef(),
79-
inputRef: {
80-
current: {
81-
contains: jest.fn(),
82-
focus: jest.fn()
83-
}
84-
},
85-
listBoxRef: React.createRef(),
86-
layout: mockLayout
87-
};
88-
8988
let {result: state} = renderHook((props) => useComboBoxState(props), {initialProps: {...props, allowsEmptyCollection: true}});
9089
act(() => {
9190
// set combobox state to open
@@ -113,22 +112,6 @@ describe('useComboBox', function () {
113112
});
114113

115114
it('calls open and toggle with the expected parameters when arrow down/up/trigger button is pressed', function () {
116-
let openSpy = jest.fn();
117-
let toggleSpy = jest.fn();
118-
let props = {
119-
label: 'test label',
120-
popoverRef: React.createRef(),
121-
buttonRef: React.createRef(),
122-
inputRef: {
123-
current: {
124-
contains: jest.fn(),
125-
focus: jest.fn()
126-
}
127-
},
128-
listBoxRef: React.createRef(),
129-
layout: mockLayout
130-
};
131-
132115
let {result: state} = renderHook((props) => useComboBoxState(props), {initialProps: props});
133116
state.current.open = openSpy;
134117
state.current.toggle = toggleSpy;
@@ -152,4 +135,29 @@ describe('useComboBox', function () {
152135
expect(toggleSpy).toHaveBeenCalledTimes(2);
153136
expect(toggleSpy).toHaveBeenLastCalledWith(null, 'manual');
154137
});
138+
139+
it.each`
140+
Name | componentProps
141+
${'disabled'} | ${{isDisabled: true}}
142+
${'readonly'} | ${{isReadOnly: true}}
143+
`('press and keyboard events on the button doesn\'t toggle the menu if $Name', function ({componentProps}) {
144+
let additionalProps = {
145+
...props,
146+
...componentProps
147+
};
148+
149+
let {result: state} = renderHook((props) => useComboBoxState(props), {initialProps: additionalProps});
150+
state.current.open = openSpy;
151+
state.current.toggle = toggleSpy;
152+
153+
let {result} = renderHook((props) => useComboBox(props, state.current), {initialProps: additionalProps});
154+
let {buttonProps} = result.current;
155+
buttonProps.onKeyDown(event({key: 'ArrowDown'}));
156+
expect(openSpy).toHaveBeenCalledTimes(0);
157+
expect(toggleSpy).toHaveBeenCalledTimes(0);
158+
buttonProps.onKeyDown(event({key: 'ArrowUp'}));
159+
expect(openSpy).toHaveBeenCalledTimes(0);
160+
expect(toggleSpy).toHaveBeenCalledTimes(0);
161+
expect(buttonProps.isDisabled).toBeTruthy();
162+
});
155163
});

packages/@react-aria/menu/src/useMenuTrigger.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -79,14 +79,14 @@ export function useMenuTrigger(props: MenuTriggerAriaProps, state: MenuTriggerSt
7979
id: menuTriggerId,
8080
onPressStart(e) {
8181
// For consistency with native, open the menu on mouse/key down, but touch up.
82-
if (e.pointerType !== 'touch' && e.pointerType !== 'keyboard') {
82+
if (e.pointerType !== 'touch' && e.pointerType !== 'keyboard' && !isDisabled) {
8383
// If opened with a screen reader, auto focus the first item.
8484
// Otherwise, the menu itself will be focused.
8585
state.toggle(e.pointerType === 'virtual' ? 'first' : null);
8686
}
8787
},
8888
onPress(e) {
89-
if (e.pointerType === 'touch') {
89+
if (e.pointerType === 'touch' && !isDisabled) {
9090
state.toggle();
9191
}
9292
},

packages/@react-aria/menu/test/useMenuTrigger.test.js

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,4 +83,16 @@ describe('useMenuTrigger', function () {
8383
expect(setFocusStrategy).toHaveBeenCalledTimes(1);
8484
expect(setFocusStrategy).toHaveBeenCalledWith(null);
8585
});
86+
87+
it('doesn\'t toggle the menu if isDisabled', function () {
88+
let {menuTriggerProps} = renderMenuTriggerHook({isDisabled: true}, state);
89+
expect(typeof menuTriggerProps.onPressStart).toBe('function');
90+
menuTriggerProps.onPressStart({pointerType: 'mouse'});
91+
expect(setOpen).toHaveBeenCalledTimes(0);
92+
expect(setFocusStrategy).toHaveBeenCalledTimes(0);
93+
94+
menuTriggerProps.onPress({pointerType: 'touch'});
95+
expect(setOpen).toHaveBeenCalledTimes(0);
96+
expect(setFocusStrategy).toHaveBeenCalledTimes(0);
97+
});
8698
});

packages/@react-spectrum/combobox/src/ComboBox.tsx

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -217,7 +217,6 @@ const ComboBoxInput = React.forwardRef(function ComboBoxInput(props: ComboBoxInp
217217
let {
218218
isQuiet,
219219
isDisabled,
220-
isReadOnly,
221220
validationState,
222221
inputProps,
223222
inputRef,
@@ -340,7 +339,6 @@ const ComboBoxInput = React.forwardRef(function ComboBoxInput(props: ComboBoxInp
340339
'spectrum-FieldButton'
341340
)
342341
}
343-
isDisabled={isDisabled || isReadOnly}
344342
isQuiet={isQuiet}
345343
validationState={validationState}>
346344
<ChevronDownMedium UNSAFE_className={classNames(styles, 'spectrum-Dropdown-chevron')} />

0 commit comments

Comments
 (0)