Skip to content

Commit

Permalink
feat: add readonly functionality to select (#12405)
Browse files Browse the repository at this point in the history
* feat: add readonly functionality to select

* feat: add readonly functionality to select

* chore: remove unnecessary scss vars

* fix: cursor following review

Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
  • Loading branch information
lee-chase and kodiakhq[bot] authored Nov 14, 2022
1 parent baa7fd5 commit 99db21a
Show file tree
Hide file tree
Showing 4 changed files with 93 additions and 0 deletions.
3 changes: 3 additions & 0 deletions packages/react/__tests__/__snapshots__/PublicAPI-test.js.snap
Original file line number Diff line number Diff line change
Expand Up @@ -6169,6 +6169,9 @@ Map {
"onChange": Object {
"type": "func",
},
"readOnly": Object {
"type": "bool",
},
"size": Object {
"args": Array [
Array [
Expand Down
27 changes: 27 additions & 0 deletions packages/react/src/components/Select/Select.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ const Select = React.forwardRef(function Select(
invalidText,
helperText,
light = false,
readOnly,
size,
warn = false,
warnText,
Expand All @@ -53,6 +54,7 @@ const Select = React.forwardRef(function Select(
[`${prefix}--select--light`]: light,
[`${prefix}--select--invalid`]: invalid,
[`${prefix}--select--disabled`]: disabled,
[`${prefix}--select--readonly`]: readOnly,
[`${prefix}--select--warning`]: warn,
[`${prefix}--select--fluid--invalid`]: isFluid && invalid,
[`${prefix}--select--fluid--focus`]: isFluid && isFocused,
Expand Down Expand Up @@ -97,6 +99,24 @@ const Select = React.forwardRef(function Select(
setIsFocused(evt.type === 'focus' ? true : false);
};

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

const input = (() => {
return (
<>
Expand All @@ -107,6 +127,8 @@ const Select = React.forwardRef(function Select(
className={inputClasses}
disabled={disabled || undefined}
aria-invalid={invalid || undefined}
aria-readonly={readOnly || undefined}
{...readOnlyEventHandlers}
ref={ref}>
{children}
</select>
Expand Down Expand Up @@ -242,6 +264,11 @@ Select.propTypes = {
*/
onChange: PropTypes.func,

/**
* Whether the select should be read-only
*/
readOnly: PropTypes.bool,

/**
* Specify the size of the Select Input.
*/
Expand Down
53 changes: 53 additions & 0 deletions packages/react/src/components/Select/__tests__/Select-test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
/**
* Copyright IBM Corp. 2016, 2018
*
* This source code is licensed under the Apache-2.0 license found in the
* LICENSE file in the root directory of this source tree.
*/

import React from 'react';
import Select from '../Select';
import SelectItem from '../../SelectItem';
import userEvent from '@testing-library/user-event';
import { render, screen } from '@testing-library/react';

describe('Select', () => {
describe('behaves as expected - Component API', () => {
it.skip('should respect readOnly prop', () => {
const onChange = jest.fn();
const onClick = jest.fn();

render(
<Select
id="select-1"
label="Select label"
readOnly={true}
onClick={onClick}
onChange={onChange}>
<SelectItem text="Choose an option" value="placeholder-item" />
<SelectItem text="Option 1" value="option-1" />
<SelectItem text="Option 2" value="option-2" />
</Select>
);

// Click events should fire
const theSelect = screen.getByRole('combobox');
userEvent.click(theSelect);
expect(onClick).toHaveBeenCalledTimes(1);

//------------------------------------------------------------------------
// Testing library - userEvent.type() does not work on <select> elements
// and using selectOption causes the value to change.
// Ideally we'd use userEvent.type(theSelect, '{arrowdown}{enter}') to test the readOnly prop
// or have a way to click on a slotted option.
// https://github.com/testing-library/user-event/issues/786
//------------------------------------------------------------------------
userEvent.selectOptions(theSelect, 'option-1');

// Change events should *not* fire
expect(screen.getByText('Option 1').selected).toBe(false);

expect(onChange).toHaveBeenCalledTimes(0);
});
});
});
10 changes: 10 additions & 0 deletions packages/styles/scss/components/select/_select.scss
Original file line number Diff line number Diff line change
Expand Up @@ -252,6 +252,16 @@
}
}

// readonly
.#{$prefix}--select--readonly .#{$prefix}--select-input {
background-color: transparent;
cursor: default;
}

.#{$prefix}--select--readonly .#{$prefix}--select__arrow {
fill: $icon-disabled;
}

//Skeleton State
.#{$prefix}--select.#{$prefix}--skeleton {
@include skeleton;
Expand Down

0 comments on commit 99db21a

Please sign in to comment.