Skip to content

Commit 601da3a

Browse files
Yihui Liaoyihuiliaoktabors
authored andcommitted
Slider follow-up from testing (#176)
* slider follow-up from testing * add thumbStyle * pull shared styling out * use size * add size to more places * fix l sizing --------- Co-authored-by: Yihui Liao <[email protected]> Co-authored-by: Kyle Taborski <[email protected]>
1 parent ad7e38e commit 601da3a

File tree

3 files changed

+123
-93
lines changed

3 files changed

+123
-93
lines changed

packages/@react-spectrum/s2/src/RangeSlider.tsx

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,9 @@ import {FormContext, useFormProps} from './Form';
2424
import {pressScale} from './pressScale';
2525

2626
export interface RangeSliderProps<T> extends Omit<SliderProps<T>, 'fillOffset' | 'thumbLabel'> {
27+
/**
28+
* The label for each of the Slider's thumbs.
29+
*/
2730
thumbLabels?: string[]
2831
}
2932

@@ -35,8 +38,8 @@ function RangeSlider<T extends number | number[]>(props: RangeSliderProps<T>, re
3538
labelPosition = 'top',
3639
size = 'M',
3740
isEmphasized,
38-
isThick,
39-
isPrecise
41+
trackStyle = 'thin',
42+
thumbStyle = 'default'
4043
} = props;
4144
let lowerThumbRef = useRef(null);
4245
let upperThumbRef = useRef(null);
@@ -54,16 +57,16 @@ function RangeSlider<T extends number | number[]>(props: RangeSliderProps<T>, re
5457
className={track({size, labelPosition, isInForm: !!formContext})}>
5558
{({state, isDisabled}) => (
5659
<>
57-
<div className={upperTrack({isDisabled, isThick})} />
58-
<div style={{width: `${Math.abs(state.getThumbPercent(0) - state.getThumbPercent(1)) * 100}%`, [cssDirection]: `${state.getThumbPercent(0) * 100}%`}} className={filledTrack({isDisabled, isEmphasized, isThick})} />
60+
<div className={upperTrack({isDisabled, trackStyle})} />
61+
<div style={{width: `${Math.abs(state.getThumbPercent(0) - state.getThumbPercent(1)) * 100}%`, [cssDirection]: `${state.getThumbPercent(0) * 100}%`}} className={filledTrack({isDisabled, isEmphasized, trackStyle})} />
5962
<SliderThumb className={thumbContainer} index={0} aria-label={thumbLabels?.[0]} ref={lowerThumbRef} style={(renderProps) => pressScale(lowerThumbRef, {transform: 'translate(-50%, -50%)', zIndex: state.getThumbPercent(0) === 1 ? 1 : undefined})({...renderProps, isPressed: renderProps.isDragging})}>
6063
{(renderProps) => (
6164
<div className={thumbHitArea({size})}>
6265
<div
6366
className={thumb({
6467
...renderProps,
6568
size,
66-
isPrecise
69+
thumbStyle
6770
})} />
6871
</div>
6972
)}
@@ -75,7 +78,7 @@ function RangeSlider<T extends number | number[]>(props: RangeSliderProps<T>, re
7578
className={thumb({
7679
...renderProps,
7780
size,
78-
isPrecise
81+
thumbStyle
7982
})} />
8083
</div>
8184
)}

packages/@react-spectrum/s2/src/Slider.tsx

Lines changed: 113 additions & 86 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,8 @@ import {FormContext, useFormProps} from './Form';
2222
import {ReactNode, useRef, forwardRef, RefObject, useContext} from 'react';
2323
import {FocusableRef, LabelPosition, InputDOMProps, Alignment} from '@react-types/shared';
2424
import {useFocusableRef} from '@react-spectrum/utils';
25-
import {style} from '../style/spectrum-theme' with {type: 'macro'};
26-
import {StyleProps, focusRing, field, getAllowedOverrides} from './style-utils' with {type: 'macro'};
25+
import {style, size} from '../style/spectrum-theme' with {type: 'macro'};
26+
import {StyleProps, focusRing, field, fieldInput, getAllowedOverrides} from './style-utils' with {type: 'macro'};
2727
import {forwardRefType} from './types';
2828
import {useNumberFormatter, useLocale} from '@react-aria/i18n';
2929
import {clamp} from '@react-aria/utils';
@@ -38,19 +38,55 @@ export interface SliderBaseProps<T> extends Omit<AriaSliderProps<T>, 'children'>
3838
labelPosition?: LabelPosition
3939
}
4040

41-
export interface SliderProps<T> extends AriaSliderProps<T>, StyleProps {
41+
export interface SliderProps<T> extends Omit<AriaSliderProps<T>, 'style' | 'className' | 'orientation'>, StyleProps {
42+
/**
43+
* The content to display as the label.
44+
*/
4245
label?: ReactNode,
46+
/**
47+
* The label for the Slider's thumb.
48+
*/
4349
thumbLabel?: string,
44-
labelAlign?: Alignment,
50+
/**
51+
* The size of the Slider.
52+
*
53+
* @default 'M'
54+
*/
4555
size?: 'S' | 'M' | 'L' | 'XL',
56+
/**
57+
* The label's horizontal alignment relative to the element it is labeling.
58+
*
59+
* @default 'start'
60+
*/
61+
labelAlign?: Alignment,
62+
/**
63+
* The label's overall position relative to the element it is labeling.
64+
*
65+
* @default 'top'
66+
*/
4667
labelPosition?: LabelPosition,
68+
/**
69+
* The offset from which to start the fill.
70+
*/
4771
fillOffset?: number,
72+
/**
73+
* Whether the Slider should be displayed with an emphasized style.
74+
*/
4875
isEmphasized?: boolean,
49-
isThick?: boolean,
50-
isPrecise?: boolean
76+
/**
77+
* The style of the Slider's track.
78+
*
79+
* @default 'thin'
80+
*/
81+
trackStyle?: 'thin' | 'thick', // TODO: add ramp
82+
/**
83+
* The style of the Slider's thumb.
84+
*
85+
* @default 'default'
86+
*/
87+
thumbStyle?: 'default' | 'precise'
5188
// TODO
5289
// isEditable?: boolean
53-
// isRamp?: boolean
5490
}
5591

5692
const slider = style({
@@ -65,17 +101,6 @@ const slider = style({
65101
default: 'neutral-subdued',
66102
isDisabled: 'disabled'
67103
},
68-
width: {
69-
default: {
70-
size: {
71-
S: 192,
72-
M: 208,
73-
L: 224,
74-
XL: 240
75-
}
76-
},
77-
isInForm: 'auto'
78-
},
79104
columnGap: {
80105
size: {
81106
S: 16,
@@ -137,9 +162,9 @@ const output = style({
137162
});
138163

139164
export let track = style({
165+
...fieldInput(),
140166
gridArea: 'track',
141167
position: 'relative',
142-
minWidth: 112, // an arbitrary number, no tokens for minwidth, can adjust if needed
143168
width: 'full',
144169
height: {
145170
size: {
@@ -151,13 +176,12 @@ export let track = style({
151176
}
152177
});
153178

154-
155179
export let thumbContainer = style({
156180
size: {
157181
size: {
158-
S: '[18px]',
182+
S: size(18),
159183
M: 20,
160-
L: '[22px]',
184+
L: size(22),
161185
XL: 24
162186
}
163187
},
@@ -169,20 +193,22 @@ export let thumbContainer = style({
169193
// if precision thumb should have a smaller hit area, then remove this
170194
export let thumbHitArea = style({
171195
size: {
172-
default: {
173-
size: {
174-
S: '[18px]',
175-
M: 20,
176-
L: '[22px]',
177-
XL: 24
178-
}
179-
},
180-
isPrecise: {
181-
size: {
182-
S: 20,
183-
M: '[22px]',
184-
L: 24,
185-
XL: '[26px]'
196+
thumbStyle: {
197+
default: {
198+
size: {
199+
S: size(18),
200+
M: 20,
201+
L: size(22),
202+
XL: 24
203+
}
204+
},
205+
precise: {
206+
size: {
207+
S: 20,
208+
M: size(22),
209+
L: 24,
210+
XL: size(26)
211+
}
186212
}
187213
}
188214
}
@@ -197,40 +223,41 @@ export let thumb = style({
197223
left: '[50%]',
198224
transform: 'translateY(-50%) translateX(-50%)',
199225
width: {
200-
default: {
201-
size: {
202-
S: '[18px]',
203-
M: 20,
204-
L: '[22px]',
205-
XL: 24
206-
}
207-
},
208-
isPrecise: '[6px]'
226+
thumbStyle: {
227+
default: {
228+
size: {
229+
S: size(18),
230+
M: 20,
231+
L: size(22),
232+
XL: 24
233+
}
234+
},
235+
precise: size(6)
236+
}
209237
},
210238
height: {
211-
default: {
212-
size: {
213-
S: '[18px]',
214-
M: 20,
215-
L: '[22px]',
216-
XL: 24
217-
}
218-
},
219-
isPrecise: {
220-
size: {
221-
S: 20,
222-
M: '[22px]',
223-
L: 24,
224-
XL: '[26px]'
239+
thumbStyle: {
240+
default: {
241+
size: {
242+
S: size(18),
243+
M: 20,
244+
L: size(22),
245+
XL: 24
246+
}
247+
},
248+
precise: {
249+
size: {
250+
S: 20,
251+
M: size(22),
252+
L: 24,
253+
XL: size(26)
254+
}
225255
}
226256
}
227257
},
228258
borderRadius: 'full',
229259
borderStyle: 'solid',
230-
borderWidth: {
231-
default: '[2px]',
232-
isPrecise: '[2px]'
233-
},
260+
borderWidth: '[2px]',
234261
borderColor: {
235262
default: 'gray-800',
236263
isHovered: 'gray-900',
@@ -243,21 +270,29 @@ export let thumb = style({
243270
backgroundColor: 'gray-25'
244271
});
245272

273+
const trackStyling = {
274+
height: {
275+
trackStyle: {
276+
thin: 4,
277+
thick: 16
278+
}
279+
},
280+
top: '[50%]',
281+
borderRadius: {
282+
trackStyle: {
283+
thin: 'lg',
284+
thick: 'sm'
285+
}
286+
}
287+
} as const;
288+
246289
export let upperTrack = style({
290+
...trackStyling,
247291
position: 'absolute',
248292
backgroundColor: {
249293
default: 'gray-300',
250294
isDisabled: 'disabled'
251295
},
252-
height: {
253-
default: 4,
254-
isThick: 16
255-
},
256-
top: '[50%]',
257-
borderRadius: {
258-
default: 'lg',
259-
isThick: 'sm'
260-
},
261296
translateY: '[-50%]',
262297
width: 'full',
263298
boxSizing: 'border-box',
@@ -273,6 +308,7 @@ export let upperTrack = style({
273308
});
274309

275310
export let filledTrack = style({
311+
...trackStyling,
276312
position: 'absolute',
277313
backgroundColor: {
278314
default: 'gray-700',
@@ -283,15 +319,6 @@ export let filledTrack = style({
283319
isDisabled: 'GrayText'
284320
}
285321
},
286-
height: {
287-
default: 4,
288-
isThick: 16
289-
},
290-
top: '[50%]',
291-
borderRadius: {
292-
default: 'lg',
293-
isThick: 'sm'
294-
},
295322
boxSizing: 'border-box',
296323
borderStyle: 'solid',
297324
borderWidth: '[.5px]',
@@ -382,8 +409,8 @@ function Slider<T extends number | number[]>(props: SliderProps<T>, ref: Focusab
382409
size = 'M',
383410
fillOffset,
384411
isEmphasized,
385-
isThick,
386-
isPrecise
412+
trackStyle = 'thin',
413+
thumbStyle = 'default'
387414
} = props;
388415
let thumbRef = useRef(null);
389416
let inputRef = useRef(null); // TODO: need to pass inputRef to SliderThumb when we release the next version of RAC 1.3.0
@@ -411,16 +438,16 @@ function Slider<T extends number | number[]>(props: SliderProps<T>, ref: Focusab
411438

412439
return (
413440
<>
414-
<div className={upperTrack({isDisabled, isThick})} />
415-
<div style={{width: `${Math.abs(fillWidth!) * 100}%`, [cssDirection]: `${offset! * 100}%`}} className={filledTrack({isDisabled, isEmphasized, isThick})} />
441+
<div className={upperTrack({isDisabled, trackStyle})} />
442+
<div style={{width: `${Math.abs(fillWidth!) * 100}%`, [cssDirection]: `${offset! * 100}%`}} className={filledTrack({isDisabled, isEmphasized, trackStyle})} />
416443
<SliderThumb className={thumbContainer} index={0} ref={thumbRef} aria-label={thumbLabel} style={(renderProps) => pressScale(thumbRef, {transform: 'translate(-50%, -50%)'})({...renderProps, isPressed: renderProps.isDragging})}>
417444
{(renderProps) => (
418445
<div className={thumbHitArea({size})}>
419446
<div
420447
className={thumb({
421448
...renderProps,
422449
size,
423-
isPrecise
450+
thumbStyle
424451
})} />
425452
</div>
426453
)}

packages/@react-spectrum/s2/stories/Form.stories.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,8 +45,8 @@ export const Example = (args: any) => (
4545
<TextArea label="Comment" name="comment" />
4646
<Switch>Wi-Fi</Switch>
4747
<Checkbox>I agree to the terms</Checkbox>
48-
<Button type="submit" variant="primary" styles={style({gridColumnStart: 'field', width: 'fit'})}>Submit</Button>
4948
<Slider label="Cookies" defaultValue={30} thumbLabel="cookie" />
5049
<RangeSlider label="Range" defaultValue={[30, 60]} thumbLabels={['start', 'end']} />
50+
<Button type="submit" variant="primary" styles={style({gridColumnStart: 'field', width: 'fit'})}>Submit</Button>
5151
</Form>
5252
);

0 commit comments

Comments
 (0)