@pareto-engineering/design-system 4.2.1 → 4.3.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 (58) hide show
  1. package/dist/cjs/f/FormInput/FormInput.js +6 -0
  2. package/dist/cjs/f/common/utils/index.js +8 -1
  3. package/dist/cjs/f/common/utils/validators.js +17 -0
  4. package/dist/cjs/f/fields/ChoicesInput/common/Choice/Choice.js +3 -2
  5. package/dist/cjs/f/fields/FileUpload/FileUpload.js +234 -0
  6. package/dist/cjs/f/fields/FileUpload/common/FilePreview/FilePreview.js +118 -0
  7. package/dist/cjs/f/fields/FileUpload/common/FilePreview/index.js +13 -0
  8. package/dist/cjs/f/fields/FileUpload/common/FilePreview/styles.scss +93 -0
  9. package/dist/cjs/f/fields/FileUpload/common/index.js +12 -0
  10. package/dist/cjs/f/fields/FileUpload/index.js +32 -0
  11. package/dist/cjs/f/fields/FileUpload/styles.scss +73 -0
  12. package/dist/cjs/f/fields/FileUpload/utils.js +45 -0
  13. package/dist/cjs/f/fields/index.js +26 -1
  14. package/dist/cjs/g/FormBuilder/FormBuilder.js +11 -3
  15. package/dist/cjs/g/FormBuilder/common/Builder/common/InputBuilder/InputBuilder.js +34 -7
  16. package/dist/cjs/g/FormBuilder/common/Builder/common/InputBuilder/styles.scss +11 -0
  17. package/dist/cjs/g/FormBuilder/common/Renderer/Renderer.js +14 -4
  18. package/dist/cjs/g/FormBuilder/common/Renderer/common/Section/Section.js +8 -4
  19. package/dist/es/f/FormInput/FormInput.js +7 -1
  20. package/dist/es/f/common/utils/index.js +2 -1
  21. package/dist/es/f/common/utils/validators.js +10 -0
  22. package/dist/es/f/fields/ChoicesInput/common/Choice/Choice.js +3 -2
  23. package/dist/es/f/fields/FileUpload/FileUpload.js +223 -0
  24. package/dist/es/f/fields/FileUpload/common/FilePreview/FilePreview.js +108 -0
  25. package/dist/es/f/fields/FileUpload/common/FilePreview/index.js +2 -0
  26. package/dist/es/f/fields/FileUpload/common/FilePreview/styles.scss +93 -0
  27. package/dist/es/f/fields/FileUpload/common/index.js +2 -0
  28. package/dist/es/f/fields/FileUpload/index.js +3 -0
  29. package/dist/es/f/fields/FileUpload/styles.scss +73 -0
  30. package/dist/es/f/fields/FileUpload/utils.js +37 -0
  31. package/dist/es/f/fields/index.js +2 -1
  32. package/dist/es/g/FormBuilder/FormBuilder.js +11 -3
  33. package/dist/es/g/FormBuilder/common/Builder/common/InputBuilder/InputBuilder.js +35 -8
  34. package/dist/es/g/FormBuilder/common/Builder/common/InputBuilder/styles.scss +11 -0
  35. package/dist/es/g/FormBuilder/common/Renderer/Renderer.js +14 -4
  36. package/dist/es/g/FormBuilder/common/Renderer/common/Section/Section.js +8 -3
  37. package/package.json +3 -3
  38. package/src/stories/f/FileUpload.stories.jsx +55 -0
  39. package/src/stories/g/FormBuilder.stories.jsx +19 -97
  40. package/src/ui/f/FormInput/FormInput.jsx +11 -0
  41. package/src/ui/f/common/utils/index.js +1 -0
  42. package/src/ui/f/common/utils/validators.js +10 -0
  43. package/src/ui/f/fields/ChoicesInput/common/Choice/Choice.jsx +2 -0
  44. package/src/ui/f/fields/FileUpload/FileUpload.jsx +279 -0
  45. package/src/ui/f/fields/FileUpload/common/FilePreview/FilePreview.jsx +160 -0
  46. package/src/ui/f/fields/FileUpload/common/FilePreview/index.js +2 -0
  47. package/src/ui/f/fields/FileUpload/common/FilePreview/styles.scss +93 -0
  48. package/src/ui/f/fields/FileUpload/common/index.js +2 -0
  49. package/src/ui/f/fields/FileUpload/index.js +3 -0
  50. package/src/ui/f/fields/FileUpload/styles.scss +73 -0
  51. package/src/ui/f/fields/FileUpload/utils.js +49 -0
  52. package/src/ui/f/fields/index.js +6 -0
  53. package/src/ui/g/FormBuilder/FormBuilder.jsx +9 -0
  54. package/src/ui/g/FormBuilder/common/Builder/common/InputBuilder/InputBuilder.jsx +53 -11
  55. package/src/ui/g/FormBuilder/common/Builder/common/InputBuilder/styles.scss +11 -0
  56. package/src/ui/g/FormBuilder/common/Renderer/Renderer.jsx +17 -3
  57. package/src/ui/g/FormBuilder/common/Renderer/common/Section/Section.jsx +11 -2
  58. package/tests/__snapshots__/Storyshots.test.js.snap +180 -154
