Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add readonly dropdown #12430

Merged
merged 10 commits into from
Dec 2, 2022
Original file line number Diff line number Diff line change
Expand Up @@ -2757,6 +2757,9 @@ Map {
"onChange": Object {
"type": "func",
},
"readOnly": Object {
"type": "bool",
},
"renderSelectedItem": Object {
"type": "func",
},
Expand Down
13 changes: 13 additions & 0 deletions packages/react/src/components/Dropdown/Dropdown-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,19 @@ describe('Dropdown', () => {
});
});

it('should respect readOnly prop', () => {
render(<Dropdown {...mockProps} readOnly={true} />);
openMenu(); // menu should not open
assertMenuClosed();

openMenu(); // menu should not open
expect(screen.queryByText('Item 0')).toBeNull();
expect(mockProps.onChange).toHaveBeenCalledTimes(0);
assertMenuClosed();

mockProps.onChange.mockClear();
});

describe('should display initially selected item found in `initialSelectedItem`', () => {
it('using an object type for the `initialSelectedItem` prop', () => {
render(
Expand Down
28 changes: 27 additions & 1 deletion packages/react/src/components/Dropdown/Dropdown.js
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ const Dropdown = React.forwardRef(function Dropdown(
initialSelectedItem,
selectedItem: controlledSelectedItem,
downshiftProps,
readOnly,
...other
},
ref
Expand Down Expand Up @@ -102,6 +103,7 @@ const Dropdown = React.forwardRef(function Dropdown(
[`${prefix}--dropdown--inline`]: inline,
[`${prefix}--dropdown--disabled`]: disabled,
[`${prefix}--dropdown--light`]: light,
[`${prefix}--dropdown--readonly`]: readOnly,
[`${prefix}--dropdown--${size}`]: size,
[`${prefix}--list-box--up`]: direction === 'top',
}
Expand Down Expand Up @@ -152,6 +154,24 @@ const Dropdown = React.forwardRef(function Dropdown(
setIsFocused(evt.type === 'focus' ? true : false);
};

const readOnlyEventHandlers = readOnly
? {
onClick: (evt) => {
// NOTE: does not prevent click
evt.preventDefault();
// focus on the element as per readonly input behavior
evt.target.focus();
},
onKeyDown: (evt) => {
const selectAccessKeys = ['ArrowDown', 'ArrowUp', ' ', 'Enter'];
// This prevents the select from opening for the above keys
if (selectAccessKeys.includes(evt.key)) {
evt.preventDefault();
}
},
}
: {};

return (
<div className={wrapperClasses} {...other}>
{titleText && (
Expand Down Expand Up @@ -184,9 +204,10 @@ const Dropdown = React.forwardRef(function Dropdown(
type="button"
className={`${prefix}--list-box__field`}
disabled={disabled}
aria-disabled={disabled}
aria-disabled={readOnly ? true : undefined} // aria-disabled to remain focusable
title={selectedItem ? itemToString(selectedItem) : label}
{...toggleButtonProps}
{...readOnlyEventHandlers}
ref={mergeRefs(toggleButtonProps.ref, ref)}>
<span className={`${prefix}--list-box__label`}>
{selectedItem
Expand Down Expand Up @@ -341,6 +362,11 @@ Dropdown.propTypes = {
*/
onChange: PropTypes.func,

/**
* Whether or not the Dropdown is readonly
*/
readOnly: PropTypes.bool,

/**
* An optional callback to render the currently selected item as a react element instead of only
* as a string.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,9 @@ export default {
open: {
table: { disable: true },
},
readOnly: {
control: { type: 'boolean' },
},
title: {
table: { disable: true },
},
Expand Down
15 changes: 15 additions & 0 deletions packages/styles/scss/components/dropdown/_dropdown.scss
Original file line number Diff line number Diff line change
Expand Up @@ -473,4 +473,19 @@
.#{$prefix}--list-box__menu-item__selected-icon {
@include high-contrast-mode('icon-fill');
}

// readonly
.#{$prefix}--dropdown--readonly,
.#{$prefix}--dropdown--readonly:hover {
background-color: transparent;
}

.#{$prefix}--dropdown--readonly .#{$prefix}--list-box__field,
.#{$prefix}--dropdown--readonly .#{$prefix}--list-box__menu-icon {
cursor: default;
}

.#{$prefix}--dropdown--readonly .#{$prefix}--list-box__menu-icon svg {
fill: $icon-disabled;
}
}