goobs-frontend 0.7.57 → 0.7.59

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "goobs-frontend",
3
- "version": "0.7.57",
3
+ "version": "0.7.59",
4
4
  "description": "A comprehensive React-based UI library built on Material-UI, offering a wide range of customizable components including grids, typography, buttons, cards, forms, navigation, pricing tables, steppers, tooltips, accordions, and more. Designed for building responsive and consistent user interfaces with advanced features like form validation, theming, and code syntax highlighting.",
5
5
  "license": "MIT",
6
6
  "main": "./src/index.ts",
@@ -25,29 +25,29 @@
25
25
  "@emotion/cache": "^11.11.0",
26
26
  "@emotion/react": "^11.11.4",
27
27
  "@emotion/styled": "^11.11.5",
28
- "@mui/icons-material": "^5.15.20",
29
- "@mui/material": "^5.15.20",
30
- "@types/lodash": "^4.17.5",
31
- "goobs-cache": "^1.2.1",
32
- "highlight.js": "^11.9.0",
28
+ "@mui/icons-material": "^5.16.0",
29
+ "@mui/material": "^5.16.0",
30
+ "@types/lodash": "^4.17.6",
31
+ "goobs-cache": "^1.3.1",
32
+ "highlight.js": "^11.10.0",
33
33
  "lodash": "^4.17.21",
34
- "next": "14.2.4"
34
+ "next": "14.2.5"
35
35
  },
36
36
  "devDependencies": {
37
- "@next/eslint-plugin-next": "^14.2.4",
38
- "@types/node": "^20.14.9",
39
- "@types/react": "18.3.0",
37
+ "@next/eslint-plugin-next": "^14.2.5",
38
+ "@types/node": "^20.14.10",
39
+ "@types/react": "18.3.3",
40
40
  "@types/react-dom": "^18.3.0",
41
- "@typescript-eslint/eslint-plugin": "^7.15.0",
42
- "@typescript-eslint/parser": "^7.15.0",
41
+ "@typescript-eslint/eslint-plugin": "^7.16.0",
42
+ "@typescript-eslint/parser": "^7.16.0",
43
43
  "eslint": "^8.57.0",
44
- "eslint-config-next": "^14.2.4",
44
+ "eslint-config-next": "^14.2.5",
45
45
  "eslint-config-prettier": "^9.1.0",
46
46
  "eslint-plugin-prettier": "^5.1.3",
47
47
  "prettier": "^3.3.2",
48
48
  "react": "^18.3.1",
49
49
  "react-dom": "^18.3.1",
50
- "typescript": "^5.5.2"
50
+ "typescript": "^5.5.3"
51
51
  },
