UNPKG

@mpxjs/webpack-plugin

Version:

mpx compile core

201 lines (200 loc) 7.11 kB
import React, { forwardRef, useCallback, useMemo, useRef, useState, useEffect, useImperativeHandle } from 'react'; import { StyleSheet, Text } from 'react-native'; import MpxPickerView from '../mpx-picker-view'; import MpxPickerViewColumn from '../mpx-picker-view-column'; import { useUpdateEffect } from '../utils'; import { years, months, daysInMonth, wrapDate, daysInMonthLength, START_YEAR, END_YEAR } from './dateData'; const START_DATE = `${START_YEAR}-01-01`; const END_DATE = `${END_YEAR}-12-31`; const START_DATE_ARR = [START_YEAR, 1, 1]; const END_DATE_ARR = [END_YEAR, 12, 31]; const styles = StyleSheet.create({ pickerContainer: { height: 240, paddingHorizontal: 10, borderTopLeftRadius: 10, borderTopRightRadius: 10 }, pickerIndicator: { height: 45 }, pickerItem: { fontSize: 16, lineHeight: 45, textAlign: 'center' } }); const getColumnLength = (fields = 'day') => { return fields === 'year' ? 1 : fields === 'month' ? 2 : 3; }; const compareDateStr = (date1, date2) => { const [y1 = START_YEAR, m1 = 0, d1 = 0] = typeof date1 === 'string' ? date1.split('-').map(Number) : date1; const [y2 = START_YEAR, m2 = 0, d2 = 0] = typeof date2 === 'string' ? date2.split('-').map(Number) : date2; const num1 = y1 * 10000 + m1 * 100 + d1; const num2 = y2 * 10000 + m2 * 100 + d2; if (num1 === num2) { return 0; } return num1 > num2 ? 1 : -1; }; const getDateArr = (date) => { const [y, m, d] = typeof date === 'string' ? date.split('-').map(Number) : date; return [y || 0, m || 0, d || 0]; }; const calibrateDate = (date, start, end) => { let startArr = getDateArr(start); let endArr = getDateArr(end); let dateArr = getDateArr(date); if (compareDateStr(startArr, endArr) > 0) { startArr = START_DATE_ARR; } if (compareDateStr(endArr, startArr) < 0) { endArr = END_DATE_ARR; } if (compareDateStr(start, end) > 0) { startArr = START_DATE_ARR; endArr = END_DATE_ARR; } if (compareDateStr(dateArr, endArr) > 0) { dateArr = endArr; } if (compareDateStr(dateArr, startArr) < 0) { dateArr = startArr; } return dateArr; }; const initDateStr2Arr = (dateStr, start, end) => { if (!dateStr) { const today = new Date(); const todayYear = today.getFullYear(); const todayMonth = today.getMonth() + 1; const todayDay = today.getDate(); dateStr = [todayYear, todayMonth, todayDay]; } const [y, m, d] = getDateArr(dateStr); const year = Math.min(Math.max(START_YEAR, y), END_YEAR); const month = Math.min(Math.max(1, m), 12); const day = Math.min(Math.max(1, d), daysInMonthLength(year, month)); const res = [year, month, day]; return calibrateDate(res, start, end); }; const valueStr2Obj = (_value = '', // eg: 2025-2-12 limit, start, end) => { const [y, m, d] = initDateStr2Arr(_value, start, end); const ans = { indexArr: [y - START_YEAR], rangeArr: [years] }; if (limit === 2) { ans.indexArr.push(m - 1); ans.rangeArr.push(months); } else if (limit === 3) { const days = daysInMonth(y, m); ans.indexArr.push(m - 1, d - 1); ans.rangeArr.push(months, days); } return ans; }; const valueChanged2Obj = (currentObj, value, limit = 3) => { const currentValue = currentObj.indexArr; const rangeArr = currentObj.rangeArr; if (limit === 3 && (currentValue[0] !== value[0] || currentValue[1] !== value[1])) { const days = daysInMonth(value[0], value[1] + 1); rangeArr[2] = days; const maxIndex = days.length - 1; if (value[2] > maxIndex) { value[2] = maxIndex; } } return { indexArr: value, rangeArr }; }; const valueChanged2Obj2 = (value, limit = 3, start, end) => { const y = value[0] + START_YEAR; const m = value[1] + 1; const d = value[2] + 1; return valueStr2Obj([y, m, d], limit, start, end); }; const valueNum2String = (value) => { return value.map((item, index) => { if (index === 0) { return item + START_YEAR; } else { return wrapDate()(item + 1); } }).join('-'); }; const hasDiff = (currentValue, value, limit = 3) => { for (let i = 0; i < limit; i++) { if (currentValue[i] !== value[i]) { return true; } } return false; }; const PickerDate = forwardRef((props, ref) => { const { value = '', start = START_DATE, end = END_DATE, fields, bindchange } = props; const nodeRef = useRef(null); const columnLength = useMemo(() => getColumnLength(fields), [fields]); const [formatObj, setFormatObj] = useState(valueStr2Obj(value, columnLength, start, end)); const timerRef = useRef(null); useEffect(() => { return () => { timerRef.current && clearTimeout(timerRef.current); }; }, []); useUpdateEffect(() => { const calibratedValue = valueStr2Obj(value, columnLength, start, end); setFormatObj(calibratedValue); }, [value, columnLength, start, end]); const updateValue = useCallback((value = '') => { const calibratedValue = valueStr2Obj(value, columnLength, start, end); setFormatObj(calibratedValue); }, [columnLength, start, end]); const _props = useRef(props); _props.current = props; useImperativeHandle(ref, () => ({ updateValue, getNodeInstance: () => ({ props: _props, nodeRef, instance: { style: {} } }) })); const onChange = useCallback((e) => { const { value } = e.detail; const currentValue = formatObj.indexArr; const newObj = valueChanged2Obj(formatObj, value, columnLength); if (hasDiff(currentValue, value, columnLength)) { setFormatObj(newObj); const newObj2 = valueChanged2Obj2(value, columnLength, start, end); if (hasDiff(newObj.indexArr, newObj2.indexArr, columnLength)) { timerRef.current && clearTimeout(timerRef.current); timerRef.current = setTimeout(() => setFormatObj(newObj2)); } } bindchange?.({ detail: { value: valueNum2String(newObj.indexArr) } }); }, [formatObj, columnLength, bindchange, start, end]); const renderColumn = () => { return formatObj.rangeArr?.map((item, index) => ( // @ts-expect-error ignore <MpxPickerViewColumn key={index}> {item.map((item, index) => { return <Text key={index} style={styles.pickerItem}> {item} </Text>; })} </MpxPickerViewColumn>)); }; return (<MpxPickerView style={styles.pickerContainer} indicator-style={styles.pickerIndicator} value={formatObj.indexArr} bindchange={onChange}> {renderColumn()} </MpxPickerView>); }); PickerDate.displayName = 'MpxPickerDate'; export default PickerDate;