@@ -21,6 +21,12 @@ Object.defineProperty(exports, "EditorInput", {
21
21
  return _EditorInput.EditorInput;
22
22
  }
23
23
  });
24
+ Object.defineProperty(exports, "FileUpload", {
25
+ enumerable: true,
26
+ get: function () {
27
+ return _FileUpload.FileUpload;
28
+ }
29
+ });
24
30
  Object.defineProperty(exports, "LinkInput", {
25
31
  enumerable: true,
26
32
  get: function () {
@@ -69,6 +75,24 @@ Object.defineProperty(exports, "TextareaInput", {
69
75
  return _TextareaInput.TextareaInput;
70
76
  }
71
77
  });
78
+ Object.defineProperty(exports, "fileUploadOptions", {
79
+ enumerable: true,
80
+ get: function () {
81
+ return _FileUpload.fileUploadOptions;
82
+ }
83
+ });
84
+ Object.defineProperty(exports, "getFileType", {
85
+ enumerable: true,
86
+ get: function () {
87
+ return _FileUpload.getFileType;
88
+ }
89
+ });
90
+ Object.defineProperty(exports, "getFileTypeFromUrl", {
91
+ enumerable: true,
92
+ get: function () {
93
+ return _FileUpload.getFileTypeFromUrl;
94
+ }
95
+ });
72
96
  var _TextInput = require("./TextInput");
73
97
  var _SelectInput = require("./SelectInput");
74
98
  var _ChoicesInput = require("./ChoicesInput");
@@ -79,4 +103,5 @@ var _QuerySelect = require("./QuerySelect");
79
103
  var _Checkbox = require("./Checkbox");
80
104
  var _QueryChoices = require("./QueryChoices");
81
105
  var _LinkInput = require("./LinkInput");
82
- var _EditorInput = require("./EditorInput");
106
+ var _EditorInput = require("./EditorInput");
107
+ var _FileUpload = require("./FileUpload");
@@ -37,7 +37,9 @@ const FormBuilder = _ref => {
37
37
  onRendererError,
38
38
  onRendererFormSave,
39
39
  onBuilderValidate,
40
- initialBuilderValues
40
+ initialBuilderValues,
41
+ fileUploadStatus,
42
+ handleFileDelete
41
43
  // ...otherProps
42
44
  } = _ref;
43
45
  return /*#__PURE__*/React.createElement("div", {
@@ -56,7 +58,9 @@ const FormBuilder = _ref => {
56
58
  onSave: onRendererFormSave,
57
59
  readOnly: readOnly,
58
60
  shouldSubmit: shouldSubmit,
59
- onError: onRendererError
61
+ onError: onRendererError,
62
+ fileUploadStatus: fileUploadStatus,
63
+ handleFileDelete: handleFileDelete
60
64
  }));
61
65
  };
62
66
  FormBuilder.propTypes = {
@@ -99,7 +103,11 @@ FormBuilder.propTypes = {
99
103
  /**
100
104
  * Whether the form builder in renderer mode should submit the form values itself
101
105
  */
102
- shouldSubmit: _propTypes.default.bool
106
+ shouldSubmit: _propTypes.default.bool,
107
+ /**
108
+ * The upload status of files if any
109
+ */
110
+ fileUploadStatus: _propTypes.default.objectOf(_propTypes.default.string)
103
111
  };
104
112
  FormBuilder.defaultProps = {
105
113
  mode: 'build',
@@ -22,6 +22,9 @@ function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e;
22
22
 
23
23
  const baseClassName = _exports.default.base;
24
24
  const componentClassName = 'input-builder';
25
+ const getToggleSwitchStyles = condition => condition ? {
26
+ '--slider-background-color': 'var(--disabled)'
27
+ } : {};
25
28
 
26
29
  /**
27
30
  * This is the component description.
@@ -45,11 +48,6 @@ const InputBuilder = _ref => {
45
48
  const handleToggleRequired = () => {
46
49
  setFieldValue(`sections.${sectionIndex}.inputs.${inputIndex}.required`, !input?.required);
47
50
  };
48
- const toggleSwitchStyles = {
49
- ...(!input?.required ? {
50
- '--slider-background-color': 'var(--disabled)'
51
- } : {})
52
- };
53
51
  const [hasDescription, setHasDescription] = (0, _react.useState)(false);
54
52
 
55
53
  // TODO: handle nav logic
@@ -69,6 +67,10 @@ const InputBuilder = _ref => {
69
67
  } = e.target;
70
68
  setFieldValue(`sections.${sectionIndex}.inputs.${inputIndex}.options.${optionIndex}.label`, value);
71
69
  };
70
+ const isFile = input?.type === 'file';
71
+ const handleToggleShowSpecificFileTypes = () => {
72
+ setFieldValue(`sections.${sectionIndex}.inputs.${inputIndex}.showSpecificFileTypes`, !input.showSpecificFileTypes);
73
+ };
72
74
  return /*#__PURE__*/React.createElement("div", {
73
75
  id: id,
74
76
  className: [baseClassName, componentClassName, userClassName].filter(e => e).join(' '),
@@ -102,6 +104,9 @@ const InputBuilder = _ref => {
102
104
  }, {
103
105
  value: 'choices',
104
106
  label: 'Radio buttons'
107
+ }, {
108
+ value: 'file',
109
+ label: 'File upload'
105
110
  }]
106
111
  }), /*#__PURE__*/React.createElement("div", {
107
112
  className: "controls"
@@ -117,7 +122,7 @@ const InputBuilder = _ref => {
117
122
  }, "Required"), /*#__PURE__*/React.createElement(_a.ToggleSwitch, {
118
123
  handleOnChange: handleToggleRequired,
119
124
  checked: input?.required,
120
- style: toggleSwitchStyles,
125
+ style: getToggleSwitchStyles(!input?.required),
121
126
  inputId: `sections_${sectionIndex}_inputs.${inputIndex}_toggle`
122
127
  })), /*#__PURE__*/React.createElement(_ActionsContainer.ActionsContainer, null, /*#__PURE__*/React.createElement("p", null, "Show"), /*#__PURE__*/React.createElement("ul", null, /*#__PURE__*/React.createElement("li", {
123
128
  className: `option ${hasDescription ? 'with-check-mark' : ''}`
@@ -181,7 +186,29 @@ const InputBuilder = _ref => {
181
186
  }, "+")), /*#__PURE__*/React.createElement("span", {
182
187
  className: "text x-paragraph c-x"
183
188
  }, "Add Option")));
184
- })));
189
+ }), isFile && /*#__PURE__*/React.createElement("div", {
190
+ className: "input-file-options"
191
+ }, /*#__PURE__*/React.createElement(_f.TextInput, {
192
+ label: "Maximum number of files",
193
+ name: `sections.${sectionIndex}.inputs.${inputIndex}.maxCount`,
194
+ placeholder: "1",
195
+ type: "number",
196
+ min: "0",
197
+ validate: _f.integerAndGreaterThanZero
198
+ }), /*#__PURE__*/React.createElement("div", {
199
+ className: "specific-file-types"
200
+ }, /*#__PURE__*/React.createElement(_a.ToggleSwitch, {
201
+ handleOnChange: handleToggleShowSpecificFileTypes,
202
+ checked: input?.showSpecificFileTypes,
203
+ style: getToggleSwitchStyles(!input?.showSpecificFileTypes),
204
+ inputId: `sections_${sectionIndex}_inputs.${inputIndex}_show_specific_file_types`
205
+ }), /*#__PURE__*/React.createElement("span", {
206
+ className: "s0"
207
+ }, "Allow only specific file types")), input?.showSpecificFileTypes && /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(_f.ChoicesInput, {
208
+ name: `sections.${sectionIndex}.inputs.${inputIndex}.accept`,
209
+ options: _f.fileUploadOptions,
210
+ multiple: true
211
+ })))));
185
212
  };
