@verifiedinc-public/shared-ui-elements 0.11.6 → 0.12.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 (90) hide show
  1. package/README.md +41 -0
  2. package/package.json +6 -24
  3. package/src/components/Alert/Alert.tsx +8 -0
  4. package/src/components/Alert/FullWidthAlert.tsx +27 -0
  5. package/src/components/Alert/index.ts +2 -0
  6. package/src/components/Button/index.tsx +8 -0
  7. package/src/components/CredentialRequestsEditor/CredentialRequestsEditor.context.tsx +98 -0
  8. package/src/components/CredentialRequestsEditor/components/CredentialRequestsField.tsx +103 -0
  9. package/src/components/CredentialRequestsEditor/components/DataFieldAccordion.tsx +337 -0
  10. package/src/components/CredentialRequestsEditor/components/DataFieldDeleteModal.tsx +64 -0
  11. package/src/components/CredentialRequestsEditor/components/DataFieldDescription.tsx +68 -0
  12. package/src/components/CredentialRequestsEditor/components/DataFieldMandatory.tsx +84 -0
  13. package/src/components/CredentialRequestsEditor/components/DataFieldMulti.tsx +74 -0
  14. package/src/components/CredentialRequestsEditor/components/DataFieldOptionType.tsx +84 -0
  15. package/src/components/CredentialRequestsEditor/components/DataFieldSection.tsx +48 -0
  16. package/src/components/CredentialRequestsEditor/components/DataFieldUserInput.tsx +71 -0
  17. package/src/components/CredentialRequestsEditor/components/RadioOption.tsx +89 -0
  18. package/src/components/CredentialRequestsEditor/contexts/CredentialRequestFieldContext.tsx +36 -0
  19. package/src/components/CredentialRequestsEditor/index.tsx +15 -0
  20. package/src/components/CredentialRequestsEditor/types/compositeCredentialSchema.ts +1 -0
  21. package/src/components/CredentialRequestsEditor/types/credentialSchemasDto.ts +3 -0
  22. package/src/components/CredentialRequestsEditor/types/form.ts +28 -0
  23. package/src/components/CredentialRequestsEditor/types/mandatoryEnum.ts +5 -0
  24. package/src/components/CredentialRequestsEditor/utils/buildDataFieldValue.ts +65 -0
  25. package/src/components/CredentialRequestsEditor/utils/prettyField.ts +16 -0
  26. package/src/components/Image.tsx +10 -0
  27. package/src/components/QRCodeDisplay/index.tsx +50 -0
  28. package/src/components/RequiredLabel/index.tsx +15 -0
  29. package/src/components/TextField/index.tsx +8 -0
  30. package/src/components/Tip/index.tsx +18 -0
  31. package/src/components/Typography/index.tsx +8 -0
  32. package/src/components/When.tsx +28 -0
  33. package/src/components/form/CountrySelector.tsx +96 -0
  34. package/src/components/form/DataFieldClearAdornment.tsx +28 -0
  35. package/src/components/form/DateInput.tsx +117 -0
  36. package/src/components/form/DefaultInput.tsx +28 -0
  37. package/src/components/form/InputMask.tsx +41 -0
  38. package/src/components/form/OTPInput.tsx +246 -0
  39. package/src/components/form/PhoneInput.tsx +153 -0
  40. package/src/components/form/SSNInput.tsx +100 -0
  41. package/src/components/form/SelectInput.tsx +89 -0
  42. package/src/components/form/TextMaskCustom.tsx +48 -0
  43. package/src/components/form/index.ts +5 -0
  44. package/src/components/form/styles/input.ts +24 -0
  45. package/src/components/index.ts +10 -0
  46. package/src/components/terms/AcceptTermsNotice.tsx +27 -0
  47. package/src/components/terms/LegalLink.tsx +22 -0
  48. package/src/components/verified/VerifiedImage.tsx +272 -0
  49. package/src/components/verified/VerifiedIncLogo.tsx +11 -0
  50. package/src/components/verified/index.ts +2 -0
  51. package/src/hooks/index.ts +5 -0
  52. package/src/hooks/useCallbackRef.ts +22 -0
  53. package/src/hooks/useCopyToClipboard.ts +76 -0
  54. package/src/hooks/useDisclosure.ts +96 -0
  55. package/src/hooks/useLocalStorage.ts +24 -0
  56. package/src/hooks/usePrevious.ts +17 -0
  57. package/src/hooks/useQRCode.ts +62 -0
  58. package/src/index.ts +5 -0
  59. package/src/stories/components/Alert.stories.tsx +41 -0
  60. package/src/stories/components/Button.stories.ts +49 -0
  61. package/src/stories/components/CredentialRequestsEditor.stories.tsx +98 -0
  62. package/src/stories/components/QRCodeDisplay.stories.tsx +60 -0
  63. package/src/stories/components/TextField.stories.ts +59 -0
  64. package/src/stories/components/Typography.stories.ts +140 -0
  65. package/src/stories/components/VerifiedImage.stories.tsx +32 -0
  66. package/src/stories/components/form/DateInput.stories.ts +39 -0
  67. package/src/stories/components/form/OTPInput.stories.tsx +90 -0
  68. package/src/stories/components/form/PhoneInput.stories.tsx +34 -0
  69. package/src/stories/components/form/SSNInput.stories.ts +30 -0
  70. package/src/stories/components/form/SelectInput.stories.ts +39 -0
  71. package/src/stories/hooks/useCopyToClipboard.stories.tsx +45 -0
  72. package/src/styles/colors.ts +34 -0
  73. package/src/styles/index.ts +2 -0
  74. package/src/styles/theme.ts +209 -0
  75. package/src/utils/date.ts +41 -0
  76. package/src/utils/index.ts +5 -0
  77. package/src/utils/masks/index.ts +6 -0
  78. package/src/utils/omitProperty.ts +19 -0
  79. package/src/utils/phone.ts +76 -0
  80. package/src/utils/wrapPromise.ts +19 -0
  81. package/src/validations/birthDate.schema.ts +54 -0
  82. package/src/validations/date.schema.ts +10 -0
  83. package/src/validations/description.schema.ts +5 -0
  84. package/src/validations/email.schema.ts +3 -0
  85. package/src/validations/field.schema.ts +3 -0
  86. package/src/validations/index.ts +9 -0
  87. package/src/validations/phone.schema.ts +6 -0
  88. package/src/validations/ssn.schema.ts +6 -0
  89. package/src/validations/state.schema.ts +3 -0
  90. package/src/validations/unix.schema.ts +11 -0
