@@ -4,17 +4,11 @@ import { useNumberField, useLocale, AriaNumberFieldProps } from "react-aria";
4
4
import { mergeRefs } from "@react-aria/utils" ;
5
5
6
6
import clx from "clsx" ;
7
- import {
8
- inputStyles ,
9
- inputSizes ,
10
- inputIntent ,
11
- inputRootIntent ,
12
- rootInput ,
13
- rootInputFocused ,
14
- } from "@/ui/text-field/text-field.css" ;
7
+ import * as textFieldStyles from "@/ui/text-field/text-field.css" ;
15
8
import FieldLabel from "@/ui/field-label" ;
16
9
import Stack from "@/ui/stack" ;
17
10
import Box from "@/ui/box" ;
11
+ import TextFieldAddon from "@/ui/text-field-addon" ;
18
12
import useTheme from "../hooks/use-theme" ;
19
13
import * as styles from "./number-field.css" ;
20
14
import type { NumberInputProps } from "./number-field.types" ;
@@ -39,12 +33,18 @@ const NumberInput = forwardRef<HTMLInputElement, NumberInputProps>(
39
33
id = useId ( ) ,
40
34
label,
41
35
isDisabled,
42
- size = "sm" ,
43
- intent = "default" ,
36
+ disabled,
37
+ readOnly,
38
+ isReadOnly,
39
+ size,
40
+ intent,
44
41
clampValueOnBlur = true ,
45
42
formatOptions = defaultFormatOptions ,
46
43
} = props ;
47
44
45
+ const isFinalDisabled = isDisabled ?? disabled ?? false ;
46
+ const isFinalReadOnly = isReadOnly ?? readOnly ?? false ;
47
+
48
48
const { theme } = useTheme ( ) ;
49
49
const { locale } = useLocale ( ) ;
50
50
const [ internalValue , setInternalValue ] = useState < number | null > (
@@ -135,6 +135,7 @@ const NumberInput = forwardRef<HTMLInputElement, NumberInputProps>(
135
135
136
136
// Default mode, fallback to react-aria logic
137
137
if ( clampValueOnBlur ) {
138
+ console . log ( "old mode" ) ;
138
139
newValue = state . numberValue ;
139
140
applyFormatting ( newValue ) ;
140
141
inputProps . onBlur ?.( e ) ;
@@ -201,6 +202,9 @@ const NumberInput = forwardRef<HTMLInputElement, NumberInputProps>(
201
202
}
202
203
} , [ state . inputValue , formatValue , internalValue , strValue ] ) ;
203
204
205
+ const hasStartAddon = props . canDecrement && props . decrementButton != null ;
206
+ const hasEndAddon = props . canIncrement && props . incrementButton != null ;
207
+
204
208
return (
205
209
< Box className = { props . className } { ...props . attributes } >
206
210
< Stack direction = "vertical" space = "$4" >
@@ -209,22 +213,51 @@ const NumberInput = forwardRef<HTMLInputElement, NumberInputProps>(
209
213
< div
210
214
{ ...groupProps }
211
215
className = { clx (
212
- rootInput ,
213
- isFocused ? rootInputFocused : null ,
214
- props . isDisabled
215
- ? inputRootIntent . disabled
216
- : inputRootIntent [ props . intent ] ,
216
+ textFieldStyles . textField ( {
217
+ intent : intent ,
218
+ size : size ,
219
+ theme : theme ,
220
+ } ) ,
217
221
props . inputContainer ,
218
222
) }
223
+ tabIndex = { props . disabled ? undefined : 0 }
224
+ data-element-type = "input"
225
+ data-intent = { props . intent ?? "none" }
226
+ data-state = {
227
+ isFocused ? "focused" : props . disabled ? "disabled" : "default"
228
+ }
219
229
>
220
- { props . canDecrement && React . isValidElement ( props . decrementButton )
221
- ? React . cloneElement ( props . decrementButton , decrementButtonProps )
222
- : props ?. decrementButton }
230
+ { hasStartAddon && (
231
+ < TextFieldAddon
232
+ position = "start"
233
+ divider = { props . addonDivider ?? true }
234
+ intent = { props . intent }
235
+ disabled = { props . disabled }
236
+ >
237
+ { hasStartAddon && React . isValidElement ( props . decrementButton )
238
+ ? React . cloneElement (
239
+ props . decrementButton ,
240
+ decrementButtonProps ,
241
+ )
242
+ : props ?. decrementButton }
243
+ </ TextFieldAddon >
244
+ ) }
223
245
224
246
< Box
225
247
as = "input"
226
248
attributes = { {
227
249
...inputProps ,
250
+ "data-state" : isFinalReadOnly
251
+ ? "readonly"
252
+ : isFocused
253
+ ? "focused"
254
+ : isFinalDisabled
255
+ ? "disabled"
256
+ : "default" ,
257
+ "data-intent" : props . intent ?? "none" ,
258
+ "data-theme" : theme ,
259
+ readOnly : isFinalReadOnly ,
260
+ disabled : isFinalDisabled ,
228
261
value : inputValue ,
229
262
onChange : clampValueOnBlur ? inputProps . onChange : handleChange ,
230
263
onBlur : clampValueOnBlur ? inputProps . onBlur : handleBlur ,
@@ -233,23 +266,42 @@ const NumberInput = forwardRef<HTMLInputElement, NumberInputProps>(
233
266
textAlign = { props . textAlign }
234
267
fontSize = { props . fontSize }
235
268
className = { clx (
236
- inputStyles [ theme ] ,
237
- inputSizes [ size ] ,
238
- props . isDisabled ? inputIntent . disabled : inputIntent [ intent ] ,
239
- props . inputClassName ,
240
- isDisabled && props . decrementButton
269
+ textFieldStyles . input ,
270
+ isFinalDisabled && props . decrementButton
241
271
? styles . withDecrementButton
242
272
: null ,
243
- isDisabled && props . incrementButton
273
+ isFinalDisabled && props . incrementButton
244
274
? styles . withIncrementButton
245
275
: null ,
246
276
props . borderless ? styles . borderless : null ,
277
+ props . inputClassName ,
247
278
) }
248
279
/>
249
280
250
- { props . canIncrement && React . isValidElement ( props . incrementButton )
251
- ? React . cloneElement ( props . incrementButton , incrementButtonProps )
252
- : props ?. incrementButton }
281
+ < div
282
+ className = { textFieldStyles . borderElement }
283
+ data-theme = { theme }
284
+ data-intent = { props . intent ?? "none" }
285
+ data-state = {
286
+ isFocused ? "focused" : props . disabled ? "disabled" : "default"
287
+ }
288
+ />
289
+
290
+ { hasEndAddon && (
291
+ < TextFieldAddon
292
+ position = "end"
293
+ divider = { props . addonDivider ?? true }
294
+ intent = { props . intent }
295
+ disabled = { props . disabled }
296
+ >
297
+ { hasEndAddon && React . isValidElement ( props . incrementButton )
298
+ ? React . cloneElement (
299
+ props . incrementButton ,
300
+ incrementButtonProps ,
301
+ )
302
+ : props ?. incrementButton }
303
+ </ TextFieldAddon >
304
+ ) }
253
305
</ div >
254
306
</ Stack >
255
307
</ Box >
0 commit comments