import { Icon } from '@rexd/icon' ; import cx from 'classnames' ; import React , { useMemo } from 'react' ; import { useGesture } from 'react-use-gesture' ; import { Dayjs } from '../../dayjs' ; import { Button } from '../button' ; import { Box , Flex } from '../layout' ; import { useDateTableContext } from './date-context' ; import { DateLocale } from './date-types' ; import { StyledCell , StyledCellContent , StyledHeadCell , StyledRow , StyledTable } from './styled' ; param visibleMonth returns const getDateList = ( visibleMonth ) => { const startDayOfMonth = visibleMonth . startOf ( 'month' ) ; const endDayOfMonth = visibleMonth . endOf ( 'month' ) ; const startDayOfList = startDayOfMonth . weekday ( 0 ) ; const endDayOfList = endDayOfMonth . weekday ( 6 ) ; const list = [ ] ; let current = startDayOfMonth ; while ( current . isSameOrBefore ( endDayOfMonth ) ) { list . push ( current . clone ( ) ) ; current = current . add ( 1 , 'day' ) ; } current = startDayOfMonth ; while ( current . isAfter ( startDayOfList ) ) { current = current . add ( - 1 , 'day' ) ; list . unshift ( current . clone ( ) ) ; } current = endDayOfMonth . add ( 1 , 'day' ) ; while ( current . isSameOrBefore ( endDayOfList ) ) { list . push ( current . clone ( ) ) ; current = current . add ( 1 , 'day' ) ; } while ( list . length < 42 ) { current = current . add ( 1 , 'day' ) ; list . push ( current . clone ( ) ) ; } const list2d = [ ] ; const chunk = 7 ; const total = list . length ; for ( let i = 0 ; i < total ; i += chunk ) { list2d . push ( list . slice ( i , i + chunk ) ) ; } return list2d ; } ; const monthButtonStyle = { padding : '0 4px' , } ; export interface DateTableProps { /**
     * 是否显示关闭按钮
     */ hasClose ? : boolean ; /**
     * 点击关闭按钮的回调
     */ onClose ? : ( ) => void ; /**
     * 当前显示的月份
     */ visibleMonth ? : Dayjs ; /**
     * 文案
     */ locale ? : DateLocale ; } export function DateTable ( props ) { const { visibleMonth , locale } = props ; const ctx = useDateTableContext ( ) ; const bind = useGesture ( { onDrag : ( { vxvy : [ vx , vy ] , last } ) => { if ( last && vy > 0 ) { ctx . onSelectMonth ( visibleMonth . add ( - 1 , 'month' ) ) ; } else if ( last && vy < 0 ) { ctx . onSelectMonth ( visibleMonth . add ( 1 , 'month' ) ) ; } } , } , { drag : { threshold : 100 , } , } ) ; const dateList = useMemo ( ( ) => { return getDateList ( visibleMonth ) ; } , [ visibleMonth ] ) ; return ( < Box > < Flex justify = "space-between" align = "center" px = "m" pb = "s" > < Box height = "formHeights.s" > < Button shape = "text" size = "small" onClick = { ( ) => { ctx . onChangeMode ( 'year' ) ; } } > { visibleMonth . year ( ) } 年 < /Button> < Button shape = "text" size = "small" iconOnly onClick = { ( ) => ctx . onSelectMonth ( visibleMonth . add ( - 1 , 'month' ) ) } > < Icon type = "arrow-left-bold" / > < /Button> < Button shape = "text" size = "small" style = { monthButtonStyle } onClick = { ( ) => ctx . onChangeMode ( 'month' ) } > { locale . months [ visibleMonth . month ( ) ] } < /Button> < Button shape = "text" size = "small" iconOnly onClick = { ( ) => ctx . onSelectMonth ( visibleMonth . add ( 1 , 'month' ) ) } > < Icon type = "arrow-right-bold" / > < /Button> < /Box> < Button shape = "text" size = "small" type = "primary" onClick = { ( ) => { ctx . onSelectMonth ( ctx . today . clone ( ) ) ; ctx . onSelectDate ( ctx . today . clone ( ) ) ; } } > 今日 < /Button> < /Flex> < StyledTable { ... bind ( ) } > < Box className = "rex-date-table-header" bg = "emphasis.20" px = "l" > < StyledRow > { locale . weekdays . map ( ( item ) => ( < StyledHeadCell key = { item } > < StyledCellContent > { item } < /StyledCellContent> < /StyledHeadCell>))} < /StyledRow> < /Box> < Box className = "rex-date-table-body" px = "l" > { dateList . map ( ( dateRow ) => ( < DateRow key = { dateRow [ 0 ] . week ( ) } items = { dateRow } / > ) ) } < /Box> < /StyledTable> < /Box>); } interface DateRowProps extends React . ComponentPropsWithoutRef < 'div' > { items ? : Dayjs [ ] ; } function DateRow ( props ) { const { items = [ ] , ... rest } = props ; const ctx = useDateTableContext ( ) ; return ( < StyledRow { ... rest } > { items . map ( ( item ) => { const date = item . format ( ctx . format ) ; return < DateCell key = { date } title = { date } date = { item } / > ; } ) } < /StyledRow>); } interface DateCellProps extends React . ComponentPropsWithoutRef < 'div' > { date : Dayjs ; } function DateCell ( props ) { const { date , ... rest } = props ; const ctx = useDateTableContext ( ) ; const disabled = ctx . getDisabledDate ( date ) ; const clazz = cx ( { 'rex-active' : ctx . check ( ( { startValue , endValue } ) => { if ( startValue && startValue . isSame ( date , 'date' ) ) { return true ; } if ( endValue && endValue . isSame ( date , 'date' ) ) { return true ; } return false ; } ) , 'rex-startValue' : ctx . check ( ( { startValue } ) => { if ( startValue && startValue . isSame ( date , 'date' ) ) { return true ; } return false ; } ) , 'rex-endValue' : ctx . check ( ( { endValue } ) => { if ( endValue && endValue . isSame ( date , 'date' ) ) { return true ; } return false ; } ) , 'rex-inRange' : ctx . check ( ( { startValue , endValue } ) => { if ( startValue && endValue && startValue . isSameOrBefore ( date , 'date' ) && endValue . isSameOrAfter ( date , 'date' ) ) { return true ; } return false ; } ) , 'rex-today' : ctx . check ( ( { today } ) => { return today . isSame ( date , 'date' ) ; } ) , 'rex-otherMonth' : ctx . check ( ( { visibleMonth } ) => { return ! visibleMonth . isSame ( date , 'month' ) ; } ) , 'rex-disabled' : disabled , } ) ; const handleClick = ( e ) => { let nextDate = date . clone ( ) ; if ( ctx . timeValue ) { nextDate = date . hour ( ctx . timeValue . hour ( ) ) . minute ( ctx . timeValue . minute ( ) ) . second ( ctx . timeValue . second ( ) ) ; } ctx . onSelectDate ( nextDate , { event : e } ) ; } ; return ( < StyledCell className = { clazz } onClick = { disabled ? undefined : handleClick } { ... rest } > < StyledCellContent > { date . date ( ) } < /StyledCellContent> < /StyledCell>); }