@@ -20,14 +20,15 @@ import {
20
20
useCallback ,
21
21
useEffect ,
22
22
useMemo ,
23
- useRef
23
+ useRef ,
24
+ useState
24
25
} from 'react' ;
25
26
// @ts -ignore
26
27
import intlMessages from '../intl/*.json' ;
27
28
import { isAndroid , isIOS , isIPhone , mergeProps , useId } from '@react-aria/utils' ;
28
29
import { NumberFieldState } from '@react-stately/numberfield' ;
29
30
import { TextInputDOMProps } from '@react-types/shared' ;
30
- import { useFocus } from '@react-aria/interactions' ;
31
+ import { useFocus , useFocusWithin } from '@react-aria/interactions' ;
31
32
import {
32
33
useMessageFormatter ,
33
34
useNumberFormatter
@@ -115,10 +116,12 @@ export function useNumberField(props: AriaNumberFieldProps, state: NumberFieldSt
115
116
}
116
117
) ;
117
118
119
+ let [ focusWithin , setFocusWithin ] = useState ( false ) ;
120
+ let { focusWithinProps} = useFocusWithin ( { isDisabled, onFocusWithinChange : setFocusWithin } ) ;
121
+
118
122
let onWheel = useCallback ( ( e ) => {
119
- // If the input isn't supposed to receive input, do nothing.
120
123
// If the ctrlKey is pressed, this is a zoom event, do nothing.
121
- if ( isDisabled || isReadOnly || e . ctrlKey ) {
124
+ if ( e . ctrlKey ) {
122
125
return ;
123
126
}
124
127
@@ -130,8 +133,10 @@ export function useNumberField(props: AriaNumberFieldProps, state: NumberFieldSt
130
133
} else if ( e . deltaY < 0 ) {
131
134
decrement ( ) ;
132
135
}
133
- } , [ isReadOnly , isDisabled , decrement , increment ] ) ;
134
- useScrollWheel ( { onScroll : onWheel , capture : false } , inputRef ) ;
136
+ } , [ decrement , increment ] ) ;
137
+ // If the input isn't supposed to receive input, disable scrolling.
138
+ let scrollingDisabled = isDisabled || isReadOnly || ! focusWithin ;
139
+ useScrollWheel ( { onScroll : onWheel , capture : false , isDisabled : scrollingDisabled } , inputRef ) ;
135
140
136
141
// The inputMode attribute influences the software keyboard that is shown on touch devices.
137
142
// Browsers and operating systems are quite inconsistent about what keys are available, however.
@@ -374,7 +379,8 @@ export function useNumberField(props: AriaNumberFieldProps, state: NumberFieldSt
374
379
groupProps : {
375
380
role : 'group' ,
376
381
'aria-disabled' : isDisabled ,
377
- 'aria-invalid' : validationState === 'invalid' ? 'true' : undefined
382
+ 'aria-invalid' : validationState === 'invalid' ? 'true' : undefined ,
383
+ ...focusWithinProps
378
384
} ,
379
385
labelProps,
380
386
inputProps,
@@ -384,13 +390,18 @@ export function useNumberField(props: AriaNumberFieldProps, state: NumberFieldSt
384
390
}
385
391
386
392
// scroll wheel needs to be added not passively so it's cancelable, small helper hook to remember that
387
- function useScrollWheel ( { onScroll, capture} : { onScroll : ( e ) => void , capture : boolean } , ref : RefObject < HTMLElement > ) {
393
+ function useScrollWheel ( { onScroll, capture, isDisabled } : { onScroll : ( e ) => void , capture : boolean , isDisabled : boolean } , ref : RefObject < HTMLElement > ) {
388
394
useEffect ( ( ) => {
389
395
let elem = ref . current ;
390
- elem . addEventListener ( 'wheel' , onScroll , capture ) ;
396
+
397
+ if ( ! isDisabled ) {
398
+ elem . addEventListener ( 'wheel' , onScroll , capture ) ;
399
+ }
391
400
392
401
return ( ) => {
393
- elem . removeEventListener ( 'wheel' , onScroll , capture ) ;
402
+ if ( ! isDisabled ) {
403
+ elem . removeEventListener ( 'wheel' , onScroll , capture ) ;
404
+ }
394
405
} ;
395
- } , [ onScroll , ref , capture ] ) ;
406
+ } , [ onScroll , ref , capture , isDisabled ] ) ;
396
407
}
0 commit comments