@uiw/react-native
Version:
UIW for React Native
334 lines (331 loc) • 12.2 kB
JavaScript
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;