186
213
  InputBuilder.propTypes = {
187
214
  /**
@@ -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
 
@@ -22,9 +22,14 @@ const reconstructFormDataWithValues = (formData, values) => {
22
22
  const newData = {
23
23
  ...formData
24
24
  };
25
- Object.keys(values).forEach(key => {
25
+ Object.keys(values).forEach(async key => {
26
26
  const [sectionIdx, inputIdx] = key.match(/\d+/g).map(Number);
27
- newData.sections[sectionIdx].inputs[inputIdx].value = values[key];
27
+ if (key.includes('files')) {
28
+ const files = values[key].map(file => URL.createObjectURL(file));
29
+ newData.sections[sectionIdx].inputs[inputIdx].files = files;
30
+ } else {
31
+ newData.sections[sectionIdx].inputs[inputIdx].value = values[key];
32
+ }
28
33
  });
29
34
  return newData;
30
35
  };
@@ -52,7 +57,9 @@ const Renderer = _ref => {
52
57
  readOnly,
53
58
  onSave,
54
59
  onError,
55
- shouldSubmit
60
+ shouldSubmit,
61
+ fileUploadStatus,
62
+ handleFileDelete
56
63
  // ...otherProps
57
64
  } = _ref;
58
65
  const [currentSectionIndex, setCurrentSectionIndex] = (0, _react.useState)(0);
@@ -125,7 +132,10 @@ const Renderer = _ref => {
125
132
  return /*#__PURE__*/React.createElement(_formik.Form, null, updatedFormData.sections.map((section, sectionIndex) => sectionIndex === currentSectionIndex && /*#__PURE__*/React.createElement(_common.Section, _extends({
126
133
  key: `${section.title}`
127
134
  }, section, {
128
- readOnly: readOnly
135
+ readOnly: readOnly,
136
+ setUpdatedFormData: setUpdatedFormData,
137
+ fileUploadStatus: fileUploadStatus,
138
+ handleFileDelete: handleFileDelete
129
139
  }))), /*#__PURE__*/React.createElement("div", {
130
140
  className: "navigator-container"
131
141
  }, /*#__PURE__*/React.createElement(_b.Button, {
@@ -12,7 +12,7 @@ var _exports = _interopRequireDefault(require("@pareto-engineering/bem/exports")
12
12
  function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
13
13
  function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function (e) { return e ? t : r; })(e); }
14
14
  function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && {}.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; }
15
- function _extends() { _extends = Object.assign ? Object.assign.bind() : function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); } /* @pareto-engineering/generator-front 1.1.1-alpha.2 */ // Local Definitions
15
+ function _extends() { _extends = Object.assign ? Object.assign.bind() : function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); } /* eslint-disable no-alert */ /* @pareto-engineering/generator-front 1.1.1-alpha.2 */ // Local Definitions
16
16
  const baseClassName = _exports.default.base;
17
17
  const componentClassName = 'section';
18
18
 
@@ -27,7 +27,9 @@ const Section = _ref => {
27
27
  title,
28
28
  description,
29
29
  inputs,
30
- readOnly
30
+ readOnly,
31
+ fileUploadStatus,
32
+ handleFileDelete
31
33
  // ...otherProps
32
34
  } = _ref;
33
35
  return /*#__PURE__*/React.createElement("div", {
@@ -39,10 +41,12 @@ const Section = _ref => {
39
41
  }, title), /*#__PURE__*/React.createElement(_.ExpandableLexicalPreview, {
40
42
  nodes: description,
41
43
  name: "instructions"
42
- }), inputs.map(input => /*#__PURE__*/React.createElement(_f.FormInput, _extends({
44
+ }), inputs?.map(input => /*#__PURE__*/React.createElement(_f.FormInput, _extends({
43
45
  key: input.name
44
46
  }, input, {
45
- disabled: readOnly
47
+ disabled: readOnly,
48
+ uploadStatus: fileUploadStatus,
49
+ handleFileDelete: handleFileDelete
46
50
  }))));
47
51
  };
48
52
  Section.propTypes = {
@@ -3,7 +3,7 @@ function _extends() { _extends = Object.assign ? Object.assign.bind() : function
3
3
  import * as React from 'react';
4
4
  import { memo } from 'react';
5
5
  import PropTypes from 'prop-types';
6
- import { TextInput, TextareaInput, ChoicesInput, SelectInput, QueryCombobox, QuerySelect, RatingsInput, Checkbox, QueryChoices, LinkInput, EditorInput } from "../fields";
6
+ import { TextInput, TextareaInput, ChoicesInput, SelectInput, QueryCombobox, QuerySelect, RatingsInput, Checkbox, QueryChoices, LinkInput, EditorInput, FileUpload } from "../fields";
7
7
  import "./styles.scss";
8
8
 
9
9
  // Local Definitions
@@ -89,6 +89,12 @@ const FormInput = ({
89
89
  disabled: disabled
90
90
  }, otherProps));
91
91
  }
92
+ if (type === 'file') {
93
+ return /*#__PURE__*/React.createElement(FileUpload, _extends({
94
+ className: newClassName,
95
+ disabled: disabled
96
+ }, otherProps));
97
+ }
92
98
  if (extraTypes?.[type]) {
93
99
  const Component = extraTypes[type];
94
100
  return /*#__PURE__*/React.createElement(Component, _extends({
@@ -1 +1,2 @@
1
- export { lookUpInputValueFromFetchedOptions } from "./lookUpInputValueFromFetchedOptions";
1
+ export { lookUpInputValueFromFetchedOptions } from "./lookUpInputValueFromFetchedOptions";
2
+ export { integerAndGreaterThanZero } from "./validators";
@@ -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
+ };
@@ -23,7 +23,8 @@ const Choice = ({
23
23
  value,
24
24
  multiple,
25
25
  validate,
26
- disabled
26
+ disabled,
27
+ ...otherProps
27
28
  }) => {
28
29
  const type = multiple ? 'checkbox' : 'radio';
29
30
  const [field] = useField({
@@ -39,7 +40,7 @@ const Choice = ({
39
40
  type: type,
40
41
  id: id,
41
42
  name: name
42
- }, field, {
43
+ }, field, otherProps, {
43
44
  value: value,
44
45
  disabled: disabled
45
46
  })), /*#__PURE__*/React.createElement("label", {
@@ -0,0 +1,223 @@
1
+ /* @pareto-engineering/generator-front 1.1.1-alpha.2 */
2
+ import * as React from 'react';
3
+ import PropTypes from 'prop-types';
4
+ import { useField } from 'formik';
5
+ import styleNames from '@pareto-engineering/bem/exports';
6
+ import "./styles.scss";
7
+ import { FilePreview } from "./common";
8
+ import { FormLabel, FormDescription } from "../../common";
9
+
10
+ // Local Definitions
11
+
12
+ const baseClassName = styleNames.base;
13
+ const componentClassName = 'file-upload';
14
+
15
+ /**
16
+ * This is the component description.
17
+ */
18
+ const FileUpload = ({
19
+ id,
20
+ className: userClassName,
21
+ style,
22
+ label,
23
+ description,
24
+ accept,
25
+ multiple,
26
+ name,
27
+ disabled,
28
+ maxCount,
29
+ maxCountError,
30
+ maxSize,
31
+ maxSizeError,
32
+ onChange,
33
+ uploadStatus,
34
+ filePreviewAlignment,
35
+ optional,
36
+ labelColor,
37
+ color,
38
+ viewOnly,
39
+ handleFileDelete
40
+ // ...otherProps
41
+ }) => {
42
+ const [field,, helpers] = useField({
43
+ name
44
+ });
45
+ const {
46
+ value
47
+ } = field;
48
+ const {
49
+ setError,
50
+ setValue,
51
+ setTouched
52
+ } = helpers;
53
+ const handleChange = event => {
54
+ setTouched(true, false);
55
+ const newFiles = Array.from(event.currentTarget.files);
56
+ const currentFiles = value || [];
57
+ const currentCount = currentFiles.length + newFiles.length;
58
+ if (maxCount && currentCount > maxCount) {
59
+ setError(maxCountError || `Maximum of ${maxCount} files allowed`);
60
+ return;
61
+ }
62
+ const duplicateFiles = newFiles.filter(newFile => currentFiles.some(currentFile => currentFile.name === newFile.name));
63
+ if (duplicateFiles.length > 0) {
64
+ setError('You cannot upload the same file twice.');
65
+ return;
66
+ }
67
+ if (maxSize) {
68
+ const oversizedFiles = newFiles.filter(file => file.size > maxSize);
69
+ if (oversizedFiles.length > 0) {
70
+ setError(maxSizeError || `File size exceeds the limit of ${maxSize} bytes`);
71
+ return;
72
+ }
73
+ }
74
+ const updatedFiles = [...currentFiles, ...newFiles];
75
+ setValue(updatedFiles);
76
+ onChange?.(updatedFiles);
77
+
78
+ // eslint-disable-next-line no-param-reassign
79
+ event.target.value = null;
80
+ };
81
+ const handleDelete = ({
82
+ fileIndex,
83
+ identifier
84
+ }) => {
85
+ const updatedFiles = value?.filter((_, i) => i !== fileIndex);
86
+ setValue(updatedFiles);
87
+ handleFileDelete?.({
88
+ fileIndex,
89
+ identifier
90
+ });
91
+ };
92
+ const acceptOptions = Array.isArray(accept) ? accept?.join(',') : accept;
93
+ return /*#__PURE__*/React.createElement("div", {
94
+ id: id,
95
+ className: [baseClassName, componentClassName, userClassName, `preview-${filePreviewAlignment}`, `y-${color}`].filter(e => e).join(' '),
96
+ style: style
97
+ }, /*#__PURE__*/React.createElement("p", null, label), /*#__PURE__*/React.createElement(FormDescription, {
98
+ className: "s-1",
99
+ description: description,
100
+ name: name
101
+ }), !viewOnly && /*#__PURE__*/React.createElement(FormLabel, {
102
+ name: name,
103
+ color: labelColor,
104
+ optional: optional
105
+ }, /*#__PURE__*/React.createElement("input", {
106
+ id: name,
107
+ className: "file",
108
+ type: "file",
109
+ accept: acceptOptions,
110
+ multiple: multiple || maxCount && maxCount > 0,
111
+ disabled: disabled,
112
+ onChange: handleChange
113
+ }), /*#__PURE__*/React.createElement("span", {
114
+ className: "ai-icon"
115
+ }, "U"), /*#__PURE__*/React.createElement("span", null, "Attach file")), value?.length > 0 && /*#__PURE__*/React.createElement("div", {
116
+ className: "attached-files"
117
+ }, /*#__PURE__*/React.createElement("p", null, "Attached files:"), /*#__PURE__*/React.createElement("div", {
118
+ className: "files"
119
+ }, value.map((file, indx) => {
120
+ const isFileObject = file instanceof File;
121
+ return /*#__PURE__*/React.createElement(FilePreview, {
122
+ file: file,
123
+ key: isFileObject ? file.name : file,
124
+ disabled: disabled,
125
+ handleDelete: () => handleDelete({
126
+ fileIndex: indx,
127
+ identifier: isFileObject ? file.name : file?.id
128
+ }),
129
+ uploadStatus: uploadStatus?.[file?.name],
130
+ viewOnly: viewOnly
131
+ });
132
+ }))));
133
+ };
134
+ FileUpload.propTypes = {
135
+ /**
136
+ * The HTML id for this element
137
+ */
138
+ id: PropTypes.string,
139
+ /**
140
+ * The HTML class names for this element
141
+ */
142
+ className: PropTypes.string,
143
+ /**
144
+ * The React-written, css properties for this element.
145
+ */
146
+ style: PropTypes.objectOf(PropTypes.string),
147
+ /**
148
+ * The label text for the file input
149
+ */
150
+ label: PropTypes.string,
151
+ /**
152
+ * The description text below the label
153
+ */
154
+ description: PropTypes.string,
155
+ /**
156
+ * The color of the text
157
+ */
158
+ color: PropTypes.string,
159
+ /**
160
+ * The accepted file types (e.g., 'image/*')
161
+ */
162
+ accept: PropTypes.string,
163
+ /**
164
+ * Whether to allow multiple file uploads
165
+ */
166
+ multiple: PropTypes.bool,
167
+ /**
168
+ * The name attribute for the input
169
+ */
170
+ name: PropTypes.string.isRequired,
171
+ /**
172
+ * Whether the the input should be disabled
173
+ */
174
+ disabled: PropTypes.bool,
175
+ /**
176
+ * The maximum number of files allowed
177
+ */
178
+ maxCount: PropTypes.number,
179
+ /**
180
+ * The error message when max count is exceeded
181
+ */
182
+ maxCountError: PropTypes.string,
183
+ /**
184
+ * The maximum size of files allowed (in bytes)
185
+ */
186
+ maxSize: PropTypes.number,
187
+ /**
188
+ * The error message when file size exceeds max size
189
+ */
190
+ maxSizeError: PropTypes.string,
191
+ /**
192
+ * The upload progress value (0-100)
193
+ */
194
+ // progress:PropTypes.number,
195
+
196
+ /**
197
+ * The function to handle file change events
198
+ */
199
+ onChange: PropTypes.func,
200
+ /**
201
+ * The function to handle file delete events
202
+ */
203
+ handleFileDelete: PropTypes.func,
204
+ /**
205
+ * The upload status of the file with the file name as the key
206
+ */
207
+ uploadStatus: PropTypes.objectOf(PropTypes.string),
208
+ /**
209
+ * The alignment for file previews WRT the upload input
210
+ */
211
+ filePreviewAlignment: PropTypes.oneOf(['left', 'right', 'top', 'bottom']),
212
+ /**
213
+ * Whether the file upload is in view only mode
214
+ */
215
+ viewOnly: PropTypes.bool
216
+ };
217
+ FileUpload.defaultProps = {
218
+ disabled: false,
219
+ color: 'paragraph',
220
+ filePreviewAlignment: 'bottom',
221
+ viewOnly: false
222
+ };
223
+ export default FileUpload;
@@ -0,0 +1,108 @@
1
+ /* @pareto-engineering/generator-front 1.1.1-alpha.2 */
2
+ import * as React from 'react';
3
+ import PropTypes from 'prop-types';
4
+ import styleNames from '@pareto-engineering/bem/exports';
5
+ import { LoadingCircle, ProgressBar } from "../../../../../a";
6
+
7
+ // Local Definitions
8
+
9
+ import "./styles.scss";
10
+ import { Button } from "../../../../../b";
11
+ import { getFileType, getFileTypeFromUrl } from "../../utils";
12
+ const baseClassName = styleNames.base;
13
+ const componentClassName = 'file-preview';
14
+ const statusColorMap = {
15
+ pending: 'yellow',
16
+ error: 'red',
17
+ success: 'green'
18
+ };
19
+ const FILE_UPLOAD_COMPLETE_PROGRESS = 100;
20
+
21
+ /**
22
+ * This is the component description.
23
+ */
24
+ const FilePreview = ({
25
+ id,
26
+ className: userClassName,
27
+ style,
28
+ file,
29
+ disabled,
30
+ handleDelete,
31
+ uploadStatus,
32
+ color,
33
+ uploadProgress
34
+ // ...otherProps
35
+ }) => {
36
+ const isFileObject = file instanceof File;
37
+ const type = isFileObject ? getFileType(file) : getFileTypeFromUrl(file?.url);
38
+ const status = uploadStatus?.status;
39
+ const statusColor = statusColorMap[status] ?? color;
40
+ const isPending = status === 'pending';
41
+ // isPreview means the file is uploaded and previewed while other files can still be uploaded
42
+ const isSuccess = status === 'success' || file?.isPreview;
43
+ const handlePreview = () => {
44
+ if (!isFileObject) {
45
+ window.open(file.url, '_blank');
46
+ }
47
+ };
48
+ const canDelete = file?.isPreview || isFileObject;
49
+ return /*#__PURE__*/React.createElement("div", {
50
+ id: id,
51
+ className: [baseClassName, componentClassName, userClassName].filter(e => e).join(' '),
52
+ style: style
53
+ }, /*#__PURE__*/React.createElement("div", {
54
+ className: "identity"
55
+ }, /*#__PURE__*/React.createElement("span", {
56
+ className: ['type', type.toLowerCase()].filter(e => e).join(' ')
57
+ }, type), /*#__PURE__*/React.createElement("span", {
58
+ title: file.name,
59
+ className: "name"
60
+ }, file.name), /*#__PURE__*/React.createElement(Button, {
61
+ isCompact: true,
62
+ isSimple: true,
63
+ onClick: () => canDelete ? handleDelete() : handlePreview()
64
+ }, /*#__PURE__*/React.createElement("span", {
65
+ className: "icon x-ui-icons c-x"
66
+ }, canDelete ? 'Y' : '9'))), !disabled && /*#__PURE__*/React.createElement("div", {
67
+ className: `progress-status x-${statusColor}`
68
+ }, /*#__PURE__*/React.createElement("div", {
69
+ className: "status"
70
+ }, isPending ? /*#__PURE__*/React.createElement(LoadingCircle, {
71
+ className: `x-${statusColor}`,
72
+ heightWidth: "1rem",
73
+ color: statusColor
74
+ }) : /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement("span", {
75
+ className: "icon"
76
+ }, isSuccess ? 'I' : 'Y'), /*#__PURE__*/React.createElement("span", null, isSuccess ? 'Uploaded' : 'Error'))), /*#__PURE__*/React.createElement(ProgressBar, {
77
+ color: statusColor,
78
+ progress: isPending ? uploadProgress : FILE_UPLOAD_COMPLETE_PROGRESS,
79
+ height: "3px"
80
+ })));
81
+ };
82
+ FilePreview.propTypes = {
83
+ /**
84
+ * The HTML id for this element
85
+ */
86
+ id: PropTypes.string,
87
+ /**
88
+ * The HTML class names for this element
89
+ */
90
+ className: PropTypes.string,
91
+ /**
92
+ * The React-written, css properties for this element.
93
+ */
94
+ style: PropTypes.objectOf(PropTypes.string),
95
+ /**
96
+ * The base color of the file preview
97
+ */
98
+ color: PropTypes.string,
99
+ /**
100
+ * The upload progress of the file
101
+ */
102
+ uploadProgress: PropTypes.number
103
+ };
104
+ FilePreview.defaultProps = {
105
+ color: 'green',
106
+ uploadProgress: 45
107
+ };
108
+ export default FilePreview;
@@ -0,0 +1,2 @@
1
+ /* @pareto-engineering/generator-front 1.1.1-alpha.2 */
2
+ export { default as FilePreview } from "./FilePreview";