Skip to content

Commit

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

* fix: cursor following review

Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
  • Loading branch information
lee-chase and kodiakhq[bot] committed Nov 15, 2022
1 parent 6d9f602 commit 31a69e2
Show file tree
Hide file tree
Showing 3 changed files with 118 additions and 6 deletions.
21 changes: 15 additions & 6 deletions packages/react/src/components/Slider/Slider.js
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,11 @@ export default class Slider extends PureComponent {
*/
onRelease: PropTypes.func,

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

/**
* `true` to specify if the control is required.
*/
Expand Down Expand Up @@ -176,6 +181,7 @@ export default class Slider extends PureComponent {
ariaLabelInput: FeatureFlags.enabled('enable-v11-release')
? undefined
: 'Slider number input',
readOnly: false,
};

static contextType = FeatureFlagContext;
Expand Down Expand Up @@ -267,7 +273,7 @@ export default class Slider extends PureComponent {
*/
onDragStart = (evt) => {
// Do nothing if component is disabled
if (this.props.disabled) {
if (this.props.disabled || this.props.readOnly) {
return;
}

Expand All @@ -292,7 +298,7 @@ export default class Slider extends PureComponent {
*/
onDragStop = () => {
// Do nothing if component is disabled
if (this.props.disabled) {
if (this.props.disabled || this.props.readOnly) {
return;
}

Expand All @@ -318,7 +324,7 @@ export default class Slider extends PureComponent {
*/
_onDrag = (evt) => {
// Do nothing if component is disabled or we have no event
if (this.props.disabled || !evt) {
if (this.props.disabled || this.props.readOnly || !evt) {
return;
}

Expand Down Expand Up @@ -357,7 +363,7 @@ export default class Slider extends PureComponent {
*/
onKeyDown = (evt) => {
// Do nothing if component is disabled or we don't have a valid event
if (this.props.disabled || !('which' in evt)) {
if (this.props.disabled || this.props.readOnly || !('which' in evt)) {
return;
}

Expand Down Expand Up @@ -401,7 +407,7 @@ export default class Slider extends PureComponent {

onChange = (evt) => {
// Do nothing if component is disabled
if (this.props.disabled) {
if (this.props.disabled || this.props.readOnly) {
return;
}

Expand Down Expand Up @@ -551,6 +557,7 @@ export default class Slider extends PureComponent {
disabled,
name,
light,
readOnly,
...other
} = this.props;

Expand All @@ -577,6 +584,7 @@ export default class Slider extends PureComponent {
const sliderClasses = classNames(
`${prefix}--slider`,
{ [`${prefix}--slider--disabled`]: disabled },
{ [`${prefix}--slider--readonly`]: readOnly },
[enabled ? null : className]
);

Expand Down Expand Up @@ -629,7 +637,7 @@ export default class Slider extends PureComponent {
className={`${prefix}--slider__thumb`}
role="slider"
id={id}
tabIndex={0}
tabIndex={!readOnly ? 0 : -1}
aria-valuemax={max}
aria-valuemin={min}
aria-valuenow={value}
Expand Down Expand Up @@ -669,6 +677,7 @@ export default class Slider extends PureComponent {
onKeyUp={this.onInputKeyUp}
data-invalid={isValid ? null : true}
aria-invalid={isValid ? null : true}
readOnly={readOnly}
/>
</div>
</div>
Expand Down
89 changes: 89 additions & 0 deletions packages/react/src/components/Slider/__tests__/Slider-test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
/**
* 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 Slider from '../Slider';
import userEvent from '@testing-library/user-event';
import { render, screen } from '@testing-library/react';

describe('Slider', () => {
describe('behaves as expected - Component API', () => {
it('should respect work normally when not readonly prop', () => {
const onChange = jest.fn();
const onClick = jest.fn();

render(
<Slider
id="Slider-1"
className="extra-class"
label="Slider label"
onClick={onClick}
onChange={onChange}
value={1}
min={1}
max={3}
step={1}
/>
);

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

userEvent.type(theSlider, '{arrowright}');

expect(onChange).toHaveBeenCalledTimes(1);
expect(onChange).toHaveBeenCalledWith(
expect.objectContaining({
value: 2,
})
);

const theInput = screen.getByRole('spinbutton');
userEvent.type(theInput, '{selectall}3');
expect(onChange).toHaveBeenCalledTimes(2);
expect(onChange).toHaveBeenCalledWith(
expect.objectContaining({
value: 3,
})
);
});

it('should respect readOnly prop', () => {
const onChange = jest.fn();
const onClick = jest.fn();

render(
<Slider
id="Slider-1"
className="extra-class"
label="Slider label"
readOnly={true}
onClick={onClick}
onChange={onChange}
value={1}
min={1}
max={3}
step={1}
/>
);

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

userEvent.type(theSlider, '{arrowright}');

const theInput = screen.getByRole('spinbutton');
userEvent.type(theInput, '{selectall}3');

expect(onChange).toHaveBeenCalledTimes(0);
});
});
});
14 changes: 14 additions & 0 deletions packages/styles/scss/components/slider/_slider.scss
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,20 @@
}
}

// readonly state
.#{$prefix}--slider--readonly {
cursor: default;
}

.#{$prefix}--slider--readonly .#{$prefix}--slider__thumb {
width: 0;
height: 0;
}

.#{$prefix}--slider--readonly ~ .#{$prefix}--slider-text-input {
background-color: transparent;
}

// Skeleton state
.#{$prefix}--slider-container.#{$prefix}--skeleton
.#{$prefix}--slider__range-label {
Expand Down

0 comments on commit 31a69e2

Please sign in to comment.