/** * ✔ checked * ✔ type * ✔ disabled * ✔ color */ import { Switch, SwitchProps, ViewStyle, NativeSyntheticEvent } from 'react-native' import { useRef, useEffect, forwardRef, JSX, useState, useContext, createElement } from 'react' import { warn } from '@mpxjs/utils' import useNodesRef, { HandlerRef } from './useNodesRef' // 引入辅助函数 import useInnerProps, { getCustomEvent } from './getInnerListeners' import CheckBox from './mpx-checkbox' import Portal from './mpx-portal' import { FormContext, FormFieldValue } from './context' import { useTransformStyle, useLayout, extendObject } from './utils' interface _SwitchProps extends SwitchProps { style?: ViewStyle name?: string checked?: boolean type: 'switch' | 'checkbox' disabled: boolean color: string 'enable-var'?: boolean 'parent-font-size'?: number 'parent-width'?: number 'parent-height'?: number 'external-var-context'?: Record bindchange?: (event: NativeSyntheticEvent | unknown) => void catchchange?: (event: NativeSyntheticEvent | unknown) => void } const _Switch = forwardRef, _SwitchProps>((props, ref): JSX.Element => { const { style = {}, checked = false, type = 'switch', disabled = false, color = '#04BE02', 'enable-var': enableVar, 'external-var-context': externalVarContext, 'parent-font-size': parentFontSize, 'parent-width': parentWidth, 'parent-height': parentHeight, bindchange, catchchange } = props const [isChecked, setIsChecked] = useState(checked) const changeHandler = bindchange || catchchange let formValuesMap: Map | undefined const formContext = useContext(FormContext) if (formContext) { formValuesMap = formContext.formValuesMap } const { normalStyle, hasSelfPercent, setWidth, setHeight, hasPositionFixed } = useTransformStyle(style, { enableVar, externalVarContext, parentFontSize, parentWidth, parentHeight }) useEffect(() => { setIsChecked(checked) }, [checked]) const nodeRef = useRef(null) useNodesRef(props, ref, nodeRef, { style: normalStyle }) const { layoutRef, layoutStyle, layoutProps } = useLayout({ props, hasSelfPercent, setWidth, setHeight, nodeRef }) const onChange = (evt: NativeSyntheticEvent | boolean, { checked }: { checked?: boolean } = {}) => { if (type === 'switch') { setIsChecked(evt as boolean) changeHandler && changeHandler(getCustomEvent('change', {}, { layoutRef, detail: { value: evt } }, props)) } else { setIsChecked(checked as boolean) changeHandler && changeHandler(getCustomEvent('change', evt, { layoutRef, detail: { value: checked } }, props)) } } const resetValue = () => { setIsChecked(false) } const getValue = () => { return isChecked } if (formValuesMap) { if (!props.name) { warn('If a form component is used, the name attribute is required.') } else { formValuesMap.set(props.name, { getValue, resetValue }) } } useEffect(() => { return () => { if (formValuesMap && props.name) { formValuesMap.delete(props.name) } } }, []) const innerProps = useInnerProps( extendObject( {}, props, layoutProps, { ref: nodeRef, style: extendObject({}, normalStyle, layoutStyle) }, !disabled ? { [type === 'switch' ? 'onValueChange' : '_onChange']: onChange } : {} ), [ 'checked', 'disabled', 'type', 'color' ], { layoutRef } ) if (type === 'checkbox') { return createElement( CheckBox, extendObject({}, innerProps, { color: color, style: normalStyle, checked: isChecked }) ) } let finalComponent: JSX.Element = createElement( Switch, extendObject({}, innerProps, { style: normalStyle, value: isChecked, trackColor: { false: '#FFF', true: color }, thumbColor: isChecked ? '#FFF' : '#f4f3f4', ios_backgroundColor: '#FFF' }) ) if (hasPositionFixed) { finalComponent = createElement(Portal, null, finalComponent) } return finalComponent }) _Switch.displayName = 'MpxSwitch' export default _Switch