@rivtn/noseur 1.0.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 (138) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +2 -0
  3. package/dist/esm/Template.d.ts +7 -0
  4. package/dist/esm/Template.js +13 -0
  5. package/dist/esm/compose/Composed.css +437 -0
  6. package/dist/esm/compose/exotic/ColorPicker.d.ts +41 -0
  7. package/dist/esm/compose/exotic/ColorPicker.js +85 -0
  8. package/dist/esm/compose/exotic/ColorSlider.d.ts +30 -0
  9. package/dist/esm/compose/exotic/ColorSlider.js +99 -0
  10. package/dist/esm/compose/form/ComposedPassword.d.ts +25 -0
  11. package/dist/esm/compose/form/ComposedPassword.js +103 -0
  12. package/dist/esm/compose/form/DateTimeInput.d.ts +28 -0
  13. package/dist/esm/compose/form/DateTimeInput.js +154 -0
  14. package/dist/esm/compose/form/DateTimePicker.d.ts +341 -0
  15. package/dist/esm/compose/form/DateTimePicker.js +1265 -0
  16. package/dist/esm/compose/form/FormControl.d.ts +33 -0
  17. package/dist/esm/compose/form/FormControl.js +163 -0
  18. package/dist/esm/compose/form/FormGroup.d.ts +14 -0
  19. package/dist/esm/compose/form/FormGroup.js +58 -0
  20. package/dist/esm/compose/overlay/Alert.d.ts +56 -0
  21. package/dist/esm/compose/overlay/Alert.js +267 -0
  22. package/dist/esm/constants/Alignment.d.ts +17 -0
  23. package/dist/esm/constants/Alignment.js +18 -0
  24. package/dist/esm/constants/Direction.d.ts +26 -0
  25. package/dist/esm/constants/Direction.js +22 -0
  26. package/dist/esm/constants/Orientation.d.ts +8 -0
  27. package/dist/esm/constants/Orientation.js +9 -0
  28. package/dist/esm/constants/Scheme.d.ts +39 -0
  29. package/dist/esm/constants/Scheme.js +43 -0
  30. package/dist/esm/constants/Transition.d.ts +81 -0
  31. package/dist/esm/constants/Transition.js +85 -0
  32. package/dist/esm/constants/Types.d.ts +74 -0
  33. package/dist/esm/constants/Types.js +14 -0
  34. package/dist/esm/core/ComponentBaseProps.d.ts +53 -0
  35. package/dist/esm/core/ComponentBaseProps.js +33 -0
  36. package/dist/esm/core/noseur.css +2390 -0
  37. package/dist/esm/data/Column.d.ts +235 -0
  38. package/dist/esm/data/Column.js +98 -0
  39. package/dist/esm/data/Data.css +213 -0
  40. package/dist/esm/data/Data.d.ts +98 -0
  41. package/dist/esm/data/Data.js +142 -0
  42. package/dist/esm/data/List.d.ts +14 -0
  43. package/dist/esm/data/List.js +117 -0
  44. package/dist/esm/data/Table.d.ts +22 -0
  45. package/dist/esm/data/Table.js +236 -0
  46. package/dist/esm/form/Button.d.ts +35 -0
  47. package/dist/esm/form/Button.js +131 -0
  48. package/dist/esm/form/Calendar.d.ts +20 -0
  49. package/dist/esm/form/Calendar.js +46 -0
  50. package/dist/esm/form/Checkbox.d.ts +20 -0
  51. package/dist/esm/form/Checkbox.js +155 -0
  52. package/dist/esm/form/ColorMap.d.ts +22 -0
  53. package/dist/esm/form/ColorMap.js +43 -0
  54. package/dist/esm/form/ColorPalette.d.ts +28 -0
  55. package/dist/esm/form/ColorPalette.js +87 -0
  56. package/dist/esm/form/Dropdown.d.ts +78 -0
  57. package/dist/esm/form/Dropdown.js +360 -0
  58. package/dist/esm/form/FileInput.d.ts +134 -0
  59. package/dist/esm/form/FileInput.js +523 -0
  60. package/dist/esm/form/Form.css +467 -0
  61. package/dist/esm/form/Input.d.ts +45 -0
  62. package/dist/esm/form/Input.js +186 -0
  63. package/dist/esm/form/RadioButton.d.ts +21 -0
  64. package/dist/esm/form/RadioButton.js +178 -0
  65. package/dist/esm/form/Slider.d.ts +21 -0
  66. package/dist/esm/form/Slider.js +163 -0
  67. package/dist/esm/hooks/useSearchParams.d.ts +15 -0
  68. package/dist/esm/hooks/useSearchParams.js +50 -0
  69. package/dist/esm/hooks/useSubscription.d.ts +9 -0
  70. package/dist/esm/hooks/useSubscription.js +26 -0
  71. package/dist/esm/index.d.ts +60 -0
  72. package/dist/esm/index.js +73 -0
  73. package/dist/esm/layout/GridView.d.ts +23 -0
  74. package/dist/esm/layout/GridView.js +34 -0
  75. package/dist/esm/layout/Layout.css +5 -0
  76. package/dist/esm/misc/Misc.css +164 -0
  77. package/dist/esm/misc/ProgressBar.d.ts +22 -0
  78. package/dist/esm/misc/ProgressBar.js +86 -0
  79. package/dist/esm/overlay/Dialog.d.ts +46 -0
  80. package/dist/esm/overlay/Dialog.js +290 -0
  81. package/dist/esm/overlay/Message.d.ts +35 -0
  82. package/dist/esm/overlay/Message.js +187 -0
  83. package/dist/esm/overlay/Overlay.css +382 -0
  84. package/dist/esm/overlay/Popover.d.ts +30 -0
  85. package/dist/esm/overlay/Popover.js +245 -0
  86. package/dist/esm/overlay/Portal.d.ts +11 -0
  87. package/dist/esm/overlay/Portal.js +29 -0
  88. package/dist/esm/overlay/Toast.d.ts +49 -0
  89. package/dist/esm/overlay/Toast.js +341 -0
  90. package/dist/esm/panel/Accordion.d.ts +26 -0
  91. package/dist/esm/panel/Accordion.js +127 -0
  92. package/dist/esm/panel/Panel.css +317 -0
  93. package/dist/esm/panel/Panel.d.ts +43 -0
  94. package/dist/esm/panel/Panel.js +125 -0
  95. package/dist/esm/panel/ScrollPanel.d.ts +27 -0
  96. package/dist/esm/panel/ScrollPanel.js +43 -0
  97. package/dist/esm/panel/TabPane.d.ts +82 -0
  98. package/dist/esm/panel/TabPane.js +237 -0
  99. package/dist/esm/presentation/Chart.d.ts +49 -0
  100. package/dist/esm/presentation/Chart.js +62 -0
  101. package/dist/esm/presentation/Paginator.d.ts +90 -0
  102. package/dist/esm/presentation/Paginator.js +331 -0
  103. package/dist/esm/presentation/Presentation.css +23 -0
  104. package/dist/esm/sensor/DragSensor.d.ts +50 -0
  105. package/dist/esm/sensor/DragSensor.js +156 -0
  106. package/dist/esm/sensor/ViewportSensor.d.ts +18 -0
  107. package/dist/esm/sensor/ViewportSensor.js +85 -0
  108. package/dist/esm/utils/BoolHelper.d.ts +13 -0
  109. package/dist/esm/utils/BoolHelper.js +105 -0
  110. package/dist/esm/utils/Classname.d.ts +9 -0
  111. package/dist/esm/utils/Classname.js +20 -0
  112. package/dist/esm/utils/ColorHelper.d.ts +127 -0
  113. package/dist/esm/utils/ColorHelper.js +198 -0
  114. package/dist/esm/utils/DOMUtils.d.ts +142 -0
  115. package/dist/esm/utils/DOMUtils.js +759 -0
  116. package/dist/esm/utils/DateHelper.d.ts +115 -0
  117. package/dist/esm/utils/DateHelper.js +338 -0
  118. package/dist/esm/utils/Debugger.d.ts +12 -0
  119. package/dist/esm/utils/Debugger.js +30 -0
  120. package/dist/esm/utils/FileHelper.d.ts +8 -0
  121. package/dist/esm/utils/FileHelper.js +65 -0
  122. package/dist/esm/utils/FunctionStackManager.d.ts +13 -0
  123. package/dist/esm/utils/FunctionStackManager.js +59 -0
  124. package/dist/esm/utils/InputHelper.d.ts +37 -0
  125. package/dist/esm/utils/InputHelper.js +70 -0
  126. package/dist/esm/utils/MicroBuilder.d.ts +24 -0
  127. package/dist/esm/utils/MicroBuilder.js +61 -0
  128. package/dist/esm/utils/ObjectHelper.d.ts +51 -0
  129. package/dist/esm/utils/ObjectHelper.js +334 -0
  130. package/dist/esm/utils/StringHelper.d.ts +10 -0
  131. package/dist/esm/utils/StringHelper.js +54 -0
  132. package/dist/esm/utils/Subscriber.d.ts +14 -0
  133. package/dist/esm/utils/Subscriber.js +27 -0
  134. package/dist/esm/utils/Timer.d.ts +32 -0
  135. package/dist/esm/utils/Timer.js +68 -0
  136. package/dist/esm/utils/TypeChecker.d.ts +12 -0
  137. package/dist/esm/utils/TypeChecker.js +38 -0
  138. package/package.json +63 -0
