11/* eslint-disable import/no-duplicates */
22
3- import classNames from " classnames"
4- import type React from " react"
5- import { type KeyboardEvent , useCallback , useState } from " react"
3+ import classNames from ' classnames'
4+ import type React from ' react'
5+ import { type KeyboardEvent , useCallback , useState } from ' react'
66
7- import { CheckIcon } from " lib/icons/Check.js"
8- import { CloseIcon } from " lib/icons/Close.js"
9- import { EditIcon } from " lib/icons/Edit.js"
7+ import { CheckIcon } from ' lib/icons/Check.js'
8+ import { CloseIcon } from ' lib/icons/Close.js'
9+ import { EditIcon } from ' lib/icons/Edit.js'
1010
1111export type SeamDeviceNameProps = {
12- onEdit ?: ( newName : string ) => void ;
13- editable ?: boolean ;
14- tagName ?: string ;
15- value : string ;
16- } & React . HTMLAttributes < HTMLElement > ;
17-
18- function IconButton ( props : React . PropsWithChildren < React . HTMLAttributes < HTMLButtonElement > > ) : JSX . Element {
19- return < button { ...props } className = { classNames ( "seam-editable-device-name-icon-button" , props . className ) } >
20- { props . children }
21- </ button >
12+ onEdit ?: ( newName : string ) => void
13+ editable ?: boolean
14+ tagName ?: string
15+ value : string
16+ } & React . HTMLAttributes < HTMLElement >
17+
18+ function IconButton (
19+ props : React . PropsWithChildren < React . HTMLAttributes < HTMLButtonElement > >
20+ ) : JSX . Element {
21+ return (
22+ < button
23+ { ...props }
24+ className = { classNames (
25+ 'seam-editable-device-name-icon-button' ,
26+ props . className
27+ ) }
28+ >
29+ { props . children }
30+ </ button >
31+ )
2232}
2333
2434function fixName ( name : string ) : string {
25- return name . replace ( / \s + / g, " " ) . trim ( )
35+ return name . replace ( / \s + / g, ' ' ) . trim ( )
2636}
2737
28- function isValidName ( name : string ) : { type : 'success' } | { type : 'error' , message : string } {
38+ function isValidName (
39+ name : string
40+ ) : { type : 'success' } | { type : 'error' ; message : string } {
2941 if ( name . length < 2 ) {
3042 return {
3143 type : 'error' ,
32- message : 'Name must be at least 2 characters long'
44+ message : 'Name must be at least 2 characters long' ,
3345 }
3446 }
3547
3648 if ( name . length > 64 ) {
3749 return {
3850 type : 'error' ,
39- message : 'Name must be at most 64 characters long'
51+ message : 'Name must be at most 64 characters long' ,
4052 }
4153 }
4254
@@ -45,88 +57,110 @@ function isValidName(name: string): { type: 'success' } | { type: 'error', messa
4557 } as const
4658}
4759
48- export function SeamEditableDeviceName ( { onEdit, editable = true , tagName, value, ...props } : SeamDeviceNameProps ) : JSX . Element {
49- const [ editing , setEditing ] = useState ( false ) ;
60+ export function SeamEditableDeviceName ( {
61+ onEdit,
62+ editable = true ,
63+ tagName,
64+ value,
65+ ...props
66+ } : SeamDeviceNameProps ) : JSX . Element {
67+ const [ editing , setEditing ] = useState ( false )
5068 const [ errorText , setErrorText ] = useState < null | string > ( null )
51- const [ currentValue , setCurrentValue ] = useState ( value ) ;
52- const Tag = ( tagName ?? " span" ) as " div" ;
69+ const [ currentValue , setCurrentValue ] = useState ( value )
70+ const Tag = ( tagName ?? ' span' ) as ' div'
5371
5472 const handleCheck = useCallback ( ( ) => {
55- const fixedName = fixName ( currentValue ) ;
56- const valid = isValidName ( fixedName ) ;
73+ const fixedName = fixName ( currentValue )
74+ const valid = isValidName ( fixedName )
5775
5876 if ( valid . type === 'error' ) {
59- setErrorText ( valid . message ) ;
60- return ;
77+ setErrorText ( valid . message )
78+ return
6179 }
6280
63- setEditing ( false ) ;
81+ setEditing ( false )
6482 setCurrentValue ( fixedName )
65- onEdit ?.( fixedName ) ;
83+ onEdit ?.( fixedName )
6684 } , [ currentValue , onEdit ] )
6785
68- const handleChange = useCallback ( ( event : React . ChangeEvent < HTMLInputElement > ) : void => {
69- setCurrentValue ( event . target . value ) ;
70- setErrorText ( null ) ;
71- } , [ ] )
86+ const handleChange = useCallback (
87+ ( event : React . ChangeEvent < HTMLInputElement > ) : void => {
88+ setCurrentValue ( event . target . value )
89+ setErrorText ( null )
90+ } ,
91+ [ ]
92+ )
7293
7394 const handleCancel = useCallback ( ( ) => {
74- setEditing ( false ) ;
75- setCurrentValue ( value ) ;
76- setErrorText ( null ) ;
95+ setEditing ( false )
96+ setCurrentValue ( value )
97+ setErrorText ( null )
7798 } , [ value ] )
7899
79- const handleInputKeydown = useCallback ( ( e : KeyboardEvent < HTMLInputElement > ) : void => {
80- if ( e . repeat ) return ;
100+ const handleInputKeydown = useCallback (
101+ ( e : KeyboardEvent < HTMLInputElement > ) : void => {
102+ if ( e . repeat ) return
81103
82- if ( e . key === "Enter" ) {
83- handleCheck ( ) ;
84- } else if ( e . key === "Escape" ) {
85- handleCancel ( ) ;
86- }
87- } , [ handleCheck , handleCancel ] ) ;
104+ if ( e . key === 'Enter' ) {
105+ handleCheck ( )
106+ } else if ( e . key === 'Escape' ) {
107+ handleCancel ( )
108+ }
109+ } ,
110+ [ handleCheck , handleCancel ]
111+ )
88112
89113 return (
90- < Tag { ...props } className = { classNames ( "seam-editable-device-name" , props . className ) } >
91- { editing
92- ? (
93- < span className = "seam-editable-device-name-input-wrapper" >
94- < input
95- type = "text"
96- defaultValue = { value }
97- onChange = { handleChange }
98- onKeyDown = { handleInputKeydown }
99- ref = { ( el ) => {
100- setTimeout ( ( ) => {
101- el ?. focus ( ) ;
102- } , 0 )
103- } }
104- />
105-
106- { errorText != null && < span className = "seam-editable-device-name-input-error" > { errorText } </ span > }
107- </ span >
108- ) : (
109- < span > { value } </ span >
110- ) }
111-
112- < span className = "seam-editable-device-name-icon-wrapper" >
114+ < Tag
115+ { ...props }
116+ className = { classNames ( 'seam-editable-device-name' , props . className ) }
117+ >
118+ { editing ? (
119+ < span className = 'seam-editable-device-name-input-wrapper' >
120+ < input
121+ type = 'text'
122+ defaultValue = { value }
123+ onChange = { handleChange }
124+ onKeyDown = { handleInputKeydown }
125+ ref = { ( el ) => {
126+ setTimeout ( ( ) => {
127+ el ?. focus ( )
128+ } , 0 )
129+ } }
130+ />
131+
132+ { errorText != null && (
133+ < span className = 'seam-editable-device-name-input-error' >
134+ { errorText }
135+ </ span >
136+ ) }
137+ </ span >
138+ ) : (
139+ < span > { value } </ span >
140+ ) }
141+
142+ < span className = 'seam-editable-device-name-icon-wrapper' >
113143 { editable ? (
114- editing
115- ? ( < >
144+ editing ? (
145+ < >
116146 < IconButton onClick = { handleCheck } >
117- < CheckIcon width = " 1em" height = " 1em" viewBox = " 0 0 24 24" />
147+ < CheckIcon width = ' 1em' height = ' 1em' viewBox = ' 0 0 24 24' />
118148 </ IconButton >
119149 < IconButton onClick = { handleCancel } >
120- < CloseIcon width = " 1em" height = " 1em" viewBox = " 0 0 24 24" />
150+ < CloseIcon width = ' 1em' height = ' 1em' viewBox = ' 0 0 24 24' />
121151 </ IconButton >
122- </ > ) : (
123- < IconButton onClick = { ( ) => { setEditing ( true ) } } >
124- < EditIcon width = "1em" height = "1em" viewBox = "0 0 24 24" />
125- </ IconButton >
126- )
152+ </ >
153+ ) : (
154+ < IconButton
155+ onClick = { ( ) => {
156+ setEditing ( true )
157+ } }
158+ >
159+ < EditIcon width = '1em' height = '1em' viewBox = '0 0 24 24' />
160+ </ IconButton >
161+ )
127162 ) : null }
128163 </ span >
129164 </ Tag >
130- ) ;
131-
132- }
165+ )
166+ }
0 commit comments