52
52
  "files": [
53
53
  "src"
@@ -7,46 +7,24 @@ import Typography from '../Typography'
7
7
  import { get, JSONValue } from 'goobs-cache'
8
8
  import { red } from '../../styles/palette'
9
9
 
10
- /**
11
- * Defines the possible alignment options for button content.
12
- */
13
10
  export type ButtonAlignment = 'left' | 'center' | 'right'
14
11
 
15
- /**
16
- * Defines the structure of helper footer messages used for form validation.
17
- */
18
12
  export interface HelperFooterMessage {
19
- /** Indicates whether the message represents an error or success state */
20
13
  status: 'error' | 'success'
21
- /** The message to display in the status area */
22
14
  statusMessage: string
23
- /** The message to spread across multiple components */
24
15
  spreadMessage: string
25
- /** Priority of the spread message for determining which message to show */
26
16
  spreadMessagePriority: number
27
- /** The name of the form this message is associated with */
28
17
  formname: string
29
- /** Indicates if the field associated with this message is required */
30
18
  required: boolean
31
19
  }
32
20
 
33
- /**
34
- * Props for the CustomButton component.
35
- * Extends ButtonProps from Material-UI, omitting 'color' and 'variant'.
36
- */
37
21
  export interface CustomButtonProps
38
22
  extends Omit<ButtonProps, 'color' | 'variant'> {
39
- /** Text to display on the button */
40
23
  text?: string
41
- /** Background color of the button */
42
24
  backgroundcolor?: string
43
- /** Color of the button's outline */
44
25
  outlinecolor?: string
45
- /** Color of the button's text */
46
26
  fontcolor?: string
47
- /** Alignment of the button's text */
48
27
  fontlocation?: ButtonAlignment
49
- /** Typography variant for the button's text */
50
28
  fontvariant?:
51
29
  | 'arapeyh1'
52
30
  | 'arapeyh2'
@@ -75,32 +53,18 @@ export interface CustomButtonProps
75
53
  | 'merriparagraph'
76
54
  | 'merrihelperheader'
77
55
  | 'merrihelperfooter'
78
- /** Icon to display on the button. Set to false to hide the icon */
79
56
  icon?: React.ReactNode | false
80
- /** Color of the icon */
81
57
  iconcolor?: string
82
- /** Size of the icon */
83
58
  iconsize?: string
84
- /** Position of the icon relative to the text */
85
59
  iconlocation?: 'left' | 'top' | 'right'
86
- /** Style variant of the button */
87
60
  variant?: 'text' | 'outlined' | 'contained'
88
- /** Function to call when the button is clicked */
89
61
  onClick?: () => void
90
- /** Helper footer message for form validation */
91
62
  helperfooter?: HelperFooterMessage
92
- /** Width of the button */
93
63
  width?: string
94
- /** Name of the form this button is associated with */
95
64
  formname?: string
96
- /** Name attribute for the button element */
97
65
  name?: string
98
66
  }
99
67
 
100
- /**
101
- * CustomButton component renders a customizable button with integrated form validation.
102
- * It displays error messages based on helper footers and form validation status.
103
- */
104
68
  const CustomButton: React.FC<CustomButtonProps> = props => {
105
69
  const {
106
70
  text,
@@ -121,24 +85,16 @@ const CustomButton: React.FC<CustomButtonProps> = props => {
121
85
  width,
122
86
  } = props
123
87
 
124
- /** State for storing the current error message */
125
88
  const [errorMessage, setErrorMessage] = useState<string | undefined>(
126
89
  undefined
127
90
  )
128
- /** State for tracking whether the associated form is valid */
129
91
  const [isFormValid, setIsFormValid] = useState<boolean>(true)
130
- /** State for storing helper footer messages */
131
92
  const [helperFooterValue, setHelperFooterValue] = useState<
132
93
  Record<string, HelperFooterMessage>
133
94
  >({})
134
95
 
135
- /**
136
- * Updates the form validation status and error message based on helper footers.
137
- * This function filters relevant footers, checks for errors and empty required fields,
138
- * and updates the error message and form validity accordingly.
139
- */
140
96
  const updateFormValidation = useCallback(() => {
141
- if (formname) {
97
+ if (formname && helperFooterValue) {
142
98
  const relevantFooters = Object.values(helperFooterValue).filter(
143
99
  footer => footer?.formname === formname
144
100
  )
@@ -168,13 +124,12 @@ const CustomButton: React.FC<CustomButtonProps> = props => {
168
124
  setErrorMessage(undefined)
169
125
  setIsFormValid(true)
170
126
  }
127
+ } else {
128
+ setErrorMessage(undefined)
129
+ setIsFormValid(true)
171
130
  }
172
131
  }, [formname, helperFooterValue])
173
132
 
174
- /**
175
- * Fetches helper footer data from the cache when formname changes.
176
- * This effect runs whenever the formname prop changes.
177
- */
178
133
  useEffect(() => {
179
134
  const fetchHelperFooter = async () => {
180
135
  const helperFooterResult = await get('helperFooter', 'client')
@@ -189,28 +144,18 @@ const CustomButton: React.FC<CustomButtonProps> = props => {
189
144
  HelperFooterMessage
190
145
  >
191
146
  )
147
+ } else {
148
+ setHelperFooterValue({})
192
149
  }
193
150
  }
194
151
 
195
152
  fetchHelperFooter()
196
153
  }, [formname])
197
154
 
198
- /**
199
- * Triggers form validation whenever helperFooterValue changes.
200
- * This effect ensures that the form validation is updated whenever
201
- * the helper footer messages change.
202
- */
203
155
  useEffect(() => {
204
156
  updateFormValidation()
205
157
  }, [updateFormValidation])
206
158
 
207
- /**
208
- * Renders the icon element based on the provided icon prop.
209
- * If the icon prop is false, it returns null.
210
- * If the icon is a valid React element, it clones it with the specified size.
211
- * Otherwise, it renders a default StarIcon.
212
- * @returns The rendered icon element or null.
213
- */
214
159
  const renderIcon = () => {
215
160
  if (icon === false) {
216
161
  return null
@@ -223,10 +168,6 @@ const CustomButton: React.FC<CustomButtonProps> = props => {
223
168
  return <StarIcon style={{ fontSize: iconsize }} />
224
169
  }
225
170
 
226
- /**
227
- * Handles the button click event.
228
- * If the form is valid and an onClick handler is provided, it calls the handler.
229
- */
230
171
  const handleButtonClick = async () => {
231
172
  if (!isFormValid) {
232
173
  return
@@ -4,12 +4,16 @@ import { Input, Box } from '@mui/material'
4
4
  import { useCodeConfirmation } from './utils/useCodeConfirmation'
5
5
  import { columnconfig } from '../../components/Grid'
6
6
  import { red, green } from '../../styles/palette'
7
+ import { set } from 'goobs-cache'
7
8
 
8
9
  export interface ConfirmationCodeInputsProps {
9
10
  identifier?: string
10
11
  columnconfig?: columnconfig
11
12
  isValid: boolean
12
13
  codeLength?: number
14
+ 'aria-label'?: string
15
+ 'aria-required'?: boolean
16
+ 'aria-invalid'?: boolean
13
17
  }
14
18
 
15
19
  /**
@@ -21,12 +25,17 @@ export interface ConfirmationCodeInputsProps {
21
25
  const ConfirmationCodeInputs: React.FC<ConfirmationCodeInputsProps> = ({
22
26
  codeLength = 6,
23
27
  isValid,
28
+ 'aria-label': ariaLabel,
29
+ 'aria-required': ariaRequired,
30
+ 'aria-invalid': ariaInvalid,
24
31
  ...props
25
32
  }) => {
26
- const { handleCodeChange, handleKeyDown } = useCodeConfirmation({
27
- codeLength,
28
- isValid,
29
- })
33
+ const { handleCodeChange, handleKeyDown, combinedCode } = useCodeConfirmation(
34
+ {
35
+ codeLength,
36
+ isValid,
37
+ }
38
+ )
30
39
 
31
40
  /**
32
41
  * handleChange function is called when the value of an input field changes.
@@ -63,8 +72,29 @@ const ConfirmationCodeInputs: React.FC<ConfirmationCodeInputsProps> = ({
63
72
  handleKeyDown(event, index)
64
73
  }
65
74
 
75
+ /**
76
+ * useEffect hook is used to set the verification code into an atom using goobs-cache.
77
+ * It sets the code whenever the combinedCode changes and the code is valid.
78
+ */
79
+ React.useEffect(() => {
80
+ if (isValid) {
81
+ set(
82
+ 'verificationCode',
83
+ combinedCode,
84
+ new Date(Date.now() + 3600000),
85
+ 'memory'
86
+ )
87
+ }
88
+ }, [combinedCode, isValid])
89
+
66
90
  return (
67
- <Box display="flex" flexDirection="row" alignItems="center">
91
+ <Box
92
+ display="flex"
93
+ flexDirection="row"
94
+ alignItems="center"
95
+ role="group"
96
+ aria-label={ariaLabel || 'Confirmation Code'}
97
+ >
68
98
  <Box display="flex" gap={1}>
69
99
  {Array.from({ length: codeLength }, (_, index) => (
70
100
  <Input
@@ -72,6 +102,9 @@ const ConfirmationCodeInputs: React.FC<ConfirmationCodeInputsProps> = ({
72
102
  name={`code${index + 1}`}
73
103
  inputProps={{
74
104
  maxLength: 1,
105
+ 'aria-label': `Code Digit ${index + 1}`,
106
+ 'aria-required': ariaRequired,
107
+ 'aria-invalid': ariaInvalid,
75
108
  }}
76
109
  sx={{
77
110
  border: '1px solid',
@@ -100,6 +133,8 @@ const ConfirmationCodeInputs: React.FC<ConfirmationCodeInputsProps> = ({
100
133
  borderRadius="50%"
101
134
  bgcolor={isValid ? green.main : red.main}
102
135
  ml={2}
136
+ role="status"
137
+ aria-label={isValid ? 'Code is valid' : 'Code is invalid'}
103
138
  />
104
139
  </Box>
105
140
  )
@@ -42,9 +42,6 @@ const useStyledComponent = (grid: {
42
42
  label,
43
43
  shrunklabellocation,
44
44
  value,
45
- onChange,
46
- defaultValue,
47
- inputRef,
48
45
  columnconfig: itemColumnConfig,
49
46
  valuestatus,
50
47
  cellconfig,
@@ -88,9 +85,6 @@ const useStyledComponent = (grid: {
88
85
  label={label}
89
86
  shrunklabellocation={shrunklabellocation}
90
87
  value={value}
91
- onChange={onChange}
92
- defaultValue={defaultValue}
93
- inputRef={inputRef}
94
88
  valuestatus={valuestatus}
95
89
  required={required}
96
90
  {...restProps}
@@ -1,150 +1,187 @@
1
1
  'use client'
2
- import React, { forwardRef, useImperativeHandle, useRef } from 'react'
2
+
3
+ import React, {
4
+ forwardRef,
5
+ useImperativeHandle,
6
+ useRef,
7
+ useMemo,
8
+ useCallback,
9
+ } from 'react'
3
10
  import { Close } from '@mui/icons-material'
4
11
  import { Dialog, IconButton, Box } from '@mui/material'
5
12
  import ContentSection, { ContentSectionProps } from '../../Content'
6
13
  import { formContainerStyle } from './../../../styles/Form'
7
14
  import { ExtendedTypographyProps } from '../../Content/Structure/typography/useGridTypography'
8
- import Typography from '../../Typography'
9
15
 
10
16
  /**
11
17
  * Props for the PopupForm component.
18
+ * @interface PopupFormProps
12
19
  */
13
20
  export interface PopupFormProps {
14
- /** Title of the popup form */
21
+ /** The title of the popup form */
15
22
  title?: string
16
- /** Description of the popup form */
23
+ /** The description of the popup form */
17
24
  description?: string
18
- /** Boolean to control the open state of the dialog */
19
- open: boolean
20
- /** Function to call when closing the dialog */
21
- onClose: () => void
22
- /** ContentSectionProps to render the form content */
23
- grids: ContentSectionProps['grids']
24
- /** Optional function to handle form submission */
25
- onSubmit?: () => void
25
+ /** The grid configuration for the form content */
26
+ grids?: ContentSectionProps['grids']
27
+ /** Callback function to handle form submission */
28
+ onSubmit?: (event: React.FormEvent<HTMLFormElement>) => void
29
+ /** Custom content to render inside the form */
30
+ content?: React.ReactNode
31
+ /** The type of popup to render ('dialog' or 'modal') */
32
+ popupType: 'dialog' | 'modal'
33
+ /** Whether the popup is open (only applicable for 'dialog' type) */
34
+ open?: boolean
35
+ /** Callback function to handle closing the popup (only applicable for 'dialog' type) */
36
+ onClose?: () => void
26
37
  }
27
38
 
28
39
  /**
29
- * PopupForm component renders a popup form with a title, description, and content sections.
30
- * It uses the ContentSection component to render the form content within a Material-UI Dialog.
31
- * Handles form submission and displays submitted data internally.
40
+ * PopupForm Component
41
+ *
42
+ * A flexible popup form component that can be rendered as either a dialog or a modal.
43
+ * It supports custom content, grids, and header configuration.
32
44
  *
33
- * @param props The props for the PopupForm component.
34
- * @param ref Ref forwarded to the form element.
35
- * @returns The rendered popup form.
45
+ * @component
46
+ * @example
47
+ * <PopupForm
48
+ * title="Login"
49
+ * description="Please enter your credentials"
50
+ * popupType="dialog"
51
+ * open={isOpen}
52
+ * onClose={handleClose}
53
+ * onSubmit={handleSubmit}
54
+ * content={<LoginForm />}
55
+ * />
36
56
  */
37
57
  const PopupForm = forwardRef<HTMLFormElement, PopupFormProps>(
38
- ({ title, description, open, onClose, grids, onSubmit }, ref) => {
39
- const [submittedData, setSubmittedData] = React.useState<
40
- Record<string, string>
41
- >({})
58
+ (
59
+ { title, description, grids, onSubmit, content, popupType, open, onClose },
60
+ ref
61
+ ) => {
42
62
  const internalFormRef = useRef<HTMLFormElement>(null)
43
63
 
64
+ // Expose the internal form ref to the parent component
44
65
  useImperativeHandle(ref, () => internalFormRef.current as HTMLFormElement)
45
66
 
46
67
  /**
47
- * headerGrid contains the grid configuration for the form header.
48
- * It includes the title and description as typography items.
68
+ * Memoized header grid configuration
49
69
  */
50
- const headerGrid: ContentSectionProps['grids'][0] = {
51
- grid: {
52
- gridconfig: {
53
- gridname: 'formHeader',
54
- marginbottom: 1,
55
- gridwidth: '100%',
56
- },
57
- },
58
- typography: [
59
- {
60
- text: title,
61
- fontvariant: 'merrih5',
62
- fontcolor: 'black',
63
- columnconfig: {
64
- column: 1,
70
+ const headerGrid: ContentSectionProps['grids'][0] = useMemo(
71
+ () => ({
72
+ grid: {
73
+ gridconfig: {
65
74
  gridname: 'formHeader',
66
- columnwidth: '100%',
67
- alignment: 'left',
68
- marginbottom: 0.5,
75
+ marginbottom: 1,
76
+ gridwidth: '100%',
69
77
  },
70
78
  },
71
- {
72
- text: description,
73
- fontvariant: 'merriparagraph',
74
- fontcolor: 'black',
75
- columnconfig: {
76
- column: 1,
77
- gridname: 'formHeader',
78
- columnwidth: '100%',
79
+ typography: [
80
+ {
81
+ text: title,
82
+ fontvariant: 'merrih5',
83
+ fontcolor: 'black',
84
+ columnconfig: {
85
+ row: 1,
86
+ column: 1,
87
+ gridname: 'formHeader',
88
+ columnwidth: '100%',
89
+ alignment: 'left',
90
+ marginbottom: 1.5,
91
+ },
79
92
  },
80
- },
81
- ] as ExtendedTypographyProps[],
82
- }
83
-
84
- /** Combine the header grid with the provided content grids */
85
- const contentSectionGrids: ContentSectionProps['grids'] = [
86
- headerGrid,
87
- ...grids,
88
- ]
93
+ {
94
+ text: description,
95
+ fontvariant: 'merriparagraph',
96
+ fontcolor: 'black',
97
+ columnconfig: {
98
+ row: 2,
99
+ column: 1,
100
+ alignment: 'left',
101
+ gridname: 'formHeader',
102
+ columnwidth: '100%',
103
+ },
104
+ },
105
+ ] as ExtendedTypographyProps[],
106
+ }),
107
+ [title, description]
108
+ )
89
109
 
90
110
  /**
91
- * Handles form submission and processes form data internally.
92
- * @param event - The form submission event
111
+ * Handle form submission
112
+ * @param {React.FormEvent<HTMLFormElement>} event - The form submission event
93
113
  */
94
- const handleSubmit = (event: React.FormEvent<HTMLFormElement>) => {
95
- event.preventDefault()
96
- const formData = new FormData(event.currentTarget)
97
- const data: Record<string, string> = {}
98
-
99
- formData.forEach((value, key) => {
100
- data[key] = value.toString()
101
- })
102
-
103
- setSubmittedData(data)
114
+ const handleSubmit = useCallback(
115
+ (event: React.FormEvent<HTMLFormElement>) => {
116
+ event.preventDefault()
117
+ if (onSubmit) {
118
+ onSubmit(event)
119
+ }
120
+ },
121
+ [onSubmit]
122
+ )
104
123
 
105
- if (onSubmit) {
106
- onSubmit()
107
- }
108
- }
124
+ /**
125
+ * Memoized header render function
126
+ */
127
+ const renderHeader = useMemo(
128
+ () => <ContentSection grids={[headerGrid]} />,
129
+ [headerGrid]
130
+ )
109
131
 
110
- return (
111
- <Dialog open={open} onClose={onClose} fullWidth maxWidth="sm">
112
- {/* Close button */}
113
- <IconButton
114
- size="small"
115
- onClick={onClose}
116
- sx={{
117
- position: 'absolute',
118
- right: 8,
119
- top: 8,
120
- color: theme => theme.palette.grey[500],
121
- }}
122
- >
123
- <Close />
124
- </IconButton>
125
- {/* Form container */}
132
+ /**
133
+ * Memoized content render function
134
+ */
135
+ const renderContent = useMemo(
136
+ () => (
126
137
  <Box
127
138
  // @ts-ignore
128
139
  sx={formContainerStyle}
129
140
  >
141
+ <Box mb={0}>{renderHeader}</Box>
130
142
  <form onSubmit={handleSubmit} ref={internalFormRef}>
131
- {/* Render the form content using ContentSection */}
132
- <ContentSection grids={contentSectionGrids} />
143
+ {React.isValidElement(content)
144
+ ? React.cloneElement(content as React.ReactElement, {
145
+ onSubmit: handleSubmit,
146
+ })
147
+ : content || (grids && <ContentSection grids={grids} />)}
133
148
  </form>
134
- {/* Display submitted data */}
135
- {Object.keys(submittedData).length > 0 && (
136
- <Box mt={2}>
137
- <Typography fontvariant="merrih6" text="Submitted Data:" />
138
- {Object.entries(submittedData).map(([key, value]) => (
139
- <Typography
140
- key={key}
141
- fontvariant="merriparagraph"
142
- text={`${key}: ${value}`}
143
- />
144
- ))}
145
- </Box>
146
- )}
147
149
  </Box>
150
+ ),
151
+ [renderHeader, handleSubmit, content, grids]
152
+ )
153
+
154
+ if (popupType === 'modal') {
155
+ return (
156
+ <Dialog
157
+ open={true}
158
+ fullWidth
159
+ maxWidth="sm"
160
+ disableEscapeKeyDown
161
+ hideBackdrop
162
+ >
163
+ {renderContent}
164
+ </Dialog>
165
+ )
166
+ }
167
+
168
+ return (
169
+ <Dialog open={open || false} onClose={onClose} fullWidth maxWidth="sm">
170
+ {onClose && (
171
+ <IconButton
172
+ size="small"
173
+ onClick={onClose}
174
+ sx={{
175
+ position: 'absolute',
176
+ right: 8,
177
+ top: 8,
178
+ color: theme => theme.palette.grey[500],
179
+ }}
180
+ >
181
+ <Close />
182
+ </IconButton>
183
+ )}
184
+ {renderContent}
148
185
  </Dialog>
149
186
  )
150
187
  }
@@ -1,16 +1,27 @@
1
1
  import React, { useState } from 'react'
2
2
  import { InputAdornment, Button, Box } from '@mui/material'
3
- import SearchIcon from '../../components/Icons/Search'
4
- import ShowHideEyeIcon from '../../components/Icons/ShowHideEye'
5
- import DownArrowFilledIcon from '../../components/Icons/DownArrowFilled'
6
- import { AdornmentProps } from './index'
3
+ import SearchIcon from '../../Icons/Search'
4
+ import ShowHideEyeIcon from '../../Icons/ShowHideEye'
5
+ import DownArrowFilledIcon from '../../Icons/DownArrowFilled'
6
+
7
+ /**
8
+ * Props interface for the Adornment components
9
+ */
10
+ export interface AdornmentProps {
11
+ componentvariant: string
12
+ iconcolor?: string
13
+ passwordVisible?: boolean
14
+ marginRight?: number | string
15
+ handleIncrement?: () => void
16
+ handleDecrement?: () => void
17
+ }
7
18
 
8
19
  /**
9
20
  * StartAdornment component renders the start adornment for the input component.
10
21
  * @param props The props for the StartAdornment component.
11
22
  * @returns The start adornment component or null.
12
23
  */
13
- const StartAdornment: React.FC<AdornmentProps> = props => {
24
+ export const StartAdornment: React.FC<AdornmentProps> = props => {
14
25
  const { componentvariant, iconcolor } = props
15
26
  // Render the search icon for the search bar variant
16
27
  if (componentvariant === 'searchbar') {
@@ -28,26 +39,22 @@ const StartAdornment: React.FC<AdornmentProps> = props => {
28
39
  * @param props The props for the EndAdornment component.
29
40
  * @returns The end adornment component or null.
30
41
  */
31
- const EndAdornment: React.FC<AdornmentProps> = props => {
42
+ export const EndAdornment: React.FC<AdornmentProps> = props => {
32
43
  const {
33
44
  componentvariant,
34
45
  passwordVisible,
35
46
  handleIncrement,
36
47
  handleDecrement,
37
48
  } = props
38
-
39
49
  const [isPasswordVisible, setIsPasswordVisible] = useState(
40
50
  passwordVisible || false
41
51
  )
42
-
43
52
  const adornmentStyle = {
44
53
  cursor: 'pointer',
45
54
  }
46
-
47
55
  const togglePasswordVisibility = () => {
48
56
  setIsPasswordVisible(!isPasswordVisible)
49
57
  }
50
-
51
58
  // Render the show/hide eye icon for the password variant
52
59
  if (componentvariant === 'password') {
53
60
  return (
@@ -118,5 +125,3 @@ const EndAdornment: React.FC<AdornmentProps> = props => {
118
125
  }
119
126
  return null
120
127
  }
121
-
122
- export { StartAdornment, EndAdornment }