@uiw/react-native
Version:
UIW for React Native
347 lines (343 loc) • 10.8 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;