Skip to content

Commit caa8ed6

Browse files
Sebastian review
Co-Authored-By: Sebastian Silbermann <[email protected]>
1 parent db43f47 commit caa8ed6

File tree

11 files changed

+79
-30
lines changed

11 files changed

+79
-30
lines changed

docs/src/pages/components/slider/ContinuousSlider.js

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,11 @@ const useStyles = makeStyles({
1414

1515
export default function ContinuousSlider() {
1616
const classes = useStyles();
17+
const [value, setValue] = React.useState(30);
18+
19+
const handleChange = (event, newValue) => {
20+
setValue(newValue);
21+
};
1722

1823
return (
1924
<div className={classes.root}>
@@ -25,7 +30,7 @@ export default function ContinuousSlider() {
2530
<VolumeDown />
2631
</Grid>
2732
<Grid item xs>
28-
<Slider defaultValue={30} aria-labelledby="continuous-slider" />
33+
<Slider value={value} onChange={handleChange} aria-labelledby="continuous-slider" />
2934
</Grid>
3035
<Grid item>
3136
<VolumeUp />

docs/src/pages/components/slider/ContinuousSlider.tsx

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,11 @@ const useStyles = makeStyles({
1414

1515
export default function ContinuousSlider() {
1616
const classes = useStyles();
17+
const [value, setValue] = React.useState<number | number[]>(30);
18+
19+
const handleChange = (event: any, newValue: number | number[]) => {
20+
setValue(newValue);
21+
};
1722

1823
return (
1924
<div className={classes.root}>
@@ -25,7 +30,7 @@ export default function ContinuousSlider() {
2530
<VolumeDown />
2631
</Grid>
2732
<Grid item xs>
28-
<Slider defaultValue={30} aria-labelledby="continuous-slider" />
33+
<Slider value={value} onChange={handleChange} aria-labelledby="continuous-slider" />
2934
</Grid>
3035
<Grid item>
3136
<VolumeUp />

docs/src/pages/components/slider/CustomizedSlider.js

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -78,14 +78,15 @@ const IOSSlider = withStyles({
7878
boxShadow: iOSBoxShadow,
7979
marginTop: -14,
8080
marginLeft: -14,
81-
'&:focus,&:hover': {
81+
'&:focus,&:hover,&$active': {
8282
boxShadow: '0 3px 1px rgba(0,0,0,0.1),0 4px 8px rgba(0,0,0,0.3),0 0 0 1px rgba(0,0,0,0.02)',
8383
// Reset on touch devices, it doesn't add specificity
8484
'@media (hover: none)': {
8585
boxShadow: iOSBoxShadow,
8686
},
8787
},
8888
},
89+
active: {},
8990
valueLabel: {
9091
left: 'calc(-50% + 11px)',
9192
top: -22,
@@ -125,10 +126,11 @@ const PrettoSlider = withStyles({
125126
border: '2px solid currentColor',
126127
marginTop: -8,
127128
marginLeft: -12,
128-
'&:focus,&:hover': {
129+
'&:focus,&:hover,&$active': {
129130
boxShadow: 'inherit',
130131
},
131132
},
133+
active: {},
132134
valueLabel: {
133135
left: 'calc(-50% + 4px)',
134136
},
@@ -156,7 +158,7 @@ const AirbnbSlider = withStyles({
156158
marginTop: -12,
157159
marginLeft: -13,
158160
boxShadow: '#ebebeb 0px 2px 2px',
159-
'&:focus,&:hover': {
161+
'&:focus,&:hover,&$active': {
160162
boxShadow: '#ccc 0px 2px 3px 1px',
161163
},
162164
'& .bar': {
@@ -168,6 +170,7 @@ const AirbnbSlider = withStyles({
168170
marginRight: 1,
169171
},
170172
},
173+
active: {},
171174
valueLabel: {
172175
left: 'calc(-50% + 4px)',
173176
},

docs/src/pages/components/slider/CustomizedSlider.tsx

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -87,14 +87,15 @@ const IOSSlider = withStyles({
8787
boxShadow: iOSBoxShadow,
8888
marginTop: -14,
8989
marginLeft: -14,
90-
'&:focus,&:hover': {
90+
'&:focus,&:hover,&$active': {
9191
boxShadow: '0 3px 1px rgba(0,0,0,0.1),0 4px 8px rgba(0,0,0,0.3),0 0 0 1px rgba(0,0,0,0.02)',
9292
// Reset on touch devices, it doesn't add specificity
9393
'@media (hover: none)': {
9494
boxShadow: iOSBoxShadow,
9595
},
9696
},
9797
},
98+
active: {},
9899
valueLabel: {
99100
left: 'calc(-50% + 11px)',
100101
top: -22,
@@ -134,10 +135,11 @@ const PrettoSlider = withStyles({
134135
border: '2px solid currentColor',
135136
marginTop: -8,
136137
marginLeft: -12,
137-
'&:focus,&:hover': {
138+
'&:focus,&:hover,&$active': {
138139
boxShadow: 'inherit',
139140
},
140141
},
142+
active: {},
141143
valueLabel: {
142144
left: 'calc(-50% + 4px)',
143145
},
@@ -165,7 +167,7 @@ const AirbnbSlider = withStyles({
165167
marginTop: -12,
166168
marginLeft: -13,
167169
boxShadow: '#ebebeb 0px 2px 2px',
168-
'&:focus,&:hover': {
170+
'&:focus,&:hover,&$active': {
169171
boxShadow: '#ccc 0px 2px 3px 1px',
170172
},
171173
'& .bar': {
@@ -177,6 +179,7 @@ const AirbnbSlider = withStyles({
177179
marginRight: 1,
178180
},
179181
},
182+
active: {},
180183
valueLabel: {
181184
left: 'calc(-50% + 4px)',
182185
},

docs/src/pages/components/slider/RangeSlider.js

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,14 +15,20 @@ function valuetext(value) {
1515

1616
export default function RangeSlider() {
1717
const classes = useStyles();
18+
const [value, setValue] = React.useState([20, 37]);
19+
20+
const handleChange = (event, newValue) => {
21+
setValue(newValue);
22+
};
1823

1924
return (
2025
<div className={classes.root}>
2126
<Typography id="range-slider" gutterBottom>
2227
Temperature range
2328
</Typography>
2429
<Slider
25-
defaultValue={[20, 37]}
30+
value={value}
31+
onChange={handleChange}
2632
valueLabelDisplay="auto"
2733
aria-labelledby="range-slider"
2834
getAriaValueText={valuetext}

docs/src/pages/components/slider/RangeSlider.tsx

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,14 +16,20 @@ function valuetext(value: number) {
1616

1717
export default function RangeSlider() {
1818
const classes = useStyles();
19+
const [value, setValue] = React.useState<number | number[]>([20, 37]);
20+
21+
const handleChange = (event: any, newValue: number | number[]) => {
22+
setValue(newValue);
23+
};
1924

2025
return (
2126
<div className={classes.root}>
2227
<Typography id="range-slider" gutterBottom>
2328
Temperature range
2429
</Typography>
2530
<Slider
26-
defaultValue={[20, 37]}
31+
value={value}
32+
onChange={handleChange}
2733
valueLabelDisplay="auto"
2834
aria-labelledby="range-slider"
2935
getAriaValueText={valuetext}

docs/src/pages/components/slider/slider.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,4 +53,6 @@ The component handles most of the work necessary to make it accessible.
5353
However, you need to make sure that:
5454

5555
- The slider, as a whole, has a label (`aria-label` or `aria-labelledby` prop).
56-
- Each thumb has its current value labeled correctly (`getAriaValueText` or `aria-valuetext` prop).
56+
- Each thumb has a user-friendly name for its current value.
57+
This is not required if the value matches the semantics of the label.
58+
You can change the name with the `getAriaValueText` or `aria-valuetext` prop.

packages/material-ui-lab/src/Slider/Slider.js

Lines changed: 27 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import React from 'react';
44
import PropTypes from 'prop-types';
55
import clsx from 'clsx';
66
import { useTheme, withStyles, fade, lighten } from '@material-ui/core/styles';
7-
import { useForkRef, ownerWindow } from '@material-ui/core/utils';
7+
import { useForkRef, ownerWindow, useIsFocusVisible } from '@material-ui/core/utils';
88
import { chainPropTypes } from '@material-ui/utils';
99
import ValueLabel from './ValueLabel';
1010

@@ -163,9 +163,9 @@ export const styles = theme => ({
163163
marginRight: 20,
164164
},
165165
},
166-
/* Styles applied to the root element if `orientation="vertical"`. */
166+
/* Pseudo-class applied to the root element if `orientation="vertical"`. */
167167
vertical: {},
168-
/* Styles applied to the root element if `disabled={true}`. */
168+
/* Pseudo-class applied to the root element if `disabled={true}`. */
169169
disabled: {},
170170
/* Styles applied to the rail element. */
171171
rail: {
@@ -174,7 +174,7 @@ export const styles = theme => ({
174174
height: 2,
175175
borderRadius: 1,
176176
backgroundColor: 'currentColor',
177-
opacity: 0.24,
177+
opacity: 0.38,
178178
'$vertical &': {
179179
height: '100%',
180180
width: 2,
@@ -207,8 +207,11 @@ export const styles = theme => ({
207207
transition: theme.transitions.create(['box-shadow'], {
208208
duration: theme.transitions.duration.shortest,
209209
}),
210-
'&:focus,&:hover': {
210+
'&$focusVisible,&:hover': {
211211
boxShadow: `0px 0px 0px 8px ${fade(theme.palette.primary.main, 0.16)}`,
212+
'@media (hover: none)': {
213+
boxShadow: 'none',
214+
},
212215
},
213216
'&$active': {
214217
boxShadow: `0px 0px 0px 14px ${fade(theme.palette.primary.main, 0.16)}`,
@@ -219,7 +222,7 @@ export const styles = theme => ({
219222
height: 8,
220223
marginLeft: -4,
221224
marginTop: -3,
222-
'&:focus,&:hover': {
225+
'&:hover': {
223226
boxShadow: 'none',
224227
},
225228
},
@@ -232,8 +235,10 @@ export const styles = theme => ({
232235
marginBottom: -4,
233236
},
234237
},
235-
/* Styles applied to the thumb element if it's active. */
238+
/* Pseudo-class applied to the thumb element if it's active. */
236239
active: {},
240+
/* Pseudo-class applied to the thumb element if keyboard focused. */
241+
focusVisible: {},
237242
/* Styles applied to the thumb label element. */
238243
valueLabel: {},
239244
/* Styles applied to the mark element. */
@@ -320,11 +325,21 @@ const Slider = React.forwardRef(function Slider(props, ref) {
320325
source: valueDerived, // Keep track of the input value to leverage immutable state comparison.
321326
};
322327

328+
const { isFocusVisible, onBlurVisible, ref: focusVisibleRef } = useIsFocusVisible();
329+
const [focusVisible, setFocusVisible] = React.useState(-1);
330+
323331
const handleFocus = useEventCallback(event => {
324332
const index = Number(event.currentTarget.getAttribute('data-index'));
333+
if (isFocusVisible(event)) {
334+
setFocusVisible(index);
335+
}
325336
setOpen(index);
326337
});
327338
const handleBlur = useEventCallback(() => {
339+
if (focusVisible !== -1) {
340+
setFocusVisible(-1);
341+
onBlurVisible();
342+
}
328343
setOpen(-1);
329344
});
330345
const handleMouseOver = useEventCallback(event => {
@@ -412,7 +427,8 @@ const Slider = React.forwardRef(function Slider(props, ref) {
412427
});
413428

414429
const sliderRef = React.useRef();
415-
const handleRef = useForkRef(sliderRef, ref);
430+
const handleFocusRef = useForkRef(focusVisibleRef, sliderRef);
431+
const handleRef = useForkRef(ref, handleFocusRef);
416432
const previousIndex = React.useRef();
417433
let axis = orientation;
418434
if (theme.direction === 'rtl' && orientation === 'horizontal') {
@@ -663,6 +679,7 @@ const Slider = React.forwardRef(function Slider(props, ref) {
663679
<ThumbComponent
664680
className={clsx(classes.thumb, {
665681
[classes.active]: active === index,
682+
[classes.focusVisible]: focusVisible === index,
666683
})}
667684
tabIndex={disabled ? null : 0}
668685
role="slider"
@@ -690,11 +707,11 @@ const Slider = React.forwardRef(function Slider(props, ref) {
690707

691708
Slider.propTypes = {
692709
/**
693-
* An alternative to `aria-labelledby`.
710+
* The label of the slider.
694711
*/
695712
'aria-label': PropTypes.string,
696713
/**
697-
* Refers to the element containing the name of the slider.
714+
* The id of the element containing a label for the slider.
698715
*/
699716
'aria-labelledby': PropTypes.string,
700717
/**

packages/material-ui/src/utils/focusVisible.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ function handleVisibilityChange() {
7575
}
7676
}
7777

78-
export function prepare(ownerDocument) {
78+
function prepare(ownerDocument) {
7979
ownerDocument.addEventListener('keydown', handleKeyDown, true);
8080
ownerDocument.addEventListener('mousedown', handlePointerDown, true);
8181
ownerDocument.addEventListener('pointerdown', handlePointerDown, true);
@@ -91,7 +91,7 @@ export function teardown(ownerDocument) {
9191
ownerDocument.removeEventListener('visibilitychange', handleVisibilityChange, true);
9292
}
9393

94-
export function isFocusVisible(event) {
94+
function isFocusVisible(event) {
9595
const { target } = event;
9696
try {
9797
return target.matches(':focus-visible');
@@ -110,7 +110,7 @@ export function isFocusVisible(event) {
110110
/**
111111
* Should be called if a blur event is fired on a focus-visible element
112112
*/
113-
export function handleBlurVisible() {
113+
function handleBlurVisible() {
114114
// To detect a tab/window switch, we look for a blur event followed
115115
// rapidly by a visibility change.
116116
// If we don't see a visibility change within 100ms, it's probably a
Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
export { default as deprecatedPropType } from './deprecatedPropType';
22
export * from './helpers';
33
export * from './reactHelpers';
4-
export { default as requirePropFactory } from './requirePropFactory';
4+
export { useIsFocusVisible } from './focusVisible';
55
export { default as ownerDocument } from './ownerDocument';
66
export { default as ownerWindow } from './ownerWindow';
7+
export { default as requirePropFactory } from './requirePropFactory';
78
export { default as unsupportedProp } from './unsupportedProp';
89
export { default as withForwardedRef } from './withForwardedRef';

0 commit comments

Comments
 (0)