UNPKG

@mpxjs/webpack-plugin

Version:

mpx compile core

126 lines (125 loc) 5.47 kB
import { View } from 'react-native'; import React, { createElement, forwardRef, useRef } from 'react'; import useInnerProps, { getCustomEvent } from '../getInnerListeners'; import useNodesRef from '../useNodesRef'; import { useLayout, splitProps, splitStyle, wrapChildren, useTransformStyle, extendObject } from '../utils'; import { PickerViewStyleContext } from './pickerVIewContext'; import Portal from '../mpx-portal'; const styles = { wrapper: { display: 'flex', flex: 1, flexDirection: 'row', justifyContent: 'space-around', overflow: 'hidden', alignItems: 'center' } }; const DefaultPickerItemH = 36; const _PickerView = forwardRef((props, ref) => { const { children, value = [], bindchange, style, 'indicator-style': indicatorStyle = {}, 'mask-style': pickerMaskStyle = {}, 'enable-var': enableVar, 'external-var-context': externalVarContext } = props; const { height: indicatorH, ...pickerIndicatorStyle } = indicatorStyle; const nodeRef = useRef(null); const cloneRef = useRef(null); const activeValueRef = useRef(value); activeValueRef.current = value.slice(); const snapActiveValueRef = useRef(null); const { normalStyle, hasVarDec, varContextRef, hasSelfPercent, setWidth, setHeight, hasPositionFixed } = useTransformStyle(style, { enableVar, externalVarContext }); useNodesRef(props, ref, nodeRef, { style: normalStyle }); const { layoutRef, layoutProps, layoutStyle } = useLayout({ props, hasSelfPercent, setWidth, setHeight, nodeRef: nodeRef }); const { textProps } = splitProps(props); const { textStyle } = splitStyle(normalStyle); const onSelectChange = (columnIndex, selectedIndex) => { const activeValue = activeValueRef.current; activeValue[columnIndex] = selectedIndex; const eventData = getCustomEvent('change', {}, { detail: { value: activeValue.slice(), source: 'change' }, layoutRef }); bindchange?.(eventData); snapActiveValueRef.current = activeValueRef.current; }; const hasDiff = (a = [], b) => { return a.some((v, i) => v !== b[i]); }; const onInitialChange = (isInvalid, value) => { if (isInvalid || !snapActiveValueRef.current || hasDiff(snapActiveValueRef.current, value)) { const eventData = getCustomEvent('change', {}, { detail: { value: value.slice(), source: 'change' }, layoutRef }); bindchange?.(eventData); snapActiveValueRef.current = value.slice(); } }; const innerProps = useInnerProps(extendObject({}, props, layoutProps, { ref: nodeRef, style: extendObject({}, normalStyle, layoutStyle, { position: 'relative', overflow: 'hidden' }) }), [ 'enable-offset', 'indicator-style', 'indicator-class', 'mask-style', 'mask-class' ], { layoutRef }); const renderColumn = (child, index, columnData, initialIndex) => { const childProps = child?.props || {}; const wrappedProps = extendObject({}, childProps, { columnData, ref: cloneRef, columnIndex: index, key: `pick-view-${index}`, wrapperStyle: { height: normalStyle?.height || DefaultPickerItemH, itemHeight: indicatorH || DefaultPickerItemH }, onSelectChange: onSelectChange.bind(null, index), initialIndex, pickerIndicatorStyle, pickerMaskStyle }); const realElement = React.cloneElement(child, wrappedProps); return wrapChildren({ children: realElement }, { hasVarDec, varContext: varContextRef.current, textStyle, textProps }); }; const validateChildInitialIndex = (index, data) => { return Math.max(0, Math.min(value[index] || 0, data.length - 1)); }; const flatColumnChildren = (data) => { const columnData = React.Children.toArray(data?.props?.children); if (columnData.length === 1 && React.isValidElement(columnData[0]) && columnData[0].type === React.Fragment) { // 只有一个 Fragment 嵌套情况 return React.Children.toArray(columnData[0].props.children); } return columnData; }; const renderPickerColumns = () => { const columns = React.Children.toArray(children); const renderColumns = []; const validValue = []; let isInvalid = false; columns.forEach((item, index) => { const columnData = flatColumnChildren(item); const validIndex = validateChildInitialIndex(index, columnData); if (validIndex !== value[index]) { isInvalid = true; } validValue.push(validIndex); renderColumns.push(renderColumn(item, index, columnData, validIndex)); }); onInitialChange(isInvalid, validValue); return renderColumns; }; const finalComponent = createElement(PickerViewStyleContext.Provider, { value: textStyle }, createElement(View, innerProps, createElement(View, { style: [styles.wrapper] }, renderPickerColumns()))); if (hasPositionFixed) { return createElement(Portal, null, finalComponent); } return finalComponent; }); _PickerView.displayName = 'MpxPickerView'; export default _PickerView;