@@ -0,0 +1,64 @@
1
+ import {
2
+ Dialog,
3
+ DialogActions,
4
+ DialogContent,
5
+ DialogTitle,
6
+ type SxProps,
7
+ Typography,
8
+ } from '@mui/material';
9
+
10
+ import { Button } from '../../Button';
11
+
12
+ const buttonStyle: SxProps = {
13
+ minHeight: 20,
14
+ mt: 2,
15
+ py: 1,
16
+ px: 1.25,
17
+ fontWeight: '800',
18
+ fontSize: '13px',
19
+ };
20
+
21
+ interface DataFieldDeleteModalProps {
22
+ open: boolean;
23
+ onClose: () => void;
24
+ onConfirm: () => void;
25
+ }
26
+
27
+ export function DataFieldDeleteModal({
28
+ open,
29
+ onClose,
30
+ onConfirm,
31
+ }: DataFieldDeleteModalProps): React.JSX.Element {
32
+ return (
33
+ <Dialog open={open} onClose={onClose}>
34
+ <DialogTitle>Delete Data Field?</DialogTitle>
35
+ <DialogContent>
36
+ <Typography>
37
+ Are you sure you want to delete this data field?
38
+ </Typography>
39
+ </DialogContent>
40
+ <DialogActions sx={{ justifyContent: 'space-between' }}>
41
+ <Button
42
+ variant='text'
43
+ color='neutral'
44
+ size='small'
45
+ onClick={onClose}
46
+ sx={buttonStyle}
47
+ data-testid='custom-demo-dialog-data-field-delete-cancel-button'
48
+ >
49
+ Don't Delete
50
+ </Button>
51
+ <Button
52
+ variant='contained'
53
+ color='error'
54
+ size='small'
55
+ onClick={onConfirm}
56
+ sx={buttonStyle}
57
+ data-testid='custom-demo-dialog-data-field-delete-confirm-button'
58
+ >
59
+ Delete
60
+ </Button>
61
+ </DialogActions>
62
+ </Dialog>
63
+ );
64
+ }
@@ -0,0 +1,68 @@
1
+ import { useRef, useState } from 'react';
2
+ import { useController } from 'react-hook-form';
3
+ import debounce from 'lodash/debounce';
4
+ import { TextField } from '@mui/material';
5
+
6
+ import { type CredentialRequestsEditorForm } from '../types/form';
7
+ import { useCredentialRequestsEditor } from '../CredentialRequestsEditor.context';
8
+ import { useCredentialRequestField } from '../contexts/CredentialRequestFieldContext';
9
+ import { DataFieldSection } from './DataFieldSection';
10
+
11
+ export function DataFieldDescription(): React.JSX.Element {
12
+ const { features } = useCredentialRequestsEditor();
13
+ const isFeatureDisabled = features?.description?.disabled === true;
14
+
15
+ const credentialRequestField = useCredentialRequestField();
16
+ const description = useController<CredentialRequestsEditorForm>({
17
+ name: `${credentialRequestField?.path as any}.description` as any,
18
+ });
19
+ const [value, setValue] = useState(description.field.value ?? '');
20
+
21
+ const debounceChange = useRef(
22
+ debounce((value: string) => {
23
+ // Update form state
24
+ description.field.onChange({ target: { value } });
25
+ }, 500),
26
+ ).current;
27
+
28
+ const handleChange = (e: any): void => {
29
+ if (isFeatureDisabled) return;
30
+ setValue(e.target.value);
31
+ debounceChange(e.target.value);
32
+ };
33
+
34
+ return (
35
+ <DataFieldSection
36
+ title='Field Description'
37
+ description='What text appears under the field'
38
+ tip={
39
+ <>
40
+ <pre>POST /1-click</pre>
41
+ <pre>{`{\n description?: string\n}`}</pre>
42
+ </>
43
+ }
44
+ sx={{
45
+ opacity: isFeatureDisabled ? 0.5 : 1,
46
+ }}
47
+ >
48
+ <TextField
49
+ {...description.field}
50
+ value={value}
51
+ onChange={handleChange}
52
+ error={!!description.fieldState.error}
53
+ helperText={
54
+ description.fieldState.error?.message ??
55
+ 'Optional — defaults to empty'
56
+ }
57
+ label='Description'
58
+ color='success'
59
+ size='small'
60
+ className='original'
61
+ inputProps={{
62
+ 'data-testid': 'custom-demo-dialog-data-field-description-input',
63
+ }}
64
+ disabled={isFeatureDisabled}
65
+ />
66
+ </DataFieldSection>
67
+ );
68
+ }
@@ -0,0 +1,84 @@
1
+ import { useController } from 'react-hook-form';
2
+ import { RadioGroup } from '@mui/material';
3
+
4
+ import { type CredentialRequestsEditorForm } from '../types/form';
5
+ import { MandatoryEnum } from '../types/mandatoryEnum';
6
+ import { useCredentialRequestsEditor } from '../CredentialRequestsEditor.context';
7
+ import { useCredentialRequestField } from '../contexts/CredentialRequestFieldContext';
8
+ import { RadioOption } from './RadioOption';
9
+ import { DataFieldSection } from './DataFieldSection';
10
+
11
+ export function DataFieldMandatory(): React.JSX.Element {
12
+ const { features } = useCredentialRequestsEditor();
13
+ const isFeatureDisabled = features?.mandatory?.disabled === true;
14
+
15
+ const credentialRequestField = useCredentialRequestField();
16
+ const mandatory = useController<CredentialRequestsEditorForm>({
17
+ name: `${credentialRequestField?.path as any}.mandatory` as any,
18
+ });
19
+
20
+ return (
21
+ <DataFieldSection
22
+ title='Optional or Required'
23
+ description="Whether it's optional or required for the user to share this data"
24
+ tip={
25
+ <>
26
+ <pre>POST /1-click</pre>
27
+ <pre>{`{\n mandatory?: enum\n}`}</pre>
28
+ </>
29
+ }
30
+ sx={{
31
+ opacity: isFeatureDisabled ? 0.5 : 1,
32
+ }}
33
+ >
34
+ <RadioGroup
35
+ value={mandatory.field.value}
36
+ onChange={(e) => {
37
+ if (isFeatureDisabled) return;
38
+ const value = e.target.value as MandatoryEnum;
39
+
40
+ // Update form state
41
+ mandatory.field.onChange({ target: { value } });
42
+ }}
43
+ >
44
+ <RadioOption
45
+ isDefault
46
+ value={MandatoryEnum.NO}
47
+ title='Optional'
48
+ description='Optional for the user to share'
49
+ tip={MandatoryEnum.NO}
50
+ inputProps={
51
+ {
52
+ 'data-testid': 'custom-demo-dialog-mandatory-no-radio',
53
+ } as any
54
+ }
55
+ disabled={isFeatureDisabled}
56
+ />
57
+ <RadioOption
58
+ value={MandatoryEnum.IF_AVAILABLE}
59
+ title='Required if available'
60
+ description='Required to share, if the user has it'
61
+ tip={MandatoryEnum.IF_AVAILABLE}
62
+ inputProps={
63
+ {
64
+ 'data-testid': 'custom-demo-dialog-mandatory-if_available-radio',
65
+ } as any
66
+ }
67
+ disabled={isFeatureDisabled}
68
+ />
69
+ <RadioOption
70
+ value={MandatoryEnum.YES}
71
+ title='Required'
72
+ description="Required — flow fails if user doesn't have it"
73
+ tip={MandatoryEnum.YES}
74
+ inputProps={
75
+ {
76
+ 'data-testid': 'custom-demo-dialog-mandatory-yes-radio',
77
+ } as any
78
+ }
79
+ disabled={isFeatureDisabled}
80
+ />
81
+ </RadioGroup>
82
+ </DataFieldSection>
83
+ );
84
+ }
@@ -0,0 +1,74 @@
1
+ import { RadioGroup } from '@mui/material';
2
+ import { useController } from 'react-hook-form';
3
+
4
+ import { type CredentialRequestsEditorForm } from '../types/form';
5
+ import { useCredentialRequestsEditor } from '../CredentialRequestsEditor.context';
6
+ import { useCredentialRequestField } from '../contexts/CredentialRequestFieldContext';
7
+ import { RadioOption } from './RadioOption';
8
+ import { DataFieldSection } from './DataFieldSection';
9
+
10
+ export function DataFieldMulti(): React.JSX.Element | null {
11
+ const { features } = useCredentialRequestsEditor();
12
+ const isFeatureDisabled = features?.multi?.disabled === true;
13
+
14
+ const credentialRequestField = useCredentialRequestField();
15
+ const multi = useController<CredentialRequestsEditorForm>({
16
+ name: `${credentialRequestField?.path as any}.multi` as any,
17
+ });
18
+
19
+ if ((credentialRequestField?.level ?? 0) > 0) return null;
20
+
21
+ return (
22
+ <DataFieldSection
23
+ title='Multiple Values'
24
+ description='Whether multiple data values should be included if available'
25
+ tip={
26
+ <>
27
+ <pre>POST /1-click</pre>
28
+ <pre>{`{\n multi?: boolean\n}`}</pre>
29
+ </>
30
+ }
31
+ sx={{
32
+ opacity: isFeatureDisabled ? 0.5 : 1,
33
+ }}
34
+ >
35
+ <RadioGroup
36
+ value={multi.field.value ?? false}
37
+ onChange={(_, value) => {
38
+ if (isFeatureDisabled) return;
39
+
40
+ // Update form state
41
+ multi.field.onChange({
42
+ target: { value: value === 'true' },
43
+ });
44
+ }}
45
+ >
46
+ <RadioOption
47
+ value={true}
48
+ title='Yes'
49
+ description='Multiple values will be included if available'
50
+ tip='true'
51
+ inputProps={
52
+ {
53
+ 'data-testid': 'custom-demo-dialog-multi-yes-radio',
54
+ } as any
55
+ }
56
+ disabled={isFeatureDisabled}
57
+ />
58
+ <RadioOption
59
+ isDefault
60
+ value={false}
61
+ title='No'
62
+ description="Multiple values won't be included"
63
+ tip='false'
64
+ inputProps={
65
+ {
66
+ 'data-testid': 'custom-demo-dialog-multi-no-radio',
67
+ } as any
68
+ }
69
+ disabled={isFeatureDisabled}
70
+ />
71
+ </RadioGroup>
72
+ </DataFieldSection>
73
+ );
74
+ }
@@ -0,0 +1,84 @@
1
+ import { useMemo } from 'react';
2
+ import { useController } from 'react-hook-form';
3
+ import { Autocomplete, TextField } from '@mui/material';
4
+
5
+ import { prettyField } from '../utils/prettyField';
6
+
7
+ import {
8
+ type CredentialRequests,
9
+ type CredentialRequestsEditorForm,
10
+ } from '../types/form';
11
+ import { buildDataFieldValue } from '../utils/buildDataFieldValue';
12
+ import { useCredentialRequestField } from '../contexts/CredentialRequestFieldContext';
13
+ import { useCredentialRequestsEditor } from '../CredentialRequestsEditor.context';
14
+ import { DataFieldSection } from './DataFieldSection';
15
+
16
+ export function DataFieldOptionType(): React.JSX.Element {
17
+ const credentialRequestField = useCredentialRequestField();
18
+ const field = useController<CredentialRequestsEditorForm>({
19
+ name: `${credentialRequestField?.path as any}` as any,
20
+ });
21
+
22
+ const { schemas } = useCredentialRequestsEditor();
23
+ const schemaValues = useMemo(() => {
24
+ if (!schemas) return [];
25
+ return Object.values(schemas)
26
+ .map((schema) => ({
27
+ label: prettyField(schema.$id),
28
+ id: schema.$id as string,
29
+ }))
30
+ .filter((schema) => {
31
+ const blacklist = ['IdentityCredential'];
32
+ return !blacklist.includes(schema.id);
33
+ })
34
+ .sort((a, b) => (a.label < b.label ? -1 : 1));
35
+ }, [schemas]);
36
+ const selectedValue = useMemo(() => {
37
+ const type = (field.field?.value as CredentialRequests)?.type;
38
+ return schemaValues?.find((value) => value.id === type);
39
+ }, [field, schemaValues]);
40
+
41
+ return (
42
+ <DataFieldSection
43
+ key={JSON.stringify(selectedValue)}
44
+ title='Field Type'
45
+ description='What type of user data this field is for'
46
+ tip={
47
+ <>
48
+ <pre>POST /1-click</pre>
49
+ <pre>{`{\n type: string\n}`}</pre>
50
+ </>
51
+ }
52
+ >
53
+ <Autocomplete
54
+ value={selectedValue}
55
+ onChange={(_, value) => {
56
+ if (!value) return;
57
+
58
+ credentialRequestField?.fieldArray.update(
59
+ credentialRequestField?.index,
60
+ buildDataFieldValue(value.id, schemas),
61
+ );
62
+ }}
63
+ options={schemaValues}
64
+ disablePortal
65
+ renderInput={(params) => (
66
+ <TextField
67
+ {...params}
68
+ label='Type'
69
+ color='success'
70
+ size='small'
71
+ className='original'
72
+ fullWidth
73
+ inputProps={{
74
+ ...params.inputProps,
75
+ 'data-testid': 'custom-demo-dialog-data-field-type-input',
76
+ }}
77
+ placeholder='Choose a type...'
78
+ />
79
+ )}
80
+ disabled={(credentialRequestField?.level ?? 0) > 0 || schemas === null}
81
+ />
82
+ </DataFieldSection>
83
+ );
84
+ }
@@ -0,0 +1,48 @@
1
+ import { type ReactNode } from 'react';
2
+ import { Stack, SxProps, Typography } from '@mui/material';
3
+
4
+ import { Tip } from '../../Tip';
5
+
6
+ interface DataFieldSectionProps {
7
+ children: ReactNode;
8
+ title: string;
9
+ description?: string;
10
+ tip?: ReactNode;
11
+ sx?: SxProps;
12
+ }
13
+
14
+ export function DataFieldSection(
15
+ props: DataFieldSectionProps,
16
+ ): React.JSX.Element {
17
+ const { children, title, description, tip, sx } = props;
18
+
19
+ return (
20
+ <Stack sx={sx}>
21
+ <Stack direction='row' alignItems='center' spacing={0.5}>
22
+ <Typography
23
+ variant='body1'
24
+ sx={{ fontSize: '16px', fontWeight: '700' }}
25
+ data-testid='custom-demo-dialog-data-field-title'
26
+ >
27
+ {title}
28
+ </Typography>
29
+ <Tip>{tip}</Tip>
30
+ </Stack>
31
+ {description && (
32
+ <Typography
33
+ variant='body2'
34
+ color='text.secondary'
35
+ sx={{
36
+ textAlign: 'left !important',
37
+ fontSize: '12px',
38
+ fontWeight: '400',
39
+ }}
40
+ data-testid='custom-demo-dialog-data-field-description'
41
+ >
42
+ {description}
43
+ </Typography>
44
+ )}
45
+ <Stack sx={{ mt: 3 }}>{children}</Stack>
46
+ </Stack>
47
+ );
48
+ }
@@ -0,0 +1,71 @@
1
+ import { RadioGroup } from '@mui/material';
2
+ import { useController } from 'react-hook-form';
3
+
4
+ import { type CredentialRequestsEditorForm } from '../types/form';
5
+ import { useCredentialRequestsEditor } from '../CredentialRequestsEditor.context';
6
+ import { useCredentialRequestField } from '../contexts/CredentialRequestFieldContext';
7
+ import { RadioOption } from './RadioOption';
8
+ import { DataFieldSection } from './DataFieldSection';
9
+
10
+ export function DataFieldUserInput(): React.JSX.Element {
11
+ const { features } = useCredentialRequestsEditor();
12
+ const isFeatureDisabled = features?.description?.disabled === true;
13
+
14
+ const credentialRequestField = useCredentialRequestField();
15
+ const allowUserInput = useController<CredentialRequestsEditorForm>({
16
+ name: `${credentialRequestField?.path as any}.allowUserInput` as any,
17
+ });
18
+
19
+ return (
20
+ <DataFieldSection
21
+ title='Allow User Input'
22
+ description='Whether the user is allowed to add or edit data for this field'
23
+ tip={
24
+ <>
25
+ <pre>POST /1-click</pre>
26
+ <pre>{`{\n allowUserInput?: boolean\n}`}</pre>
27
+ </>
28
+ }
29
+ sx={{
30
+ opacity: isFeatureDisabled ? 0.5 : 1,
31
+ }}
32
+ >
33
+ <RadioGroup
34
+ value={allowUserInput.field.value}
35
+ onChange={(_, value) => {
36
+ if (isFeatureDisabled) return;
37
+ // Update form state
38
+ allowUserInput.field.onChange({
39
+ target: { value: value === 'true' },
40
+ });
41
+ }}
42
+ >
43
+ <RadioOption
44
+ isDefault
45
+ value={true}
46
+ title='Yes'
47
+ description='The user can add or edit data for the user to share'
48
+ tip='true'
49
+ inputProps={
50
+ {
51
+ 'data-testid': 'custom-demo-dialog-user-input-yes-radio',
52
+ } as any
53
+ }
54
+ disabled={isFeatureDisabled}
55
+ />
56
+ <RadioOption
57
+ value={false}
58
+ title='No'
59
+ description="The user can't add or edit data"
60
+ tip='false'
61
+ inputProps={
62
+ {
63
+ 'data-testid': 'custom-demo-dialog-user-input-no-radio',
64
+ } as any
65
+ }
66
+ disabled={isFeatureDisabled}
67
+ />
68
+ </RadioGroup>
69
+ </DataFieldSection>
70
+ );
71
+ }
@@ -0,0 +1,89 @@
1
+ import type { ReactNode } from 'react';
2
+ import {
3
+ Chip,
4
+ Radio,
5
+ type RadioProps,
6
+ Stack,
7
+ type SxProps,
8
+ Typography,
9
+ Box,
10
+ } from '@mui/material';
11
+
12
+ import { Tip } from '../../Tip';
13
+
14
+ type RadioOptionProps = RadioProps & {
15
+ isDefault?: boolean;
16
+ title: string;
17
+ description?: string;
18
+ tip?: ReactNode;
19
+ sx?: SxProps;
20
+ };
21
+ export function RadioOption(props: RadioOptionProps): React.JSX.Element {
22
+ const { isDefault, title, description, tip, sx, ...radioProps } = props;
23
+ return (
24
+ <Stack
25
+ direction='row'
26
+ justifyContent='space-between'
27
+ alignItems='center'
28
+ sx={{ mb: 1, ...(sx as any) }}
29
+ >
30
+ <Stack sx={{ alignItems: 'flex-start' }}>
31
+ <Stack direction='row' spacing={1}>
32
+ <Radio
33
+ {...(radioProps as any)}
34
+ sx={{
35
+ mt: '1px',
36
+ width: 34,
37
+ height: 34,
38
+ ...sx,
39
+ '&.Mui-checked': {
40
+ color: '#0dbc3d',
41
+ },
42
+ }}
43
+ />
44
+ <Stack>
45
+ <Stack direction='row' alignItems='center' spacing={1}>
46
+ <Typography
47
+ variant='body1'
48
+ sx={{
49
+ fontSize: '16px',
50
+ fontWeight: '400',
51
+ textAlign: 'left !important',
52
+ }}
53
+ >
54
+ {title}
55
+ </Typography>
56
+ <Tip>{tip}</Tip>
57
+ </Stack>
58
+ {description && (
59
+ <Typography
60
+ variant='body2'
61
+ color='text.disabled'
62
+ sx={{
63
+ textAlign: 'left !important',
64
+ alignSelf: 'flex-start',
65
+ fontSize: '12px',
66
+ fontWeight: '400',
67
+ mt: 0.5,
68
+ }}
69
+ >
70
+ {description}
71
+ </Typography>
72
+ )}
73
+ </Stack>
74
+ </Stack>
75
+ </Stack>
76
+ <Box sx={{ mt: 1, alignSelf: 'flex-start' }}>
77
+ {isDefault && (
78
+ <Chip
79
+ size='small'
80
+ label='Default'
81
+ color='info'
82
+ variant='outlined'
83
+ sx={{ fontWeight: 700 }}
84
+ />
85
+ )}
86
+ </Box>
87
+ </Stack>
88
+ );
89
+ }
@@ -0,0 +1,36 @@
1
+ import React, {
2
+ createContext,
3
+ type PropsWithChildren,
4
+ useContext,
5
+ } from 'react';
6
+ import {
7
+ type FieldArrayWithId,
8
+ type UseFieldArrayReturn,
9
+ } from 'react-hook-form';
10
+ import type { CredentialRequestsEditorForm } from '../types/form';
11
+
12
+ type CredentialRequestFieldContext = PropsWithChildren & {
13
+ path: string | undefined;
14
+ field: FieldArrayWithId<CredentialRequestsEditorForm, 'credentialRequests'>;
15
+ fieldArray: UseFieldArrayReturn<
16
+ CredentialRequestsEditorForm,
17
+ 'credentialRequests'
18
+ >;
19
+ index: number;
20
+ level: number;
21
+ onAllFieldsDelete: () => void;
22
+ };
23
+
24
+ const Context = createContext<CredentialRequestFieldContext | null>(null);
25
+
26
+ export const useCredentialRequestField =
27
+ (): CredentialRequestFieldContext | null => {
28
+ return useContext(Context);
29
+ };
30
+
31
+ export function CredentialRequestFieldProvider({
32
+ children,
33
+ ...props
34
+ }: CredentialRequestFieldContext): React.JSX.Element {
35
+ return <Context.Provider value={props}>{children}</Context.Provider>;
36
+ }
@@ -0,0 +1,15 @@
1
+ import {
2
+ type CredentialRequestsEditorProps,
3
+ CredentialRequestsEditorProvider,
4
+ } from './CredentialRequestsEditor.context';
5
+ import { CredentialRequestsField } from './components/CredentialRequestsField';
6
+
7
+ export function CredentialRequestsEditor(
8
+ props: Omit<CredentialRequestsEditorProps, 'children'>,
9
+ ): React.JSX.Element {
10
+ return (
11
+ <CredentialRequestsEditorProvider {...props}>
12
+ <CredentialRequestsField />
13
+ </CredentialRequestsEditorProvider>
14
+ );
15
+ }
@@ -0,0 +1 @@
1
+ export type CompositeCredentialSchema = Record<string, any>;
@@ -0,0 +1,3 @@
1
+ export interface CredentialSchemaDto {
2
+ schemas: Record<string, any>;
3
+ }
@@ -0,0 +1,28 @@
1
+ import { type MandatoryEnum } from './mandatoryEnum';
2
+
3
+ export interface CredentialRequests {
4
+ type: string;
5
+ issuers?: string[];
6
+ required?: boolean;
7
+ mandatory?: MandatoryEnum;
8
+ description?: string;
9
+ allowUserInput?: boolean;
10
+ multi?: boolean;
11
+ children?: CredentialRequests[];
12
+ }
13
+
14
+ export interface CredentialRequestsWithNew {
15
+ type: string;
16
+ issuers?: string[];
17
+ required?: boolean;
18
+ mandatory?: MandatoryEnum;
19
+ description?: string;
20
+ allowUserInput?: boolean;
21
+ multi?: boolean;
22
+ children?: CredentialRequestsWithNew[];
23
+ isNew?: boolean;
24
+ }
25
+
26
+ export interface CredentialRequestsEditorForm {
27
+ credentialRequests: CredentialRequestsWithNew[];
28
+ }
@@ -0,0 +1,5 @@
1
+ export enum MandatoryEnum {
2
+ YES = 'yes',
3
+ NO = 'no',
4
+ IF_AVAILABLE = 'if_available',
5
+ }