UNPKG

@uiw/react-native

Version:
347 lines (343 loc) 10.8 kB
import React, { useEffect, useState } from 'react'; import { View, StyleSheet, TouchableOpacity, Dimensions, Platform } from 'react-native'; import Icon from '../Icon'; import Ellipsis from '../Ellipsis'; import { getMonths, getWeeksArray, getType, getNameLen } from './utils'; import ShowDate from './show'; import { useTheme } from '@shopify/restyle'; import Text from '../Typography/Text'; export let MainWidth = Dimensions.get('window').width; export let MainHeight = Dimensions.get('window').height; export let newDates = new Date(); export let toYear = newDates.getFullYear(); export let toMonth = newDates.getMonth(); export let toDays = newDates.getDate(); const Calendar = props => { const bars = { barRightText: 'Menu', title: 'Calendar', barLeftText: 'Today', onPressBarLeft: undefined, render: undefined }; const theme = useTheme(); const styles = createStyles({ bgColor: theme.colors.mask, themeColor: theme.colors.primary_background, themeText: theme.colors.text }); const { color = theme.colors.primary_background, lunarHoliday = false, bar = bars, showLunar = false, onChange, showBar = true, renderDay, value } = props; const { barRightText, title, barLeftText, onPressBarLeft, render } = bar; const [currentYear, setCurrentYear] = useState(toYear); const [currentMonth, setCurrentMonth] = useState(toMonth); const [currentDays, setCurrentDays] = useState(toDays); const [dayData, setDayData] = useState([]); const [lastData, setLastData] = useState([]); const [nextData, setNextData] = useState([]); const [lunarName, setLunarName] = useState(''); useEffect(() => { if (value) { let toYear = value.getFullYear(); let toMonth = value.getMonth(); let toDays = value.getDate(); setCurrentYear(toYear); setCurrentMonth(toMonth); setCurrentDays(toDays); } }, [value]); useEffect(() => { let toMonths = getMonths(currentYear, currentMonth, currentDays); setLastData(toMonths[0]); setDayData(toMonths[1]); setNextData(toMonths[2]); // const date = currentYear + '-' + (currentMonth + 1) + '-' + currentDays; // onChange?.(date); }, [currentYear, currentMonth, currentDays]); /** * 头部导航栏 * barRightText 左侧文字 * title 标题 * barLeftText 右侧文字 * onPressBarLeft 左侧点击事件 * render 自定义导航栏 */ const renderBar = render ? render : <View style={[styles.header, { backgroundColor: color }]}> <TouchableOpacity style={styles.headerBtnWrap} onPress={() => onPressBarLeft && onPressBarLeft()}> <View style={styles.headerBtn}> <Icon name="left" size={20} color={theme.colors.mask} /> <Text color="mask" style={styles.headerText}>{barRightText}</Text> </View> </TouchableOpacity> <View style={styles.headerTextWrap}> <Text color="mask" style={styles.headerText}>{title}</Text> </View> <TouchableOpacity style={styles.headerTextTouch} onPress={() => goToday()}> <Text color="mask" style={styles.headerText}>{barLeftText}</Text> </TouchableOpacity> </View>; const renderWeekDays = () => { let weekdays = ['日', '一', '二', '三', '四', '五', '六']; return weekdays.map(day => { return <Text key={day} style={styles.calendarWedText}> {day.toLocaleUpperCase()} </Text>; }); }; const renderWeeks = () => { let groupedDays = getWeeksArray(lastData, dayData, nextData, currentYear, currentMonth); return groupedDays.map((weekDays, index) => { return <View key={index} style={styles.weekDay}> {renderDays(weekDays)} </View>; }); }; const renderDays = weekDays => { return weekDays.map((day, index) => { let lunarAll = getType(day, currentYear, currentMonth, currentDays, toYear, toMonth, toDays); if (lunarAll.lunarShow !== '' && lunarName === '') { setLunarName(lunarAll.lunarShow); } let nameLen = getNameLen(day.lunarHolidays); let lineHeight = lunarHoliday === true && Platform.OS === 'ios' ? 0 : lunarHoliday === true ? 18 : MainWidth / 7 - 4.5; let paddingTop = lunarHoliday === true ? 4 : 0; let colorType = ''; if (day.colorType === '') { colorType = '#828282'; } else { colorType = color; } return <TouchableOpacity key={index} style={lunarAll.type === 1 ? [styles.dateBase, styles.otherMonth] : lunarAll.type === 2 ? [styles.currentMonth, styles.dateBase, { backgroundColor: color }] : lunarAll.type === 3 ? [styles.selectMonth, styles.dateBase, { borderColor: color }] : styles.dateBase} onPress={() => goSelectDay(day)}> <View> {renderDay?.(day.date || '', currentYear + '-' + (currentMonth + 1))} <Text style={[styles.dayText, { color: lunarAll.type === 1 ? theme.colors.disabled : lunarAll.type === 2 ? '#fff' : theme.colors.text, lineHeight: lineHeight, paddingTop: paddingTop }]}> {day.monthDays} </Text> {lunarHoliday === true && <Text style={[styles.dayText, { color: lunarAll.type === 1 ? theme.colors.disabled : lunarAll.type === 2 ? '#fff' : colorType, fontSize: 13 }]}> {nameLen > 3 ? <Ellipsis maxLen={2}>{day.lunarHolidays}</Ellipsis> : day.lunarHolidays || day.lunar} </Text>} </View> </TouchableOpacity>; }); }; const goSelectDay = day => { let lunarName = `农历${day.lunarMonth}${day.lunar}`; if (day.type === 'current') { setLunarName(lunarName); setCurrentDays(day.monthDays); } else if (day.type === 'last') { setCurrentDays(day.monthDays); getCurrentMonth('last'); } else { setCurrentDays(day.monthDays); getCurrentMonth('next'); } onChange?.(day.date || ''); }; const getCurrentYear = type => { let year = 0; let month; if (type === 'last') { year = currentYear - 1; setCurrentYear(year); month = currentMonth === 0 ? 11 : currentMonth; } else { year = currentYear + 1; setCurrentYear(year); month = currentMonth === 11 ? 0 : currentMonth; } onChange?.(year + '-' + (month + 1) + '-' + currentDays); }; const getCurrentMonth = type => { let month; if (type === 'last') { month = currentMonth - 1; if (month < 0) { setCurrentMonth(11); getCurrentYear('last'); } else { setCurrentMonth(month); onChange?.(currentYear + '-' + (month + 1) + '-' + currentDays); } } else { month = currentMonth + 1; if (month > 11) { setCurrentMonth(0); getCurrentYear('next'); } else { setCurrentMonth(month); onChange?.(currentYear + '-' + (month + 1) + '-' + currentDays); } } }; const goToday = () => { setCurrentYear(toYear); setCurrentMonth(toMonth); setCurrentDays(toDays); onChange?.(toYear + '-' + (toMonth + 1) + '-' + toDays); }; const goCurrentDay = day => { setCurrentDays(day); }; return <View style={{ flex: 1, position: 'relative' }}> <View style={{ flex: 1, backgroundColor: theme.colors.mask }}> {showBar && renderBar} <View style={styles.calendarHeader}> <View style={styles.calendarHeaderItem}> <TouchableOpacity onPress={() => getCurrentYear('last')}> <Icon name="left" size={20} color={theme.colors.text} /> </TouchableOpacity> <Text style={styles.calendarHeaderText}>{currentYear}年</Text> <TouchableOpacity onPress={() => getCurrentYear('next')}> <Icon name="right" size={20} color={theme.colors.text} /> </TouchableOpacity> </View> <View style={styles.calendarHeaderItem}> <TouchableOpacity onPress={() => getCurrentMonth('last')}> <Icon name="left" size={20} color={theme.colors.text} /> </TouchableOpacity> <Text style={styles.calendarHeaderText}>{currentMonth + 1}月</Text> <TouchableOpacity onPress={() => getCurrentMonth('next')}> <Icon name="right" size={20} color={theme.colors.text} /> </TouchableOpacity> </View> </View> <View style={styles.calendarWeekdays}>{renderWeekDays()}</View> <View style={styles.calendarDays}>{renderWeeks()}</View> </View> {showLunar === true && <ShowDate iconColor={color} lunar={lunarName} />} </View>; }; function createStyles({ bgColor, themeColor, themeText }) { return StyleSheet.create({ header: { flex: 1, display: 'flex', backgroundColor: themeColor, flexDirection: 'row', padding: 10, alignItems: 'center', justifyContent: 'space-between' }, headerBtnWrap: { flex: 1 }, headerBtn: { flexDirection: 'row', alignItems: 'center' // width: 50, }, headerTextWrap: { flex: 1, alignItems: 'center' }, headerTextTouch: { flex: 1, display: 'flex', flexDirection: 'row-reverse' }, headerText: { fontSize: 20 }, calendarHeader: { flexDirection: 'row', padding: 10, justifyContent: 'space-between' }, calendarHeaderItem: { flexDirection: 'row', justifyContent: 'space-between', alignItems: 'center', paddingTop: 10 }, calendarHeaderText: { paddingHorizontal: 30, fontSize: 20, fontWeight: '500', color: themeText }, calendarWeekdays: { flexDirection: 'row', justifyContent: 'space-between', alignItems: 'center', paddingHorizontal: MainWidth / 7 - 33, paddingTop: 10 }, calendarWedText: { textAlign: 'center' }, calendarDays: { marginVertical: 10 }, weekDay: { flexDirection: 'row', paddingHorizontal: 2 }, dateBase: { marginHorizontal: 2, width: MainWidth / 7 - 4.5, height: MainWidth / 7 - 4.5, ...Platform.select({ ios: {}, android: { justifyContent: 'center' } }) }, currentMonth: { backgroundColor: themeColor, borderRadius: 50 }, selectMonth: { borderWidth: 1, borderColor: themeColor, borderRadius: 50 }, otherMonth: { borderRadius: 50 }, dayText: { textAlign: 'center', fontSize: 17, fontWeight: '500' } }); } export default Calendar;