@verifiedinc-public/shared-ui-elements 0.11.6 → 0.11.7-beta.0

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.
Files changed (89) hide show
  1. package/package.json +11 -24
  2. package/src/components/Alert/Alert.tsx +8 -0
  3. package/src/components/Alert/FullWidthAlert.tsx +27 -0
  4. package/src/components/Alert/index.ts +2 -0
  5. package/src/components/Button/index.tsx +8 -0
  6. package/src/components/CredentialRequestsEditor/CredentialRequestsEditor.context.tsx +98 -0
  7. package/src/components/CredentialRequestsEditor/components/CredentialRequestsField.tsx +103 -0
  8. package/src/components/CredentialRequestsEditor/components/DataFieldAccordion.tsx +337 -0
  9. package/src/components/CredentialRequestsEditor/components/DataFieldDeleteModal.tsx +64 -0
  10. package/src/components/CredentialRequestsEditor/components/DataFieldDescription.tsx +68 -0
  11. package/src/components/CredentialRequestsEditor/components/DataFieldMandatory.tsx +84 -0
  12. package/src/components/CredentialRequestsEditor/components/DataFieldMulti.tsx +74 -0
  13. package/src/components/CredentialRequestsEditor/components/DataFieldOptionType.tsx +84 -0
  14. package/src/components/CredentialRequestsEditor/components/DataFieldSection.tsx +48 -0
  15. package/src/components/CredentialRequestsEditor/components/DataFieldUserInput.tsx +71 -0
  16. package/src/components/CredentialRequestsEditor/components/RadioOption.tsx +89 -0
  17. package/src/components/CredentialRequestsEditor/contexts/CredentialRequestFieldContext.tsx +36 -0
  18. package/src/components/CredentialRequestsEditor/index.tsx +15 -0
  19. package/src/components/CredentialRequestsEditor/types/compositeCredentialSchema.ts +1 -0
  20. package/src/components/CredentialRequestsEditor/types/credentialSchemasDto.ts +3 -0
  21. package/src/components/CredentialRequestsEditor/types/form.ts +28 -0
  22. package/src/components/CredentialRequestsEditor/types/mandatoryEnum.ts +5 -0
  23. package/src/components/CredentialRequestsEditor/utils/buildDataFieldValue.ts +65 -0
  24. package/src/components/CredentialRequestsEditor/utils/prettyField.ts +16 -0
  25. package/src/components/Image.tsx +10 -0
  26. package/src/components/QRCodeDisplay/index.tsx +50 -0
  27. package/src/components/RequiredLabel/index.tsx +15 -0
  28. package/src/components/TextField/index.tsx +8 -0
  29. package/src/components/Tip/index.tsx +18 -0
  30. package/src/components/Typography/index.tsx +8 -0
  31. package/src/components/When.tsx +28 -0
  32. package/src/components/form/CountrySelector.tsx +96 -0
  33. package/src/components/form/DataFieldClearAdornment.tsx +28 -0
  34. package/src/components/form/DateInput.tsx +117 -0
  35. package/src/components/form/DefaultInput.tsx +28 -0
  36. package/src/components/form/InputMask.tsx +41 -0
  37. package/src/components/form/OTPInput.tsx +246 -0
  38. package/src/components/form/PhoneInput.tsx +153 -0
  39. package/src/components/form/SSNInput.tsx +100 -0
  40. package/src/components/form/SelectInput.tsx +89 -0
  41. package/src/components/form/TextMaskCustom.tsx +48 -0
  42. package/src/components/form/index.ts +5 -0
  43. package/src/components/form/styles/input.ts +24 -0
  44. package/src/components/index.ts +10 -0
  45. package/src/components/terms/AcceptTermsNotice.tsx +27 -0
  46. package/src/components/terms/LegalLink.tsx +22 -0
  47. package/src/components/verified/VerifiedImage.tsx +272 -0
  48. package/src/components/verified/VerifiedIncLogo.tsx +11 -0
  49. package/src/components/verified/index.ts +2 -0
  50. package/src/hooks/index.ts +5 -0
  51. package/src/hooks/useCallbackRef.ts +22 -0
  52. package/src/hooks/useCopyToClipboard.ts +76 -0
  53. package/src/hooks/useDisclosure.ts +96 -0
  54. package/src/hooks/useLocalStorage.ts +24 -0
  55. package/src/hooks/usePrevious.ts +17 -0
  56. package/src/hooks/useQRCode.ts +62 -0
  57. package/src/index.ts +5 -0
  58. package/src/stories/components/Alert.stories.tsx +41 -0
  59. package/src/stories/components/Button.stories.ts +49 -0
  60. package/src/stories/components/CredentialRequestsEditor.stories.tsx +98 -0
  61. package/src/stories/components/QRCodeDisplay.stories.tsx +60 -0
  62. package/src/stories/components/TextField.stories.ts +59 -0
  63. package/src/stories/components/Typography.stories.ts +140 -0
  64. package/src/stories/components/VerifiedImage.stories.tsx +32 -0
  65. package/src/stories/components/form/DateInput.stories.ts +39 -0
  66. package/src/stories/components/form/OTPInput.stories.tsx +90 -0
  67. package/src/stories/components/form/PhoneInput.stories.tsx +34 -0
  68. package/src/stories/components/form/SSNInput.stories.ts +30 -0
  69. package/src/stories/components/form/SelectInput.stories.ts +39 -0
  70. package/src/stories/hooks/useCopyToClipboard.stories.tsx +45 -0
  71. package/src/styles/colors.ts +34 -0
  72. package/src/styles/index.ts +2 -0
  73. package/src/styles/theme.ts +209 -0
  74. package/src/utils/date.ts +41 -0
  75. package/src/utils/index.ts +5 -0
  76. package/src/utils/masks/index.ts +6 -0
  77. package/src/utils/omitProperty.ts +19 -0
  78. package/src/utils/phone.ts +76 -0
  79. package/src/utils/wrapPromise.ts +19 -0
  80. package/src/validations/birthDate.schema.ts +54 -0
  81. package/src/validations/date.schema.ts +10 -0
  82. package/src/validations/description.schema.ts +5 -0
  83. package/src/validations/email.schema.ts +3 -0
  84. package/src/validations/field.schema.ts +3 -0
  85. package/src/validations/index.ts +9 -0
  86. package/src/validations/phone.schema.ts +6 -0
  87. package/src/validations/ssn.schema.ts +6 -0
  88. package/src/validations/state.schema.ts +3 -0
  89. package/src/validations/unix.schema.ts +11 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@verifiedinc-public/shared-ui-elements",
