Skip to content

Commit b282eb7

Browse files
author
梁朝飞
committed
fix: 优化三元表达式
1 parent 46268a3 commit b282eb7

File tree

3 files changed

+248
-18
lines changed

3 files changed

+248
-18
lines changed

src/MotionThumb.tsx

Lines changed: 22 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -120,25 +120,29 @@ export default function MotionThumb(props: MotionThumbInterface) {
120120
}
121121
}, [value]);
122122

123-
const thumbStart = React.useMemo(
124-
() =>
125-
vertical
126-
? toPX(prevStyle?.top ?? 0)
127-
: direction === 'rtl'
128-
? toPX(-(prevStyle?.right as number))
129-
: toPX(prevStyle?.left as number),
130-
[vertical, direction, prevStyle],
131-
);
123+
const thumbStart = React.useMemo(() => {
124+
if (vertical) {
125+
return toPX(prevStyle?.top ?? 0);
126+
}
132127

133-
const thumbActive = React.useMemo(
134-
() =>
135-
vertical
136-
? toPX(nextStyle?.top ?? 0)
137-
: direction === 'rtl'
138-
? toPX(-(nextStyle?.right as number))
139-
: toPX(nextStyle?.left as number),
140-
[vertical, direction, nextStyle],
141-
);
128+
if (direction === 'rtl') {
129+
return toPX(-(prevStyle?.right as number));
130+
}
131+
132+
return toPX(prevStyle?.left as number);
133+
}, [vertical, direction, prevStyle]);
134+
135+
const thumbActive = React.useMemo(() => {
136+
if (vertical) {
137+
return toPX(nextStyle?.top ?? 0);
138+
}
139+
140+
if (direction === 'rtl') {
141+
return toPX(-(nextStyle?.right as number));
142+
}
143+
144+
return toPX(nextStyle?.left as number);
145+
}, [vertical, direction, nextStyle]);
142146

143147
// =========================== Motion ===========================
144148
const onAppearStart = () =>

tests/__snapshots__/index.test.tsx.snap

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -202,6 +202,68 @@ exports[`rc-segmented render segmented ok 1`] = `
202202
</div>
203203
`;
204204

