goobs-frontend 0.7.65 → 0.7.67
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +2 -2
- package/src/app/_app.tsx +8 -8
- package/src/components/Button/hook/useHelperFooter.tsx +65 -75
- package/src/components/Button/index.tsx +4 -9
- package/src/components/Form/Popup/index.tsx +108 -145
- package/src/components/StyledComponent/hooks/useDropdown.tsx +31 -27
- package/src/components/StyledComponent/hooks/useInputHelperFooter.tsx +133 -176
- package/src/components/StyledComponent/hooks/usePhoneNumber.tsx +9 -6
- package/src/components/StyledComponent/hooks/useRequiredFieldsValidator.tsx +130 -77
- package/src/components/StyledComponent/hooks/useSearchbar.tsx +2 -0
- package/src/components/StyledComponent/hooks/useSplitButton.tsx +15 -11
- package/src/components/StyledComponent/index.tsx +212 -165
- package/src/components/StyledComponent/{useEffects → useCallbacks}/index.tsx +17 -20
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
'use client'
|
|
2
2
|
|
|
3
|
-
import React, {
|
|
3
|
+
import React, { useRef, useCallback, useMemo } from 'react'
|
|
4
4
|
import { Box, InputLabel, OutlinedInput, styled } from '@mui/material'
|
|
5
5
|
import { session } from 'goobs-cache'
|
|
6
6
|
import { useDropdown } from './hooks/useDropdown'
|
|
@@ -15,32 +15,20 @@ import {
|
|
|
15
15
|
} from './hooks/useInputHelperFooter'
|
|
16
16
|
import { useRequiredFieldsValidator } from './hooks/useRequiredFieldsValidator'
|
|
17
17
|
import labelStyles from '../../styles/StyledComponent/Label'
|
|
18
|
-
import {
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
*/
|
|
24
|
-
export interface StyledComponentProps {
|
|
25
|
-
/** Name attribute for the input element */
|
|
18
|
+
import { usePreventAutocomplete } from './useCallbacks'
|
|
19
|
+
import { ClientLogger } from 'goobs-testing'
|
|
20
|
+
|
|
21
|
+
export interface StyledComponentProps
|
|
22
|
+
extends React.ComponentPropsWithoutRef<'div'> {
|
|
26
23
|
name?: string
|
|
27
|
-
/** Color of the input outline */
|
|
28
24
|
outlinecolor?: string
|
|
29
|
-
/** Color of the icon */
|
|
30
25
|
iconcolor?: string
|
|
31
|
-
/** Background color of the input */
|
|
32
26
|
backgroundcolor?: string
|
|
33
|
-
/** Whether the input is notched */
|
|
34
27
|
notched?: boolean
|
|
35
|
-
/** Combined font color for the input */
|
|
36
28
|
combinedfontcolor?: string
|
|
37
|
-
/** Font color when the label is not shrunk */
|
|
38
29
|
unshrunkfontcolor?: string
|
|
39
|
-
/** Font color when the label is shrunk */
|
|
40
30
|
shrunkfontcolor?: string
|
|
41
|
-
/** Autocomplete attribute for the input */
|
|
42
31
|
autoComplete?: string
|
|
43
|
-
/** Variant of the component */
|
|
44
32
|
componentvariant?:
|
|
45
33
|
| 'multilinetextfield'
|
|
46
34
|
| 'dropdown'
|
|
@@ -58,51 +46,28 @@ export interface StyledComponentProps {
|
|
|
58
46
|
| 'time'
|
|
59
47
|
| 'date'
|
|
60
48
|
| 'splitbutton'
|
|
61
|
-
/** Options for dropdown variant */
|
|
62
49
|
options?: readonly string[]
|
|
63
|
-
/** Default option for dropdown variant */
|
|
64
50
|
defaultOption?: string
|
|
65
|
-
/** Helper footer message */
|
|
66
51
|
helperfooter?: HelperFooterMessage
|
|
67
|
-
/** Placeholder text for the input */
|
|
68
52
|
placeholder?: string
|
|
69
|
-
/** Minimum number of rows for multiline text field */
|
|
70
53
|
minRows?: number
|
|
71
|
-
/** Name of the form the input belongs to */
|
|
72
54
|
formname?: string
|
|
73
|
-
/** Label text for the input */
|
|
74
55
|
label?: string
|
|
75
|
-
/** Location of the shrunk label */
|
|
76
56
|
shrunklabellocation?: 'onnotch' | 'above'
|
|
77
|
-
/** Value of the input */
|
|
78
57
|
value?: string
|
|
79
|
-
/** Status of the value */
|
|
80
58
|
valuestatus?: boolean
|
|
81
|
-
/** Whether the input is focused */
|
|
82
59
|
focused?: boolean
|
|
83
|
-
/** Whether the input is required */
|
|
84
60
|
required?: boolean
|
|
85
|
-
/** Whether the form has been submitted */
|
|
86
61
|
formSubmitted?: boolean
|
|
87
|
-
/** ARIA label for the input */
|
|
88
62
|
'aria-label'?: string
|
|
89
|
-
/** ARIA required attribute */
|
|
90
63
|
'aria-required'?: boolean
|
|
91
|
-
/** ARIA invalid attribute */
|
|
92
64
|
'aria-invalid'?: boolean
|
|
93
|
-
/** ARIA describedby attribute */
|
|
94
65
|
'aria-describedby'?: string
|
|
95
|
-
/** Callback function when an option is selected (for dropdown variant) */
|
|
96
66
|
onOptionSelect?: (option: string) => void
|
|
97
|
-
/** Callback function when the input value changes */
|
|
98
67
|
onChange?: (event: React.ChangeEvent<HTMLInputElement>) => void
|
|
99
|
-
/** Priority of the spread message */
|
|
100
68
|
spreadMessagePriority?: number
|
|
101
69
|
}
|
|
102
70
|
|
|
103
|
-
/**
|
|
104
|
-
* Styled OutlinedInput component that prevents autofill styling.
|
|
105
|
-
*/
|
|
106
71
|
const NoAutofillOutlinedInput = styled(OutlinedInput)(() => ({
|
|
107
72
|
'& .MuiInputBase-input': {
|
|
108
73
|
'&:-webkit-autofill': {
|
|
@@ -120,12 +85,9 @@ const NoAutofillOutlinedInput = styled(OutlinedInput)(() => ({
|
|
|
120
85
|
},
|
|
121
86
|
}))
|
|
122
87
|
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
* @returns {React.ReactElement} The rendered StyledComponent
|
|
127
|
-
*/
|
|
128
|
-
const StyledComponent: React.FC<StyledComponentProps> = props => {
|
|
88
|
+
const StyledComponent: React.FC<StyledComponentProps> = React.memo(props => {
|
|
89
|
+
ClientLogger.debug('StyledComponent render', { props })
|
|
90
|
+
|
|
129
91
|
const {
|
|
130
92
|
label,
|
|
131
93
|
componentvariant,
|
|
@@ -137,7 +99,6 @@ const StyledComponent: React.FC<StyledComponentProps> = props => {
|
|
|
137
99
|
shrunkfontcolor,
|
|
138
100
|
shrunklabellocation,
|
|
139
101
|
value,
|
|
140
|
-
valuestatus,
|
|
141
102
|
placeholder,
|
|
142
103
|
formname,
|
|
143
104
|
formSubmitted = false,
|
|
@@ -148,137 +109,226 @@ const StyledComponent: React.FC<StyledComponentProps> = props => {
|
|
|
148
109
|
onOptionSelect,
|
|
149
110
|
onChange,
|
|
150
111
|
spreadMessagePriority,
|
|
112
|
+
minRows,
|
|
113
|
+
...restProps
|
|
151
114
|
} = props
|
|
152
115
|
|
|
153
|
-
const
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
const
|
|
158
|
-
const
|
|
116
|
+
const helperFooterAtom = useMemo(
|
|
117
|
+
() => session.atom<Record<string, HelperFooterMessage>>({}),
|
|
118
|
+
[]
|
|
119
|
+
)
|
|
120
|
+
const [helperFooters] = session.useAtom(helperFooterAtom)
|
|
121
|
+
const { validateField, useShowErrorEffect } =
|
|
122
|
+
useInputHelperFooter(helperFooterAtom)
|
|
159
123
|
|
|
160
|
-
const
|
|
124
|
+
const inputValueAtom = useMemo(() => session.atom(value || ''), [value])
|
|
125
|
+
const [inputValue, setInputValue] = session.useAtom(inputValueAtom)
|
|
126
|
+
const hasInput = useMemo(() => !!inputValue, [inputValue])
|
|
127
|
+
const hasInputRef = useRef(hasInput)
|
|
128
|
+
hasInputRef.current = hasInput
|
|
161
129
|
|
|
162
|
-
|
|
130
|
+
const memoizedRequiredFieldsProps = useMemo(() => [props], [props])
|
|
131
|
+
useRequiredFieldsValidator(
|
|
132
|
+
formname || '',
|
|
133
|
+
memoizedRequiredFieldsProps,
|
|
134
|
+
hasInputRef,
|
|
135
|
+
helperFooterAtom
|
|
136
|
+
)
|
|
163
137
|
|
|
164
|
-
const
|
|
165
|
-
const [
|
|
166
|
-
const
|
|
167
|
-
const
|
|
138
|
+
const isFocusedAtom = useMemo(() => session.atom(false), [])
|
|
139
|
+
const [isFocused, setIsFocused] = session.useAtom(isFocusedAtom)
|
|
140
|
+
const passwordVisibleAtom = useMemo(() => session.atom(false), [])
|
|
141
|
+
const [passwordVisible, setPasswordVisible] =
|
|
142
|
+
session.useAtom(passwordVisibleAtom)
|
|
143
|
+
const inputRefInternal = useRef<HTMLInputElement | null>(null)
|
|
168
144
|
const inputBoxRef = useRef<HTMLDivElement>(null)
|
|
169
145
|
|
|
170
|
-
const
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
146
|
+
const memoizedDropdownProps = useMemo(
|
|
147
|
+
() => ({
|
|
148
|
+
componentvariant,
|
|
149
|
+
options: props.options,
|
|
150
|
+
value: inputValue,
|
|
151
|
+
defaultOption: props.defaultOption,
|
|
152
|
+
}),
|
|
153
|
+
[componentvariant, props.options, inputValue, props.defaultOption]
|
|
174
154
|
)
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
155
|
+
|
|
156
|
+
const {
|
|
157
|
+
renderMenu,
|
|
158
|
+
selectedOption,
|
|
159
|
+
handleDropdownClick,
|
|
160
|
+
updateDropdownState,
|
|
161
|
+
} = useDropdown(memoizedDropdownProps, inputBoxRef, onOptionSelect)
|
|
162
|
+
|
|
163
|
+
const { phoneNumber, handlePhoneNumberChange, checkAndUpdatePhoneNumber } =
|
|
164
|
+
usePhoneNumber(inputValue, componentvariant)
|
|
165
|
+
|
|
166
|
+
const memoizedSplitButtonProps = useMemo(
|
|
167
|
+
() => ({ value: inputValue }),
|
|
168
|
+
[inputValue]
|
|
178
169
|
)
|
|
179
170
|
const {
|
|
180
171
|
value: splitButtonValue,
|
|
181
172
|
handleIncrement,
|
|
182
173
|
handleDecrement,
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
setShowError(formSubmitted || hasInput)
|
|
194
|
-
}, 1000)
|
|
195
|
-
|
|
196
|
-
return () => clearTimeout(timer)
|
|
197
|
-
}, [formSubmitted, hasInput, setShowError])
|
|
198
|
-
|
|
199
|
-
useEffect(() => {
|
|
200
|
-
hasInputRef.current = !!value
|
|
201
|
-
}, [value])
|
|
202
|
-
|
|
203
|
-
const currentHelperFooter = name ? helperFooterValue[name] : undefined
|
|
204
|
-
|
|
205
|
-
/**
|
|
206
|
-
* Handle change event for the input
|
|
207
|
-
* @param {React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>} e - The change event
|
|
208
|
-
*/
|
|
209
|
-
const handleChange = (
|
|
210
|
-
e: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>
|
|
211
|
-
) => {
|
|
212
|
-
if (componentvariant === 'phonenumber') {
|
|
213
|
-
handlePhoneNumberChange(e)
|
|
214
|
-
if (onChange) {
|
|
215
|
-
onChange(e as React.ChangeEvent<HTMLInputElement>)
|
|
174
|
+
updateValueFromProps,
|
|
175
|
+
} = useSplitButton(memoizedSplitButtonProps)
|
|
176
|
+
|
|
177
|
+
const setInputAttributes = usePreventAutocomplete()
|
|
178
|
+
|
|
179
|
+
const inputRef = useCallback(
|
|
180
|
+
(node: HTMLInputElement | null) => {
|
|
181
|
+
inputRefInternal.current = node
|
|
182
|
+
if (node) {
|
|
183
|
+
setInputAttributes(node)
|
|
216
184
|
}
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
185
|
+
},
|
|
186
|
+
[setInputAttributes]
|
|
187
|
+
)
|
|
188
|
+
|
|
189
|
+
const showError = useShowErrorEffect(formSubmitted, hasInput, isFocused)
|
|
190
|
+
|
|
191
|
+
const handleChange = useCallback(
|
|
192
|
+
(e: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>) => {
|
|
193
|
+
ClientLogger.debug('handleChange', {
|
|
194
|
+
componentvariant,
|
|
195
|
+
value: e.target.value,
|
|
196
|
+
name: e.target.name,
|
|
197
|
+
})
|
|
198
|
+
|
|
199
|
+
setInputValue(e.target.value)
|
|
200
|
+
|
|
201
|
+
if (componentvariant === 'phonenumber') {
|
|
202
|
+
handlePhoneNumberChange(e)
|
|
203
|
+
if (onChange) {
|
|
204
|
+
onChange(e as React.ChangeEvent<HTMLInputElement>)
|
|
205
|
+
}
|
|
206
|
+
} else if (componentvariant === 'splitbutton') {
|
|
207
|
+
const numValue = e.target.value.replace(/[^0-9]/g, '')
|
|
208
|
+
e.target.value = numValue
|
|
209
|
+
if (onChange) {
|
|
210
|
+
onChange(e as React.ChangeEvent<HTMLInputElement>)
|
|
211
|
+
}
|
|
212
|
+
} else if (onChange) {
|
|
221
213
|
onChange(e as React.ChangeEvent<HTMLInputElement>)
|
|
222
214
|
}
|
|
223
|
-
} else if (onChange) {
|
|
224
|
-
onChange(e as React.ChangeEvent<HTMLInputElement>)
|
|
225
|
-
}
|
|
226
215
|
|
|
227
|
-
|
|
228
|
-
|
|
216
|
+
const newHasInput = !!e.target.value
|
|
217
|
+
hasInputRef.current = newHasInput
|
|
229
218
|
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
}
|
|
219
|
+
const formData = new FormData()
|
|
220
|
+
formData.append(e.target.name, e.target.value)
|
|
221
|
+
if (name && label && formname) {
|
|
222
|
+
validateField(name, formData, label, formname, spreadMessagePriority)
|
|
223
|
+
}
|
|
236
224
|
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
225
|
+
if (componentvariant === 'dropdown') {
|
|
226
|
+
updateDropdownState()
|
|
227
|
+
} else if (componentvariant === 'phonenumber') {
|
|
228
|
+
checkAndUpdatePhoneNumber()
|
|
229
|
+
} else if (componentvariant === 'splitbutton') {
|
|
230
|
+
updateValueFromProps()
|
|
231
|
+
}
|
|
232
|
+
},
|
|
233
|
+
[
|
|
234
|
+
componentvariant,
|
|
235
|
+
handlePhoneNumberChange,
|
|
236
|
+
onChange,
|
|
237
|
+
name,
|
|
238
|
+
label,
|
|
239
|
+
formname,
|
|
240
|
+
validateField,
|
|
241
|
+
spreadMessagePriority,
|
|
242
|
+
updateDropdownState,
|
|
243
|
+
checkAndUpdatePhoneNumber,
|
|
244
|
+
updateValueFromProps,
|
|
245
|
+
setInputValue,
|
|
246
|
+
]
|
|
247
|
+
)
|
|
248
|
+
|
|
249
|
+
const handleFocus = useCallback(() => {
|
|
250
|
+
ClientLogger.debug('handleFocus')
|
|
241
251
|
setIsFocused(true)
|
|
242
|
-
}
|
|
252
|
+
}, [setIsFocused])
|
|
243
253
|
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
254
|
+
const handleBlur = useCallback(() => {
|
|
255
|
+
ClientLogger.debug('handleBlur', {
|
|
256
|
+
name,
|
|
257
|
+
label,
|
|
258
|
+
hasInput: hasInputRef.current,
|
|
259
|
+
formname,
|
|
260
|
+
})
|
|
248
261
|
setIsFocused(false)
|
|
249
|
-
if (name && label && !
|
|
262
|
+
if (name && label && !hasInputRef.current && formname) {
|
|
250
263
|
const formData = new FormData()
|
|
251
264
|
formData.append(name, '')
|
|
252
265
|
validateField(name, formData, label, formname, spreadMessagePriority)
|
|
253
266
|
}
|
|
254
|
-
}
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
const
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
const
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
267
|
+
}, [
|
|
268
|
+
name,
|
|
269
|
+
label,
|
|
270
|
+
formname,
|
|
271
|
+
validateField,
|
|
272
|
+
spreadMessagePriority,
|
|
273
|
+
setIsFocused,
|
|
274
|
+
])
|
|
275
|
+
|
|
276
|
+
const togglePasswordVisibility = useCallback(() => {
|
|
277
|
+
setPasswordVisible(prev => {
|
|
278
|
+
ClientLogger.debug('togglePasswordVisibility', { passwordVisible: !prev })
|
|
279
|
+
return !prev
|
|
280
|
+
})
|
|
281
|
+
}, [setPasswordVisible])
|
|
282
|
+
|
|
283
|
+
const isDropdownVariant = useMemo(
|
|
284
|
+
() => componentvariant === 'dropdown',
|
|
285
|
+
[componentvariant]
|
|
286
|
+
)
|
|
287
|
+
const isSplitButtonVariant = useMemo(
|
|
288
|
+
() => componentvariant === 'splitbutton',
|
|
289
|
+
[componentvariant]
|
|
290
|
+
)
|
|
291
|
+
const isNotchedVariant = useMemo(
|
|
292
|
+
() =>
|
|
293
|
+
!isDropdownVariant &&
|
|
294
|
+
!isSplitButtonVariant &&
|
|
295
|
+
shrunklabellocation !== 'above' &&
|
|
296
|
+
!!label,
|
|
297
|
+
[isDropdownVariant, isSplitButtonVariant, shrunklabellocation, label]
|
|
298
|
+
)
|
|
299
|
+
const hasPlaceholder = useMemo(() => !!placeholder, [placeholder])
|
|
300
|
+
|
|
301
|
+
const shouldShrinkLabel = useMemo(
|
|
302
|
+
() => !!inputValue || isFocused || hasPlaceholder,
|
|
303
|
+
[inputValue, isFocused, hasPlaceholder]
|
|
304
|
+
)
|
|
305
|
+
|
|
306
|
+
const shouldNotch = useMemo(
|
|
307
|
+
() => shouldShrinkLabel && isNotchedVariant,
|
|
308
|
+
[shouldShrinkLabel, isNotchedVariant]
|
|
309
|
+
)
|
|
310
|
+
|
|
311
|
+
ClientLogger.debug('Rendering StyledComponent', {
|
|
312
|
+
isDropdownVariant,
|
|
313
|
+
isSplitButtonVariant,
|
|
314
|
+
isNotchedVariant,
|
|
315
|
+
hasPlaceholder,
|
|
316
|
+
shouldShrinkLabel,
|
|
317
|
+
shouldNotch,
|
|
318
|
+
componentvariant,
|
|
319
|
+
name,
|
|
320
|
+
label,
|
|
321
|
+
inputValue,
|
|
322
|
+
phoneNumber,
|
|
323
|
+
selectedOption,
|
|
324
|
+
splitButtonValue,
|
|
325
|
+
showError,
|
|
326
|
+
currentHelperFooter: name ? helperFooters[name]?.statusMessage : undefined,
|
|
327
|
+
})
|
|
279
328
|
|
|
280
329
|
return (
|
|
281
330
|
<Box
|
|
331
|
+
{...restProps}
|
|
282
332
|
sx={{
|
|
283
333
|
boxSizing: 'border-box',
|
|
284
334
|
display: 'flex',
|
|
@@ -316,7 +366,8 @@ const StyledComponent: React.FC<StyledComponentProps> = props => {
|
|
|
316
366
|
)}
|
|
317
367
|
<Box ref={inputBoxRef} sx={{ width: '100%' }}>
|
|
318
368
|
<NoAutofillOutlinedInput
|
|
319
|
-
|
|
369
|
+
inputRef={inputRef}
|
|
370
|
+
minRows={minRows}
|
|
320
371
|
style={{
|
|
321
372
|
backgroundColor: backgroundcolor || 'inherit',
|
|
322
373
|
width: '100%',
|
|
@@ -347,7 +398,7 @@ const StyledComponent: React.FC<StyledComponentProps> = props => {
|
|
|
347
398
|
'aria-invalid': ariaInvalid,
|
|
348
399
|
'aria-required': ariaRequired,
|
|
349
400
|
'aria-describedby':
|
|
350
|
-
ariaDescribedBy ||
|
|
401
|
+
ariaDescribedBy || (name && helperFooters[name]?.statusMessage)
|
|
351
402
|
? `${name}-helper-text`
|
|
352
403
|
: undefined,
|
|
353
404
|
}}
|
|
@@ -388,39 +439,35 @@ const StyledComponent: React.FC<StyledComponentProps> = props => {
|
|
|
388
439
|
? selectedOption
|
|
389
440
|
: isSplitButtonVariant
|
|
390
441
|
? splitButtonValue
|
|
391
|
-
:
|
|
442
|
+
: inputValue
|
|
392
443
|
}
|
|
393
444
|
readOnly={isDropdownVariant}
|
|
394
|
-
notched={
|
|
395
|
-
(isNotchedVariant && shouldShrinkLabel) ||
|
|
396
|
-
((isDropdownVariant || isSplitButtonVariant) &&
|
|
397
|
-
shrunklabellocation !== 'above') ||
|
|
398
|
-
hasPlaceholder ||
|
|
399
|
-
(componentvariant === 'phonenumber' && phoneNumber !== '')
|
|
400
|
-
}
|
|
445
|
+
notched={shouldNotch}
|
|
401
446
|
/>
|
|
402
447
|
{isDropdownVariant && renderMenu}
|
|
403
448
|
</Box>
|
|
404
449
|
</Box>
|
|
405
|
-
{showError &&
|
|
450
|
+
{showError && name && helperFooters[name]?.statusMessage && (
|
|
406
451
|
<Typography
|
|
407
452
|
id={`${name}-helper-text`}
|
|
408
453
|
fontvariant="merrihelperfooter"
|
|
409
454
|
fontcolor={
|
|
410
|
-
|
|
455
|
+
helperFooters[name]?.status === 'error'
|
|
411
456
|
? red.main
|
|
412
|
-
:
|
|
457
|
+
: helperFooters[name]?.status === 'success'
|
|
413
458
|
? green.dark
|
|
414
459
|
: undefined
|
|
415
460
|
}
|
|
416
461
|
marginTop={0.5}
|
|
417
462
|
marginBottom={0}
|
|
418
463
|
align="left"
|
|
419
|
-
text={
|
|
464
|
+
text={helperFooters[name]?.statusMessage}
|
|
420
465
|
/>
|
|
421
466
|
)}
|
|
422
467
|
</Box>
|
|
423
468
|
)
|
|
424
|
-
}
|
|
469
|
+
})
|
|
470
|
+
|
|
471
|
+
StyledComponent.displayName = 'StyledComponent'
|
|
425
472
|
|
|
426
473
|
export default StyledComponent
|
|
@@ -1,25 +1,21 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { useCallback } from 'react'
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* Custom hook that tracks whether an input field has a value or a specific status.
|
|
5
5
|
*
|
|
6
6
|
* @param {string | undefined} value - The current value of the input field.
|
|
7
7
|
* @param {boolean | undefined} valuestatus - A boolean status associated with the input field.
|
|
8
|
-
*
|
|
8
|
+
*
|
|
9
|
+
* @returns {boolean} - Whether the input field has a value or a specific status.
|
|
9
10
|
*
|
|
10
11
|
* @example
|
|
11
|
-
* const
|
|
12
|
-
* useHasInputEffect(inputValue, inputStatus, setHasInput);
|
|
12
|
+
* const hasInput = useHasInput(inputValue, inputStatus);
|
|
13
13
|
*/
|
|
14
|
-
export const
|
|
14
|
+
export const useHasInput = (
|
|
15
15
|
value: string | undefined,
|
|
16
|
-
valuestatus: boolean | undefined
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
useEffect(() => {
|
|
20
|
-
const hasInput = !!value || !!valuestatus
|
|
21
|
-
setHasInput(hasInput)
|
|
22
|
-
}, [value, valuestatus, setHasInput])
|
|
16
|
+
valuestatus: boolean | undefined
|
|
17
|
+
): boolean => {
|
|
18
|
+
return !!value || !!valuestatus
|
|
23
19
|
}
|
|
24
20
|
|
|
25
21
|
/**
|
|
@@ -28,22 +24,23 @@ export const useHasInputEffect = (
|
|
|
28
24
|
*
|
|
29
25
|
* @param {React.RefObject<HTMLInputElement>} inputRefInternal - React ref object for the input element.
|
|
30
26
|
*
|
|
27
|
+
* @returns {(input: HTMLInputElement | null) => void} - A callback function to set the attributes on the input element.
|
|
28
|
+
*
|
|
31
29
|
* @example
|
|
32
30
|
* const inputRef = useRef<HTMLInputElement>(null);
|
|
33
|
-
*
|
|
31
|
+
* const setInputAttributes = usePreventAutocomplete();
|
|
34
32
|
* // In your JSX:
|
|
35
|
-
* <input ref={inputRef} ... />
|
|
33
|
+
* <input ref={el => { inputRef.current = el; setInputAttributes(el); }} ... />
|
|
36
34
|
*/
|
|
37
|
-
export const
|
|
38
|
-
|
|
39
|
-
) => {
|
|
40
|
-
|
|
41
|
-
const input = inputRefInternal.current
|
|
35
|
+
export const usePreventAutocomplete = (): ((
|
|
36
|
+
input: HTMLInputElement | null
|
|
37
|
+
) => void) => {
|
|
38
|
+
return useCallback((input: HTMLInputElement | null) => {
|
|
42
39
|
if (input) {
|
|
43
40
|
input.setAttribute('autocomplete', 'new-password')
|
|
44
41
|
input.setAttribute('autocorrect', 'off')
|
|
45
42
|
input.setAttribute('autocapitalize', 'none')
|
|
46
43
|
input.setAttribute('spellcheck', 'false')
|
|
47
44
|
}
|
|
48
|
-
}, [
|
|
45
|
+
}, [])
|
|
49
46
|
}
|