3
- "version": "0.11.6",
3
+ "version": "0.11.7-beta.0",
4
4
  "description": "A set of UI components, utilities that is shareable with the core apps.",
5
5
  "private": false,
6
6
  "keywords": [],
@@ -12,33 +12,20 @@
12
12
  "main": "/dist/shared-ui-elements.mjs",
13
13
  "types": "/dist/index.d.ts",
14
14
  "files": [
15
- "dist"
15
+ "dist",
16
+ "src"
16
17
  ],
17
18
  "exports": {
18
19
  ".": {
20
+ "types": "./dist/index.d.ts",
19
21
  "import": "./dist/shared-ui-elements.mjs",
20
- "types": "./dist/index.d.ts"
22
+ "require": "./dist/shared-ui-elements.mjs"
21
23
  },
22
- "./components": {
23
- "import": "./dist/shared-ui-elements.mjs",
24
- "types": "./dist/index.d.ts"
25
- },
26
- "./hooks": {
27
- "import": "./dist/shared-ui-elements.mjs",
28
- "types": "./dist/index.d.ts"
29
- },
30
- "./utils": {
31
- "import": "./dist/shared-ui-elements.mjs",
32
- "types": "./dist/index.d.ts"
33
- },
34
- "./validations": {
35
- "import": "./dist/shared-ui-elements.mjs",
36
- "types": "./dist/index.d.ts"
37
- },
38
- "./styles": {
39
- "import": "./dist/shared-ui-elements.mjs",
40
- "types": "./dist/index.d.ts"
41
- }
24
+ "./components": "./src/components/index.ts",
25
+ "./hooks": "./src/hooks/index.ts",
26
+ "./styles": "./src/styles/index.ts",
27
+ "./utils": "./src/utils/index.ts",
28
+ "./validations": "./src/validations/index.ts"
42
29
  },
