mirror of
https://github.com/zhigang1992/react.git
synced 2026-04-28 12:15:32 +08:00
style(prettier): format code style
This commit is contained in:
@@ -5,12 +5,13 @@ import { nativeEvent, updateWrapper } from 'tests/utils'
|
||||
import { act } from 'react-dom/test-utils'
|
||||
|
||||
const triggerDrag = (el: HTMLElement, x = 0) => {
|
||||
window.Element.prototype.getBoundingClientRect = () => ({
|
||||
width: 100,
|
||||
left: 0,
|
||||
right: 100,
|
||||
x: 0,
|
||||
} as DOMRect)
|
||||
window.Element.prototype.getBoundingClientRect = () =>
|
||||
({
|
||||
width: 100,
|
||||
left: 0,
|
||||
right: 100,
|
||||
x: 0,
|
||||
} as DOMRect)
|
||||
const mousedown = new MouseEvent('mousedown')
|
||||
const mousemove = new MouseEvent('mousemove', {
|
||||
clientX: x,
|
||||
@@ -23,18 +24,19 @@ const triggerDrag = (el: HTMLElement, x = 0) => {
|
||||
|
||||
describe('Slider', () => {
|
||||
beforeAll(() => {
|
||||
window.Element.prototype.getBoundingClientRect = () => ({
|
||||
x: 0,
|
||||
y: 0,
|
||||
width: 100,
|
||||
height: 10,
|
||||
top: 0,
|
||||
bottom: 10,
|
||||
left: 0,
|
||||
right: 100,
|
||||
} as DOMRect)
|
||||
window.Element.prototype.getBoundingClientRect = () =>
|
||||
({
|
||||
x: 0,
|
||||
y: 0,
|
||||
width: 100,
|
||||
height: 10,
|
||||
top: 0,
|
||||
bottom: 10,
|
||||
left: 0,
|
||||
right: 100,
|
||||
} as DOMRect)
|
||||
})
|
||||
|
||||
|
||||
it('should render correctly', () => {
|
||||
const wrapper = mount(<Slider initialValue={20} />)
|
||||
expect(wrapper.html()).toMatchSnapshot()
|
||||
@@ -43,98 +45,91 @@ describe('Slider', () => {
|
||||
|
||||
it('should trigger events when click', async () => {
|
||||
let value = 0
|
||||
const changeHandler = jest.fn()
|
||||
.mockImplementation(val => value = val)
|
||||
const changeHandler = jest.fn().mockImplementation((val) => (value = val))
|
||||
const wrapper = mount(<Slider initialValue={20} onChange={changeHandler} />)
|
||||
wrapper.find('.slider')
|
||||
.simulate('click', {
|
||||
...nativeEvent,
|
||||
clientX: 50,
|
||||
})
|
||||
wrapper.find('.slider').simulate('click', {
|
||||
...nativeEvent,
|
||||
clientX: 50,
|
||||
})
|
||||
await updateWrapper(wrapper, 350)
|
||||
expect(changeHandler).toHaveBeenCalled()
|
||||
expect(value).toEqual(50)
|
||||
changeHandler.mockRestore()
|
||||
})
|
||||
|
||||
|
||||
it('should trigger events when drag', async () => {
|
||||
let value = 0
|
||||
const changeHandler = jest.fn()
|
||||
.mockImplementation(val => value = val)
|
||||
const changeHandler = jest.fn().mockImplementation((val) => (value = val))
|
||||
const wrapper = mount(<Slider initialValue={0} onChange={changeHandler} />)
|
||||
const dot = wrapper.find('.dot').getDOMNode() as HTMLDivElement
|
||||
|
||||
|
||||
act(() => triggerDrag(dot, 50))
|
||||
expect(changeHandler).toHaveBeenCalled()
|
||||
expect(value).toEqual(50)
|
||||
changeHandler.mockRestore()
|
||||
})
|
||||
|
||||
|
||||
it('should ignore events when disabled', async () => {
|
||||
let value = 0
|
||||
const changeHandler = jest.fn()
|
||||
.mockImplementation(val => value = val)
|
||||
const changeHandler = jest.fn().mockImplementation((val) => (value = val))
|
||||
const wrapper = mount(<Slider initialValue={0} disabled onChange={changeHandler} />)
|
||||
const dot = wrapper.find('.dot').getDOMNode() as HTMLDivElement
|
||||
|
||||
|
||||
act(() => triggerDrag(dot, 50))
|
||||
expect(changeHandler).not.toHaveBeenCalled()
|
||||
expect(value).not.toEqual(50)
|
||||
|
||||
wrapper.find('.slider')
|
||||
.simulate('click', {
|
||||
...nativeEvent,
|
||||
clientX: 50,
|
||||
})
|
||||
|
||||
wrapper.find('.slider').simulate('click', {
|
||||
...nativeEvent,
|
||||
clientX: 50,
|
||||
})
|
||||
await updateWrapper(wrapper, 350)
|
||||
expect(changeHandler).not.toHaveBeenCalled()
|
||||
expect(value).not.toEqual(50)
|
||||
changeHandler.mockRestore()
|
||||
})
|
||||
|
||||
|
||||
it('should move unit length is step', async () => {
|
||||
let value = 0
|
||||
const changeHandler = jest.fn()
|
||||
.mockImplementation(val => value = val)
|
||||
const changeHandler = jest.fn().mockImplementation((val) => (value = val))
|
||||
const wrapper = mount(<Slider step={10} onChange={changeHandler} />)
|
||||
const dot = wrapper.find('.dot').getDOMNode() as HTMLDivElement
|
||||
|
||||
|
||||
act(() => triggerDrag(dot, 6))
|
||||
expect(changeHandler).toHaveBeenCalled()
|
||||
expect(value).toEqual(10)
|
||||
changeHandler.mockRestore()
|
||||
})
|
||||
|
||||
|
||||
it('should return the specified when the limit is exceeded', () => {
|
||||
let value = 0
|
||||
const changeHandler = jest.fn()
|
||||
.mockImplementation(val => value = val)
|
||||
const changeHandler = jest.fn().mockImplementation((val) => (value = val))
|
||||
const wrapper = mount(<Slider min={10} max={20} onChange={changeHandler} />)
|
||||
const dot = wrapper.find('.dot').getDOMNode() as HTMLDivElement
|
||||
|
||||
|
||||
act(() => triggerDrag(dot, -5))
|
||||
expect(changeHandler).toHaveBeenCalled()
|
||||
expect(value).toEqual(10)
|
||||
|
||||
|
||||
act(() => triggerDrag(dot, 101))
|
||||
expect(changeHandler).toHaveBeenCalled()
|
||||
expect(value).toEqual(20)
|
||||
|
||||
|
||||
changeHandler.mockRestore()
|
||||
})
|
||||
|
||||
|
||||
it('should render number in dot', () => {
|
||||
let wrapper = mount(<Slider initialValue={20} />)
|
||||
expect(wrapper.find('.dot').text()).toContain('20')
|
||||
|
||||
|
||||
wrapper = mount(<Slider value={50} />)
|
||||
expect(wrapper.find('.dot').text()).toContain('50')
|
||||
})
|
||||
|
||||
|
||||
it('should work with markers', () => {
|
||||
let wrapper = mount(<Slider step={10} showMarkers />)
|
||||
expect(wrapper.html()).toMatchSnapshot()
|
||||
|
||||
|
||||
wrapper = mount(<Slider step={20} showMarkers />)
|
||||
expect(wrapper.html()).toMatchSnapshot()
|
||||
})
|
||||
|
||||
@@ -17,53 +17,53 @@ const defaultProps = {
|
||||
type NativeAttrs = Omit<React.HTMLAttributes<any>, keyof Props>
|
||||
export type SliderDotProps = Props & typeof defaultProps & NativeAttrs
|
||||
|
||||
const SliderDot = React.forwardRef<HTMLDivElement, React.PropsWithChildren<SliderDotProps>>(({
|
||||
children, disabled, left, isClick,
|
||||
}, ref: React.Ref<HTMLDivElement>) => {
|
||||
const theme = useTheme()
|
||||
|
||||
return (
|
||||
<div className={`dot ${disabled ? 'disabled' : ''} ${isClick ? 'click' : ''}`} ref={ref}>
|
||||
{children}
|
||||
<style jsx>{`
|
||||
.dot {
|
||||
position: absolute;
|
||||
left: ${left}%;
|
||||
top: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
height: 1.25rem;
|
||||
line-height: 1.25rem;
|
||||
border-radius: .625rem;
|
||||
user-select: none;
|
||||
font-weight: 700;
|
||||
font-size: .75rem;
|
||||
z-index: 100;
|
||||
background-color: ${theme.palette.success};
|
||||
color: ${theme.palette.background};
|
||||
text-align: center;
|
||||
padding: 0 calc(.86 * ${theme.layout.gapHalf});
|
||||
}
|
||||
|
||||
.dot.disabled {
|
||||
cursor: not-allowed !important;
|
||||
background-color: ${theme.palette.accents_2};
|
||||
color: ${theme.palette.accents_4};
|
||||
}
|
||||
|
||||
.dot.click {
|
||||
transition: all 200ms ease;
|
||||
}
|
||||
|
||||
.dot:hover {
|
||||
cursor: grab;
|
||||
}
|
||||
|
||||
.dot:active {
|
||||
cursor: grabbing;
|
||||
}
|
||||
`}</style>
|
||||
</div>
|
||||
)
|
||||
})
|
||||
const SliderDot = React.forwardRef<HTMLDivElement, React.PropsWithChildren<SliderDotProps>>(
|
||||
({ children, disabled, left, isClick }, ref: React.Ref<HTMLDivElement>) => {
|
||||
const theme = useTheme()
|
||||
|
||||
return (
|
||||
<div className={`dot ${disabled ? 'disabled' : ''} ${isClick ? 'click' : ''}`} ref={ref}>
|
||||
{children}
|
||||
<style jsx>{`
|
||||
.dot {
|
||||
position: absolute;
|
||||
left: ${left}%;
|
||||
top: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
height: 1.25rem;
|
||||
line-height: 1.25rem;
|
||||
border-radius: 0.625rem;
|
||||
user-select: none;
|
||||
font-weight: 700;
|
||||
font-size: 0.75rem;
|
||||
z-index: 100;
|
||||
background-color: ${theme.palette.success};
|
||||
color: ${theme.palette.background};
|
||||
text-align: center;
|
||||
padding: 0 calc(0.86 * ${theme.layout.gapHalf});
|
||||
}
|
||||
|
||||
.dot.disabled {
|
||||
cursor: not-allowed !important;
|
||||
background-color: ${theme.palette.accents_2};
|
||||
color: ${theme.palette.accents_4};
|
||||
}
|
||||
|
||||
.dot.click {
|
||||
transition: all 200ms ease;
|
||||
}
|
||||
|
||||
.dot:hover {
|
||||
cursor: grab;
|
||||
}
|
||||
|
||||
.dot:active {
|
||||
cursor: grabbing;
|
||||
}
|
||||
`}</style>
|
||||
</div>
|
||||
)
|
||||
},
|
||||
)
|
||||
|
||||
export default withDefaults(SliderDot, defaultProps)
|
||||
|
||||
@@ -11,23 +11,16 @@ export type MarkLeftValue = number
|
||||
|
||||
export type Marks = Array<MarkLeftValue>
|
||||
|
||||
const getMarks = (
|
||||
min: number,
|
||||
max: number,
|
||||
step: number,
|
||||
): Marks => {
|
||||
const getMarks = (min: number, max: number, step: number): Marks => {
|
||||
const value = max - min
|
||||
const roundFunc = !(value % step) ? Math.floor : Math.ceil
|
||||
const count = roundFunc(value / step) - 1
|
||||
if (count >= 99) return []
|
||||
|
||||
return [...new Array(count)]
|
||||
.map((_, index) => (step * (index + 1) * 100) / value)
|
||||
|
||||
return [...new Array(count)].map((_, index) => (step * (index + 1) * 100) / value)
|
||||
}
|
||||
|
||||
const SliderMark: React.FC<React.PropsWithChildren<Props>> = ({
|
||||
step, max, min,
|
||||
}) => {
|
||||
const SliderMark: React.FC<React.PropsWithChildren<Props>> = ({ step, max, min }) => {
|
||||
const theme = useTheme()
|
||||
const marks = useMemo(() => getMarks(min, max, step), [min, max, step])
|
||||
|
||||
|
||||
@@ -34,7 +34,7 @@ export type SliderProps = Props & typeof defaultProps & NativeAttrs
|
||||
const getRefWidth = (elementRef: RefObject<HTMLElement> | null): number => {
|
||||
if (!elementRef || !elementRef.current) return 0
|
||||
const rect = elementRef.current.getBoundingClientRect()
|
||||
return rect.width || (rect.right - rect.left)
|
||||
return rect.width || rect.right - rect.left
|
||||
}
|
||||
|
||||
const getValue = (
|
||||
@@ -46,42 +46,52 @@ const getValue = (
|
||||
): number => {
|
||||
if (offsetX < 0) return min
|
||||
if (offsetX > railWidth) return max
|
||||
const widthForEachStep = railWidth / (max - min) * step
|
||||
const widthForEachStep = (railWidth / (max - min)) * step
|
||||
if (widthForEachStep <= 0) return min
|
||||
|
||||
|
||||
const slideDistance = Math.round(offsetX / widthForEachStep) * step + min
|
||||
return Number.isInteger(slideDistance) ? slideDistance : Number.parseFloat(slideDistance.toFixed(1))
|
||||
return Number.isInteger(slideDistance)
|
||||
? slideDistance
|
||||
: Number.parseFloat(slideDistance.toFixed(1))
|
||||
}
|
||||
|
||||
const Slider: React.FC<React.PropsWithChildren<SliderProps>> = ({
|
||||
disabled, step, max, min, initialValue, value: customValue,
|
||||
onChange, className, showMarkers, ...props
|
||||
disabled,
|
||||
step,
|
||||
max,
|
||||
min,
|
||||
initialValue,
|
||||
value: customValue,
|
||||
onChange,
|
||||
className,
|
||||
showMarkers,
|
||||
...props
|
||||
}) => {
|
||||
const theme = useTheme()
|
||||
const [value, setValue] = useState<number>(initialValue)
|
||||
const [, setSliderWidth, sideWidthRef] = useCurrentState<number>(0)
|
||||
const [, setLastDargOffset, lastDargOffsetRef] = useCurrentState<number>(0)
|
||||
const [isClick, setIsClick] = useState<boolean>(false)
|
||||
|
||||
|
||||
const sliderRef = useRef<HTMLDivElement>(null)
|
||||
const dotRef = useRef<HTMLDivElement>(null)
|
||||
|
||||
const currentRatio = useMemo(
|
||||
() => (value - min) / (max - min) * 100,
|
||||
[value, max, min],
|
||||
)
|
||||
|
||||
|
||||
const currentRatio = useMemo(() => ((value - min) / (max - min)) * 100, [value, max, min])
|
||||
|
||||
const setLastOffsetManually = (val: number) => {
|
||||
const width = getRefWidth(sliderRef)
|
||||
const shouldOffset = (val - min) / (max - min) * width
|
||||
const shouldOffset = ((val - min) / (max - min)) * width
|
||||
setLastDargOffset(shouldOffset)
|
||||
}
|
||||
|
||||
const updateValue = useCallback((offset) => {
|
||||
const currentValue = getValue(max, min, step, offset, sideWidthRef.current)
|
||||
setValue(currentValue)
|
||||
onChange && onChange(currentValue)
|
||||
}, [max, min, step, sideWidthRef])
|
||||
|
||||
const updateValue = useCallback(
|
||||
(offset) => {
|
||||
const currentValue = getValue(max, min, step, offset, sideWidthRef.current)
|
||||
setValue(currentValue)
|
||||
onChange && onChange(currentValue)
|
||||
},
|
||||
[max, min, step, sideWidthRef],
|
||||
)
|
||||
|
||||
const dragHandler = (event: DraggingEvent) => {
|
||||
if (disabled) return
|
||||
@@ -116,24 +126,21 @@ const Slider: React.FC<React.PropsWithChildren<SliderProps>> = ({
|
||||
if (customValue === value) return
|
||||
setValue(customValue)
|
||||
}, [customValue, value])
|
||||
|
||||
|
||||
useEffect(() => {
|
||||
initialValue && setLastOffsetManually(initialValue)
|
||||
}, [])
|
||||
|
||||
return (
|
||||
<div className={`slider ${className}`}
|
||||
onClick={clickHandler}
|
||||
ref={sliderRef} {...props}>
|
||||
<SliderDot disabled={disabled}
|
||||
ref={dotRef}
|
||||
isClick={isClick}
|
||||
left={currentRatio}>{value}</SliderDot>
|
||||
<div className={`slider ${className}`} onClick={clickHandler} ref={sliderRef} {...props}>
|
||||
<SliderDot disabled={disabled} ref={dotRef} isClick={isClick} left={currentRatio}>
|
||||
{value}
|
||||
</SliderDot>
|
||||
{showMarkers && <SliderMark max={max} min={min} step={step} />}
|
||||
<style jsx>{`
|
||||
.slider {
|
||||
width: 100%;
|
||||
height: .5rem;
|
||||
height: 0.5rem;
|
||||
border-radius: 50px;
|
||||
background-color: ${disabled ? theme.palette.accents_2 : theme.palette.accents_8};
|
||||
position: relative;
|
||||
|
||||
Reference in New Issue
Block a user