dynamic-modal 1.0.11 → 1.0.13
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/.idea/dynamic-modal.iml +12 -0
- package/.idea/inspectionProfiles/Project_Default.xml +6 -0
- package/.idea/modules.xml +8 -0
- package/.idea/vcs.xml +6 -0
- package/README-ES.md +119 -119
- package/README.md +119 -119
- package/dist/components/input-upload/input-upload.js +18 -8
- package/dist/components/make-autocomplete/make-autocomplete.js +24 -17
- package/dist/components/make-input/make-input.js +24 -17
- package/dist/components/make-multi-select/make-multi-select.js +24 -17
- package/dist/components/make-select/make-select.js +24 -17
- package/dist/components/make-textarea/make-textarea.js +23 -16
- package/dist/components/make-toggle/make-toggle.js +36 -14
- package/dist/components/make-upload/make-upload.js +20 -8
- package/dist/components/portal/portal.js +17 -7
- package/dist/interfaces/field.d.ts +7 -4
- package/dist/interfaces/input-upload.d.ts +1 -15
- package/dist/modal.js +17 -7
- package/eslint.config.mjs +13 -13
- package/examples/enable-if.ts +129 -129
- package/examples/live-data.ts +63 -63
- package/examples/render-if.ts +130 -130
- package/examples/simple.ts +76 -76
- package/index.ts +2 -2
- package/package.json +48 -48
- package/src/components/input-upload/input-upload.tsx +72 -72
- package/src/components/make-autocomplete/make-autocomplete.tsx +54 -53
- package/src/components/make-button/make-button.tsx +17 -17
- package/src/components/make-input/make-input.tsx +47 -46
- package/src/components/make-multi-select/make-multi-select.tsx +56 -55
- package/src/components/make-select/make-select.tsx +54 -53
- package/src/components/make-text/make-text.tsx +16 -16
- package/src/components/make-textarea/make-textarea.tsx +48 -47
- package/src/components/make-title/make-title.tsx +12 -12
- package/src/components/make-toggle/make-toggle.tsx +44 -44
- package/src/components/make-upload/make-upload.tsx +34 -41
- package/src/components/portal/portal.tsx +36 -36
- package/src/hooks/field-render.ts +108 -108
- package/src/hooks/modal-handler.ts +37 -37
- package/src/interfaces/field.ts +35 -31
- package/src/interfaces/input-upload.ts +21 -37
- package/src/interfaces/make-autocomplete.ts +13 -13
- package/src/interfaces/make-button.ts +20 -20
- package/src/interfaces/make-field-group.ts +13 -13
- package/src/interfaces/make-field.ts +14 -14
- package/src/interfaces/make-multi-select.ts +14 -14
- package/src/interfaces/make-select.ts +12 -12
- package/src/interfaces/make-text.ts +12 -12
- package/src/interfaces/make-textarea.ts +11 -11
- package/src/interfaces/make-title.ts +3 -3
- package/src/interfaces/make-toggle.ts +9 -9
- package/src/interfaces/make-upload.ts +14 -14
- package/src/interfaces/modal.ts +51 -51
- package/src/interfaces/option.ts +3 -3
- package/src/interfaces/portal.ts +8 -8
- package/src/modal.tsx +174 -174
- package/src/tools/general.ts +6 -6
- package/tsconfig.json +13 -13
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import { IField, IFieldProps } from './field'
|
|
2
|
-
|
|
3
|
-
export interface IMakeToggle extends IField{
|
|
4
|
-
elementType: 'toggle'
|
|
5
|
-
}
|
|
6
|
-
|
|
7
|
-
export interface IMakeToggleProps extends IFieldProps {
|
|
8
|
-
element: IMakeToggle
|
|
9
|
-
}
|
|
1
|
+
import { IField, IFieldProps } from './field'
|
|
2
|
+
|
|
3
|
+
export interface IMakeToggle extends IField{
|
|
4
|
+
elementType: 'toggle'
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
export interface IMakeToggleProps extends IFieldProps {
|
|
8
|
+
element: IMakeToggle
|
|
9
|
+
}
|
|
@@ -1,14 +1,14 @@
|
|
|
1
|
-
import { IField, IFieldProps } from './field'
|
|
2
|
-
|
|
3
|
-
export interface IMakeUpload extends Omit<IField, 'defaultValue'> {
|
|
4
|
-
elementType: 'upload';
|
|
5
|
-
helpText?: string;
|
|
6
|
-
read: boolean;
|
|
7
|
-
image?: boolean;
|
|
8
|
-
accept?:string;
|
|
9
|
-
readAsArrayBuffer?: boolean;
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
export interface IMakeUploadProps extends IFieldProps {
|
|
13
|
-
element: IMakeUpload
|
|
14
|
-
}
|
|
1
|
+
import { IField, IFieldProps } from './field'
|
|
2
|
+
|
|
3
|
+
export interface IMakeUpload extends Omit<IField, 'defaultValue'> {
|
|
4
|
+
elementType: 'upload';
|
|
5
|
+
helpText?: string;
|
|
6
|
+
read: boolean;
|
|
7
|
+
image?: boolean;
|
|
8
|
+
accept?:string;
|
|
9
|
+
readAsArrayBuffer?: boolean;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export interface IMakeUploadProps extends IFieldProps {
|
|
13
|
+
element: IMakeUpload
|
|
14
|
+
}
|
package/src/interfaces/modal.ts
CHANGED
|
@@ -1,51 +1,51 @@
|
|
|
1
|
-
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
2
|
-
import { CSSProperties } from 'react'
|
|
3
|
-
import { IMakeSelect } from './make-select'
|
|
4
|
-
import { IMakeInput } from './make-field'
|
|
5
|
-
import { IMakeTextarea } from './make-textarea'
|
|
6
|
-
import { IMakeToggle } from './make-toggle'
|
|
7
|
-
import { IMakeMultiSelect } from './make-multi-select'
|
|
8
|
-
import { IMakeText } from './make-text'
|
|
9
|
-
import { IMakeFieldGroup } from './make-field-group'
|
|
10
|
-
import { IMakeUpload } from './make-upload'
|
|
11
|
-
import { IOption } from './option'
|
|
12
|
-
import { IMakeButton } from './make-button'
|
|
13
|
-
import { IMakeAutoComplete } from './make-autocomplete'
|
|
14
|
-
|
|
15
|
-
export type IModalField = IMakeSelect | IMakeInput | IMakeFieldGroup | IMakeTextarea | IMakeToggle | IMakeMultiSelect | IMakeText | IMakeUpload | IMakeButton | IMakeAutoComplete
|
|
16
|
-
|
|
17
|
-
export type IFormField = IMakeSelect | IMakeInput | IMakeTextarea | IMakeToggle | IMakeMultiSelect
|
|
18
|
-
|
|
19
|
-
export type IModalRenderCondition = Record<string, Array<string | number>>
|
|
20
|
-
|
|
21
|
-
export type IModalLiveDataCondition = {
|
|
22
|
-
action: (data: string, ...args: any[]) => Promise<Array<IOption>>;
|
|
23
|
-
condition: Array<string>
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
export interface IModalConfigProps {
|
|
27
|
-
fields: Array<IModalField>
|
|
28
|
-
title: string
|
|
29
|
-
action: {
|
|
30
|
-
name: string
|
|
31
|
-
action?: (data: any) => void
|
|
32
|
-
hide?: boolean
|
|
33
|
-
}
|
|
34
|
-
cancel?: {
|
|
35
|
-
name?: string;
|
|
36
|
-
action?: () => void
|
|
37
|
-
hide?: boolean;
|
|
38
|
-
}
|
|
39
|
-
reservedData?: Record<string, any>
|
|
40
|
-
styles?: CSSProperties;
|
|
41
|
-
overFlowBody?: string | number
|
|
42
|
-
minHeightBody?: string | number
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
export type IModalConfigLoader<T = any, D = any> = (props: T, action: (modalResult: D) => void) => IModalConfigProps
|
|
46
|
-
|
|
47
|
-
export interface IModal {
|
|
48
|
-
open: boolean;
|
|
49
|
-
close: () => void
|
|
50
|
-
config: IModalConfigProps
|
|
51
|
-
}
|
|
1
|
+
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
2
|
+
import { CSSProperties } from 'react'
|
|
3
|
+
import { IMakeSelect } from './make-select'
|
|
4
|
+
import { IMakeInput } from './make-field'
|
|
5
|
+
import { IMakeTextarea } from './make-textarea'
|
|
6
|
+
import { IMakeToggle } from './make-toggle'
|
|
7
|
+
import { IMakeMultiSelect } from './make-multi-select'
|
|
8
|
+
import { IMakeText } from './make-text'
|
|
9
|
+
import { IMakeFieldGroup } from './make-field-group'
|
|
10
|
+
import { IMakeUpload } from './make-upload'
|
|
11
|
+
import { IOption } from './option'
|
|
12
|
+
import { IMakeButton } from './make-button'
|
|
13
|
+
import { IMakeAutoComplete } from './make-autocomplete'
|
|
14
|
+
|
|
15
|
+
export type IModalField = IMakeSelect | IMakeInput | IMakeFieldGroup | IMakeTextarea | IMakeToggle | IMakeMultiSelect | IMakeText | IMakeUpload | IMakeButton | IMakeAutoComplete
|
|
16
|
+
|
|
17
|
+
export type IFormField = IMakeSelect | IMakeInput | IMakeTextarea | IMakeToggle | IMakeMultiSelect
|
|
18
|
+
|
|
19
|
+
export type IModalRenderCondition = Record<string, Array<string | number>>
|
|
20
|
+
|
|
21
|
+
export type IModalLiveDataCondition = {
|
|
22
|
+
action: (data: string, ...args: any[]) => Promise<Array<IOption>>;
|
|
23
|
+
condition: Array<string>
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export interface IModalConfigProps {
|
|
27
|
+
fields: Array<IModalField>
|
|
28
|
+
title: string
|
|
29
|
+
action: {
|
|
30
|
+
name: string
|
|
31
|
+
action?: (data: any) => void
|
|
32
|
+
hide?: boolean
|
|
33
|
+
}
|
|
34
|
+
cancel?: {
|
|
35
|
+
name?: string;
|
|
36
|
+
action?: () => void
|
|
37
|
+
hide?: boolean;
|
|
38
|
+
}
|
|
39
|
+
reservedData?: Record<string, any>
|
|
40
|
+
styles?: CSSProperties;
|
|
41
|
+
overFlowBody?: string | number
|
|
42
|
+
minHeightBody?: string | number
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export type IModalConfigLoader<T = any, D = any> = (props: T, action: (modalResult: D) => void) => IModalConfigProps
|
|
46
|
+
|
|
47
|
+
export interface IModal {
|
|
48
|
+
open: boolean;
|
|
49
|
+
close: () => void
|
|
50
|
+
config: IModalConfigProps
|
|
51
|
+
}
|
package/src/interfaces/option.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export interface IOption {
|
|
2
|
-
id: string;
|
|
3
|
-
name: string;
|
|
1
|
+
export interface IOption {
|
|
2
|
+
id: string;
|
|
3
|
+
name: string;
|
|
4
4
|
}
|
package/src/interfaces/portal.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { ReactNode } from 'react'
|
|
2
|
-
|
|
3
|
-
export interface IPortal {
|
|
4
|
-
children: ReactNode;
|
|
5
|
-
closeTime: number;
|
|
6
|
-
portalOpen: boolean;
|
|
7
|
-
portalTag?: string;
|
|
8
|
-
}
|
|
1
|
+
import { ReactNode } from 'react'
|
|
2
|
+
|
|
3
|
+
export interface IPortal {
|
|
4
|
+
children: ReactNode;
|
|
5
|
+
closeTime: number;
|
|
6
|
+
portalOpen: boolean;
|
|
7
|
+
portalTag?: string;
|
|
8
|
+
}
|
package/src/modal.tsx
CHANGED
|
@@ -1,174 +1,174 @@
|
|
|
1
|
-
'use client'
|
|
2
|
-
import React, { useEffect, useState } from 'react'
|
|
3
|
-
import { useForm } from 'react-hook-form'
|
|
4
|
-
import { Button } from '@nextui-org/react'
|
|
5
|
-
import { Portal } from './components/portal/portal'
|
|
6
|
-
import MakeToggle from './components/make-toggle/make-toggle'
|
|
7
|
-
import MakeInput from './components/make-input/make-input'
|
|
8
|
-
import MakeSelect from './components/make-select/make-select'
|
|
9
|
-
import MakeTextarea from './components/make-textarea/make-textarea'
|
|
10
|
-
import { IModal, IModalField, IModalConfigProps, IFormField } from './interfaces/modal'
|
|
11
|
-
import MakeMultiSelect from './components/make-multi-select/make-multi-select'
|
|
12
|
-
import MakeText from './components/make-text/make-text'
|
|
13
|
-
import { IFieldProps } from './interfaces/field'
|
|
14
|
-
import MakeUpload from './components/make-upload/make-upload'
|
|
15
|
-
import MakeButton from './components/make-button/make-button'
|
|
16
|
-
import MakeAutocomplete from './components/make-autocomplete/make-autocomplete'
|
|
17
|
-
|
|
18
|
-
export const Modal = ({ open, close, config }: IModal) => {
|
|
19
|
-
const [modalReady, setModalReady] = useState<IModalConfigProps | undefined>(undefined)
|
|
20
|
-
const [defaultLoaded, setDefaultLoaded] = useState<boolean>(false)
|
|
21
|
-
|
|
22
|
-
const {
|
|
23
|
-
control,
|
|
24
|
-
handleSubmit,
|
|
25
|
-
getValues,
|
|
26
|
-
unregister,
|
|
27
|
-
setValue,
|
|
28
|
-
watch
|
|
29
|
-
} = useForm()
|
|
30
|
-
|
|
31
|
-
const formValueHandler = (element: IFormField) => {
|
|
32
|
-
if (['group', 'upload', 'text'].includes(element.elementType)) return
|
|
33
|
-
if(!element.defaultValue && element.renderIf) {
|
|
34
|
-
unregister(element.name)
|
|
35
|
-
return
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
const defaultValue = element.defaultValue ?? ''
|
|
39
|
-
const parsedValue: boolean | string | Array<string> | undefined = defaultValue === 'true' ? true : defaultValue === 'false' ? false : defaultValue
|
|
40
|
-
setValue(element.name, parsedValue ?? '')
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
const autoLoadGroup = (groupFields: Array<IModalField>) => {
|
|
44
|
-
groupFields.forEach(element => {
|
|
45
|
-
formValueHandler(element as IFormField)
|
|
46
|
-
})
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
const autoLoadField = (modalFields: Array<IModalField>) => {
|
|
50
|
-
if (defaultLoaded) return
|
|
51
|
-
|
|
52
|
-
modalFields.forEach(element => {
|
|
53
|
-
if (element.elementType === 'group') {
|
|
54
|
-
autoLoadGroup(element.groups)
|
|
55
|
-
return
|
|
56
|
-
}
|
|
57
|
-
formValueHandler(element as IFormField)
|
|
58
|
-
})
|
|
59
|
-
|
|
60
|
-
setDefaultLoaded(true)
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
const getRender = (element: IModalField, index: number, isEndOfRender: boolean = false) => {
|
|
64
|
-
if (isEndOfRender && modalReady) setTimeout(() => autoLoadField(modalReady.fields), 200)
|
|
65
|
-
|
|
66
|
-
const props: IFieldProps = {
|
|
67
|
-
control,
|
|
68
|
-
watch,
|
|
69
|
-
setValue,
|
|
70
|
-
unregister
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
return element.elementType === 'input'
|
|
74
|
-
? <MakeInput {...props} key={`modal-input-${index}`} element={element} />
|
|
75
|
-
: element.elementType === 'select'
|
|
76
|
-
? <MakeSelect {...props} key={`modal-select-${index}`} element={element} />
|
|
77
|
-
: element.elementType === 'textarea'
|
|
78
|
-
? <MakeTextarea {...props} key={`modal-textarea-${index}`} element={element} />
|
|
79
|
-
: element.elementType === 'toggle'
|
|
80
|
-
? <MakeToggle {...props} key={`modal-toggle-${index}`} element={element} />
|
|
81
|
-
: element.elementType === 'multiselect'
|
|
82
|
-
? <MakeMultiSelect {...props} key={`modal-multiselect-${index}`} element={element} />
|
|
83
|
-
: element.elementType === 'text'
|
|
84
|
-
? <MakeText {...props} key={`modal-text-${index}`} element={element} />
|
|
85
|
-
: element.elementType === 'upload'
|
|
86
|
-
? <MakeUpload {...props} key={`modal-upload-${index}`} element={element} />
|
|
87
|
-
: element.elementType === 'button'
|
|
88
|
-
? <MakeButton {...props} key={`modal-button-${index}`} element={element} />
|
|
89
|
-
: element.elementType === 'autocomplete'
|
|
90
|
-
? <MakeAutocomplete {...props} key={`modal-autocomplete-${index}`} element={element} />
|
|
91
|
-
: null
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
const closeHandler = (): void => {
|
|
95
|
-
if (modalReady?.cancel && modalReady.cancel.action) modalReady.cancel.action()
|
|
96
|
-
setTimeout(() => {
|
|
97
|
-
const form = getValues()
|
|
98
|
-
unregister(Object.keys(form))
|
|
99
|
-
setModalReady(undefined)
|
|
100
|
-
setDefaultLoaded(false)
|
|
101
|
-
close()
|
|
102
|
-
}, 200)
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
const actionHandler = (data: Record<string, string | number | object>): void => {
|
|
106
|
-
if (modalReady?.action && modalReady.action.action) modalReady.action.action({ ...modalReady?.reservedData, ...data })
|
|
107
|
-
closeHandler()
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
useEffect(() => {
|
|
111
|
-
if (open && !modalReady) setModalReady(config)
|
|
112
|
-
}, [config, modalReady, open])
|
|
113
|
-
|
|
114
|
-
return (
|
|
115
|
-
modalReady
|
|
116
|
-
? <Portal closeTime={200} portalOpen={open} portalTag={'#modal-portal'}>
|
|
117
|
-
<div className='rounded bg-white relative w-auto h-auto min-h-[200px] min-w-[500px]' style={{ ...modalReady.styles }} >
|
|
118
|
-
<form className='flex flex-col p-4 gap-4' autoComplete='off' onSubmit={handleSubmit(actionHandler)}>
|
|
119
|
-
<h2 className='text-bold text-center border-b pb-4 font-semibold'>{modalReady.title}</h2>
|
|
120
|
-
<div
|
|
121
|
-
className='flex flex-col items-center gap-4 py-4'
|
|
122
|
-
style={{
|
|
123
|
-
overflowY: modalReady.overFlowBody ? 'auto' : undefined,
|
|
124
|
-
height: modalReady.overFlowBody,
|
|
125
|
-
minHeight: modalReady.minHeightBody
|
|
126
|
-
}}
|
|
127
|
-
>
|
|
128
|
-
{
|
|
129
|
-
modalReady.fields.map((element, index) => {
|
|
130
|
-
const isEndOfRender: boolean = index + 1 === modalReady.fields.length
|
|
131
|
-
|
|
132
|
-
if (element.elementType === 'group') {
|
|
133
|
-
return (
|
|
134
|
-
<div key={`modal-group-${index}`} className='flex gap-4 w-full' style={element.style} >
|
|
135
|
-
{
|
|
136
|
-
element.groups
|
|
137
|
-
.filter(sub => ['input', 'select', 'toggle', 'multiselect', 'upload', 'button', 'autocomplete'].includes(sub.elementType))
|
|
138
|
-
.map((sub, subIndex) => getRender(sub, index + subIndex, isEndOfRender))
|
|
139
|
-
}
|
|
140
|
-
</div>
|
|
141
|
-
)
|
|
142
|
-
} else { return getRender(element, index, isEndOfRender) }
|
|
143
|
-
})
|
|
144
|
-
}
|
|
145
|
-
</div>
|
|
146
|
-
<div className='flex items-center justify-around gap-4 py-2 border-t'>
|
|
147
|
-
{modalReady.cancel &&
|
|
148
|
-
<Button
|
|
149
|
-
variant='bordered'
|
|
150
|
-
onClick={closeHandler}
|
|
151
|
-
type='reset'
|
|
152
|
-
className='w-[140px]'
|
|
153
|
-
>
|
|
154
|
-
{modalReady.cancel.name ?? 'Close'}
|
|
155
|
-
</Button>
|
|
156
|
-
}
|
|
157
|
-
{modalReady.action &&
|
|
158
|
-
<Button
|
|
159
|
-
color='primary'
|
|
160
|
-
type='submit'
|
|
161
|
-
className='w-[140px]'
|
|
162
|
-
>
|
|
163
|
-
{modalReady.action.name ?? 'Ok'}
|
|
164
|
-
</Button>
|
|
165
|
-
}
|
|
166
|
-
</div>
|
|
167
|
-
</form>
|
|
168
|
-
</div>
|
|
169
|
-
</Portal>
|
|
170
|
-
: null
|
|
171
|
-
)
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
export default Modal
|
|
1
|
+
'use client'
|
|
2
|
+
import React, { useEffect, useState } from 'react'
|
|
3
|
+
import { useForm } from 'react-hook-form'
|
|
4
|
+
import { Button } from '@nextui-org/react'
|
|
5
|
+
import { Portal } from './components/portal/portal'
|
|
6
|
+
import MakeToggle from './components/make-toggle/make-toggle'
|
|
7
|
+
import MakeInput from './components/make-input/make-input'
|
|
8
|
+
import MakeSelect from './components/make-select/make-select'
|
|
9
|
+
import MakeTextarea from './components/make-textarea/make-textarea'
|
|
10
|
+
import { IModal, IModalField, IModalConfigProps, IFormField } from './interfaces/modal'
|
|
11
|
+
import MakeMultiSelect from './components/make-multi-select/make-multi-select'
|
|
12
|
+
import MakeText from './components/make-text/make-text'
|
|
13
|
+
import { IFieldProps } from './interfaces/field'
|
|
14
|
+
import MakeUpload from './components/make-upload/make-upload'
|
|
15
|
+
import MakeButton from './components/make-button/make-button'
|
|
16
|
+
import MakeAutocomplete from './components/make-autocomplete/make-autocomplete'
|
|
17
|
+
|
|
18
|
+
export const Modal = ({ open, close, config }: IModal) => {
|
|
19
|
+
const [modalReady, setModalReady] = useState<IModalConfigProps | undefined>(undefined)
|
|
20
|
+
const [defaultLoaded, setDefaultLoaded] = useState<boolean>(false)
|
|
21
|
+
|
|
22
|
+
const {
|
|
23
|
+
control,
|
|
24
|
+
handleSubmit,
|
|
25
|
+
getValues,
|
|
26
|
+
unregister,
|
|
27
|
+
setValue,
|
|
28
|
+
watch
|
|
29
|
+
} = useForm()
|
|
30
|
+
|
|
31
|
+
const formValueHandler = (element: IFormField) => {
|
|
32
|
+
if (['group', 'upload', 'text'].includes(element.elementType)) return
|
|
33
|
+
if(!element.defaultValue && element.renderIf) {
|
|
34
|
+
unregister(element.name)
|
|
35
|
+
return
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
const defaultValue = element.defaultValue ?? ''
|
|
39
|
+
const parsedValue: boolean | string | Array<string> | undefined = defaultValue === 'true' ? true : defaultValue === 'false' ? false : defaultValue
|
|
40
|
+
setValue(element.name, parsedValue ?? '')
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
const autoLoadGroup = (groupFields: Array<IModalField>) => {
|
|
44
|
+
groupFields.forEach(element => {
|
|
45
|
+
formValueHandler(element as IFormField)
|
|
46
|
+
})
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
const autoLoadField = (modalFields: Array<IModalField>) => {
|
|
50
|
+
if (defaultLoaded) return
|
|
51
|
+
|
|
52
|
+
modalFields.forEach(element => {
|
|
53
|
+
if (element.elementType === 'group') {
|
|
54
|
+
autoLoadGroup(element.groups)
|
|
55
|
+
return
|
|
56
|
+
}
|
|
57
|
+
formValueHandler(element as IFormField)
|
|
58
|
+
})
|
|
59
|
+
|
|
60
|
+
setDefaultLoaded(true)
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
const getRender = (element: IModalField, index: number, isEndOfRender: boolean = false) => {
|
|
64
|
+
if (isEndOfRender && modalReady) setTimeout(() => autoLoadField(modalReady.fields), 200)
|
|
65
|
+
|
|
66
|
+
const props: IFieldProps = {
|
|
67
|
+
control,
|
|
68
|
+
watch,
|
|
69
|
+
setValue,
|
|
70
|
+
unregister
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
return element.elementType === 'input'
|
|
74
|
+
? <MakeInput {...props} key={`modal-input-${index}`} element={element} />
|
|
75
|
+
: element.elementType === 'select'
|
|
76
|
+
? <MakeSelect {...props} key={`modal-select-${index}`} element={element} />
|
|
77
|
+
: element.elementType === 'textarea'
|
|
78
|
+
? <MakeTextarea {...props} key={`modal-textarea-${index}`} element={element} />
|
|
79
|
+
: element.elementType === 'toggle'
|
|
80
|
+
? <MakeToggle {...props} key={`modal-toggle-${index}`} element={element} />
|
|
81
|
+
: element.elementType === 'multiselect'
|
|
82
|
+
? <MakeMultiSelect {...props} key={`modal-multiselect-${index}`} element={element} />
|
|
83
|
+
: element.elementType === 'text'
|
|
84
|
+
? <MakeText {...props} key={`modal-text-${index}`} element={element} />
|
|
85
|
+
: element.elementType === 'upload'
|
|
86
|
+
? <MakeUpload {...props} key={`modal-upload-${index}`} element={element} />
|
|
87
|
+
: element.elementType === 'button'
|
|
88
|
+
? <MakeButton {...props} key={`modal-button-${index}`} element={element} />
|
|
89
|
+
: element.elementType === 'autocomplete'
|
|
90
|
+
? <MakeAutocomplete {...props} key={`modal-autocomplete-${index}`} element={element} />
|
|
91
|
+
: null
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
const closeHandler = (): void => {
|
|
95
|
+
if (modalReady?.cancel && modalReady.cancel.action) modalReady.cancel.action()
|
|
96
|
+
setTimeout(() => {
|
|
97
|
+
const form = getValues()
|
|
98
|
+
unregister(Object.keys(form))
|
|
99
|
+
setModalReady(undefined)
|
|
100
|
+
setDefaultLoaded(false)
|
|
101
|
+
close()
|
|
102
|
+
}, 200)
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
const actionHandler = (data: Record<string, string | number | object>): void => {
|
|
106
|
+
if (modalReady?.action && modalReady.action.action) modalReady.action.action({ ...modalReady?.reservedData, ...data })
|
|
107
|
+
closeHandler()
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
useEffect(() => {
|
|
111
|
+
if (open && !modalReady) setModalReady(config)
|
|
112
|
+
}, [config, modalReady, open])
|
|
113
|
+
|
|
114
|
+
return (
|
|
115
|
+
modalReady
|
|
116
|
+
? <Portal closeTime={200} portalOpen={open} portalTag={'#modal-portal'}>
|
|
117
|
+
<div className='rounded bg-white relative w-auto h-auto min-h-[200px] min-w-[500px]' style={{ ...modalReady.styles }} >
|
|
118
|
+
<form className='flex flex-col p-4 gap-4' autoComplete='off' onSubmit={handleSubmit(actionHandler)}>
|
|
119
|
+
<h2 className='text-bold text-center border-b pb-4 font-semibold'>{modalReady.title}</h2>
|
|
120
|
+
<div
|
|
121
|
+
className='flex flex-col items-center gap-4 py-4'
|
|
122
|
+
style={{
|
|
123
|
+
overflowY: modalReady.overFlowBody ? 'auto' : undefined,
|
|
124
|
+
height: modalReady.overFlowBody,
|
|
125
|
+
minHeight: modalReady.minHeightBody
|
|
126
|
+
}}
|
|
127
|
+
>
|
|
128
|
+
{
|
|
129
|
+
modalReady.fields.map((element, index) => {
|
|
130
|
+
const isEndOfRender: boolean = index + 1 === modalReady.fields.length
|
|
131
|
+
|
|
132
|
+
if (element.elementType === 'group') {
|
|
133
|
+
return (
|
|
134
|
+
<div key={`modal-group-${index}`} className='flex gap-4 w-full' style={element.style} >
|
|
135
|
+
{
|
|
136
|
+
element.groups
|
|
137
|
+
.filter(sub => ['input', 'select', 'toggle', 'multiselect', 'upload', 'button', 'autocomplete'].includes(sub.elementType))
|
|
138
|
+
.map((sub, subIndex) => getRender(sub, index + subIndex, isEndOfRender))
|
|
139
|
+
}
|
|
140
|
+
</div>
|
|
141
|
+
)
|
|
142
|
+
} else { return getRender(element, index, isEndOfRender) }
|
|
143
|
+
})
|
|
144
|
+
}
|
|
145
|
+
</div>
|
|
146
|
+
<div className='flex items-center justify-around gap-4 py-2 border-t'>
|
|
147
|
+
{modalReady.cancel &&
|
|
148
|
+
<Button
|
|
149
|
+
variant='bordered'
|
|
150
|
+
onClick={closeHandler}
|
|
151
|
+
type='reset'
|
|
152
|
+
className='w-[140px]'
|
|
153
|
+
>
|
|
154
|
+
{modalReady.cancel.name ?? 'Close'}
|
|
155
|
+
</Button>
|
|
156
|
+
}
|
|
157
|
+
{modalReady.action &&
|
|
158
|
+
<Button
|
|
159
|
+
color='primary'
|
|
160
|
+
type='submit'
|
|
161
|
+
className='w-[140px]'
|
|
162
|
+
>
|
|
163
|
+
{modalReady.action.name ?? 'Ok'}
|
|
164
|
+
</Button>
|
|
165
|
+
}
|
|
166
|
+
</div>
|
|
167
|
+
</form>
|
|
168
|
+
</div>
|
|
169
|
+
</Portal>
|
|
170
|
+
: null
|
|
171
|
+
)
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
export default Modal
|
package/src/tools/general.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
export const generateId = (): string => {
|
|
2
|
-
return Math.random()
|
|
3
|
-
.toString(36)
|
|
4
|
-
.split('.')[1]
|
|
5
|
-
.substring(0, 6)
|
|
6
|
-
}
|
|
1
|
+
export const generateId = (): string => {
|
|
2
|
+
return Math.random()
|
|
3
|
+
.toString(36)
|
|
4
|
+
.split('.')[1]
|
|
5
|
+
.substring(0, 6)
|
|
6
|
+
}
|
package/tsconfig.json
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
|
-
{
|
|
2
|
-
"compilerOptions": {
|
|
3
|
-
"target": "ES2016",
|
|
4
|
-
"module": "commonjs",
|
|
5
|
-
"declaration": true,
|
|
6
|
-
"outDir": "./dist",
|
|
7
|
-
"strict": true,
|
|
8
|
-
"jsx": "react",
|
|
9
|
-
"esModuleInterop": true,
|
|
10
|
-
"skipLibCheck": true
|
|
11
|
-
},
|
|
12
|
-
"include": ["src/**/*"]
|
|
13
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ES2016",
|
|
4
|
+
"module": "commonjs",
|
|
5
|
+
"declaration": true,
|
|
6
|
+
"outDir": "./dist",
|
|
7
|
+
"strict": true,
|
|
8
|
+
"jsx": "react",
|
|
9
|
+
"esModuleInterop": true,
|
|
10
|
+
"skipLibCheck": true
|
|
11
|
+
},
|
|
12
|
+
"include": ["src/**/*"]
|
|
13
|
+
}
|