205+
exports[`rc-segmented render segmented with CSSMotion (vertical) basic vertical 1`] = `
206+
<div
207+
aria-label="segmented control"
208+
class="rc-segmented rc-segmented-vertical"
209+
role="listbox"
210+
>
211+
<div
212+
class="rc-segmented-group"
213+
>
214+
<label
215+
class="rc-segmented-item rc-segmented-item-selected"
216+
>
217+
<input
218+
checked=""
219+
class="rc-segmented-item-input"
220+
type="radio"
221+
/>
222+
<div
223+
aria-selected="true"
224+
class="rc-segmented-item-label"
225+
role="option"
226+
title="iOS"
227+
>
228+
iOS
229+
</div>
230+
</label>
231+
<label
232+
class="rc-segmented-item"
233+
>
234+
<input
235+
class="rc-segmented-item-input"
236+
type="radio"
237+
/>
238+
<div
239+
aria-selected="false"
240+
class="rc-segmented-item-label"
241+
role="option"
242+
title="Android"
243+
>
244+
Android
245+
</div>
246+
</label>
247+
<label
248+
class="rc-segmented-item"
249+
>
250+
<input
251+
class="rc-segmented-item-input"
252+
type="radio"
253+
/>
254+
<div
255+
aria-selected="false"
256+
class="rc-segmented-item-label"
257+
role="option"
258+
title="Web3"
259+
>
260+
Web3
261+
</div>
262+
</label>
263+
</div>
264+
</div>
265+
`;
266+
205267
exports[`rc-segmented render segmented with CSSMotion (vertical) basic vertical movement 1`] = `
206268
<div
207269
aria-label="segmented control"

tests/index.test.tsx

Lines changed: 164 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -451,6 +451,170 @@ describe('rc-segmented', () => {
451451
offsetParentSpy.mockRestore();
452452
});
453453
});
454+
describe('render segmented with CSSMotion (vertical)', () => {
455+
it('basic vertical', () => {
456+
const offsetParentSpy = jest
457+
.spyOn(HTMLElement.prototype, 'offsetParent', 'get')
458+
.mockImplementation(() => {
459+
return container;
460+
});
461+
const handleValueChange = jest.fn();
462+
const { container, asFragment } = render(
463+
<Segmented
464+
options={['iOS', 'Android', 'Web3']}
465+
onChange={(value) => handleValueChange(value)}
466+
vertical
467+
/>,
468+
);
469+
expect(asFragment().firstChild).toMatchSnapshot();
470+
471+
expectMatchChecked(container, [true, false, false]);
472+
expect(container.querySelectorAll('.rc-segmented-item')[0]).toHaveClass(
473+
'rc-segmented-item-selected',
474+
);
475+
476+
// >>> Click: Web3
477+
fireEvent.click(
478+
container.querySelectorAll('.rc-segmented-item-input')[2],
479+
);
480+
expect(handleValueChange).toBeCalledWith('Web3');
481+
expectMatchChecked(container, [false, false, true]);
482+
483+
expect(container.querySelectorAll('.rc-segmented-thumb')[0]).toHaveClass(
484+
'rc-segmented-thumb-motion',
485+
);
486+
487+
// thumb appeared at `iOS`
488+
exceptThumbHaveStyle(container, {
489+
'--thumb-start-top': '0px',
490+
'--thumb-start-height': '62px',
491+
});
492+
493+
// Motion => active
494+
act(() => {
495+
jest.runAllTimers();
496+
});
497+
498+
// Motion enter end
499+
fireEvent.animationEnd(container.querySelector('.rc-segmented-thumb')!);
500+
act(() => {
501+
jest.runAllTimers();
502+
});
503+
504+
// thumb should disappear
505+
expect(container.querySelector('.rc-segmented-thumb')).toBeFalsy();
506+
507+
// >>> Click: Android
508+
fireEvent.click(
509+
container.querySelectorAll('.rc-segmented-item-input')[1],
510+
);
511+
expect(handleValueChange).toBeCalledWith('Android');
512+
expectMatchChecked(container, [false, true, false]);
513+
514+
// thumb should move
515+
expect(container.querySelector('.rc-segmented-thumb')).toHaveClass(
516+
'rc-segmented-thumb-motion',
517+
);
518+
519+
// thumb appeared at `Web3`
520+
exceptThumbHaveStyle(container, {
521+
'--thumb-start-top': '62px', // Start position for 'Web3'
522+
'--thumb-start-height': '76px', // Height of the thumb
523+
});
524+
525+
// Motion appear end
526+
act(() => {
527+
jest.runAllTimers();
528+
});
529+
exceptThumbHaveStyle(container, {
530+
'--thumb-active-top': '180px', // Active position for 'Android'
531+
'--thumb-active-height': '118px', // Final height of the thumb
532+
});
533+
fireEvent.animationEnd(container.querySelector('.rc-segmented-thumb')!);
534+
act(() => {
535+
jest.runAllTimers();
536+
});
537+
538+
// thumb should disappear
539+
expect(container.querySelector('.rc-segmented-thumb')).toBeFalsy();
540+
541+
offsetParentSpy.mockRestore();
542+
});
543+
544+
it('quick switch vertical', () => {
545+
const offsetParentSpy = jest
546+
.spyOn(HTMLElement.prototype, 'offsetParent', 'get')
547+
.mockImplementation(() => {
548+
return container;
549+
});
550+
const { container } = render(
551+
<Segmented
552+
options={['IOS', 'Android', 'Web3']}
553+
defaultValue="Android"
554+
vertical
555+
/>,
556+
);
557+
558+
// >>> Click: Web3
559+
fireEvent.click(
560+
container.querySelectorAll('.rc-segmented-item-input')[2],
561+
);
562+
563+
// Motion to active
564+
act(() => {
565+
jest.runAllTimers();
566+
});
567+
expect(container.querySelector('.rc-segmented-thumb')).toHaveClass(
568+
'rc-segmented-thumb-motion-appear-active',
569+
);
570+
571+
exceptThumbHaveStyle(container, {
572+
'--thumb-active-top': '180px',
573+
'--thumb-active-height': '76px',
574+
});
575+
576+
// >>> Click: IOS
577+
fireEvent.click(
578+
container.querySelectorAll('.rc-segmented-item-input')[0],
579+
);
580+
581+
exceptThumbHaveStyle(container, {
582+
'--thumb-active-top': '0px',
583+
'--thumb-active-height': '62px',
584+
});
585+
586+
offsetParentSpy.mockRestore();
587+
});
588+
589+
it('stop animation early in hidden parent (vertical)', () => {
590+
const offsetParentSpy = jest
591+
.spyOn(HTMLElement.prototype, 'offsetParent', 'get')
592+
.mockImplementation(() => null);
593+
const Demo = () => {
594+
const [value, setValue] = React.useState<string>('iOS');
595+
React.useEffect(() => setValue('Web3'), []);
596+
return (
597+
<Segmented
598+
options={['iOS', 'Android', 'Web3']}
599+
value={value}
600+
vertical
601+
/>
602+
);
603+
};
604+
605+
const { container } = render(<Demo />);
606+
607+
// stop animation early and place "selected" class
608+
expect(container.querySelectorAll('.rc-segmented-item')[2]).toHaveClass(
609+
'rc-segmented-item-selected',
610+
);
611+
612+
// thumb should disappear
613+
expect(container.querySelector('.rc-segmented-thumb')).toBeFalsy();
614+
615+
offsetParentSpy.mockRestore();
616+
});
617+
});
454618

455619
it('render segmented with options null/undefined', () => {
456620
const handleValueChange = jest.fn();

0 commit comments

Comments
 (0)