UNPKG

@mpxjs/webpack-plugin

Version:

mpx compile core

145 lines (144 loc) 5.02 kB
/** * ✔ value * ✔ disabled * ✔ checked * ✔ color */ import { useRef, useState, forwardRef, useEffect, useContext, createElement } from 'react'; import { View, StyleSheet } from 'react-native'; import { warn } from '@mpxjs/utils'; import { LabelContext, RadioGroupContext } from './context'; import useInnerProps, { getCustomEvent } from './getInnerListeners'; import useNodesRef from './useNodesRef'; import { splitProps, splitStyle, useLayout, useTransformStyle, wrapChildren, extendObject } from './utils'; import Icon from './mpx-icon'; import Portal from './mpx-portal'; const styles = StyleSheet.create({ container: { flexDirection: 'row', alignItems: 'center' }, wrapper: { alignItems: 'center', justifyContent: 'center', width: 24, height: 24, borderColor: '#D1D1D1', borderWidth: 1, borderRadius: 12, backgroundColor: '#ffffff', marginRight: 5, overflow: 'hidden' }, wrapperChecked: { borderWidth: 0 }, wrapperDisabled: { backgroundColor: '#E1E1E1' }, icon: { opacity: 0 }, iconDisabled: { backgroundColor: '#ADADAD' }, iconChecked: { opacity: 1 } }); const Radio = forwardRef((radioProps, ref) => { const { textProps, innerProps: props = {} } = splitProps(radioProps); const { value = '', disabled = false, checked = false, color = '#09BB07', style = [], 'enable-var': enableVar, 'external-var-context': externalVarContext, 'parent-font-size': parentFontSize, 'parent-width': parentWidth, 'parent-height': parentHeight, bindtap } = props; const [isChecked, setIsChecked] = useState(!!checked); const groupContext = useContext(RadioGroupContext); let groupValue; let notifyChange; const labelContext = useContext(LabelContext); const defaultStyle = extendObject({}, styles.wrapper, isChecked ? styles.wrapperChecked : {}, disabled ? styles.wrapperDisabled : {}); const styleObj = extendObject({}, styles.container, style); const onChange = (evt) => { if (disabled || isChecked) return; setIsChecked(!isChecked); if (groupValue) { for (const [key, radio] of Object.entries(groupValue)) { if (!radio) continue; radio.setValue(key === value); radio.checked = key === value; } } notifyChange && notifyChange(evt); }; const onTap = (evt) => { bindtap && bindtap(getCustomEvent('tap', evt, { layoutRef }, props)); onChange(evt); }; const { hasPositionFixed, hasSelfPercent, normalStyle, hasVarDec, varContextRef, setWidth, setHeight } = useTransformStyle(styleObj, { enableVar, externalVarContext, parentFontSize, parentWidth, parentHeight }); const { textStyle, backgroundStyle, innerStyle = {} } = splitStyle(normalStyle); if (backgroundStyle) { warn('Radio does not support background image-related styles!'); } const nodeRef = useRef(null); useNodesRef(props, ref, nodeRef, { style: extendObject({}, defaultStyle, normalStyle), change: onChange }); const { layoutRef, layoutStyle, layoutProps } = useLayout({ props, hasSelfPercent, setWidth, setHeight, nodeRef }); if (groupContext) { groupValue = groupContext.groupValue; notifyChange = groupContext.notifyChange; } if (labelContext) { labelContext.current.triggerChange = onChange; } const innerProps = useInnerProps(extendObject({}, props, layoutProps, { ref: nodeRef, style: extendObject({}, innerStyle, layoutStyle), bindtap: !disabled && onTap }), [ 'value', 'disabled', 'checked' ], { layoutRef }); useEffect(() => { if (groupValue) { groupValue[value] = { checked: checked, setValue: setIsChecked }; } return () => { if (groupValue) { delete groupValue[value]; } }; }, []); useEffect(() => { if (checked !== isChecked) { setIsChecked(checked); if (groupValue) { groupValue[value].checked = checked; } } }, [checked]); const finalComponent = createElement(View, innerProps, createElement(View, { style: defaultStyle }, createElement(Icon, { type: 'success', size: 24, color: disabled ? '#E1E1E1' : color, style: extendObject({}, styles.icon, isChecked && styles.iconChecked, disabled && styles.iconDisabled) })), wrapChildren(props, { hasVarDec, varContext: varContextRef.current, textStyle, textProps })); if (hasPositionFixed) { return createElement(Portal, null, finalComponent); } return finalComponent; }); Radio.displayName = 'MpxRadio'; export default Radio;