@pareto-engineering/design-system 4.2.1-alpha.0 → 4.2.3
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/dist/cjs/a/XMLEditor/XMLEditor.js +3 -15
- package/dist/cjs/f/FormInput/FormInput.js +6 -0
- package/dist/cjs/f/common/utils/index.js +8 -1
- package/dist/cjs/f/common/utils/validators.js +17 -0
- package/dist/cjs/f/fields/ChoicesInput/common/Choice/Choice.js +3 -2
- package/dist/cjs/f/fields/EditorInput/EditorInput.js +2 -15
- package/dist/cjs/f/fields/EditorInput/common/StopPropagationPlugin.js +2 -7
- package/dist/cjs/f/fields/FileUpload/FileUpload.js +228 -0
- package/dist/cjs/f/fields/FileUpload/common/FilePreview/FilePreview.js +90 -0
- package/dist/cjs/f/fields/FileUpload/common/FilePreview/index.js +13 -0
- package/dist/cjs/f/fields/FileUpload/common/FilePreview/styles.scss +92 -0
- package/dist/cjs/f/fields/FileUpload/common/index.js +12 -0
- package/dist/cjs/f/fields/FileUpload/fileUploadOptions.js +31 -0
- package/dist/cjs/f/fields/FileUpload/index.js +20 -0
- package/dist/cjs/f/fields/FileUpload/styles.scss +73 -0
- package/dist/cjs/f/fields/SelectInput/common/Menu/Menu.js +1 -1
- package/dist/cjs/f/fields/SelectInput/common/Multiple/Multiple.js +1 -1
- package/dist/cjs/f/fields/SelectInput/styles.scss +1 -1
- package/dist/cjs/f/fields/index.js +14 -1
- package/dist/cjs/g/FormBuilder/common/Builder/common/InputBuilder/InputBuilder.js +34 -7
- package/dist/cjs/g/FormBuilder/common/Builder/common/InputBuilder/styles.scss +11 -0
- package/dist/cjs/g/FormBuilder/common/Renderer/Renderer.js +9 -3
- package/dist/cjs/g/FormBuilder/common/Renderer/common/Section/Section.js +2 -2
- package/dist/es/a/XMLEditor/XMLEditor.js +3 -15
- package/dist/es/f/FormInput/FormInput.js +7 -1
- package/dist/es/f/common/utils/index.js +2 -1
- package/dist/es/f/common/utils/validators.js +10 -0
- package/dist/es/f/fields/ChoicesInput/common/Choice/Choice.js +3 -2
- package/dist/es/f/fields/EditorInput/EditorInput.js +2 -15
- package/dist/es/f/fields/EditorInput/common/StopPropagationPlugin.js +2 -6
- package/dist/es/f/fields/FileUpload/FileUpload.js +218 -0
- package/dist/es/f/fields/FileUpload/common/FilePreview/FilePreview.js +80 -0
- package/dist/es/f/fields/FileUpload/common/FilePreview/index.js +2 -0
- package/dist/es/f/fields/FileUpload/common/FilePreview/styles.scss +92 -0
- package/dist/es/f/fields/FileUpload/common/index.js +2 -0
- package/dist/es/f/fields/FileUpload/fileUploadOptions.js +25 -0
- package/dist/es/f/fields/FileUpload/index.js +3 -0
- package/dist/es/f/fields/FileUpload/styles.scss +73 -0
- package/dist/es/f/fields/SelectInput/common/Menu/Menu.js +1 -1
- package/dist/es/f/fields/SelectInput/common/Multiple/Multiple.js +1 -1
- package/dist/es/f/fields/SelectInput/styles.scss +1 -1
- package/dist/es/f/fields/index.js +2 -1
- package/dist/es/g/FormBuilder/common/Builder/common/InputBuilder/InputBuilder.js +35 -8
- package/dist/es/g/FormBuilder/common/Builder/common/InputBuilder/styles.scss +11 -0
- package/dist/es/g/FormBuilder/common/Renderer/Renderer.js +9 -3
- package/dist/es/g/FormBuilder/common/Renderer/common/Section/Section.js +2 -1
- package/package.json +4 -4
- package/src/stories/f/FileUpload.stories.jsx +55 -0
- package/src/stories/g/FormBuilder.stories.jsx +19 -97
- package/src/ui/a/XMLEditor/XMLEditor.jsx +1 -15
- package/src/ui/f/FormInput/FormInput.jsx +11 -0
- package/src/ui/f/common/utils/index.js +1 -0
- package/src/ui/f/common/utils/validators.js +10 -0
- package/src/ui/f/fields/ChoicesInput/common/Choice/Choice.jsx +2 -0
- package/src/ui/f/fields/EditorInput/EditorInput.jsx +1 -15
- package/src/ui/f/fields/EditorInput/common/StopPropagationPlugin.jsx +2 -6
- package/src/ui/f/fields/FileUpload/FileUpload.jsx +277 -0
- package/src/ui/f/fields/FileUpload/common/FilePreview/FilePreview.jsx +115 -0
- package/src/ui/f/fields/FileUpload/common/FilePreview/index.js +2 -0
- package/src/ui/f/fields/FileUpload/common/FilePreview/styles.scss +92 -0
- package/src/ui/f/fields/FileUpload/common/index.js +2 -0
- package/src/ui/f/fields/FileUpload/fileUploadOptions.js +32 -0
- package/src/ui/f/fields/FileUpload/index.js +3 -0
- package/src/ui/f/fields/FileUpload/styles.scss +73 -0
- package/src/ui/f/fields/SelectInput/common/Menu/Menu.jsx +1 -0
- package/src/ui/f/fields/SelectInput/common/Multiple/Multiple.jsx +1 -1
- package/src/ui/f/fields/SelectInput/styles.scss +1 -1
- package/src/ui/f/fields/index.js +1 -0
- package/src/ui/g/FormBuilder/common/Builder/common/InputBuilder/InputBuilder.jsx +53 -11
- package/src/ui/g/FormBuilder/common/Builder/common/InputBuilder/styles.scss +11 -0
- package/src/ui/g/FormBuilder/common/Renderer/Renderer.jsx +13 -3
- package/src/ui/g/FormBuilder/common/Renderer/common/Section/Section.jsx +7 -2
- package/tests/__snapshots__/Storyshots.test.js.snap +163 -159
|
@@ -41,109 +41,28 @@ export const Builder = {
|
|
|
41
41
|
)
|
|
42
42
|
},
|
|
43
43
|
}
|
|
44
|
+
|
|
44
45
|
const sampleFormData = {
|
|
45
46
|
sections:[
|
|
46
47
|
{
|
|
47
|
-
title :'
|
|
48
|
-
description:'{"root":{"children":[{"children":[{"detail":0,"format":0,"mode":"normal","style":"","text":"
|
|
48
|
+
title :'Hello',
|
|
49
|
+
description:'{"root":{"children":[{"children":[{"detail":0,"format":0,"mode":"normal","style":"","text":"Test file upload ","type":"text","version":1}],"direction":"ltr","format":"","indent":0,"type":"paragraph","version":1}],"direction":"ltr","format":"","indent":0,"type":"root","version":1}}',
|
|
49
50
|
key :'section-0',
|
|
50
51
|
inputs :[
|
|
51
52
|
{
|
|
52
|
-
name
|
|
53
|
-
label
|
|
54
|
-
type
|
|
55
|
-
required
|
|
56
|
-
options
|
|
57
|
-
conditionalLogic:null,
|
|
58
|
-
description
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
required :false,
|
|
65
|
-
options :[],
|
|
66
|
-
conditionalLogic:null,
|
|
67
|
-
description :'brief model description',
|
|
68
|
-
},
|
|
69
|
-
],
|
|
70
|
-
orderedInputDragIds:[],
|
|
71
|
-
navigation :{
|
|
72
|
-
nextSection:'next',
|
|
73
|
-
},
|
|
74
|
-
},
|
|
75
|
-
{
|
|
76
|
-
title :'Rate the Models',
|
|
77
|
-
description:'{"root":{"children":[{"children":[{"detail":0,"format":0,"mode":"normal","style":"","text":"Best LLM models for software developers","type":"text","version":1}],"direction":"ltr","format":"","indent":0,"type":"paragraph","version":1},{"children":[{"children":[{"detail":0,"format":0,"mode":"normal","style":"","text":"Chat GPT","type":"text","version":1}],"direction":"ltr","format":"","indent":0,"type":"listitem","version":1,"value":1},{"children":[{"detail":0,"format":0,"mode":"normal","style":"","text":"Perplexity","type":"text","version":1}],"direction":"ltr","format":"","indent":0,"type":"listitem","version":1,"value":2},{"children":[{"detail":0,"format":0,"mode":"normal","style":"","text":"Gemini","type":"text","version":1}],"direction":"ltr","format":"","indent":0,"type":"listitem","version":1,"value":3},{"children":[{"detail":0,"format":0,"mode":"normal","style":"","text":"Claude","type":"text","version":1}],"direction":"ltr","format":"","indent":0,"type":"listitem","version":1,"value":4}],"direction":"ltr","format":"","indent":0,"type":"list","version":1,"listType":"bullet","start":1,"tag":"ul"},{"children":[{"detail":0,"format":0,"mode":"normal","style":"","text":"Please add more exciting models that we might missed","type":"text","version":1}],"direction":"ltr","format":"","indent":0,"type":"quote","version":1},{"children":[{"detail":0,"format":0,"mode":"normal","style":"","text":"You can make them ","type":"text","version":1},{"detail":0,"format":1,"mode":"normal","style":"","text":"bold","type":"text","version":1},{"detail":0,"format":0,"mode":"normal","style":"","text":" or ","type":"text","version":1},{"detail":0,"format":2,"mode":"normal","style":"","text":"Italic or ","type":"text","version":1},{"detail":0,"format":10,"mode":"normal","style":"","text":"underlined","type":"text","version":1}],"direction":"ltr","format":"","indent":0,"type":"paragraph","version":1},{"children":[{"detail":0,"format":4,"mode":"normal","style":"","text":"You can also color them and strike through them!","type":"text","version":1}],"direction":"ltr","format":"","indent":0,"type":"paragraph","version":1}],"direction":"ltr","format":"","indent":0,"type":"root","version":1}}',
|
|
78
|
-
key :'section-1',
|
|
79
|
-
inputs :[
|
|
80
|
-
{
|
|
81
|
-
type :'choices',
|
|
82
|
-
options:[
|
|
83
|
-
{
|
|
84
|
-
key :'sections-1-inputs-0-options--1',
|
|
85
|
-
value :'Chat GPT',
|
|
86
|
-
label :'Chat GPT',
|
|
87
|
-
nextSection:'',
|
|
88
|
-
},
|
|
89
|
-
{
|
|
90
|
-
key :'sections-1-inputs-0-options-0',
|
|
91
|
-
value :'Gemini',
|
|
92
|
-
label :'Gemini',
|
|
93
|
-
nextSection:'',
|
|
94
|
-
},
|
|
53
|
+
name :'section_0_input_0',
|
|
54
|
+
label :'The file upload ',
|
|
55
|
+
type :'file',
|
|
56
|
+
required :false,
|
|
57
|
+
options :[],
|
|
58
|
+
conditionalLogic :null,
|
|
59
|
+
description :'',
|
|
60
|
+
maxCount :3,
|
|
61
|
+
showSpecificFileTypes:true,
|
|
62
|
+
accept :[
|
|
63
|
+
'.mp4,.ogg,.webm,video/mp4,video/ogg,video/webm',
|
|
64
|
+
'.pdf,application/pdf',
|
|
95
65
|
],
|
|
96
|
-
required :true,
|
|
97
|
-
description:'',
|
|
98
|
-
name :'section_1_input_0',
|
|
99
|
-
label :'Which is better between the 2?',
|
|
100
|
-
},
|
|
101
|
-
{
|
|
102
|
-
name :'section_1_input_1',
|
|
103
|
-
label :'Choose the worst of them ',
|
|
104
|
-
type :'multiple',
|
|
105
|
-
required:false,
|
|
106
|
-
options :[
|
|
107
|
-
{
|
|
108
|
-
key :'sections-1-inputs-1-options--1',
|
|
109
|
-
value :'Chat GPT',
|
|
110
|
-
label :'Chat GPT',
|
|
111
|
-
nextSection:'',
|
|
112
|
-
},
|
|
113
|
-
{
|
|
114
|
-
key :'sections-1-inputs-1-options-0',
|
|
115
|
-
value :'Gemini',
|
|
116
|
-
label :'Gemini',
|
|
117
|
-
nextSection:'',
|
|
118
|
-
},
|
|
119
|
-
{
|
|
120
|
-
key :'sections-1-inputs-1-options-1',
|
|
121
|
-
value :'Claude',
|
|
122
|
-
label :'Claude',
|
|
123
|
-
nextSection:'',
|
|
124
|
-
},
|
|
125
|
-
],
|
|
126
|
-
conditionalLogic:null,
|
|
127
|
-
description :'',
|
|
128
|
-
},
|
|
129
|
-
],
|
|
130
|
-
orderedInputDragIds:[],
|
|
131
|
-
navigation :{
|
|
132
|
-
nextSection:'next',
|
|
133
|
-
},
|
|
134
|
-
},
|
|
135
|
-
{
|
|
136
|
-
title :'General sentiments',
|
|
137
|
-
description:'{"root":{"children":[{"children":[{"detail":0,"format":0,"mode":"normal","style":"","text":"Best LLM models for software developers","type":"text","version":1}],"direction":"ltr","format":"","indent":0,"type":"heading","version":1,"tag":"h3"},{"children":[{"children":[{"detail":0,"format":0,"mode":"normal","style":"","text":"Chat GPT","type":"text","version":1}],"direction":"ltr","format":"","indent":0,"type":"listitem","version":1,"value":1},{"children":[{"detail":0,"format":0,"mode":"normal","style":"","text":"Perplexity","type":"text","version":1}],"direction":"ltr","format":"","indent":0,"type":"listitem","version":1,"value":2},{"children":[{"detail":0,"format":0,"mode":"normal","style":"","text":"Gemini","type":"text","version":1}],"direction":"ltr","format":"","indent":0,"type":"listitem","version":1,"value":3},{"children":[{"detail":0,"format":0,"mode":"normal","style":"","text":"Claude","type":"text","version":1}],"direction":"ltr","format":"","indent":0,"type":"listitem","version":1,"value":4}],"direction":"ltr","format":"","indent":0,"type":"list","version":1,"listType":"bullet","start":1,"tag":"ul"},{"children":[{"detail":0,"format":0,"mode":"normal","style":"","text":"Please add more exciting models that we might missed","type":"text","version":1}],"direction":"ltr","format":"","indent":0,"type":"quote","version":1},{"children":[{"detail":0,"format":0,"mode":"normal","style":"","text":"You can make them ","type":"text","version":1},{"detail":0,"format":1,"mode":"normal","style":"","text":"bold","type":"text","version":1},{"detail":0,"format":0,"mode":"normal","style":"","text":" or ","type":"text","version":1},{"detail":0,"format":2,"mode":"normal","style":"","text":"Italic or ","type":"text","version":1},{"detail":0,"format":10,"mode":"normal","style":"","text":"underlined","type":"text","version":1}],"direction":"ltr","format":"","indent":0,"type":"paragraph","version":1},{"children":[{"detail":0,"format":4,"mode":"normal","style":"","text":"You can also color them and strike through them!","type":"text","version":1}],"direction":"ltr","format":"","indent":0,"type":"paragraph","version":1}],"direction":"ltr","format":"","indent":0,"type":"root","version":1}}',
|
|
138
|
-
key :'section-2',
|
|
139
|
-
inputs :[
|
|
140
|
-
{
|
|
141
|
-
type :'textarea',
|
|
142
|
-
options :[],
|
|
143
|
-
required :true,
|
|
144
|
-
description:'',
|
|
145
|
-
name :'section_2_input_0',
|
|
146
|
-
label :'Give a final brief description of your findings',
|
|
147
66
|
},
|
|
148
67
|
],
|
|
149
68
|
orderedInputDragIds:[],
|
|
@@ -168,7 +87,10 @@ export const Renderer = {
|
|
|
168
87
|
|
|
169
88
|
return (
|
|
170
89
|
<>
|
|
171
|
-
<FormBuilder
|
|
90
|
+
<FormBuilder
|
|
91
|
+
{...args}
|
|
92
|
+
onRendererFormSave={handleFormDataUpdateWithValues}
|
|
93
|
+
/>
|
|
172
94
|
<pre>{JSON.stringify(values, null, 2)}</pre>
|
|
173
95
|
</>
|
|
174
96
|
)
|
|
@@ -58,8 +58,6 @@ const XMLEditor = ({
|
|
|
58
58
|
config,
|
|
59
59
|
onChange,
|
|
60
60
|
onBlur,
|
|
61
|
-
stopAllPropagation,
|
|
62
|
-
stopPropagationKeys,
|
|
63
61
|
}) => {
|
|
64
62
|
const editorRef = useRef()
|
|
65
63
|
|
|
@@ -93,9 +91,7 @@ const XMLEditor = ({
|
|
|
93
91
|
}),
|
|
94
92
|
EditorView.domEventHandlers({
|
|
95
93
|
keydown(e) {
|
|
96
|
-
|
|
97
|
-
e.stopPropagation()
|
|
98
|
-
}
|
|
94
|
+
e.stopPropagation()
|
|
99
95
|
},
|
|
100
96
|
}),
|
|
101
97
|
],
|
|
@@ -172,20 +168,10 @@ XMLEditor.propTypes = {
|
|
|
172
168
|
*/
|
|
173
169
|
gutterWidth:PropTypes.string,
|
|
174
170
|
|
|
175
|
-
/**
|
|
176
|
-
* The keys to stop propagation on.
|
|
177
|
-
*/
|
|
178
|
-
stopPropagationKeys:PropTypes.arrayOf(PropTypes.string),
|
|
179
|
-
|
|
180
171
|
/**
|
|
181
172
|
* The callback for when the editor loses focus.
|
|
182
173
|
*/
|
|
183
174
|
onBlur:PropTypes.func,
|
|
184
|
-
|
|
185
|
-
/**
|
|
186
|
-
* Whether to stop all propagation of keys to keep focus on the editor.
|
|
187
|
-
*/
|
|
188
|
-
stopAllPropagation:PropTypes.bool,
|
|
189
175
|
}
|
|
190
176
|
|
|
191
177
|
XMLEditor.defaultProps = {
|
|
@@ -17,6 +17,7 @@ import {
|
|
|
17
17
|
QueryChoices,
|
|
18
18
|
LinkInput,
|
|
19
19
|
EditorInput,
|
|
20
|
+
FileUpload,
|
|
20
21
|
} from '../fields'
|
|
21
22
|
|
|
22
23
|
import './styles.scss'
|
|
@@ -147,6 +148,16 @@ const FormInput = ({
|
|
|
147
148
|
)
|
|
148
149
|
}
|
|
149
150
|
|
|
151
|
+
if (type === 'file') {
|
|
152
|
+
return (
|
|
153
|
+
<FileUpload
|
|
154
|
+
className={newClassName}
|
|
155
|
+
disabled={disabled}
|
|
156
|
+
{...otherProps}
|
|
157
|
+
/>
|
|
158
|
+
)
|
|
159
|
+
}
|
|
160
|
+
|
|
150
161
|
if (extraTypes?.[type]) {
|
|
151
162
|
const Component = extraTypes[type]
|
|
152
163
|
return (
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export const integerAndGreaterThanZero = (value) => {
|
|
2
|
+
let error = ''
|
|
3
|
+
if ((value && value <= 0) || value === 0) {
|
|
4
|
+
error = 'Value must be greator than zero.'
|
|
5
|
+
}
|
|
6
|
+
if (value && value % 1 !== 0) {
|
|
7
|
+
error = 'You must enter a whole number.'
|
|
8
|
+
}
|
|
9
|
+
return error
|
|
10
|
+
}
|
|
@@ -27,6 +27,7 @@ const Choice = ({
|
|
|
27
27
|
multiple,
|
|
28
28
|
validate,
|
|
29
29
|
disabled,
|
|
30
|
+
...otherProps
|
|
30
31
|
}) => {
|
|
31
32
|
const type = multiple ? 'checkbox' : 'radio'
|
|
32
33
|
|
|
@@ -53,6 +54,7 @@ const Choice = ({
|
|
|
53
54
|
id={id}
|
|
54
55
|
name={name}
|
|
55
56
|
{...field}
|
|
57
|
+
{...otherProps}
|
|
56
58
|
value={value}
|
|
57
59
|
disabled={disabled}
|
|
58
60
|
/>
|
|
@@ -51,7 +51,6 @@ const EditorInput = ({
|
|
|
51
51
|
style,
|
|
52
52
|
name,
|
|
53
53
|
label,
|
|
54
|
-
// validate,
|
|
55
54
|
resize,
|
|
56
55
|
color,
|
|
57
56
|
rows,
|
|
@@ -60,7 +59,6 @@ const EditorInput = ({
|
|
|
60
59
|
description,
|
|
61
60
|
disabled,
|
|
62
61
|
showDebugger,
|
|
63
|
-
stopPropagationKeys,
|
|
64
62
|
setEditorState,
|
|
65
63
|
// ...otherProps
|
|
66
64
|
}) => {
|
|
@@ -186,9 +184,7 @@ const EditorInput = ({
|
|
|
186
184
|
<TabIndentationPlugin />
|
|
187
185
|
{setEditorState && <ExposeEditorStatePlugin setEditorState={setEditorState} />}
|
|
188
186
|
<HistoryPlugin />
|
|
189
|
-
|
|
190
|
-
<StopPropagationPlugin stopPropagationKeys={stopPropagationKeys} />
|
|
191
|
-
)}
|
|
187
|
+
<StopPropagationPlugin />
|
|
192
188
|
<FormDescription className="s-1" description={description} name={name} />
|
|
193
189
|
{ showDebugger && <TreeViewPlugin /> }
|
|
194
190
|
</div>
|
|
@@ -222,11 +218,6 @@ EditorInput.propTypes = {
|
|
|
222
218
|
*/
|
|
223
219
|
label:PropTypes.string.isRequired,
|
|
224
220
|
|
|
225
|
-
/**
|
|
226
|
-
* The input value validator function
|
|
227
|
-
*/
|
|
228
|
-
// validate:PropTypes.func,
|
|
229
|
-
|
|
230
221
|
/**
|
|
231
222
|
* The number of rows int the text area
|
|
232
223
|
*/
|
|
@@ -266,11 +257,6 @@ EditorInput.propTypes = {
|
|
|
266
257
|
* Whether to show the debugger or not
|
|
267
258
|
*/
|
|
268
259
|
showDebugger:PropTypes.bool,
|
|
269
|
-
|
|
270
|
-
/**
|
|
271
|
-
* Map to stop propagation of the given keys
|
|
272
|
-
*/
|
|
273
|
-
stopPropagationKeys:PropTypes.arrayOf(PropTypes.string),
|
|
274
260
|
}
|
|
275
261
|
|
|
276
262
|
EditorInput.defaultProps = {
|
|
@@ -1,16 +1,12 @@
|
|
|
1
1
|
import { useInsertionEffect } from 'react'
|
|
2
2
|
import { useLexicalComposerContext } from '@lexical/react/LexicalComposerContext'
|
|
3
3
|
|
|
4
|
-
const StopPropagationPlugin = ({
|
|
5
|
-
stopPropagationKeys,
|
|
6
|
-
}) => {
|
|
4
|
+
const StopPropagationPlugin = () => {
|
|
7
5
|
const [editor] = useLexicalComposerContext()
|
|
8
6
|
|
|
9
7
|
useInsertionEffect(() => {
|
|
10
8
|
const onKeyDown = (e) => {
|
|
11
|
-
|
|
12
|
-
e.stopPropagation()
|
|
13
|
-
}
|
|
9
|
+
e.stopPropagation()
|
|
14
10
|
}
|
|
15
11
|
|
|
16
12
|
return editor.registerRootListener(
|
|
@@ -0,0 +1,277 @@
|
|
|
1
|
+
/* @pareto-engineering/generator-front 1.1.1-alpha.2 */
|
|
2
|
+
import * as React from 'react'
|
|
3
|
+
|
|
4
|
+
import PropTypes from 'prop-types'
|
|
5
|
+
|
|
6
|
+
import { useField } from 'formik'
|
|
7
|
+
|
|
8
|
+
import styleNames from '@pareto-engineering/bem/exports'
|
|
9
|
+
|
|
10
|
+
import './styles.scss'
|
|
11
|
+
|
|
12
|
+
import { FilePreview } from './common'
|
|
13
|
+
|
|
14
|
+
import { FormLabel, FormDescription } from '../../common'
|
|
15
|
+
|
|
16
|
+
// Local Definitions
|
|
17
|
+
|
|
18
|
+
const baseClassName = styleNames.base
|
|
19
|
+
|
|
20
|
+
const componentClassName = 'file-upload'
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* This is the component description.
|
|
24
|
+
*/
|
|
25
|
+
const FileUpload = ({
|
|
26
|
+
id,
|
|
27
|
+
className:userClassName,
|
|
28
|
+
style,
|
|
29
|
+
label,
|
|
30
|
+
description,
|
|
31
|
+
accept,
|
|
32
|
+
multiple,
|
|
33
|
+
name,
|
|
34
|
+
disabled,
|
|
35
|
+
maxCount,
|
|
36
|
+
maxCountError,
|
|
37
|
+
maxSize,
|
|
38
|
+
maxSizeError,
|
|
39
|
+
onChange,
|
|
40
|
+
onDelete,
|
|
41
|
+
// TODO: TBD when connecting with BE
|
|
42
|
+
// onPreview,
|
|
43
|
+
// progress,
|
|
44
|
+
// percent,
|
|
45
|
+
// uploadStatus,
|
|
46
|
+
filePreviewAlignment,
|
|
47
|
+
optional,
|
|
48
|
+
labelColor,
|
|
49
|
+
color,
|
|
50
|
+
// ...otherProps
|
|
51
|
+
}) => {
|
|
52
|
+
const [field, , helpers] = useField({ name })
|
|
53
|
+
|
|
54
|
+
const { value } = field
|
|
55
|
+
|
|
56
|
+
const { setError, setValue, setTouched } = helpers
|
|
57
|
+
|
|
58
|
+
const handleChange = (event) => {
|
|
59
|
+
setTouched(true, false)
|
|
60
|
+
const newFiles = Array.from(event.currentTarget.files)
|
|
61
|
+
const currentFiles = value || []
|
|
62
|
+
|
|
63
|
+
const currentCount = currentFiles.length + newFiles.length
|
|
64
|
+
if (maxCount && currentCount > maxCount) {
|
|
65
|
+
setError(maxCountError || `Maximum of ${maxCount} files allowed`)
|
|
66
|
+
return
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
const duplicateFiles = newFiles.filter(
|
|
70
|
+
(newFile) => currentFiles.some((currentFile) => currentFile.name === newFile.name),
|
|
71
|
+
)
|
|
72
|
+
|
|
73
|
+
if (duplicateFiles.length > 0) {
|
|
74
|
+
setError('You cannot upload the same file twice.')
|
|
75
|
+
return
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
if (maxSize) {
|
|
79
|
+
const oversizedFiles = newFiles.filter((file) => file.size > maxSize)
|
|
80
|
+
if (oversizedFiles.length > 0) {
|
|
81
|
+
setError(maxSizeError || `File size exceeds the limit of ${maxSize} bytes`)
|
|
82
|
+
return
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
const updatedFiles = [...currentFiles, ...newFiles]
|
|
87
|
+
|
|
88
|
+
setValue(updatedFiles)
|
|
89
|
+
onChange?.(updatedFiles)
|
|
90
|
+
|
|
91
|
+
// eslint-disable-next-line no-param-reassign
|
|
92
|
+
event.target.value = null
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
const handleDelete = (fileIndex) => {
|
|
96
|
+
const updatedFiles = value.filter((_, i) => i !== fileIndex)
|
|
97
|
+
setValue(updatedFiles)
|
|
98
|
+
|
|
99
|
+
onDelete?.(fileIndex)
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
const acceptOptions = Array.isArray(accept) ? accept?.join(',') : accept
|
|
103
|
+
|
|
104
|
+
return (
|
|
105
|
+
<div
|
|
106
|
+
id={id}
|
|
107
|
+
className={[
|
|
108
|
+
|
|
109
|
+
baseClassName,
|
|
110
|
+
|
|
111
|
+
componentClassName,
|
|
112
|
+
userClassName,
|
|
113
|
+
`preview-${filePreviewAlignment}`,
|
|
114
|
+
`y-${color}`,
|
|
115
|
+
]
|
|
116
|
+
.filter((e) => e)
|
|
117
|
+
.join(' ')}
|
|
118
|
+
style={style}
|
|
119
|
+
>
|
|
120
|
+
<p>{label}</p>
|
|
121
|
+
<FormDescription className="s-1" description={description} name={name} />
|
|
122
|
+
{!disabled && (
|
|
123
|
+
<FormLabel
|
|
124
|
+
name={name}
|
|
125
|
+
color={labelColor}
|
|
126
|
+
optional={optional}
|
|
127
|
+
>
|
|
128
|
+
<input
|
|
129
|
+
id={name}
|
|
130
|
+
className="file"
|
|
131
|
+
type="file"
|
|
132
|
+
accept={acceptOptions}
|
|
133
|
+
multiple={multiple || (maxCount && maxCount > 0)}
|
|
134
|
+
disabled={disabled}
|
|
135
|
+
onChange={handleChange}
|
|
136
|
+
/>
|
|
137
|
+
<span className="ai-icon">
|
|
138
|
+
U
|
|
139
|
+
</span>
|
|
140
|
+
<span>
|
|
141
|
+
Attach file
|
|
142
|
+
</span>
|
|
143
|
+
</FormLabel>
|
|
144
|
+
)}
|
|
145
|
+
{value?.length > 0 && (
|
|
146
|
+
<div className="attached-files">
|
|
147
|
+
<p>Attached files:</p>
|
|
148
|
+
<div className="files">
|
|
149
|
+
{value.map((file, indx) => (
|
|
150
|
+
<FilePreview
|
|
151
|
+
file={file}
|
|
152
|
+
key={file.name}
|
|
153
|
+
disabled={disabled}
|
|
154
|
+
handleDelete={() => handleDelete(indx)}
|
|
155
|
+
/>
|
|
156
|
+
))}
|
|
157
|
+
</div>
|
|
158
|
+
</div>
|
|
159
|
+
)}
|
|
160
|
+
</div>
|
|
161
|
+
)
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
FileUpload.propTypes = {
|
|
165
|
+
/**
|
|
166
|
+
* The HTML id for this element
|
|
167
|
+
*/
|
|
168
|
+
id:PropTypes.string,
|
|
169
|
+
|
|
170
|
+
/**
|
|
171
|
+
* The HTML class names for this element
|
|
172
|
+
*/
|
|
173
|
+
className:PropTypes.string,
|
|
174
|
+
|
|
175
|
+
/**
|
|
176
|
+
* The React-written, css properties for this element.
|
|
177
|
+
*/
|
|
178
|
+
style:PropTypes.objectOf(PropTypes.string),
|
|
179
|
+
|
|
180
|
+
/**
|
|
181
|
+
* The label text for the file input
|
|
182
|
+
*/
|
|
183
|
+
label:PropTypes.string,
|
|
184
|
+
|
|
185
|
+
/**
|
|
186
|
+
* The description text below the label
|
|
187
|
+
*/
|
|
188
|
+
description:PropTypes.string,
|
|
189
|
+
|
|
190
|
+
/**
|
|
191
|
+
* The color of the text
|
|
192
|
+
*/
|
|
193
|
+
color:PropTypes.string,
|
|
194
|
+
|
|
195
|
+
/**
|
|
196
|
+
* The accepted file types (e.g., 'image/*')
|
|
197
|
+
*/
|
|
198
|
+
accept:PropTypes.string,
|
|
199
|
+
|
|
200
|
+
/**
|
|
201
|
+
* Whether to allow multiple file uploads
|
|
202
|
+
*/
|
|
203
|
+
multiple:PropTypes.bool,
|
|
204
|
+
|
|
205
|
+
/**
|
|
206
|
+
* The name attribute for the input
|
|
207
|
+
*/
|
|
208
|
+
name:PropTypes.string.isRequired,
|
|
209
|
+
|
|
210
|
+
/**
|
|
211
|
+
* Whether the the input should be disabled
|
|
212
|
+
*/
|
|
213
|
+
disabled:PropTypes.bool,
|
|
214
|
+
|
|
215
|
+
/**
|
|
216
|
+
* The maximum number of files allowed
|
|
217
|
+
*/
|
|
218
|
+
maxCount:PropTypes.number,
|
|
219
|
+
|
|
220
|
+
/**
|
|
221
|
+
* The error message when max count is exceeded
|
|
222
|
+
*/
|
|
223
|
+
maxCountError:PropTypes.string,
|
|
224
|
+
|
|
225
|
+
/**
|
|
226
|
+
* The maximum size of files allowed (in bytes)
|
|
227
|
+
*/
|
|
228
|
+
maxSize:PropTypes.number,
|
|
229
|
+
|
|
230
|
+
/**
|
|
231
|
+
* The error message when file size exceeds max size
|
|
232
|
+
*/
|
|
233
|
+
maxSizeError:PropTypes.string,
|
|
234
|
+
|
|
235
|
+
/**
|
|
236
|
+
* The upload progress value (0-100)
|
|
237
|
+
*/
|
|
238
|
+
// progress:PropTypes.number,
|
|
239
|
+
|
|
240
|
+
/**
|
|
241
|
+
* The function to handle file change events
|
|
242
|
+
*/
|
|
243
|
+
onChange:PropTypes.func,
|
|
244
|
+
|
|
245
|
+
/**
|
|
246
|
+
* The function to handle file delete events
|
|
247
|
+
*/
|
|
248
|
+
onDelete:PropTypes.func,
|
|
249
|
+
|
|
250
|
+
/**
|
|
251
|
+
* The function to handle file download events
|
|
252
|
+
*/
|
|
253
|
+
// onDownload:PropTypes.func,
|
|
254
|
+
|
|
255
|
+
/**
|
|
256
|
+
* The function to handle file preview events
|
|
257
|
+
*/
|
|
258
|
+
// onPreview:PropTypes.func,
|
|
259
|
+
|
|
260
|
+
/**
|
|
261
|
+
* The upload status of the file if being sent to an external service (e.g., 'uploading', 'done')
|
|
262
|
+
*/
|
|
263
|
+
// uploadStatus:PropTypes.oneOf(['uploading', 'done', 'failed']),
|
|
264
|
+
|
|
265
|
+
/**
|
|
266
|
+
* The alignment for file previews WRT the upload input
|
|
267
|
+
*/
|
|
268
|
+
filePreviewAlignment:PropTypes.oneOf(['left', 'right', 'top', 'bottom']),
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
FileUpload.defaultProps = {
|
|
272
|
+
disabled :false,
|
|
273
|
+
color :'paragraph',
|
|
274
|
+
filePreviewAlignment:'bottom',
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
export default FileUpload
|