1- import { type ChangeEvent , useCallback , useEffect , useState } from "react" ;
1+ import {
2+ type ChangeEvent ,
3+ type KeyboardEvent ,
4+ useCallback ,
5+ useEffect ,
6+ useState ,
7+ } from "react" ;
28
39import { MultilineTextInputDialog } from "@/components/shared/Dialogs/MultilineTextInputDialog" ;
410import { Button } from "@/components/ui/button" ;
@@ -48,6 +54,8 @@ export const AnnotationsInput = ({
4854 const inputType = config ?. type ?? "string" ;
4955 const placeholder = config ?. label ?? "" ;
5056
57+ const isNumericType = inputType === "number" || inputType === "integer" ;
58+
5159 const handleExpand = useCallback ( ( ) => {
5260 setIsDialogOpen ( true ) ;
5361 } , [ ] ) ;
@@ -88,6 +96,36 @@ export const AnnotationsInput = ({
8896 }
8997 } , [ ] ) ;
9098
99+ const handleNumericInputChange = useCallback (
100+ ( e : ChangeEvent < HTMLInputElement > ) => {
101+ let newValue = e . target . value ;
102+
103+ if ( inputType === "integer" ) {
104+ newValue = newValue . replace ( / [ . , ] / g, "" ) ;
105+ }
106+
107+ if ( newValue === "" ) {
108+ setInputValue ( newValue ) ;
109+ return ;
110+ }
111+
112+ const numericValue = Number ( newValue ) ;
113+ if ( ! isNaN ( numericValue ) ) {
114+ setInputValue ( newValue ) ;
115+ }
116+ } ,
117+ [ ] ,
118+ ) ;
119+
120+ const handleNumericInputKeyDown = useCallback (
121+ ( e : KeyboardEvent < HTMLInputElement > ) => {
122+ if ( inputType === "integer" && ( e . key === "." || e . key === "," ) ) {
123+ e . preventDefault ( ) ;
124+ }
125+ } ,
126+ [ inputType ] ,
127+ ) ;
128+
91129 const handleQuantityKeyInputChange = useCallback (
92130 ( e : ChangeEvent < HTMLInputElement > ) => {
93131 if ( ! config ?. annotation ) return ;
@@ -186,12 +224,12 @@ export const AnnotationsInput = ({
186224
187225 if ( onBlur && lastSavedValue !== inputValue && ! isInvalid ) {
188226 let value = inputValue ;
189- if (
190- config ?. type === "number" &&
191- ! isNaN ( Number ( inputValue ) ) &&
192- inputValue !== ""
193- ) {
194- value = clamp ( Number ( inputValue ) , config . min , config . max ) . toString ( ) ;
227+ if ( isNumericType && ! isNaN ( Number ( inputValue ) ) && inputValue !== "" ) {
228+ value = clamp ( Number ( inputValue ) , config ?. min , config ?. max ) . toString ( ) ;
229+
230+ if ( inputType === "integer" ) {
231+ value = Math . floor ( Number ( value ) ) . toString ( ) ;
232+ }
195233 }
196234
197235 onBlur ( value ) ;
@@ -201,6 +239,8 @@ export const AnnotationsInput = ({
201239 onBlur ,
202240 shouldSaveQuantityField ,
203241 isInvalid ,
242+ isNumericType ,
243+ inputType ,
204244 lastSavedValue ,
205245 inputValue ,
206246 config ,
@@ -261,15 +301,16 @@ export const AnnotationsInput = ({
261301 className = { className }
262302 />
263303 ) ;
264- } else if ( inputType === "number" ) {
304+ } else if ( isNumericType ) {
265305 inputElement = (
266306 < InlineStack gap = "2" wrap = "nowrap" className = "grow" >
267307 < Input
268308 type = "number"
269309 value = { inputValue }
270310 min = { config ?. min }
271311 max = { config ?. max }
272- onChange = { ( e ) => setInputValue ( e . target . value ) }
312+ onChange = { handleNumericInputChange }
313+ onKeyDown = { handleNumericInputKeyDown }
273314 onBlur = { handleBlur }
274315 autoFocus = { autoFocus }
275316 className = { className }
@@ -353,20 +394,18 @@ export const AnnotationsInput = ({
353394 ) }
354395 </ InlineStack >
355396
356- { inputType !== "boolean" &&
357- inputType !== "number" &&
358- ! config ?. options && (
359- < MultilineTextInputDialog
360- title = { dialogTitle }
361- description = "Enter a value for this annotation."
362- placeholder = { placeholder }
363- initialValue = { inputValue }
364- open = { isDialogOpen }
365- onCancel = { handleDialogCancel }
366- onConfirm = { handleDialogConfirm }
367- maxLength = { config ?. max }
368- />
369- ) }
397+ { inputType !== "boolean" && ! isNumericType && ! config ?. options && (
398+ < MultilineTextInputDialog
399+ title = { dialogTitle }
400+ description = "Enter a value for this annotation."
401+ placeholder = { placeholder }
402+ initialValue = { inputValue }
403+ open = { isDialogOpen }
404+ onCancel = { handleDialogCancel }
405+ onConfirm = { handleDialogConfirm }
406+ maxLength = { config ?. max }
407+ />
408+ ) }
370409 </ >
371410 ) ;
372411} ;
0 commit comments