43
30
  "scripts": {
44
31
  "vitest": "vitest",
@@ -104,6 +91,7 @@
104
91
  "tsconfig-paths": "^4.2.0",
105
92
  "tsx": "^3.12.4",
106
93
  "typescript": "^5.2.2",
94
+ "vite-plugin-commonjs": "^0.10.3",
107
95
  "vite-plugin-dts": "^4.3.0",
108
96
  "vitest": "^1.6.0",
109
97
  "zod": "^3.23.8"
@@ -116,7 +104,6 @@
116
104
  "@mona-health/react-input-mask": "^3.0.3",
117
105
  "@mui/icons-material": "^5",
118
106
  "@mui/material": "^5",
119
- "jsdom": "^24.1.0",
120
107
  "libphonenumber-js": "^1.11.11",
121
108
  "qrcode": "^1.5.4",
122
109
  "react": "^18",
@@ -0,0 +1,8 @@
1
+ import MUIAlert from '@mui/material/Alert';
2
+ import type { AlertProps as MUIAlertProps } from '@mui/material/Alert';
3
+
4
+ export type AlertProps = MUIAlertProps;
5
+
6
+ export function Alert(props: AlertProps): React.JSX.Element {
7
+ return <MUIAlert {...props} />;
8
+ }
@@ -0,0 +1,27 @@
1
+ import { Alert, type AlertProps } from '@mui/material';
2
+
3
+ interface FullWidthAlertProps extends AlertProps {}
4
+
5
+ export function FullWidthAlert({
6
+ children,
7
+ sx,
8
+ ...props
9
+ }: FullWidthAlertProps): React.JSX.Element {
10
+ return (
11
+ <>
12
+ <Alert
13
+ severity='info'
14
+ sx={{
15
+ maxWidth: '100%',
16
+ width: '100%',
17
+ textAlign: 'left',
18
+ alignItems: 'center',
19
+ ...sx,
20
+ }}
21
+ {...props}
22
+ >
23
+ {children}
24
+ </Alert>
25
+ </>
26
+ );
27
+ }
@@ -0,0 +1,2 @@
1
+ export * from './Alert';
2
+ export * from './FullWidthAlert';
@@ -0,0 +1,8 @@
1
+ import MUIButton from '@mui/material/Button';
2
+ import type { ButtonProps as MUIButtonProps } from '@mui/material/Button';
3
+
4
+ export type ButtonProps = MUIButtonProps;
5
+
6
+ export function Button(props: ButtonProps): React.JSX.Element {
7
+ return <MUIButton {...props} />;
8
+ }
@@ -0,0 +1,98 @@
1
+ import { createContext, type ReactNode, useContext, useEffect } from 'react';
2
+ import { FormProvider, useForm, type WatchObserver } from 'react-hook-form';
3
+ import debounce from 'lodash/debounce';
4
+
5
+ import { omitProperties } from '../../utils/omitProperty';
6
+
7
+ import {
8
+ type CredentialRequests,
9
+ type CredentialRequestsEditorForm,
10
+ type CredentialRequestsWithNew,
11
+ } from './types/form';
12
+
13
+ export interface CredentialRequestsEditorFeatures {
14
+ allowUserInput?: {
15
+ disabled?: boolean;
16
+ };
17
+ description?: {
18
+ disabled?: boolean;
19
+ };
20
+ mandatory?: {
21
+ disabled?: boolean;
22
+ };
23
+ multi?: {
24
+ disabled?: boolean;
25
+ };
26
+ }
27
+
28
+ export interface CredentialRequestsEditorProps {
29
+ addButtonText?: string;
30
+ credentialRequests: CredentialRequestsWithNew[];
31
+ schemas: Record<string, any>;
32
+ children: ReactNode;
33
+ onChange: (credentialRequests: CredentialRequests[]) => void;
34
+ features?: CredentialRequestsEditorFeatures;
35
+ }
36
+
37
+ export interface CredentialRequestsEditorContext {
38
+ addButtonText?: string;
39
+ schemas: Record<string, any>;
40
+ features?: CredentialRequestsEditorFeatures;
41
+ }
42
+
43
+ const Context = createContext<CredentialRequestsEditorContext | null>(null);
44
+
45
+ export function useCredentialRequestsEditor(): CredentialRequestsEditorContext {
46
+ const context = useContext(Context);
47
+ if (!context) {
48
+ throw new Error(
49
+ 'useCredentialRequestsEditor must be used within a CredentialRequestsEditorProvider',
50
+ );
51
+ }
52
+ return context;
53
+ }
54
+
55
+ export function CredentialRequestsEditorProvider(
56
+ props: CredentialRequestsEditorProps,
57
+ ): React.JSX.Element {
58
+ const form = useForm<CredentialRequestsEditorForm>({
59
+ defaultValues: { credentialRequests: props.credentialRequests },
60
+ });
61
+
62
+ // Listen to credentialRequests changes and call onChange event
63
+ useEffect(() => {
64
+ // Debouncing the watch observer to prevent multiple calls in a short period of time since it may dispatch child object change plus the property change
65
+ const debouncedWatchObserver = debounce<
66
+ WatchObserver<CredentialRequestsEditorForm>
67
+ >((data, { name, type }) => {
68
+ if (data.credentialRequests) {
69
+ const credentialRequestsData = data.credentialRequests.filter(
70
+ (credentialRequest) => !!credentialRequest?.type,
71
+ );
72
+
73
+ props.onChange(
74
+ omitProperties(credentialRequestsData, [
75
+ 'isNew',
76
+ 'id',
77
+ ]) as CredentialRequests[],
78
+ );
79
+ }
80
+ }, 100);
81
+ const subscription = form.watch(debouncedWatchObserver);
82
+ return subscription.unsubscribe;
83
+ }, [form.watch]);
84
+
85
+ return (
86
+ <FormProvider {...form}>
87
+ <Context.Provider
88
+ value={{
89
+ addButtonText: props.addButtonText,
90
+ schemas: props.schemas,
91
+ features: props.features,
92
+ }}
93
+ >
94
+ {props.children}
95
+ </Context.Provider>
96
+ </FormProvider>
97
+ );
98
+ }
@@ -0,0 +1,103 @@
1
+ import React from 'react';
2
+ import { Stack } from '@mui/material';
3
+ import { Add } from '@mui/icons-material';
4
+ import {
5
+ useFieldArray,
6
+ type UseFieldArrayReturn,
7
+ useFormContext,
8
+ } from 'react-hook-form';
9
+ import { DndProvider } from 'react-dnd';
10
+ import { HTML5Backend } from 'react-dnd-html5-backend';
11
+
12
+ import { Button } from '../../Button';
13
+
14
+ import { buildDataFieldValue } from '../utils/buildDataFieldValue';
15
+ import { CredentialRequestFieldProvider } from '../contexts/CredentialRequestFieldContext';
16
+ import { DataFieldAccordion } from './DataFieldAccordion';
17
+
18
+ import { useCredentialRequestsEditor } from '../CredentialRequestsEditor.context';
19
+ import {
20
+ type CredentialRequestsEditorForm,
21
+ type CredentialRequestsWithNew,
22
+ } from '../types/form';
23
+
24
+ function CredentialRequestField({
25
+ path = 'credentialRequests',
26
+ parentFieldArray,
27
+ parentIndex = 0,
28
+ level = 0,
29
+ }: Readonly<{
30
+ path?: string;
31
+ parentFieldArray?: UseFieldArrayReturn<CredentialRequestsEditorForm>;
32
+ parentIndex?: number;
33
+ level?: number;
34
+ }>): React.JSX.Element {
35
+ const customConfig = useCredentialRequestsEditor();
36
+ const form = useFormContext<CredentialRequestsEditorForm>();
37
+ const fieldArray = useFieldArray<CredentialRequestsEditorForm>({
38
+ control: form.control,
39
+ name: path as any,
40
+ });
41
+
42
+ return (
43
+ <>
44
+ {fieldArray.fields.map((field, index) => {
45
+ const _path = `${path}.${index}`;
46
+ return (
47
+ <CredentialRequestFieldProvider
48
+ key={_path + field.type}
49
+ path={_path}
50
+ field={field}
51
+ fieldArray={fieldArray}
52
+ index={index}
53
+ level={level}
54
+ onAllFieldsDelete={() => {
55
+ (parentFieldArray ?? fieldArray)?.remove(parentIndex);
56
+ }}
57
+ >
58
+ <DataFieldAccordion />
59
+ {Array.isArray(field.children) && (
60
+ <CredentialRequestField
61
+ key={`${_path}.children`}
62
+ path={`${_path}.children`}
63
+ parentFieldArray={fieldArray}
64
+ parentIndex={index}
65
+ level={level + 1}
66
+ />
67
+ )}
68
+ </CredentialRequestFieldProvider>
69
+ );
70
+ })}
71
+ {path === 'credentialRequests' && (
72
+ <Button
73
+ type='button'
74
+ onClick={() => {
75
+ if (!customConfig) return;
76
+ const newValue: CredentialRequestsWithNew = {
77
+ ...buildDataFieldValue('', customConfig.schemas),
78
+ isNew: true,
79
+ };
80
+ fieldArray.append(newValue);
81
+ }}
82
+ size='large'
83
+ variant='outlined'
84
+ startIcon={<Add />}
85
+ fullWidth
86
+ sx={{ width: '100%' }}
87
+ >
88
+ {customConfig.addButtonText ?? 'Add Credential Request'}
89
+ </Button>
90
+ )}
91
+ </>
92
+ );
93
+ }
94
+
95
+ export function CredentialRequestsField(): React.JSX.Element {
96
+ return (
97
+ <DndProvider backend={HTML5Backend}>
98
+ <Stack spacing={2}>
99
+ <CredentialRequestField />
100
+ </Stack>
101
+ </DndProvider>
102
+ );
103
+ }
@@ -0,0 +1,337 @@
1
+ import React, { useCallback, useEffect, useRef, useState } from 'react';
2
+ import {
3
+ Accordion,
4
+ AccordionDetails,
5
+ AccordionSummary,
6
+ Box,
7
+ IconButton,
8
+ Paper,
9
+ Stack,
10
+ Typography,
11
+ useTheme,
12
+ } from '@mui/material';
13
+ import {
14
+ CheckCircle,
15
+ ChevronLeft,
16
+ Close,
17
+ Delete,
18
+ Menu,
19
+ } from '@mui/icons-material';
20
+ import { useDrag, useDrop } from 'react-dnd';
21
+ import { useController, useFormContext } from 'react-hook-form';
22
+
23
+ import { RequiredLabel } from '../../RequiredLabel';
24
+
25
+ import { prettyField } from '../utils/prettyField';
26
+ import {
27
+ type CredentialRequestsEditorForm,
28
+ type CredentialRequestsWithNew,
29
+ } from '../types/form';
30
+ import { MandatoryEnum } from '../types/mandatoryEnum';
31
+ import { useCredentialRequestField } from '../contexts/CredentialRequestFieldContext';
32
+ import { DataFieldOptionType } from './DataFieldOptionType';
33
+ import { DataFieldDescription } from './DataFieldDescription';
34
+ import { DataFieldMandatory } from './DataFieldMandatory';
35
+ import { DataFieldUserInput } from './DataFieldUserInput';
36
+ import { DataFieldDeleteModal } from './DataFieldDeleteModal';
37
+ import { DataFieldMulti } from './DataFieldMulti';
38
+
39
+ interface DataFieldAccordionProps {
40
+ defaultExpanded?: boolean;
41
+ }
42
+
43
+ export function DataFieldAccordion(
44
+ props: DataFieldAccordionProps,
45
+ ): React.JSX.Element {
46
+ const { defaultExpanded } = props;
47
+ const credentialRequestField = useCredentialRequestField();
48
+ const formContext = useFormContext<CredentialRequestsEditorForm>();
49
+ const field = useController<CredentialRequestsEditorForm>({
50
+ name: `${credentialRequestField?.path as any}` as any,
51
+ });
52
+ const credentialRequest = field.field.value as CredentialRequestsWithNew;
53
+ const credentialRequests = formContext.watch('credentialRequests');
54
+ const isNew: boolean = (credentialRequestField?.field as any).isNew;
55
+ const [expanded, setOpen] = useState((defaultExpanded ?? isNew) || false);
56
+ const [modalOpen, setModalOpen] = useState(false);
57
+
58
+ const accordionRef = useRef<HTMLDivElement | null>(null);
59
+
60
+ const fieldType = String(credentialRequestField?.field.type);
61
+ const type = prettyField(fieldType || 'Choose a type...');
62
+
63
+ const theme = useTheme();
64
+ const chevronClassName = 'chevron';
65
+
66
+ const canDrop = useCallback(
67
+ (item: typeof credentialRequestField) => {
68
+ const source = item;
69
+ const target = credentialRequestField;
70
+
71
+ if (!source || !target) return false;
72
+
73
+ const getParentPath = (path: string): string =>
74
+ path.split('.').slice(0, -2).join('.');
75
+
76
+ const sourcePath = getParentPath(source?.path ?? '');
77
+ const targetPath = getParentPath(target?.path ?? '');
78
+ const isSameGroup = sourcePath === targetPath;
79
+
80
+ const fromLevel = source.level;
81
+ const fromIndex = source.index;
82
+ const toLevel = target.level;
83
+ const toIndex = target.index;
84
+
85
+ // Allow to drop only on the same level and different index
86
+ if (fromLevel !== toLevel || fromIndex === toIndex || !isSameGroup) {
87
+ return false;
88
+ }
89
+
90
+ return true;
91
+ },
92
+ [credentialRequestField],
93
+ );
94
+
95
+ const [{ opacity }, drag, preview] = useDrag(
96
+ () => ({
97
+ type: 'data-field-drag',
98
+ item: () => credentialRequestField,
99
+ collect: (monitor) => ({
100
+ opacity: monitor.isDragging() ? 0 : 1,
101
+ }),
102
+ }),
103
+ [credentialRequestField, credentialRequests],
104
+ );
105
+
106
+ const [{ opacity: dropOpacity }, drop] = useDrop(
107
+ () => ({
108
+ accept: 'data-field-drag',
109
+ canDrop(item) {
110
+ return canDrop(item as typeof credentialRequestField);
111
+ },
112
+ drop(item) {
113
+ const source = item as typeof credentialRequestField;
114
+ const target = credentialRequestField;
115
+
116
+ if (!source || !target) return;
117
+ if (!canDrop(source)) return;
118
+
119
+ const fromIndex = source.index;
120
+ const toIndex = target.index;
121
+
122
+ credentialRequestField.fieldArray.move(fromIndex, toIndex);
123
+ },
124
+ collect: (monitor) => {
125
+ if (monitor.isOver()) {
126
+ return {
127
+ opacity: monitor.canDrop() ? 0.4 : 1,
128
+ };
129
+ }
130
+ return {
131
+ opacity: 1,
132
+ };
133
+ },
134
+ }),
135
+ [credentialRequestField, credentialRequests],
136
+ );
137
+
138
+ const handleRemove = (): void => {
139
+ if (!credentialRequestField) return;
140
+ setModalOpen(false);
141
+
142
+ // Delete parent when the last field was removed from the stack of form fields.
143
+ // The validation should be against less or equal than 1 because is against a previous state check.
144
+ if (credentialRequestField.fieldArray.fields.length <= 1) {
145
+ credentialRequestField.onAllFieldsDelete();
146
+ return;
147
+ }
148
+
149
+ credentialRequestField.fieldArray.remove(credentialRequestField.index);
150
+ };
151
+
152
+ const renderTitle = (): React.JSX.Element => {
153
+ const typographyStyle = {
154
+ fontStyle: fieldType ? 'normal' : 'italic',
155
+ fontSize: '16px',
156
+ fontWeight: '800',
157
+ textAlign: 'left !important',
158
+ alignSelf: 'flex-start',
159
+ };
160
+
161
+ return (
162
+ <Typography variant='body1' sx={typographyStyle}>
163
+ {credentialRequest.mandatory !== MandatoryEnum.NO ? (
164
+ <RequiredLabel>{type}</RequiredLabel>
165
+ ) : (
166
+ type
167
+ )}
168
+ </Typography>
169
+ );
170
+ };
171
+
172
+ const renderUserInput = (): React.JSX.Element => {
173
+ const allowUserInput = credentialRequest.allowUserInput;
174
+
175
+ return (
176
+ <Stack direction='row' alignItems='center' spacing={0.5} pl={5.25}>
177
+ {allowUserInput ? (
178
+ <CheckCircle
179
+ sx={{ fontSize: '12px', color: theme.palette.text.disabled }}
180
+ />
181
+ ) : (
182
+ <Close
183
+ sx={{ fontSize: '12px', color: theme.palette.text.disabled }}
184
+ />
185
+ )}
186
+ <Typography
187
+ variant='body1'
188
+ color='text.disabled'
189
+ sx={{
190
+ fontSize: '12px',
191
+ fontWeight: '400',
192
+ alignSelf: 'flex-start',
193
+ textAlign: 'left!important',
194
+ }}
195
+ >
196
+ Allow User Input
197
+ </Typography>
198
+ </Stack>
199
+ );
200
+ };
201
+
202
+ useEffect(() => {
203
+ if (!isNew) return;
204
+ accordionRef.current?.scrollIntoView({ behavior: 'smooth' });
205
+ }, [isNew]);
206
+
207
+ return (
208
+ <Stack
209
+ ref={drop}
210
+ sx={{ position: 'relative', width: '100%', opacity: dropOpacity }}
211
+ >
212
+ <Paper
213
+ ref={(element) => preview(element)}
214
+ sx={{
215
+ p: '0!important',
216
+ width: `calc(100% - ${
217
+ (credentialRequestField?.level ?? 0) * 30
218
+ }px)!important`,
219
+ alignSelf: 'flex-end',
220
+ opacity,
221
+ }}
222
+ >
223
+ <Box>
224
+ <Accordion
225
+ defaultExpanded={isNew}
226
+ expanded={expanded}
227
+ sx={{
228
+ boxShadow: 'none',
229
+ '&::before': {
230
+ display: 'none',
231
+ },
232
+ my: '0px !important',
233
+ mt: 0,
234
+ p: '8px !important',
235
+ }}
236
+ data-testid='custom-demo-dialog-data-field-accordion'
237
+ >
238
+ <AccordionSummary
239
+ onClick={() => {
240
+ setOpen((prev) => !prev);
241
+ }}
242
+ expandIcon={
243
+ <>
244
+ <IconButton
245
+ size='small'
246
+ onClick={(e) => {
247
+ e.stopPropagation();
248
+ setModalOpen(true);
249
+ }}
250
+ data-testid='custom-demo-dialog-data-field-delete-button'
251
+ >
252
+ <Delete
253
+ fontSize='small'
254
+ sx={{
255
+ transform: 'rotate(0deg)',
256
+ }}
257
+ />
258
+ </IconButton>
259
+ <Stack
260
+ className={chevronClassName}
261
+ sx={{ ml: 1, alignSelf: 'center' }}
262
+ >
263
+ <ChevronLeft
264
+ fontSize='small'
265
+ sx={{
266
+ color: '#0dbc3d',
267
+ transform: 'rotate(0deg)',
268
+ }}
269
+ />
270
+ </Stack>
271
+ </>
272
+ }
273
+ sx={{
274
+ px: 0,
275
+ minHeight: 'auto!important',
276
+ '& .MuiAccordionSummary-content': {
277
+ my: '0px !important',
278
+ },
279
+ '& .MuiAccordionSummary-expandIconWrapper': {
280
+ alignSelf: 'flex-start',
281
+ transform: 'rotate(0deg) !important',
282
+ [`& .${chevronClassName}`]: {
283
+ transition: 'transform .3s',
284
+ },
285
+ '&.Mui-expanded': {
286
+ [`& .${chevronClassName}`]: {
287
+ transform: 'rotate(-90deg)',
288
+ },
289
+ },
290
+ },
291
+ }}
292
+ >
293
+ <Stack sx={{ alignItems: 'flex-start', mr: 0.5 }}>
294
+ <Stack direction='column' alignItems='flex-start' spacing={0}>
295
+ <Stack direction='row' alignItems='center' spacing={1}>
296
+ <IconButton
297
+ ref={drag}
298
+ size='small'
299
+ color='success'
300
+ onClick={(e) => {
301
+ e.preventDefault();
302
+ e.stopPropagation();
303
+ }}
304
+ sx={{ cursor: 'grab' }}
305
+ >
306
+ <Menu />
307
+ </IconButton>
308
+ {renderTitle()}
309
+ </Stack>
310
+ {renderUserInput()}
311
+ </Stack>
312
+ </Stack>
313
+ </AccordionSummary>
314
+ <AccordionDetails sx={{ pt: 3 }}>
315
+ {expanded && (
316
+ <Stack spacing={2}>
317
+ <DataFieldOptionType />
318
+ <DataFieldDescription />
319
+ <DataFieldMandatory />
320
+ <DataFieldUserInput />
321
+ <DataFieldMulti />
322
+ </Stack>
323
+ )}
324
+ </AccordionDetails>
325
+ </Accordion>
326
+ </Box>
327
+ </Paper>
328
+ <DataFieldDeleteModal
329
+ open={modalOpen}
330
+ onClose={() => {
331
+ setModalOpen(false);
332
+ }}
333
+ onConfirm={handleRemove}
334
+ />
335
+ </Stack>
336
+ );
337
+ }