@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.
Files changed (73) hide show
  1. package/dist/cjs/a/XMLEditor/XMLEditor.js +3 -15
  2. package/dist/cjs/f/FormInput/FormInput.js +6 -0
  3. package/dist/cjs/f/common/utils/index.js +8 -1
  4. package/dist/cjs/f/common/utils/validators.js +17 -0
  5. package/dist/cjs/f/fields/ChoicesInput/common/Choice/Choice.js +3 -2
  6. package/dist/cjs/f/fields/EditorInput/EditorInput.js +2 -15
  7. package/dist/cjs/f/fields/EditorInput/common/StopPropagationPlugin.js +2 -7
  8. package/dist/cjs/f/fields/FileUpload/FileUpload.js +228 -0
  9. package/dist/cjs/f/fields/FileUpload/common/FilePreview/FilePreview.js +90 -0
  10. package/dist/cjs/f/fields/FileUpload/common/FilePreview/index.js +13 -0
  11. package/dist/cjs/f/fields/FileUpload/common/FilePreview/styles.scss +92 -0
  12. package/dist/cjs/f/fields/FileUpload/common/index.js +12 -0
  13. package/dist/cjs/f/fields/FileUpload/fileUploadOptions.js +31 -0
  14. package/dist/cjs/f/fields/FileUpload/index.js +20 -0
  15. package/dist/cjs/f/fields/FileUpload/styles.scss +73 -0
  16. package/dist/cjs/f/fields/SelectInput/common/Menu/Menu.js +1 -1
  17. package/dist/cjs/f/fields/SelectInput/common/Multiple/Multiple.js +1 -1
  18. package/dist/cjs/f/fields/SelectInput/styles.scss +1 -1
  19. package/dist/cjs/f/fields/index.js +14 -1
  20. package/dist/cjs/g/FormBuilder/common/Builder/common/InputBuilder/InputBuilder.js +34 -7
  21. package/dist/cjs/g/FormBuilder/common/Builder/common/InputBuilder/styles.scss +11 -0
  22. package/dist/cjs/g/FormBuilder/common/Renderer/Renderer.js +9 -3
  23. package/dist/cjs/g/FormBuilder/common/Renderer/common/Section/Section.js +2 -2
  24. package/dist/es/a/XMLEditor/XMLEditor.js +3 -15
  25. package/dist/es/f/FormInput/FormInput.js +7 -1
  26. package/dist/es/f/common/utils/index.js +2 -1
  27. package/dist/es/f/common/utils/validators.js +10 -0
  28. package/dist/es/f/fields/ChoicesInput/common/Choice/Choice.js +3 -2
  29. package/dist/es/f/fields/EditorInput/EditorInput.js +2 -15
  30. package/dist/es/f/fields/EditorInput/common/StopPropagationPlugin.js +2 -6
  31. package/dist/es/f/fields/FileUpload/FileUpload.js +218 -0
  32. package/dist/es/f/fields/FileUpload/common/FilePreview/FilePreview.js +80 -0
  33. package/dist/es/f/fields/FileUpload/common/FilePreview/index.js +2 -0
  34. package/dist/es/f/fields/FileUpload/common/FilePreview/styles.scss +92 -0
  35. package/dist/es/f/fields/FileUpload/common/index.js +2 -0
  36. package/dist/es/f/fields/FileUpload/fileUploadOptions.js +25 -0
  37. package/dist/es/f/fields/FileUpload/index.js +3 -0
  38. package/dist/es/f/fields/FileUpload/styles.scss +73 -0
  39. package/dist/es/f/fields/SelectInput/common/Menu/Menu.js +1 -1
  40. package/dist/es/f/fields/SelectInput/common/Multiple/Multiple.js +1 -1
  41. package/dist/es/f/fields/SelectInput/styles.scss +1 -1
  42. package/dist/es/f/fields/index.js +2 -1
  43. package/dist/es/g/FormBuilder/common/Builder/common/InputBuilder/InputBuilder.js +35 -8
  44. package/dist/es/g/FormBuilder/common/Builder/common/InputBuilder/styles.scss +11 -0
  45. package/dist/es/g/FormBuilder/common/Renderer/Renderer.js +9 -3
  46. package/dist/es/g/FormBuilder/common/Renderer/common/Section/Section.js +2 -1
  47. package/package.json +4 -4
  48. package/src/stories/f/FileUpload.stories.jsx +55 -0
  49. package/src/stories/g/FormBuilder.stories.jsx +19 -97
  50. package/src/ui/a/XMLEditor/XMLEditor.jsx +1 -15
  51. package/src/ui/f/FormInput/FormInput.jsx +11 -0
  52. package/src/ui/f/common/utils/index.js +1 -0
  53. package/src/ui/f/common/utils/validators.js +10 -0
  54. package/src/ui/f/fields/ChoicesInput/common/Choice/Choice.jsx +2 -0
  55. package/src/ui/f/fields/EditorInput/EditorInput.jsx +1 -15
  56. package/src/ui/f/fields/EditorInput/common/StopPropagationPlugin.jsx +2 -6
  57. package/src/ui/f/fields/FileUpload/FileUpload.jsx +277 -0
  58. package/src/ui/f/fields/FileUpload/common/FilePreview/FilePreview.jsx +115 -0
  59. package/src/ui/f/fields/FileUpload/common/FilePreview/index.js +2 -0
  60. package/src/ui/f/fields/FileUpload/common/FilePreview/styles.scss +92 -0
  61. package/src/ui/f/fields/FileUpload/common/index.js +2 -0
  62. package/src/ui/f/fields/FileUpload/fileUploadOptions.js +32 -0
  63. package/src/ui/f/fields/FileUpload/index.js +3 -0
  64. package/src/ui/f/fields/FileUpload/styles.scss +73 -0
  65. package/src/ui/f/fields/SelectInput/common/Menu/Menu.jsx +1 -0
  66. package/src/ui/f/fields/SelectInput/common/Multiple/Multiple.jsx +1 -1
  67. package/src/ui/f/fields/SelectInput/styles.scss +1 -1
  68. package/src/ui/f/fields/index.js +1 -0
  69. package/src/ui/g/FormBuilder/common/Builder/common/InputBuilder/InputBuilder.jsx +53 -11
  70. package/src/ui/g/FormBuilder/common/Builder/common/InputBuilder/styles.scss +11 -0
  71. package/src/ui/g/FormBuilder/common/Renderer/Renderer.jsx +13 -3
  72. package/src/ui/g/FormBuilder/common/Renderer/common/Section/Section.jsx +7 -2
  73. package/tests/__snapshots__/Storyshots.test.js.snap +163 -159
