11import { clsx } from 'clsx' ;
22import * as React from 'react' ;
33import type { DisabledDate } from '../interface' ;
4- import { formatValue , isInRange , isSame } from '../utils/dateUtil' ;
4+ import { formatValue , isInRange , isSame , isSameMonth } from '../utils/dateUtil' ;
55import { PickerHackContext , usePanelContext } from './context' ;
6+ import { offsetPanelDate } from '@/PickerInput/hooks/useRangePickerValue' ;
67
78export interface PanelBodyProps < DateType = any > {
89 rowNum : number ;
@@ -25,6 +26,7 @@ export interface PanelBodyProps<DateType = any> {
2526 prefixColumn ?: ( date : DateType ) => React . ReactNode ;
2627 rowClassName ?: ( date : DateType ) => string ;
2728 cellSelection ?: boolean ;
29+ onChange ?: ( date : DateType ) => void ;
2830}
2931
3032export default function PanelBody < DateType extends object = any > ( props : PanelBodyProps < DateType > ) {
@@ -41,6 +43,7 @@ export default function PanelBody<DateType extends object = any>(props: PanelBod
4143 headerCells,
4244 cellSelection = true ,
4345 disabledDate,
46+ onChange,
4447 } = props ;
4548
4649 const {
@@ -64,6 +67,10 @@ export default function PanelBody<DateType extends object = any>(props: PanelBod
6467
6568 const cellPrefixCls = `${ prefixCls } -cell` ;
6669
70+ const [ focusDateTime , setFocusDateTime ] = React . useState ( values ?. [ values . length - 1 ] ?? now ) ;
71+
72+ const cellRefs = React . useRef < Record < string , HTMLDivElement | null > > ( { } ) ;
73+
6774 // ============================= Context ==============================
6875 const { onCellDblClick } = React . useContext ( PickerHackContext ) ;
6976
@@ -73,6 +80,81 @@ export default function PanelBody<DateType extends object = any>(props: PanelBod
7380 ( singleValue ) => singleValue && isSame ( generateConfig , locale , date , singleValue , type ) ,
7481 ) ;
7582
83+ // ============================== Event Handlers ===============================
84+
85+ const moveFocus = ( offset : number ) => {
86+ const nextDate = generateConfig . addDate ( focusDateTime , offset ) ;
87+ setFocusDateTime ( nextDate ) ;
88+
89+ const focusElement =
90+ cellRefs . current [
91+ formatValue ( nextDate , {
92+ locale,
93+ format : 'YYYY-MM-DD' ,
94+ generateConfig,
95+ } )
96+ ] ;
97+ if ( focusElement ) {
98+ requestAnimationFrame ( ( ) => {
99+ focusElement . focus ( ) ;
100+ } ) ;
101+ }
102+
103+ if ( type && ! isSame ( generateConfig , locale , focusDateTime , nextDate , type ) ) {
104+ return onChange ?.( nextDate ) ;
105+ }
106+ } ;
107+
108+ const onKeyDown = React . useCallback (
109+ ( event ) => {
110+ switch ( event . key ) {
111+ case 'ArrowRight' :
112+ moveFocus ( 1 ) ;
113+ break ;
114+ case 'ArrowLeft' :
115+ moveFocus ( - 1 ) ;
116+ break ;
117+ case 'ArrowDown' :
118+ moveFocus ( 7 ) ;
119+ break ;
120+ case 'ArrowUp' :
121+ moveFocus ( - 7 ) ;
122+ break ;
123+ case 'Enter' :
124+ onSelect ( focusDateTime ) ;
125+ break ;
126+
127+ case 'Esc' :
128+ break ;
129+
130+ case 'Tab' :
131+ onChange ?.( focusDateTime ) ;
132+
133+ default :
134+ return ;
135+ }
136+
137+ event . preventDefault ( ) ;
138+ } ,
139+ [ focusDateTime , generateConfig , onSelect ] ,
140+ ) ;
141+
142+ React . useEffect ( ( ) => {
143+ const focusElement =
144+ cellRefs . current [
145+ formatValue ( focusDateTime , {
146+ locale,
147+ format : 'YYYY-MM-DD' ,
148+ generateConfig,
149+ } )
150+ ] ;
151+ if ( focusElement ) {
152+ requestAnimationFrame ( ( ) => {
153+ focusElement . focus ( ) ;
154+ } ) ;
155+ }
156+ } , [ ] ) ;
157+
76158 // =============================== Body ===============================
77159 const rows : React . ReactNode [ ] = [ ] ;
78160
@@ -118,8 +200,27 @@ export default function PanelBody<DateType extends object = any>(props: PanelBod
118200 } )
119201 : undefined ;
120202
203+ const isCurrentDateFocused = isSame ( generateConfig , locale , currentDate , focusDateTime , type ) ;
204+
121205 // Render
122- const inner = < div className = { `${ cellPrefixCls } -inner` } > { getCellText ( currentDate ) } </ div > ;
206+ const inner = (
207+ < div
208+ tabIndex = { isCurrentDateFocused ? 0 : - 1 }
209+ onKeyDown = { onKeyDown }
210+ className = { `${ cellPrefixCls } -inner` }
211+ ref = { ( element ) => {
212+ cellRefs . current [
213+ formatValue ( currentDate , {
214+ locale,
215+ format : 'YYYY-MM-DD' ,
216+ generateConfig,
217+ } )
218+ ] = element ;
219+ } }
220+ >
221+ { getCellText ( currentDate ) }
222+ </ div >
223+ ) ;
123224
124225 rowNode . push (
125226 < td
0 commit comments