@@ -32,6 +32,7 @@ export function usePieSectorFocus({
3232} : UsePieSectorFocusOptions ) {
3333 const sectorFocusRef = useRef ( - 1 ) ;
3434 const lastSectorRef = useRef ( - 1 ) ;
35+ const spaceHeldRef = useRef ( false ) ;
3536 const [ inSectorMode , setInSectorMode ] = useState ( false ) ;
3637 const getSectorLabelRef = useRef ( getSectorLabel ) ;
3738 // Keep ref in sync so focusSector always uses the latest callback without re-creating the memoized function.
@@ -154,14 +155,19 @@ export function usePieSectorFocus({
154155 focusSector ( ( sectorFocusRef . current - 1 + dataLength ) % dataLength ) ;
155156 break ;
156157 }
157- case 'Enter' :
158- case ' ' : {
158+ case 'Enter' : {
159159 e . preventDefault ( ) ;
160160 if ( sectorFocusRef . current >= 0 ) {
161161 onSelect ?.( sectorFocusRef . current , e ) ;
162162 }
163163 break ;
164164 }
165+ case ' ' : {
166+ // Space activates on keyup so users can hold it, arrow to another sector, then release.
167+ e . preventDefault ( ) ;
168+ spaceHeldRef . current = true ;
169+ break ;
170+ }
165171 }
166172 } ,
167173 [ dataLength , chartRef , activeSegment , exitSectorMode , focusSector , onSelect ] ,
@@ -211,6 +217,18 @@ export function usePieSectorFocus({
211217 [ handleKeyDown , consumerOnKeyDownCapture ] ,
212218 ) ;
213219
220+ const handleKeyUp = useCallback (
221+ ( e : KeyboardEvent < HTMLDivElement > ) => {
222+ if ( e . key === ' ' && spaceHeldRef . current ) {
223+ spaceHeldRef . current = false ;
224+ if ( sectorFocusRef . current >= 0 ) {
225+ onSelect ?.( sectorFocusRef . current , e ) ;
226+ }
227+ }
228+ } ,
229+ [ onSelect ] ,
230+ ) ;
231+
214232 const handleSectorClick = useCallback (
215233 ( dataIndex : number ) => {
216234 if ( ! enabled ) {
@@ -249,6 +267,7 @@ export function usePieSectorFocus({
249267 role : 'application' as const ,
250268 'aria-roledescription' : 'chart' ,
251269 onKeyDownCapture : handleKeyDownCapture ,
270+ onKeyUp : handleKeyUp ,
252271 onBlur : handleBlur ,
253272 onFocus : handleFocus ,
254273 } ,
0 commit comments