@@ -0,0 +1,523 @@
1
+ import "./Form.css";
2
+ import React from 'react';
3
+ import { Scheme } from "../constants/Scheme";
4
+ import { Classname } from "../utils/Classname";
5
+ import { ObjectHelper } from "../utils/ObjectHelper";
6
+ import { Orientation } from "../constants/Orientation";
7
+ import { DOMHelper, ObserverHandler } from "../utils/DOMUtils";
8
+ import { Button, buildButtonControl } from "./Button";
9
+ import { FileHelper } from "../utils/FileHelper";
10
+ export var FileInputMode;
11
+ (function (FileInputMode) {
12
+ FileInputMode[FileInputMode["BUTTON"] = 0] = "BUTTON";
13
+ FileInputMode[FileInputMode["PREVIEW"] = 1] = "PREVIEW";
14
+ FileInputMode[FileInputMode["ELEMENT"] = 2] = "ELEMENT";
15
+ FileInputMode[FileInputMode["CONTROLLED"] = 3] = "CONTROLLED";
16
+ })(FileInputMode || (FileInputMode = {}));
17
+ export var FileInputPreviewType;
18
+ (function (FileInputPreviewType) {
19
+ FileInputPreviewType["PDF"] = "PDF";
20
+ FileInputPreviewType["AUTO"] = "AUTO";
21
+ FileInputPreviewType["NONE"] = "NONE";
22
+ FileInputPreviewType["HTML"] = "HTML";
23
+ FileInputPreviewType["TEXT"] = "TEXT";
24
+ FileInputPreviewType["IMAGE"] = "IMAGE";
25
+ FileInputPreviewType["VIDEO"] = "VIDEO";
26
+ FileInputPreviewType["AUDIO"] = "AUDIO";
27
+ FileInputPreviewType["BINARY"] = "BINARY";
28
+ FileInputPreviewType["CUSTOM"] = "CUSTOM";
29
+ })(FileInputPreviewType || (FileInputPreviewType = {}));
30
+ var ControlType;
31
+ (function (ControlType) {
32
+ ControlType[ControlType["CLEAR"] = 0] = "CLEAR";
33
+ ControlType[ControlType["SELECT"] = 1] = "SELECT";
34
+ ControlType[ControlType["ACTION"] = 2] = "ACTION";
35
+ })(ControlType || (ControlType = {}));
36
+ const defaultButtonProps = {
37
+ text: "Select",
38
+ outlined: true,
39
+ fillOnHover: true,
40
+ loadingProps: {
41
+ disabled: true,
42
+ leftIcon: "fa fa-spinner fa-spin"
43
+ }
44
+ };
45
+ class FileInputComponent extends React.Component {
46
+ static defaultProps = {
47
+ accepts: "*/*",
48
+ attrsRelay: {},
49
+ elementProps: {},
50
+ defaultFiles: [],
51
+ noDragAndDrop: false,
52
+ scheme: Scheme.SECONDARY,
53
+ mode: FileInputMode.PREVIEW,
54
+ buttonProps: defaultButtonProps,
55
+ orientation: Orientation.VERTICAL,
56
+ previewType: FileInputPreviewType.AUTO,
57
+ clearControl: {
58
+ scheme: Scheme.DANGER,
59
+ leftIcon: "fa fa-times",
60
+ },
61
+ selectControl: {
62
+ leftIcon: "fa fa-plus",
63
+ },
64
+ actionControl: {
65
+ leftIcon: "fa fa-upload",
66
+ },
67
+ dragAndDropRefOptions: {
68
+ count: 20,
69
+ interval: 1000,
70
+ },
71
+ };
72
+ state = {
73
+ files: ObjectHelper.clone(this.props.defaultFiles),
74
+ maxFileSizeHumanReadable: FileHelper.humanFileSize(this.props.maxFileSize, true)
75
+ };
76
+ componentUnmounted = false;
77
+ buttonManagerRef;
78
+ internalControlElement;
79
+ internalInputElement;
80
+ internalCompoundElement;
81
+ internalListenersGarbageCollection = [];
82
+ internalResizeObserverEventHandler;
83
+ constructor(props) {
84
+ super(props);
85
+ this.onDrop = this.onDrop.bind(this);
86
+ this.onCancel = this.onCancel.bind(this);
87
+ this.onChange = this.onChange.bind(this);
88
+ this.onDragOver = this.onDragOver.bind(this);
89
+ this.onDragBegin = this.onDragBegin.bind(this);
90
+ this.onDragComplete = this.onDragComplete.bind(this);
91
+ this.onControlClick = this.onControlClick.bind(this);
92
+ this.destroyElementsListeners = this.destroyElementsListeners.bind(this);
93
+ this.initializeElementsListeners = this.initializeElementsListeners.bind(this);
94
+ }
95
+ componentDidMount() {
96
+ ObjectHelper.resolveManageRef(this, {
97
+ resolve: () => this.initializeElementsListeners,
98
+ select: (e) => {
99
+ this.onControlClick(ControlType.SELECT, e);
100
+ },
101
+ clear: () => {
102
+ if (!this.internalInputElement)
103
+ return;
104
+ this.internalInputElement.files = null;
105
+ this.setState({ files: [] });
106
+ this.props.attachFileInputManageRef?.current?.clear?.();
107
+ },
108
+ files: () => {
109
+ return this.state.files;
110
+ },
111
+ value: () => {
112
+ const files = this.state.files;
113
+ return files.length ? files[0] : null;
114
+ },
115
+ setValue: (value) => {
116
+ this.setState({ files: [value] });
117
+ this.props.attachFileInputManageRef?.current?.setValue?.(value);
118
+ },
119
+ changeFiles: (files) => {
120
+ this.setState({ files });
121
+ this.props.onSelectFiles && this.props.onSelectFiles(files);
122
+ this.props.attachFileInputManageRef?.current?.changeFiles?.(files);
123
+ },
124
+ });
125
+ this.props.onMount && this.props.onMount((e) => this.onControlClick(ControlType.SELECT, e), this.onDrop, this.onDragOver);
126
+ this.initializeElementsListeners();
127
+ this.componentUnmounted = true;
128
+ this.rePositionControl();
129
+ }
130
+ rePositionControl() {
131
+ if (!this.internalControlElement || !this.internalCompoundElement || !this.props.attrsRelay.control
132
+ || !this.props.attrsRelay.control.alignment)
133
+ return;
134
+ DOMHelper.alignChildToParent(this.internalCompoundElement, this.internalControlElement, this.props.attrsRelay.control.alignment);
135
+ }
136
+ componentWillUnmount() {
137
+ if (!this.componentUnmounted)
138
+ return;
139
+ this.componentUnmounted = true;
140
+ this.props.onUnMount && this.props.onUnMount((e) => this.onControlClick(ControlType.SELECT, e), this.onDrop, this.onDragOver);
141
+ ObjectHelper.resolveManageRef(this, null);
142
+ this.destroyElementsListeners();
143
+ if (this.internalResizeObserverEventHandler) {
144
+ ObserverHandler.unobserve("resize", this.internalResizeObserverEventHandler);
145
+ this.internalResizeObserverEventHandler = undefined;
146
+ }
147
+ }
148
+ initializeElementsListeners() {
149
+ this.destroyElementsListeners();
150
+ if (this.props.dragAndDropRefs && this.props.dragAndDropRefs.length) {
151
+ this.props.dragAndDropRefs.forEach((dragAndDropRef) => {
152
+ this.internalListenersGarbageCollection.push({
153
+ element: dragAndDropRef,
154
+ events: {
155
+ drop: this.onDrop,
156
+ dragover: this.onDragOver,
157
+ dragenter: this.onDragBegin,
158
+ dragexit: this.onDragComplete,
159
+ }
160
+ });
161
+ });
162
+ }
163
+ if (this.internalInputElement) {
164
+ this.internalListenersGarbageCollection.push({
165
+ element: { current: this.internalInputElement },
166
+ events: {
167
+ cancel: this.onCancel
168
+ }
169
+ });
170
+ }
171
+ const dragAndDropRefOptions = this.props.dragAndDropRefOptions;
172
+ if (!dragAndDropRefOptions.count)
173
+ dragAndDropRefOptions.count = 20;
174
+ if (!dragAndDropRefOptions.interval)
175
+ dragAndDropRefOptions.interval = 100;
176
+ for (const record of this.internalListenersGarbageCollection) {
177
+ const { element, events } = record;
178
+ let count = 0;
179
+ const interval = setInterval(() => {
180
+ if (element.current) {
181
+ Object.keys(events).forEach((type) => {
182
+ if (element.current.addEventListener)
183
+ element.current.addEventListener(type, events[type]);
184
+ });
185
+ clearInterval(interval);
186
+ return;
187
+ }
188
+ if ((++count) >= dragAndDropRefOptions.count)
189
+ clearInterval(interval);
190
+ }, dragAndDropRefOptions.interval);
191
+ }
192
+ if (!this.internalResizeObserverEventHandler) {
193
+ this.internalResizeObserverEventHandler = (_) => {
194
+ this.rePositionControl();
195
+ };
196
+ ObserverHandler.observe("resize", this.internalResizeObserverEventHandler);
197
+ }
198
+ }
199
+ destroyElementsListeners() {
200
+ for (const record of this.internalListenersGarbageCollection) {
201
+ const { element, events } = record;
202
+ Object.keys(events).forEach((type) => {
203
+ element.current?.removeEventListener(type, events[type]);
204
+ });
205
+ }
206
+ this.internalListenersGarbageCollection = [];
207
+ }
208
+ onCancel(event) {
209
+ if (!this.state.files.length && this.internalInputElement?.files?.length) {
210
+ this.onChange(event);
211
+ return;
212
+ }
213
+ this.buttonManagerRef?.setLoadingState(false);
214
+ this.props.onCancelDialog && this.props.onCancelDialog(event);
215
+ }
216
+ onDragOver(event) {
217
+ event.preventDefault();
218
+ this.props.onDragOver && this.props.onDragOver(event);
219
+ }
220
+ onDrop(event) {
221
+ this.props.onDrop && this.props.onDrop(event);
222
+ this.props.onDragComplete && this.props.onDragComplete(event);
223
+ if (event.currentTarget === this.internalCompoundElement && this.props.noDragAndDrop)
224
+ return;
225
+ event.preventDefault();
226
+ if (!event.dataTransfer || !event.dataTransfer.files || !event.dataTransfer.files.length)
227
+ return;
228
+ this.onSelectFiles(event.dataTransfer.files);
229
+ }
230
+ onDragBegin(event) {
231
+ this.props.onDragBegin && this.props.onDragBegin(event);
232
+ }
233
+ onDragComplete(event) {
234
+ this.props.onDragComplete && this.props.onDragComplete(event);
235
+ }
236
+ onChange(event) {
237
+ this.buttonManagerRef?.setLoadingState(false);
238
+ this.props.onChange && this.props.onChange(event);
239
+ if (!event.target || !event.target.files || !event.target.files.length)
240
+ return;
241
+ this.props.onConfirmDialog && this.props.onConfirmDialog(event);
242
+ this.onSelectFiles(event.target.files);
243
+ }
244
+ onSelectFiles(fileList) {
245
+ const files = this.props.concatNewFile ? this.state.files : [];
246
+ Array.from(fileList).forEach(file => {
247
+ let errorMessage;
248
+ if (this.props.maxFileSize && file.size > this.props.maxFileSize) {
249
+ errorMessage = `${file.name} exceeds maximum size of ${this.state.maxFileSizeHumanReadable}`;
250
+ }
251
+ else if (this.props.validateFile) {
252
+ errorMessage = this.props.validateFile(file);
253
+ }
254
+ if (errorMessage && (this.props.onValidationFail && this.props.onValidationFail(file, errorMessage))) {
255
+ return;
256
+ }
257
+ files.push(file);
258
+ });
259
+ if (!files.length)
260
+ return;
261
+ this.props.attachFileInputManageRef?.current?.changeFiles(files);
262
+ if (this.props.relayToAttachFileInputOnly)
263
+ return;
264
+ this.props.onSelectFiles && this.props.onSelectFiles(files);
265
+ this.setState({ files });
266
+ }
267
+ onControlClick(type, event) {
268
+ event?.stopPropagation();
269
+ switch (type) {
270
+ case ControlType.CLEAR:
271
+ if (this.internalInputElement)
272
+ this.internalInputElement.files = null;
273
+ this.setState({ files: ObjectHelper.clone(this.props.defaultFiles) });
274
+ break;
275
+ case ControlType.ACTION:
276
+ this.props.onAction && this.props.onAction(this.state.files);
277
+ break;
278
+ case ControlType.SELECT:
279
+ default:
280
+ if (!this.internalInputElement)
281
+ return;
282
+ this.buttonManagerRef?.setLoadingState(true);
283
+ this.internalInputElement.click();
284
+ }
285
+ }
286
+ buildInput() {
287
+ const style = this.props.mode === FileInputMode.ELEMENT ? null : { display: "none" };
288
+ const eventProps = ObjectHelper.extractEventProps(this.props, [
289
+ "onMount", "onAction", "onRemoveFile", "onBeforeDrop", "onSelectFiles",
290
+ "onCancelDialog", "onConfirmDialog", "onValidationFail", "onDragBegin", "onDragComplete"
291
+ ]);
292
+ const props = {
293
+ style,
294
+ ...eventProps,
295
+ id: this.props.id,
296
+ name: this.props.name,
297
+ onChange: this.onChange,
298
+ ...this.props.elementProps,
299
+ accept: this.props.accepts,
300
+ multiple: this.props.multiple,
301
+ ref: (r) => {
302
+ if (!r)
303
+ return;
304
+ this.internalInputElement = r;
305
+ ObjectHelper.resolveRef(this.props.forwardRef, r);
306
+ },
307
+ };
308
+ if (this.props.mode === FileInputMode.ELEMENT) {
309
+ props.style = { ...(this.props.style || {}), ...props };
310
+ props.className = Classname.build(this.props.className, props.className);
311
+ }
312
+ return (React.createElement("input", { type: "file", ...props }));
313
+ }
314
+ buildInputButton() {
315
+ if (this.props.mode !== FileInputMode.BUTTON)
316
+ return null;
317
+ const props = {
318
+ ...defaultButtonProps,
319
+ ...this.props.buttonProps,
320
+ scheme: this.props.scheme,
321
+ };
322
+ return (React.createElement(Button, { ...props, onClick: (e) => this.onControlClick(ControlType.SELECT, e), manageRef: (r) => {
323
+ if (!r)
324
+ return;
325
+ this.buttonManagerRef = r;
326
+ } }));
327
+ }
328
+ buildFileItem(index, file, onRemove) {
329
+ file.key = index;
330
+ const url = URL.createObjectURL(file);
331
+ const isTemplated = !!this.props.itemTemplate;
332
+ const formattedSize = FileHelper.humanFileSize(file.size, true);
333
+ const className = Classname.build("noseur-file-input-preview", this.props.attrsRelay.preview?.className, {
334
+ "noseur-cursor-pointer": this.props.clickToChange
335
+ });
336
+ const removeButton = this.props.stickyPreview || isTemplated ? null : buildButtonControl(this.props.clearControl, {
337
+ rounded: true,
338
+ }, (e) => onRemove(file, e), "noseur-close");
339
+ const previewElement = fileInputBuildFileInputPreview({
340
+ url,
341
+ file,
342
+ onRemove,
343
+ removeButton,
344
+ formattedSize,
345
+ previewType: this.props.previewType,
346
+ });
347
+ const options = {
348
+ url,
349
+ file,
350
+ index,
351
+ onRemove,
352
+ className,
353
+ formattedSize,
354
+ previewElement,
355
+ props: this.props,
356
+ };
357
+ if (isTemplated)
358
+ return this.props.itemTemplate(options);
359
+ return React.createElement("div", { key: index, className: className, onClick: this.props.clickToChange ? (e) => this.onControlClick(ControlType.SELECT, e) : undefined }, previewElement);
360
+ }
361
+ buildInputPreviews() {
362
+ if (!(this.props.mode === FileInputMode.PREVIEW || this.props.mode === FileInputMode.CONTROLLED))
363
+ return null;
364
+ if (!this.state.files.length || this.props.selectOnly) {
365
+ if (this.props.emptyTemplate) {
366
+ return this.props.emptyTemplate((e) => this.onControlClick(ControlType.SELECT, e), this.onDrop, this.onDragOver);
367
+ }
368
+ const className = Classname.build("noseur-file-input-preview noseur-file-input-preview-empty", (this.props.scheme ? `${this.props.scheme}-bd-cl-hv` : null));
369
+ return (React.createElement("div", { className: className, onClick: (e) => this.onControlClick(ControlType.SELECT, e) },
370
+ React.createElement("i", { className: "fa-solid fa-image" })));
371
+ }
372
+ return this.state.files.map((file, index) => this.buildFileItem(index, file, (file, event) => {
373
+ event?.stopPropagation();
374
+ let files = this.state.files;
375
+ const fileIndex = files.findIndex(f => f.name === file.name && f.size === file.size);
376
+ if (fileIndex < -1)
377
+ return;
378
+ files.splice(fileIndex, 1);
379
+ if (!files.length) {
380
+ if (this.internalInputElement)
381
+ this.internalInputElement.files = null;
382
+ }
383
+ this.setState({ files });
384
+ this.props.onRemoveFile && this.props.onRemoveFile(file, event);
385
+ }));
386
+ }
387
+ renderFixture(isHeader = true) {
388
+ if (this.props.mode !== FileInputMode.CONTROLLED)
389
+ return null;
390
+ const selectControl = buildButtonControl(this.props.selectControl, {
391
+ text: "Choose",
392
+ scheme: this.props.scheme,
393
+ }, (e) => this.onControlClick(ControlType.SELECT, e), "noseur-close");
394
+ const clearControl = buildButtonControl(this.props.clearControl, {
395
+ text: "Clear",
396
+ }, (e) => this.onControlClick(ControlType.CLEAR, e), "noseur-close");
397
+ const actionControl = buildButtonControl(this.props.actionControl, {
398
+ text: "Upload",
399
+ scheme: this.props.scheme,
400
+ }, (e) => this.onControlClick(ControlType.ACTION, e), "noseur-close");
401
+ const options = {
402
+ clearControl,
403
+ actionControl,
404
+ selectControl,
405
+ props: this.props,
406
+ className: Classname.build("noseur-file-input-fixture", {
407
+ "noseur-file-input-header": isHeader,
408
+ "noseur-file-input-footer": !isHeader,
409
+ })
410
+ };
411
+ if (!isHeader) {
412
+ return this.props.footerTemplate ? this.props.footerTemplate(options) : null;
413
+ }
414
+ if (this.props.headerTemplate)
415
+ return this.props.headerTemplate(options);
416
+ return (React.createElement("div", { className: options.className },
417
+ selectControl,
418
+ actionControl,
419
+ clearControl));
420
+ }
421
+ buildControl() {
422
+ if (!this.props.control)
423
+ return;
424
+ const onClick = (this.props.controlIsManaged ? undefined : (e) => this.onControlClick(ControlType.SELECT, e));
425
+ const className = Classname.build("noseur-file-input-control", this.props.attrsRelay.control?.className);
426
+ return (React.createElement("div", { ref: (r) => {
427
+ this.internalControlElement = r;
428
+ }, onClick: onClick, className: className, style: this.props.attrsRelay.control?.style, id: this.props.attrsRelay.control?.id }, this.props.control));
429
+ }
430
+ render() {
431
+ const input = this.buildInput();
432
+ const control = this.buildControl();
433
+ const header = this.renderFixture();
434
+ const button = this.buildInputButton();
435
+ const footer = this.renderFixture(false);
436
+ const previews = this.buildInputPreviews();
437
+ const className = Classname.build("noseur-file-input", {
438
+ "noseur-rounded-bd": this.props.rounded,
439
+ "noseur-file-input-controlled": this.props.mode === FileInputMode.CONTROLLED
440
+ }, this.props.className, (this.props.scheme ? `${this.props.scheme}-vars` : null));
441
+ const previewsClassName = Classname.build("noseur-file-input-previews", this.props.attrsRelay.previews?.className, this.props.orientation === Orientation.HORIZONTAL ? "noseur-fl-d-r" : "noseur-fl-d-c");
442
+ if (this.props.mode === FileInputMode.ELEMENT)
443
+ return input;
444
+ return (React.createElement("div", { ref: (e) => {
445
+ if (!!this.internalCompoundElement && !e)
446
+ this.componentWillUnmount();
447
+ else if (this.componentUnmounted && !!e)
448
+ this.componentDidMount();
449
+ this.internalCompoundElement = e;
450
+ }, tabIndex: 0, className: className, style: this.props.style, onDragOver: this.onDragOver, onDragEnter: this.onDragBegin, onDragExit: this.onDragComplete, onDrop: this.onDrop },
451
+ input,
452
+ button,
453
+ header,
454
+ React.createElement("div", { className: previewsClassName, style: this.props.attrsRelay.previews?.style }, previews),
455
+ control,
456
+ footer));
457
+ }
458
+ }
459
+ export const FileInput = ({ ref, ...props }) => (React.createElement(FileInputComponent, { ...props, forwardRef: ref }));
460
+ export function fileInputBuildFileInputPreview(options) {
461
+ const file = options.file ?? new File([], (options.url ?? "Unknown "));
462
+ let fileType = file.type;
463
+ let previewType = options.previewType ?? FileInputPreviewType.AUTO;
464
+ if (previewType === FileInputPreviewType.AUTO) {
465
+ if (fileType.includes("pdf"))
466
+ previewType = FileInputPreviewType.PDF;
467
+ if (fileType.includes("text"))
468
+ previewType = FileInputPreviewType.TEXT;
469
+ if (fileType.includes("html"))
470
+ previewType = FileInputPreviewType.HTML;
471
+ if (fileType.includes("video"))
472
+ previewType = FileInputPreviewType.VIDEO;
473
+ if (fileType.includes("image"))
474
+ previewType = FileInputPreviewType.IMAGE;
475
+ if (fileType.includes("audio"))
476
+ previewType = FileInputPreviewType.AUDIO;
477
+ }
478
+ const onRemove = options.onRemove;
479
+ const closeButton = options.removeButton;
480
+ const url = file.__noseur__url__ ?? options.url ?? URL.createObjectURL(file);
481
+ const formattedSize = options.formattedSize || FileHelper.humanFileSize(file.size, true);
482
+ if (previewType === FileInputPreviewType.IMAGE) {
483
+ return (React.createElement(React.Fragment, null,
484
+ React.createElement("img", { ref: options.ref, className: "noseur-file-input-preview-image", style: options.style, alt: options.alt ?? file.name, src: url }),
485
+ closeButton));
486
+ }
487
+ else if (previewType === FileInputPreviewType.HTML) {
488
+ return (React.createElement(React.Fragment, null,
489
+ React.createElement("iframe", { ref: options.ref, className: "noseur-file-input-preview-html", style: options.style, frameBorder: "0", srcDoc: url }),
490
+ closeButton));
491
+ }
492
+ else if (previewType === FileInputPreviewType.PDF || previewType === FileInputPreviewType.TEXT) {
493
+ return (React.createElement(React.Fragment, null,
494
+ React.createElement("iframe", { ref: options.ref, className: "noseur-file-input-preview-pdf-text", style: options.style, frameBorder: "0", src: url }),
495
+ closeButton));
496
+ }
497
+ else if (previewType === FileInputPreviewType.VIDEO) {
498
+ return (React.createElement(React.Fragment, null,
499
+ React.createElement("video", { ref: options.ref, className: "noseur-file-input-preview-video", style: options.style, src: url, controls: true },
500
+ React.createElement("source", { src: url }),
501
+ " Your browser does not support the video tag."),
502
+ closeButton));
503
+ }
504
+ else if (previewType === FileInputPreviewType.AUDIO) {
505
+ return (React.createElement(React.Fragment, null,
506
+ React.createElement("audio", { ref: options.ref, className: "noseur-file-input-preview-audio", style: options.style, src: url, controls: true },
507
+ React.createElement("source", { src: url }),
508
+ " Your browser does not support the audio tag."),
509
+ closeButton));
510
+ }
511
+ return (React.createElement("div", { ref: options.ref, className: "noseur-file-input-preview-binary", style: options.style },
512
+ React.createElement("i", { className: "fa fa-file" }),
513
+ file.name,
514
+ "(",
515
+ formattedSize,
516
+ ")",
517
+ !onRemove ? null : React.createElement("i", { className: "fa fa-close noseur-close noseur-danger-tx", onClick: (e) => onRemove(file, e) })));
518
+ }
519
+ export function fileInputFileFromUrl(url, name = "not-specified", type = "*/*") {
520
+ const file = new File([], name, { type });
521
+ file.__noseur__url__ = url;
522
+ return file;
523
+ }