From 427cf36eaa47f41e9f9e34231fb2d74db3a1abf8 Mon Sep 17 00:00:00 2001 From: John Date: Wed, 7 Jul 2021 21:35:41 +0800 Subject: [PATCH] refactor(switch): support customize checked value #4329 (#4332) * refactor(switch): support customize checked value #4329 * test: add test case * refactor: update props name * refactor: update ts * refactor: optimize --- components/switch/__tests__/index.test.js | 28 +++++++++ components/switch/index.tsx | 74 ++++++++++++++--------- 2 files changed, 74 insertions(+), 28 deletions(-) diff --git a/components/switch/__tests__/index.test.js b/components/switch/__tests__/index.test.js index 73061036fc..55980437b9 100644 --- a/components/switch/__tests__/index.test.js +++ b/components/switch/__tests__/index.test.js @@ -4,6 +4,7 @@ import focusTest from '../../../tests/shared/focusTest'; import { resetWarned } from '../../_util/warning'; import mountTest from '../../../tests/shared/mountTest'; import { ref } from 'vue'; +import { asyncExpect } from '@/tests/utils'; describe('Switch', () => { focusTest(Switch); @@ -42,4 +43,31 @@ describe('Switch', () => { ); errorSpy.mockRestore(); }); + + it('customize checked value should work', async () => { + resetWarned(); + const checked = ref(1); + const onUpdate = val => (checked.value = val); + const wrapper = mount({ + render() { + return ( + + ); + }, + }); + await asyncExpect(() => { + wrapper.find('button').trigger('click'); + }); + expect(checked.value).toBe(2); + + await asyncExpect(() => { + wrapper.find('button').trigger('click'); + }); + expect(checked.value).toBe(1); + }); }); diff --git a/components/switch/index.tsx b/components/switch/index.tsx index 4febcce829..647b3961f0 100644 --- a/components/switch/index.tsx +++ b/components/switch/index.tsx @@ -1,4 +1,4 @@ -import type { ExtractPropTypes } from 'vue'; +import type { ExtractPropTypes, PropType } from 'vue'; import { defineComponent, inject, @@ -19,23 +19,35 @@ import { tuple, withInstall } from '../_util/type'; import { getPropsSlot } from '../_util/props-util'; import Omit from 'omit.js'; -export const SwitchSizes = tuple('small', 'default', 'large'); +export const SwitchSizes = tuple('small', 'default'); const switchProps = { prefixCls: PropTypes.string, size: PropTypes.oneOf(SwitchSizes), disabled: PropTypes.looseBool, - checkedChildren: PropTypes.any, - unCheckedChildren: PropTypes.any, + checkedChildren: PropTypes.VNodeChild, + unCheckedChildren: PropTypes.VNodeChild, tabindex: PropTypes.oneOfType([PropTypes.string, PropTypes.number]), autofocus: PropTypes.looseBool, loading: PropTypes.looseBool, - checked: PropTypes.looseBool, - onChange: PropTypes.func, - onClick: PropTypes.func, - onKeydown: PropTypes.func, - onMouseup: PropTypes.func, - 'onUpdate:checked': PropTypes.func, + checked: PropTypes.any, + checkedValue: PropTypes.any.def(true), + uncheckedValue: PropTypes.any.def(false), + onChange: { + type: Function as PropType<(checked: any, e: Event) => void>, + }, + onClick: { + type: Function as PropType<(checked: any, e: Event) => void>, + }, + onKeydown: { + type: Function as PropType<(e: Event) => void>, + }, + onMouseup: { + type: Function as PropType<(e: Event) => void>, + }, + 'onUpdate:checked': { + type: Function as PropType<(checked: any) => void>, + }, }; export type SwitchProps = Partial>; @@ -46,7 +58,7 @@ const Switch = defineComponent({ inheritAttrs: false, props: switchProps, emits: ['update:checked', 'mouseup', 'change', 'click', 'keydown'], - setup(props: SwitchProps, { attrs, slots, expose, emit }) { + setup(props, { attrs, slots, expose, emit }) { onBeforeMount(() => { warning( !('defaultChecked' in attrs), @@ -59,12 +71,13 @@ const Switch = defineComponent({ '`value` is not validate prop, do you mean `checked`?', ); }); - const checked = ref(props.checked !== undefined ? !!props.checked : !!attrs.defaultChecked); + const checked = ref(props.checked !== undefined ? props.checked : attrs.defaultChecked); + const checkedStatus = computed(() => checked.value === props.checkedValue); watch( () => props.checked, () => { - checked.value = !!props.checked; + checked.value = props.checked; }, ); @@ -92,29 +105,26 @@ const Switch = defineComponent({ }); }); - const setChecked = (check: boolean, e: MouseEvent | KeyboardEvent) => { + const setChecked = (check: any, e: MouseEvent | KeyboardEvent) => { if (props.disabled) { return; } - if (props.checked === undefined) { - checked.value = check; - } emit('update:checked', check); emit('change', check, e); }; const handleClick = (e: MouseEvent) => { focus(); - const newChecked = !checked.value; + const newChecked = checkedStatus.value ? props.uncheckedValue : props.checkedValue; setChecked(newChecked, e); emit('click', newChecked, e); }; const handleKeyDown = (e: KeyboardEvent) => { if (e.keyCode === KeyCode.LEFT) { - setChecked(false, e); + setChecked(props.uncheckedValue, e); } else if (e.keyCode === KeyCode.RIGHT) { - setChecked(true, e); + setChecked(props.checkedValue, e); } emit('keydown', e); }; @@ -123,6 +133,13 @@ const Switch = defineComponent({ refSwitchNode.value?.blur(); emit('mouseup', e); }; + + const classNames = computed(() => ({ + [`${prefixCls.value}-small`]: props.size === 'small', + [`${prefixCls.value}-loading`]: props.loading, + [`${prefixCls.value}-checked`]: checkedStatus.value, + [`${prefixCls.value}-disabled`]: props.disabled, + })); return () => (