@@ -0,0 +1,115 @@
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 styleNames from '@pareto-engineering/bem/exports'
7
+
8
+ // Local Definitions
9
+
10
+ import './styles.scss'
11
+
12
+ import { ProgressBar } from 'ui/a'
13
+
14
+ import { Button } from 'ui/b'
15
+
16
+ import { fileUploadOptions } from '../../fileUploadOptions'
17
+
18
+ const baseClassName = styleNames.base
19
+
20
+ const componentClassName = 'file-preview'
21
+
22
+ const getFileType = (file) => {
23
+ const mimeType = file.type
24
+ const extension = file.name.split('.').pop().toLowerCase()
25
+ const fileType = fileUploadOptions.find(
26
+ (option) => option.value.includes(mimeType) || option.value.includes(extension))
27
+
28
+ return fileType ? fileType.key : 'unknown'
29
+ }
30
+
31
+ /**
32
+ * This is the component description.
33
+ */
34
+ const FilePreview = ({
35
+ id,
36
+ className:userClassName,
37
+ style,
38
+ file,
39
+ disabled,
40
+ handleDelete,
41
+ // ...otherProps
42
+ }) => {
43
+ const type = getFileType(file)
44
+
45
+ return (
46
+ <div
47
+ id={id}
48
+ className={[
49
+
50
+ baseClassName,
51
+
52
+ componentClassName,
53
+ userClassName,
54
+ ]
55
+ .filter((e) => e)
56
+ .join(' ')}
57
+ style={style}
58
+ >
59
+ <div className="identity">
60
+ <span
61
+ className={
62
+ [
63
+ 'type',
64
+ type.toLowerCase(),
65
+ ]
66
+ .filter((e) => e)
67
+ .join(' ')
68
+ }
69
+ >
70
+ {type}
71
+ </span>
72
+ <span title={file.name} className="name">{file.name}</span>
73
+ <Button isCompact isSimple onClick={handleDelete}>
74
+ <span className="icon x-ui-icons c-x">Y</span>
75
+ </Button>
76
+ </div>
77
+ {!disabled && (
78
+ <div className="progress-status">
79
+ <div className="status">
80
+ <span className="icon">I</span>
81
+ <span>Uploaded</span>
82
+ </div>
83
+ <ProgressBar
84
+ color="green"
85
+ progress={100}
86
+ height="3px"
87
+ />
88
+ </div>
89
+ )}
90
+ </div>
91
+ )
92
+ }
93
+
94
+ FilePreview.propTypes = {
95
+ /**
96
+ * The HTML id for this element
97
+ */
98
+ id:PropTypes.string,
99
+
100
+ /**
101
+ * The HTML class names for this element
102
+ */
103
+ className:PropTypes.string,
104
+
105
+ /**
106
+ * The React-written, css properties for this element.
107
+ */
108
+ style:PropTypes.objectOf(PropTypes.string),
109
+ }
110
+
111
+ FilePreview.defaultProps = {
112
+ // someProp:false
113
+ }
114
+
115
+ export default FilePreview
@@ -0,0 +1,2 @@
1
+ /* @pareto-engineering/generator-front 1.1.1-alpha.2 */
2
+ export { default as FilePreview } from './FilePreview'
@@ -0,0 +1,92 @@
1
+ /* @pareto-engineering/generator-front 1.1.1-alpha.2 */
2
+
3
+ @use "@pareto-engineering/bem";
4
+
5
+ $default-padding: 1rem;
6
+ $files-per-row: 3;
7
+ $total-gaps: $files-per-row - 1;
8
+ $combined-gap: calc(var(--gap) * $total-gaps);
9
+ $width-without-gaps: calc(100% - $combined-gap);
10
+ $default-file-width: calc($width-without-gaps / $files-per-row);
11
+
12
+ .#{bem.$base}.file-preview {
13
+ border: var(--theme-default-border-style) var(--ui-lines);
14
+ border-radius: calc(var(--theme-default-border-radius) / 2);
15
+ display: flex;
16
+ flex-direction: column;
17
+ gap: calc(var(--gap) / 4);
18
+ padding: $default-padding;
19
+ width: $default-file-width;
20
+
21
+ > .identity {
22
+ align-items: center;
23
+ display: flex;
24
+ gap: calc(var(--gap) / 2);
25
+
26
+ > .type {
27
+ padding-block: calc($default-padding / 4);
28
+ padding-inline: calc($default-padding / 2);
29
+
30
+ // TODO: update the colors to use variables. These are colors from the new DS
31
+ &.pdf {
32
+ background-color: #fdead7;
33
+ color: #b93814;
34
+ }
35
+
36
+ &.file {
37
+ background-color: #eef2f6;
38
+ color: #364151;
39
+ }
40
+
41
+ &.txt {
42
+ background-color: #d1dfff;
43
+ color: #004eeb;
44
+ }
45
+
46
+
47
+ &.vid {
48
+ background-color: #ebe9fe;
49
+ color: #5a25dc;
50
+ }
51
+
52
+ &.img {
53
+ background-color: #cbfbef;
54
+ color: #107569;
55
+ }
56
+
57
+ &.aud {
58
+ background-color: #fef7c3;
59
+ color: #a15c08;
60
+ }
61
+ }
62
+
63
+ > .name {
64
+ overflow: hidden;
65
+ text-overflow: ellipsis;
66
+ white-space: nowrap;
67
+ }
68
+
69
+ > .#{bem.$base}.button {
70
+ cursor: pointer;
71
+ margin-left: auto;
72
+ }
73
+ }
74
+
75
+ > .progress-status {
76
+ > .status {
77
+ align-items: center;
78
+ // TODO handle as a prop
79
+ color: var(--green);
80
+ display: flex;
81
+ gap: calc(var(--gap) / 2);
82
+
83
+ > .icon {
84
+ background-color: var(--green);
85
+ border-radius: 50%;
86
+ color: var(--on-green);
87
+ font-size: calc(var(--s-2) * 1rem);
88
+ padding: calc($default-padding / 4);
89
+ }
90
+ }
91
+ }
92
+ }
@@ -0,0 +1,2 @@
1
+ /* @pareto-engineering/generator-front 1.1.1-alpha.2 */
2
+ export { FilePreview } from './FilePreview'
@@ -0,0 +1,32 @@
1
+ export const fileUploadOptions = [
2
+ {
3
+ key :'FILE',
4
+ value:'.doc,.docx,.odt,application/msword,application/vnd.openxmlformats-officedocument.wordprocessingml.document,application/vnd.oasis.opendocument.text',
5
+ label:'Documents',
6
+ },
7
+ {
8
+ key :'TXT',
9
+ value:'.xls,.xlsx,.ods,.csv,application/vnd.ms-excel,application/vnd.openxmlformats-officedocument.spreadsheetml.sheet,application/vnd.oasis.opendocument.spreadsheet,text/csv',
10
+ label:'Spreadsheets',
11
+ },
12
+ {
13
+ key :'PDF',
14
+ value:'.pdf,application/pdf',
15
+ label:'PDF',
16
+ },
17
+ {
18
+ key :'VID',
19
+ value:'.mp4,.ogg,.webm,video/mp4,video/ogg,video/webm',
20
+ label:'Videos',
21
+ },
22
+ {
23
+ key :'IMG',
24
+ value:'.png,.jpeg,.jpg,.gif,.webp,image/png,image/jpeg,image/gif,image/webp',
25
+ label:'Images',
26
+ },
27
+ {
28
+ key :'AUD',
29
+ value:'.mp3,.ogg,.wav,audio/mpeg,audio/ogg,audio/wav',
30
+ label:'Audio',
31
+ },
32
+ ]
@@ -0,0 +1,3 @@
1
+ /* @pareto-engineering/generator-front 1.1.1-alpha.2 */
2
+ export { default as FileUpload } from './FileUpload'
3
+ export { fileUploadOptions } from './fileUploadOptions'
@@ -0,0 +1,73 @@
1
+ /* @pareto-engineering/generator-front 1.1.1-alpha.2 */
2
+
3
+ @use "@pareto-engineering/bem";
4
+
5
+ $default-padding: 1rem;
6
+ $default-margin: 1rem;
7
+
8
+ .#{bem.$base}.file-upload {
9
+ display: flex;
10
+ flex-direction: column;
11
+ gap: var(--gap);
12
+
13
+
14
+ > p {
15
+ color: var(--y);
16
+ margin: 0;
17
+ }
18
+
19
+ > .#{bem.$base}.description {
20
+ height: auto;
21
+ }
22
+
23
+ > .#{bem.$base}.form-label {
24
+ align-items: center;
25
+ border: var(--theme-default-border-style) var(--ui-lines);
26
+ border-radius: calc(var(--theme-default-border-radius) / 2);
27
+ color: var(--heading);
28
+ cursor: pointer;
29
+ display: flex;
30
+ gap: calc(var(--gap) / 2);
31
+ padding: $default-padding;
32
+ width: fit-content;
33
+
34
+ &:has(>input:disabled) {
35
+ --icon-color: var(--hard-disabled);
36
+ color: var(--hard-disabled);
37
+ cursor: not-allowed;
38
+ }
39
+
40
+ &:has(>input:not(:disabled)) {
41
+ &:hover,
42
+ &:active {
43
+ border: var(--theme-hover-input-border);
44
+ }
45
+ }
46
+
47
+ > .ai-icon {
48
+ color: var(--icon-color, var(--interactive));
49
+ font-size: calc(var(--s2) * 1rem);
50
+ }
51
+
52
+ > input[type="file"] {
53
+ display: none;
54
+ }
55
+ }
56
+
57
+ > .attached-files {
58
+ display: flex;
59
+ gap: var(--gap);
60
+
61
+ > p {
62
+ margin: 0;
63
+ }
64
+
65
+ > .files {
66
+ align-items: center;
67
+ display: flex;
68
+ flex-wrap: wrap;
69
+ gap: var(--gap);
70
+ width: 100%;
71
+ }
72
+ }
73
+ }
@@ -45,6 +45,7 @@ const Menu = React.forwardRef(({
45
45
  {...getItemProps({ item, index })}
46
46
  className={[
47
47
  'item',
48
+ item.disabled && styleNames.modifierDisabled,
48
49
  highlightedIndex === index && styleNames.modifierActive,
49
50
  ].filter(Boolean)
50
51
  .join(' ')}
@@ -133,7 +133,7 @@ const Multiple = ({
133
133
  case useCombobox.stateChangeTypes.InputKeyDownEnter:
134
134
  case useCombobox.stateChangeTypes.ItemClick:
135
135
  case useCombobox.stateChangeTypes.InputBlur:
136
- if (selectedItem) {
136
+ if (selectedItem && !selectedItem?.disabled) {
137
137
  setSearchInputValue('')
138
138
  addSelectedItem(selectedItem)
139
139
  }
@@ -122,7 +122,7 @@ $default-gap: var(--gap);
122
122
  margin: 0;
123
123
  }
124
124
 
125
- &.#{bem.$modifier-active} {
125
+ &.#{bem.$modifier-active}:not(.disabled) {
126
126
  background-color: var(--y);
127
127
 
128
128
  > p {
@@ -9,3 +9,4 @@ export { Checkbox } from './Checkbox'
9
9
  export { QueryChoices } from './QueryChoices'
10
10
  export { LinkInput } from './LinkInput'
11
11
  export { EditorInput } from './EditorInput'
12
+ export { FileUpload, fileUploadOptions } from './FileUpload'
@@ -9,7 +9,9 @@ import { FieldArray, useFormikContext } from 'formik'
9
9
 
10
10
  import styleNames from '@pareto-engineering/bem/exports'
11
11
 
12
- import { SelectInput, TextInput } from 'ui/f'
12
+ import {
13
+ ChoicesInput, SelectInput, TextInput, integerAndGreaterThanZero, fileUploadOptions,
14
+ } from 'ui/f'
13
15
 
14
16
  import { ToggleSwitch } from 'ui/a'
15
17
 
@@ -23,6 +25,12 @@ const baseClassName = styleNames.base
23
25
 
24
26
  const componentClassName = 'input-builder'
25
27
 
28
+ const getToggleSwitchStyles = (condition) => (
29
+ condition
30
+ ? { '--slider-background-color': 'var(--disabled)' }
31
+ : {}
32
+ )
33
+
26
34
  /**
27
35
  * This is the component description.
28
36
  */
@@ -43,15 +51,6 @@ const InputBuilder = ({
43
51
  setFieldValue(`sections.${sectionIndex}.inputs.${inputIndex}.required`, !input?.required)
44
52
  }
45
53
 
46
- const toggleSwitchStyles = {
47
- ...(!input?.required
48
- ? {
49
- '--slider-background-color':'var(--disabled)',
50
- }
51
- : {}
52
- ),
53
- }
54
-
55
54
  const [hasDescription, setHasDescription] = useState(false)
56
55
 
57
56
  // TODO: handle nav logic
@@ -72,6 +71,12 @@ const InputBuilder = ({
72
71
  setFieldValue(`sections.${sectionIndex}.inputs.${inputIndex}.options.${optionIndex}.label`, value)
73
72
  }
74
73
 
74
+ const isFile = input?.type === 'file'
75
+
76
+ const handleToggleShowSpecificFileTypes = () => {
77
+ setFieldValue(`sections.${sectionIndex}.inputs.${inputIndex}.showSpecificFileTypes`, !input.showSpecificFileTypes)
78
+ }
79
+
75
80
  return (
76
81
  <div
77
82
  id={id}
@@ -121,6 +126,10 @@ const InputBuilder = ({
121
126
  value:'choices',
122
127
  label:'Radio buttons',
123
128
  },
129
+ {
130
+ value:'file',
131
+ label:'File upload',
132
+ },
124
133
  ]}
125
134
  />
126
135
  <div className="controls">
@@ -138,7 +147,7 @@ const InputBuilder = ({
138
147
  <ToggleSwitch
139
148
  handleOnChange={handleToggleRequired}
140
149
  checked={input?.required}
141
- style={toggleSwitchStyles}
150
+ style={getToggleSwitchStyles(!input?.required)}
142
151
  inputId={`sections_${sectionIndex}_inputs.${inputIndex}_toggle`}
143
152
  />
144
153
  </div>
@@ -231,6 +240,39 @@ const InputBuilder = ({
231
240
  )}
232
241
  </FieldArray>
233
242
  )}
243
+
244
+ {isFile && (
245
+ <div className="input-file-options">
246
+ <TextInput
247
+ label="Maximum number of files"
248
+ name={`sections.${sectionIndex}.inputs.${inputIndex}.maxCount`}
249
+ placeholder="1"
250
+ type="number"
251
+ min="0"
252
+ validate={integerAndGreaterThanZero}
253
+ />
254
+ <div className="specific-file-types">
255
+ <ToggleSwitch
256
+ handleOnChange={handleToggleShowSpecificFileTypes}
257
+ checked={input?.showSpecificFileTypes}
258
+ style={getToggleSwitchStyles(!input?.showSpecificFileTypes)}
259
+ inputId={`sections_${sectionIndex}_inputs.${inputIndex}_show_specific_file_types`}
260
+ />
261
+ <span className="s0">
262
+ Allow only specific file types
263
+ </span>
264
+ </div>
265
+ {input?.showSpecificFileTypes && (
266
+ <>
267
+ <ChoicesInput
268
+ name={`sections.${sectionIndex}.inputs.${inputIndex}.accept`}
269
+ options={fileUploadOptions}
270
+ multiple
271
+ />
272
+ </>
273
+ )}
274
+ </div>
275
+ )}
234
276
  </div>
235
277
  </div>
236
278
  )
@@ -137,6 +137,17 @@ $default-list-width: var(--action-button-width, 18rem);
137
137
  }
138
138
  }
139
139
  }
140
+
141
+ > .input-file-options {
142
+ display: flex;
143
+ flex-direction: column;
144
+ gap: var(--gap);
145
+ margin-bottom: $default-margin;
146
+
147
+ > .specific-file-types {
148
+ display: flex;
149
+ }
150
+ }
140
151
  }
141
152
  }
142
153
 
@@ -23,9 +23,14 @@ const componentClassName = 'renderer'
23
23
 
24
24
  const reconstructFormDataWithValues = (formData, values) => {
25
25
  const newData = { ...formData }
26
- Object.keys(values).forEach((key) => {
26
+ Object.keys(values).forEach(async (key) => {
27
27
  const [sectionIdx, inputIdx] = key.match(/\d+/g).map(Number)
28
- newData.sections[sectionIdx].inputs[inputIdx].value = values[key]
28
+ if (key.includes('files')) {
29
+ const files = values[key].map((file) => URL.createObjectURL(file))
30
+ newData.sections[sectionIdx].inputs[inputIdx].files = files
31
+ } else {
32
+ newData.sections[sectionIdx].inputs[inputIdx].value = values[key]
33
+ }
29
34
  })
30
35
  return newData
31
36
  }
@@ -144,7 +149,12 @@ const Renderer = ({
144
149
  <Form>
145
150
  {updatedFormData.sections.map((section, sectionIndex) => (
146
151
  sectionIndex === currentSectionIndex && (
147
- <Section key={`${section.title}`} {...section} readOnly={readOnly} />
152
+ <Section
153
+ key={`${section.title}`}
154
+ {...section}
155
+ readOnly={readOnly}
156
+ setUpdatedFormData={setUpdatedFormData}
157
+ />
148
158
  )
149
159
  ))}
150
160
  <div className="navigator-container">
@@ -1,3 +1,4 @@
1
+ /* eslint-disable no-alert */
1
2
  /* @pareto-engineering/generator-front 1.1.1-alpha.2 */
2
3
  import * as React from 'react'
3
4
 
@@ -46,8 +47,12 @@ const Section = ({
46
47
  nodes={description}
47
48
  name="instructions"
48
49
  />
49
- {inputs.map((input) => (
50
- <FormInput key={input.name} {...input} disabled={readOnly} />
50
+ {inputs?.map((input) => (
51
+ <FormInput
52
+ key={input.name}
53
+ {...input}
54
+ disabled={readOnly}
55
+ />
51
56
  ))}
52
57
  </div>
53
58
  )