@digital-realty/ix-file-uploader 1.0.32 → 1.0.34

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.
@@ -1,9 +1,10 @@
1
1
  import '@digital-realty/theme';
2
2
  import '@digital-realty/ix-icon-button/ix-icon-button.js';
3
3
  import { LitElement, TemplateResult } from 'lit';
4
+ import UploaderFile from './internal/uploader-file.js';
4
5
  export declare class IxFileChip extends LitElement {
5
6
  static readonly styles: import("lit").CSSResult[];
6
- file?: File;
7
+ file?: UploaderFile;
7
8
  private onClick;
8
9
  private onDelete;
9
10
  protected render(): TemplateResult<1>;
@@ -1 +1 @@
1
- {"version":3,"file":"IxFileChip.js","sourceRoot":"","sources":["../src/IxFileChip.ts"],"names":[],"mappings":";AAAA,OAAO,uBAAuB,CAAC;AAC/B,OAAO,kDAAkD,CAAC;AAC1D,OAAO,EAAE,IAAI,EAAE,UAAU,EAAkB,MAAM,KAAK,CAAC;AACvD,OAAO,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAG7C,OAAO,gBAAgB,MAAM,iCAAiC,CAAC;AAE/D,MAAM,OAAO,UAAW,SAAQ,UAAU;IAKhC,OAAO;QACb,MAAM,KAAK,GAAG,IAAI,WAAW,CAAW,eAAe,EAAE;YACvD,MAAM,EAAE;gBACN,IAAI,EAAE,IAAI,CAAC,IAAI;aAChB;SACF,CAAC,CAAC;QAEH,IAAI,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC;IAC5B,CAAC;IAEO,QAAQ;QACd,MAAM,KAAK,GAAG,IAAI,WAAW,CAAW,gBAAgB,EAAE;YACxD,MAAM,EAAE;gBACN,IAAI,EAAE,IAAI,CAAC,IAAI;aAChB;SACF,CAAC,CAAC;QAEH,IAAI,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC;IAC5B,CAAC;IAES,MAAM;;QACd,OAAO,IAAI,CAAA;qBACM,IAAI,CAAC,OAAO,KAAK,MAAA,IAAI,CAAC,IAAI,0CAAE,IAAI;;;iBAGpC,IAAI,CAAC,QAAQ;;;;;;UAMpB,CAAC;IACT,CAAC;;AApCe,iBAAM,GAAG,CAAC,gBAAgB,CAAC,CAAC;AAEhB;IAA3B,QAAQ,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;wCAAa","sourcesContent":["import '@digital-realty/theme';\nimport '@digital-realty/ix-icon-button/ix-icon-button.js';\nimport { html, LitElement, TemplateResult } from 'lit';\nimport { property } from 'lit/decorators.js';\n\nimport FileInfo from './internal/file-info.js';\nimport IxFileChipStyles from './styles/ix-file-chip-styles.js';\n\nexport class IxFileChip extends LitElement {\n static readonly styles = [IxFileChipStyles];\n\n @property({ type: Object }) file?: File;\n\n private onClick(): void {\n const event = new CustomEvent<FileInfo>('on-file-click', {\n detail: {\n file: this.file,\n },\n });\n\n this.dispatchEvent(event);\n }\n\n private onDelete(): void {\n const event = new CustomEvent<FileInfo>('on-file-delete', {\n detail: {\n file: this.file,\n },\n });\n\n this.dispatchEvent(event);\n }\n\n protected render(): TemplateResult<1> {\n return html`<li class=\"file-chip\">\n <span @click=${this.onClick}> ${this.file?.name} </span>\n\n <ix-icon-button\n @click=${this.onDelete}\n name=\"delete-button\"\n appearance=\"text\"\n icon=\"delete\"\n >\n </ix-icon-button>\n </li>`;\n }\n}\n"]}
1
+ {"version":3,"file":"IxFileChip.js","sourceRoot":"","sources":["../src/IxFileChip.ts"],"names":[],"mappings":";AAAA,OAAO,uBAAuB,CAAC;AAC/B,OAAO,kDAAkD,CAAC;AAC1D,OAAO,EAAE,IAAI,EAAE,UAAU,EAAkB,MAAM,KAAK,CAAC;AACvD,OAAO,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAG7C,OAAO,gBAAgB,MAAM,iCAAiC,CAAC;AAG/D,MAAM,OAAO,UAAW,SAAQ,UAAU;IAKhC,OAAO;QACb,MAAM,KAAK,GAAG,IAAI,WAAW,CAAW,eAAe,EAAE;YACvD,MAAM,EAAE;gBACN,IAAI,EAAE,IAAI,CAAC,IAAI;aAChB;SACF,CAAC,CAAC;QAEH,IAAI,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC;IAC5B,CAAC;IAEO,QAAQ;QACd,MAAM,KAAK,GAAG,IAAI,WAAW,CAAW,gBAAgB,EAAE;YACxD,MAAM,EAAE;gBACN,IAAI,EAAE,IAAI,CAAC,IAAI;aAChB;SACF,CAAC,CAAC;QAEH,IAAI,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC;IAC5B,CAAC;IAES,MAAM;;QACd,OAAO,IAAI,CAAA;qBACM,IAAI,CAAC,OAAO,KAAK,MAAA,IAAI,CAAC,IAAI,0CAAE,IAAI;;;iBAGpC,IAAI,CAAC,QAAQ;;;;;;UAMpB,CAAC;IACT,CAAC;;AApCe,iBAAM,GAAG,CAAC,gBAAgB,CAAC,CAAC;AAEhB;IAA3B,QAAQ,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;wCAAqB","sourcesContent":["import '@digital-realty/theme';\nimport '@digital-realty/ix-icon-button/ix-icon-button.js';\nimport { html, LitElement, TemplateResult } from 'lit';\nimport { property } from 'lit/decorators.js';\n\nimport FileInfo from './internal/file-info.js';\nimport IxFileChipStyles from './styles/ix-file-chip-styles.js';\nimport UploaderFile from './internal/uploader-file.js';\n\nexport class IxFileChip extends LitElement {\n static readonly styles = [IxFileChipStyles];\n\n @property({ type: Object }) file?: UploaderFile;\n\n private onClick(): void {\n const event = new CustomEvent<FileInfo>('on-file-click', {\n detail: {\n file: this.file,\n },\n });\n\n this.dispatchEvent(event);\n }\n\n private onDelete(): void {\n const event = new CustomEvent<FileInfo>('on-file-delete', {\n detail: {\n file: this.file,\n },\n });\n\n this.dispatchEvent(event);\n }\n\n protected render(): TemplateResult<1> {\n return html`<li class=\"file-chip\">\n <span @click=${this.onClick}> ${this.file?.name} </span>\n\n <ix-icon-button\n @click=${this.onDelete}\n name=\"delete-button\"\n appearance=\"text\"\n icon=\"delete\"\n >\n </ix-icon-button>\n </li>`;\n }\n}\n"]}
@@ -3,6 +3,7 @@ import { LitElement, PropertyValues, TemplateResult } from 'lit';
3
3
  import { Ref } from 'lit/directives/ref.js';
4
4
  import './ix-file-chip.js';
5
5
  import DataStorageUnit from './data-storage-unit.js';
6
+ import UploaderFile from './internal/uploader-file.js';
6
7
  export declare class IxFileUploader extends LitElement {
7
8
  static readonly styles: import("lit").CSSResult[];
8
9
  /** @nocollapse */
@@ -11,6 +12,7 @@ export declare class IxFileUploader extends LitElement {
11
12
  dropzoneRef: Ref<HTMLInputElement>;
12
13
  fileRef: Ref<HTMLInputElement>;
13
14
  allowMultipleFiles: boolean;
15
+ allowDuplicates: boolean;
14
16
  bodyText: string;
15
17
  extensions: string[];
16
18
  headerText: string;
@@ -18,7 +20,7 @@ export declare class IxFileUploader extends LitElement {
18
20
  maxFileSizeUnit: DataStorageUnit;
19
21
  maxFileSizeValue: number;
20
22
  name: string;
21
- files: Array<File>;
23
+ files: Array<UploaderFile>;
22
24
  private maxFileSizeInBytes;
23
25
  /**
24
26
  * The associated form element with which this element's value will submit.
@@ -16,6 +16,7 @@ export class IxFileUploader extends LitElement {
16
16
  this.dropzoneRef = createRef();
17
17
  this.fileRef = createRef();
18
18
  this.allowMultipleFiles = false;
19
+ this.allowDuplicates = false;
19
20
  this.bodyText = '';
20
21
  this.extensions = [];
21
22
  this.headerText = '';
@@ -57,6 +58,7 @@ export class IxFileUploader extends LitElement {
57
58
  filesToProcess,
58
59
  maxFileCount: this.allowMultipleFiles ? this.maxFileCount : 1,
59
60
  maxFileSizeInBytes: this.maxFileSizeInBytes,
61
+ allowDuplicates: this.allowDuplicates,
60
62
  });
61
63
  this.updateState(results);
62
64
  this.onFilesUploaded(results);
@@ -65,7 +67,7 @@ export class IxFileUploader extends LitElement {
65
67
  const filesToUpload = [];
66
68
  results.forEach(result => {
67
69
  if (result.uploaded) {
68
- filesToUpload.push(result.file);
70
+ filesToUpload.push(Object.assign(result.file, { id: result.id }));
69
71
  }
70
72
  });
71
73
  // handle multiple file setting
@@ -97,8 +99,8 @@ export class IxFileUploader extends LitElement {
97
99
  }
98
100
  onFileDelete(e) {
99
101
  var _a;
100
- const fileNameToDelete = (_a = e.detail.file) === null || _a === void 0 ? void 0 : _a.name;
101
- this.files = [...this.files].filter(file => file.name !== fileNameToDelete);
102
+ const fileIdToDelete = (_a = e.detail.file) === null || _a === void 0 ? void 0 : _a.id;
103
+ this.files = [...this.files].filter(file => file.id !== fileIdToDelete);
102
104
  const event = new CustomEvent('on-file-removed', {
103
105
  detail: { allFiles: this.files, file: e.detail.file },
104
106
  });
@@ -176,6 +178,9 @@ IxFileUploader.formAssociated = true;
176
178
  __decorate([
177
179
  property({ type: Boolean })
178
180
  ], IxFileUploader.prototype, "allowMultipleFiles", void 0);
181
+ __decorate([
182
+ property({ type: Boolean })
183
+ ], IxFileUploader.prototype, "allowDuplicates", void 0);
179
184
  __decorate([
180
185
  property()
181
186
  ], IxFileUploader.prototype, "bodyText", void 0);
@@ -1 +1 @@
1
- {"version":3,"file":"IxFileUploader.js","sourceRoot":"","sources":["../src/IxFileUploader.ts"],"names":[],"mappings":"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","sourcesContent":["import '@digital-realty/theme';\nimport { html, LitElement, nothing, PropertyValues, TemplateResult } from 'lit';\nimport { property, state } from 'lit/decorators.js';\nimport { createRef, ref, Ref } from 'lit/directives/ref.js';\n\nimport './ix-file-chip.js';\nimport DataStorageUnit from './data-storage-unit.js';\nimport FileInfo from './internal/file-info.js';\nimport FileUploadResult from './internal/file-upload-result.js';\nimport FileChangeInfo from './internal/file-change-info.js';\nimport FilesUploadedInfo from './internal/files-uploaded-info.js';\nimport getTotalBytes from './internal/get-total-bytes.js';\nimport { processFiles } from './internal/process-files.js';\nimport sortFilesAscending from './internal/sort-files-ascending.js';\nimport IxFileUploaderStyles from './styles/ix-file-uploader-styles.js';\n\nexport class IxFileUploader extends LitElement {\n static readonly styles = [IxFileUploaderStyles];\n\n /** @nocollapse */\n static readonly formAssociated = true;\n\n private readonly internals = (this as HTMLElement).attachInternals();\n\n dropzoneRef: Ref<HTMLInputElement> = createRef();\n\n fileRef: Ref<HTMLInputElement> = createRef();\n\n @property({ type: Boolean }) allowMultipleFiles: boolean = false;\n\n @property() bodyText: string = '';\n\n @property({ type: Array }) extensions: string[] = [];\n\n @property() headerText: string = '';\n\n @property({ type: Number }) maxFileCount: number = 10;\n\n @property() maxFileSizeUnit: DataStorageUnit = DataStorageUnit.MB;\n\n @property({ type: Number }) maxFileSizeValue: number = 10;\n\n @property() name: string = 'ix-file-uploader';\n\n @state() files: Array<File> = [];\n\n private maxFileSizeInBytes: number = 0;\n\n /**\n * The associated form element with which this element's value will submit.\n */\n get form() {\n return this.internals.form;\n }\n\n // called when the user drops files on the dropzone\n private onDrop(e: DragEvent): void {\n e.preventDefault();\n\n if (!e.dataTransfer) {\n return; // no files dropped\n }\n\n const filesToProcess = Array.from(e.dataTransfer.files);\n\n this.process(filesToProcess);\n }\n\n // This is called when the user selects files from the file dialog\n private onFileChange(e: Event): void {\n const fileList = (e.currentTarget as any).files as FileList;\n\n const filesToProcess = Array.from(fileList);\n\n this.process(filesToProcess);\n\n // clear the files from the file input; we are tracking state at the component level, not in the file input\n this.fileRef.value!.files = new DataTransfer().files;\n }\n\n // common method for processing files which are dropped or selected from file input dialog\n private process(filesToProcess: Array<File>): void {\n const results = processFiles({\n currentFiles: this.files,\n extensions: this.extensions,\n filesToProcess,\n maxFileCount: this.allowMultipleFiles ? this.maxFileCount : 1,\n maxFileSizeInBytes: this.maxFileSizeInBytes,\n });\n\n this.updateState(results);\n\n this.onFilesUploaded(results);\n }\n\n private updateState(results: Array<FileUploadResult> = []): void {\n const filesToUpload: Array<File> = [];\n\n results.forEach(result => {\n if (result.uploaded) {\n filesToUpload.push(result.file);\n }\n });\n\n // handle multiple file setting\n if (this.allowMultipleFiles) {\n this.files = [...this.files, ...filesToUpload];\n return;\n }\n\n // handle single file setting\n if (filesToUpload.length) {\n const file = filesToUpload[0];\n this.files = [file];\n }\n }\n\n private onFilesUploaded(results: Array<FileUploadResult>): void {\n const event = new CustomEvent<FilesUploadedInfo>('on-files-uploaded', {\n detail: {\n allFiles: this.files,\n filesUploaded: results.filter(result => result.uploaded),\n filesNotUploaded: results.filter(result => !result.uploaded),\n },\n });\n\n this.dispatchEvent(event);\n }\n\n private onFileClick(e: CustomEvent<FileInfo>): void {\n const event = new CustomEvent<FileChangeInfo>('on-file-clicked', {\n detail: { allFiles: this.files, file: e.detail.file },\n });\n\n this.dispatchEvent(event);\n }\n\n private onFileDelete(e: CustomEvent<FileInfo>): void {\n const fileNameToDelete = e.detail.file?.name;\n\n this.files = [...this.files].filter(file => file.name !== fileNameToDelete);\n\n const event = new CustomEvent<FileChangeInfo>('on-file-removed', {\n detail: { allFiles: this.files, file: e.detail.file },\n });\n\n this.dispatchEvent(event);\n }\n\n private openFileUploadDialog(): void {\n this.fileRef.value?.click();\n }\n\n protected override firstUpdated(): void {\n // connect the dropzone\n const dropzone = this.dropzoneRef.value;\n if (dropzone) {\n dropzone.addEventListener('dragenter', e => e.preventDefault());\n dropzone.addEventListener('dragover', e => e.preventDefault());\n dropzone.addEventListener('drop', this.onDrop.bind(this));\n }\n\n // connect the file input\n const fileElem = this.fileRef.value;\n if (fileElem) {\n fileElem.addEventListener('change', this.onFileChange.bind(this));\n }\n\n // calculate the maxBytes based on props\n // Calculate the max file size in bytes to use for checking if files are too large\n const totalBytesForStorageUnit = getTotalBytes(this.maxFileSizeUnit);\n this.maxFileSizeInBytes = this.maxFileSizeValue * totalBytesForStorageUnit;\n }\n\n private renderFileList(files: Array<File> = []): TemplateResult<1> {\n const sortedFiles = sortFilesAscending(files);\n\n const chips = sortedFiles.map(\n (file: File) => html`<ix-file-chip\n .file=${file}\n @on-file-click=${this.onFileClick}\n @on-file-delete=${this.onFileDelete}\n ></ix-file-chip>`\n );\n\n return html`\n <ul class=\"uploaded-file-list\">\n ${chips}\n </ul>\n `;\n }\n\n protected override updated(_: PropertyValues) {\n const formData = new FormData();\n\n this.files.forEach(file => {\n formData.append(`${this.name}[]`, file);\n });\n\n this.internals.setFormValue(formData);\n }\n\n protected render(): TemplateResult<1> {\n const accept = this.extensions.map(ext => `.${ext}`).join(', ');\n\n return html`<div class=\"ix-file-uploader\">\n <div\n class=\"dropzone\"\n @click=${this.openFileUploadDialog}\n @keyup=${this.openFileUploadDialog}\n ${ref(this.dropzoneRef)}\n >\n <div class=\"ix-file-uploader__label\">${this.headerText}</div>\n <div class=\"ix-file-uploader__help-text\">${this.bodyText}</div>\n <input\n accept=${accept}\n class=\"file-input\"\n ?multiple=${this.allowMultipleFiles}\n onchange=${this.onFileChange}\n ${ref(this.fileRef)}\n type=\"file\"\n />\n </div>\n ${this.files.length ? this.renderFileList(this.files) : nothing}\n </div>`;\n }\n}\n"]}
1
+ {"version":3,"file":"IxFileUploader.js","sourceRoot":"","sources":["../src/IxFileUploader.ts"],"names":[],"mappings":"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","sourcesContent":["import '@digital-realty/theme';\nimport { html, LitElement, nothing, PropertyValues, TemplateResult } from 'lit';\nimport { property, state } from 'lit/decorators.js';\nimport { createRef, ref, Ref } from 'lit/directives/ref.js';\n\nimport './ix-file-chip.js';\nimport DataStorageUnit from './data-storage-unit.js';\nimport FileInfo from './internal/file-info.js';\nimport FileUploadResult from './internal/file-upload-result.js';\nimport FileChangeInfo from './internal/file-change-info.js';\nimport FilesUploadedInfo from './internal/files-uploaded-info.js';\nimport getTotalBytes from './internal/get-total-bytes.js';\nimport { processFiles } from './internal/process-files.js';\nimport sortFilesAscending from './internal/sort-files-ascending.js';\nimport IxFileUploaderStyles from './styles/ix-file-uploader-styles.js';\nimport UploaderFile from './internal/uploader-file.js';\n\nexport class IxFileUploader extends LitElement {\n static readonly styles = [IxFileUploaderStyles];\n\n /** @nocollapse */\n static readonly formAssociated = true;\n\n private readonly internals = (this as HTMLElement).attachInternals();\n\n dropzoneRef: Ref<HTMLInputElement> = createRef();\n\n fileRef: Ref<HTMLInputElement> = createRef();\n\n @property({ type: Boolean }) allowMultipleFiles: boolean = false;\n\n @property({ type: Boolean }) allowDuplicates: boolean = false;\n\n @property() bodyText: string = '';\n\n @property({ type: Array }) extensions: string[] = [];\n\n @property() headerText: string = '';\n\n @property({ type: Number }) maxFileCount: number = 10;\n\n @property() maxFileSizeUnit: DataStorageUnit = DataStorageUnit.MB;\n\n @property({ type: Number }) maxFileSizeValue: number = 10;\n\n @property() name: string = 'ix-file-uploader';\n\n @state() files: Array<UploaderFile> = [];\n\n private maxFileSizeInBytes: number = 0;\n\n /**\n * The associated form element with which this element's value will submit.\n */\n get form() {\n return this.internals.form;\n }\n\n // called when the user drops files on the dropzone\n private onDrop(e: DragEvent): void {\n e.preventDefault();\n\n if (!e.dataTransfer) {\n return; // no files dropped\n }\n\n const filesToProcess = Array.from(e.dataTransfer.files);\n\n this.process(filesToProcess);\n }\n\n // This is called when the user selects files from the file dialog\n private onFileChange(e: Event): void {\n const fileList = (e.currentTarget as any).files as FileList;\n\n const filesToProcess = Array.from(fileList);\n\n this.process(filesToProcess);\n\n // clear the files from the file input; we are tracking state at the component level, not in the file input\n this.fileRef.value!.files = new DataTransfer().files;\n }\n\n // common method for processing files which are dropped or selected from file input dialog\n private process(filesToProcess: Array<File>): void {\n const results = processFiles({\n currentFiles: this.files,\n extensions: this.extensions,\n filesToProcess,\n maxFileCount: this.allowMultipleFiles ? this.maxFileCount : 1,\n maxFileSizeInBytes: this.maxFileSizeInBytes,\n allowDuplicates: this.allowDuplicates,\n });\n\n this.updateState(results);\n\n this.onFilesUploaded(results);\n }\n\n private updateState(results: Array<FileUploadResult> = []): void {\n const filesToUpload: Array<UploaderFile> = [];\n\n results.forEach(result => {\n if (result.uploaded) {\n filesToUpload.push(Object.assign(result.file, { id: result.id }));\n }\n });\n\n // handle multiple file setting\n if (this.allowMultipleFiles) {\n this.files = [...this.files, ...filesToUpload];\n return;\n }\n\n // handle single file setting\n if (filesToUpload.length) {\n const file = filesToUpload[0];\n this.files = [file];\n }\n }\n\n private onFilesUploaded(results: Array<FileUploadResult>): void {\n const event = new CustomEvent<FilesUploadedInfo>('on-files-uploaded', {\n detail: {\n allFiles: this.files,\n filesUploaded: results.filter(result => result.uploaded),\n filesNotUploaded: results.filter(result => !result.uploaded),\n },\n });\n\n this.dispatchEvent(event);\n }\n\n private onFileClick(e: CustomEvent<FileInfo>): void {\n const event = new CustomEvent<FileChangeInfo>('on-file-clicked', {\n detail: { allFiles: this.files, file: e.detail.file },\n });\n\n this.dispatchEvent(event);\n }\n\n private onFileDelete(e: CustomEvent<FileInfo>): void {\n const fileIdToDelete = e.detail.file?.id;\n\n this.files = [...this.files].filter(file => file.id !== fileIdToDelete);\n\n const event = new CustomEvent<FileChangeInfo>('on-file-removed', {\n detail: { allFiles: this.files, file: e.detail.file },\n });\n\n this.dispatchEvent(event);\n }\n\n private openFileUploadDialog(): void {\n this.fileRef.value?.click();\n }\n\n protected override firstUpdated(): void {\n // connect the dropzone\n const dropzone = this.dropzoneRef.value;\n if (dropzone) {\n dropzone.addEventListener('dragenter', e => e.preventDefault());\n dropzone.addEventListener('dragover', e => e.preventDefault());\n dropzone.addEventListener('drop', this.onDrop.bind(this));\n }\n\n // connect the file input\n const fileElem = this.fileRef.value;\n if (fileElem) {\n fileElem.addEventListener('change', this.onFileChange.bind(this));\n }\n\n // calculate the maxBytes based on props\n // Calculate the max file size in bytes to use for checking if files are too large\n const totalBytesForStorageUnit = getTotalBytes(this.maxFileSizeUnit);\n this.maxFileSizeInBytes = this.maxFileSizeValue * totalBytesForStorageUnit;\n }\n\n private renderFileList(files: Array<UploaderFile> = []): TemplateResult<1> {\n const sortedFiles = sortFilesAscending(files);\n const chips = sortedFiles.map(\n (file?: UploaderFile) => html`<ix-file-chip\n .file=${file}\n @on-file-click=${this.onFileClick}\n @on-file-delete=${this.onFileDelete}\n ></ix-file-chip>`\n );\n\n return html`\n <ul class=\"uploaded-file-list\">\n ${chips}\n </ul>\n `;\n }\n\n protected override updated(_: PropertyValues) {\n const formData = new FormData();\n\n this.files.forEach(file => {\n formData.append(`${this.name}[]`, file);\n });\n\n this.internals.setFormValue(formData);\n }\n\n protected render(): TemplateResult<1> {\n const accept = this.extensions.map(ext => `.${ext}`).join(', ');\n\n return html`<div class=\"ix-file-uploader\">\n <div\n class=\"dropzone\"\n @click=${this.openFileUploadDialog}\n @keyup=${this.openFileUploadDialog}\n ${ref(this.dropzoneRef)}\n >\n <div class=\"ix-file-uploader__label\">${this.headerText}</div>\n <div class=\"ix-file-uploader__help-text\">${this.bodyText}</div>\n <input\n accept=${accept}\n class=\"file-input\"\n ?multiple=${this.allowMultipleFiles}\n onchange=${this.onFileChange}\n ${ref(this.fileRef)}\n type=\"file\"\n />\n </div>\n ${this.files.length ? this.renderFileList(this.files) : nothing}\n </div>`;\n }\n}\n"]}
@@ -1,5 +1,6 @@
1
1
  import FileInfo from './file-info.js';
2
+ import UploaderFile from './uploader-file.js';
2
3
  interface FileChangeInfo extends FileInfo {
3
- allFiles: Array<File>;
4
+ allFiles: Array<UploaderFile>;
4
5
  }
5
6
  export default FileChangeInfo;
@@ -1 +1 @@
1
- {"version":3,"file":"file-change-info.js","sourceRoot":"","sources":["../../src/internal/file-change-info.ts"],"names":[],"mappings":"","sourcesContent":["import FileInfo from './file-info.js';\n\ninterface FileChangeInfo extends FileInfo {\n allFiles: Array<File>;\n}\n\nexport default FileChangeInfo;\n"]}
1
+ {"version":3,"file":"file-change-info.js","sourceRoot":"","sources":["../../src/internal/file-change-info.ts"],"names":[],"mappings":"","sourcesContent":["import FileInfo from './file-info.js';\nimport UploaderFile from './uploader-file.js';\n\ninterface FileChangeInfo extends FileInfo {\n allFiles: Array<UploaderFile>;\n}\n\nexport default FileChangeInfo;\n"]}
@@ -1,4 +1,5 @@
1
+ import UploaderFile from './uploader-file.js';
1
2
  interface FileInfo {
2
- file?: File;
3
+ file?: UploaderFile;
3
4
  }
4
5
  export default FileInfo;
@@ -1 +1 @@
1
- {"version":3,"file":"file-info.js","sourceRoot":"","sources":["../../src/internal/file-info.ts"],"names":[],"mappings":"","sourcesContent":["interface FileInfo {\n file?: File;\n}\n\nexport default FileInfo;\n"]}
1
+ {"version":3,"file":"file-info.js","sourceRoot":"","sources":["../../src/internal/file-info.ts"],"names":[],"mappings":"","sourcesContent":["import UploaderFile from './uploader-file.js';\n\ninterface FileInfo {\n file?: UploaderFile;\n}\n\nexport default FileInfo;\n"]}
@@ -1,4 +1,5 @@
1
1
  interface FileUploadResult {
2
+ id: string;
2
3
  file: File;
3
4
  message: string;
4
5
  uploaded: boolean;
@@ -1 +1 @@
1
- {"version":3,"file":"file-upload-result.js","sourceRoot":"","sources":["../../src/internal/file-upload-result.ts"],"names":[],"mappings":"","sourcesContent":["interface FileUploadResult {\n file: File;\n message: string;\n uploaded: boolean;\n}\n\nexport default FileUploadResult;\n"]}
1
+ {"version":3,"file":"file-upload-result.js","sourceRoot":"","sources":["../../src/internal/file-upload-result.ts"],"names":[],"mappings":"","sourcesContent":["interface FileUploadResult {\n id: string;\n file: File;\n message: string;\n uploaded: boolean;\n}\n\nexport default FileUploadResult;\n"]}
@@ -1,6 +1,7 @@
1
1
  import FileUploadResult from './file-upload-result.js';
2
+ import UploaderFile from './uploader-file.js';
2
3
  interface FilesUploadedInfo {
3
- allFiles: Array<File>;
4
+ allFiles: Array<UploaderFile>;
4
5
  filesUploaded: Array<FileUploadResult>;
5
6
  filesNotUploaded: Array<FileUploadResult>;
6
7
  }
@@ -1 +1 @@
1
- {"version":3,"file":"files-uploaded-info.js","sourceRoot":"","sources":["../../src/internal/files-uploaded-info.ts"],"names":[],"mappings":"","sourcesContent":["import FileUploadResult from './file-upload-result.js';\n\ninterface FilesUploadedInfo {\n allFiles: Array<File>;\n filesUploaded: Array<FileUploadResult>;\n filesNotUploaded: Array<FileUploadResult>;\n}\n\nexport default FilesUploadedInfo;\n"]}
1
+ {"version":3,"file":"files-uploaded-info.js","sourceRoot":"","sources":["../../src/internal/files-uploaded-info.ts"],"names":[],"mappings":"","sourcesContent":["import FileUploadResult from './file-upload-result.js';\nimport UploaderFile from './uploader-file.js';\n\ninterface FilesUploadedInfo {\n allFiles: Array<UploaderFile>;\n filesUploaded: Array<FileUploadResult>;\n filesNotUploaded: Array<FileUploadResult>;\n}\n\nexport default FilesUploadedInfo;\n"]}
@@ -1,9 +1,11 @@
1
1
  import FileUploadResult from './file-upload-result.js';
2
+ import UploaderFile from './uploader-file.js';
2
3
  export interface Config {
3
- currentFiles: Array<File>;
4
+ currentFiles: Array<UploaderFile>;
4
5
  extensions: Array<string>;
5
6
  filesToProcess: Array<File>;
6
7
  maxFileCount: number;
7
8
  maxFileSizeInBytes: number;
9
+ allowDuplicates: boolean;
8
10
  }
9
11
  export declare const processFiles: (config: Config) => Array<FileUploadResult>;
@@ -1,40 +1,63 @@
1
1
  export const processFiles = (config) => {
2
- const { currentFiles, extensions, filesToProcess, maxFileCount, maxFileSizeInBytes, } = config;
2
+ const { currentFiles, extensions, filesToProcess, maxFileCount, maxFileSizeInBytes, allowDuplicates, } = config;
3
3
  const results = [];
4
4
  let filesToUploadCount = 0; // counter for how many files we add in the "for" loop below; used to know when we reach the maximum number of files allowed
5
- for (const file of filesToProcess) {
5
+ for (let file of filesToProcess) {
6
6
  // check file extension
7
7
  const fileExtension = file.name.split('.').pop() || '';
8
8
  const isAllowedExtension = extensions.includes(fileExtension);
9
+ file = mapBrowserContentTypes(fileExtension, file);
9
10
  if (!isAllowedExtension) {
10
11
  const message = `File extension for "${file.name}" is not allowed`;
11
- results.push({ file, message, uploaded: false });
12
+ results.push({ file, message, uploaded: false, id: crypto.randomUUID() });
12
13
  continue;
13
14
  }
14
15
  // check for max file size
15
16
  if (file.size > maxFileSizeInBytes) {
16
17
  const message = `File size ${file.size} bytes is too large; maximum allowed size is ${maxFileSizeInBytes} bytes`;
17
- results.push({ file, message, uploaded: false });
18
+ results.push({ file, message, uploaded: false, id: crypto.randomUUID() });
18
19
  continue;
19
20
  }
20
21
  // check for max file count
21
22
  const noMoreFilesAllowed = currentFiles.length + filesToUploadCount >= maxFileCount;
22
23
  if (noMoreFilesAllowed) {
23
24
  const message = `File not uploaded; it would exceed the maximum number of files (${maxFileCount})`;
24
- results.push({ file, message, uploaded: false });
25
+ results.push({ file, message, uploaded: false, id: crypto.randomUUID() });
25
26
  continue;
26
27
  }
27
28
  // check for duplicate file names
28
- const isDuplicate = currentFiles.some((f) => f.name === file.name);
29
- if (isDuplicate) {
30
- const message = `File not uploaded; there is already a file named ${file.name}`;
31
- results.push({ file, message, uploaded: false });
32
- continue;
29
+ if (!allowDuplicates) {
30
+ const isDuplicate = currentFiles.some((f) => f.name === file.name);
31
+ if (isDuplicate) {
32
+ const message = `File not uploaded; there is already a file named ${file.name}`;
33
+ results.push({
34
+ file,
35
+ message,
36
+ uploaded: false,
37
+ id: crypto.randomUUID(),
38
+ });
39
+ continue;
40
+ }
33
41
  }
34
42
  // The file passes all validation and can be added
35
- results.push({ file, message: 'File uploaded', uploaded: true });
43
+ results.push({
44
+ file,
45
+ message: 'File uploaded',
46
+ uploaded: true,
47
+ id: crypto.randomUUID(),
48
+ });
36
49
  filesToUploadCount += 1;
37
50
  }
38
51
  return results;
39
52
  };
53
+ function mapBrowserContentTypes(fileExtension, file) {
54
+ if (mimeTypeMap[`${fileExtension}-${file.type}`]) {
55
+ return new File([file], file.name, { type: mimeTypeMap[`${fileExtension}-${file.type}`] });
56
+ }
57
+ return file;
58
+ }
59
+ // key is source file extension and browser infered content type
60
+ const mimeTypeMap = {
61
+ "csv-application/vnd.ms-excel": "text/csv"
62
+ };
40
63
  //# sourceMappingURL=process-files.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"process-files.js","sourceRoot":"","sources":["../../src/internal/process-files.ts"],"names":[],"mappings":"AAUA,MAAM,CAAC,MAAM,YAAY,GAAG,CAAC,MAAc,EAA2B,EAAE;IACtE,MAAM,EACJ,YAAY,EACZ,UAAU,EACV,cAAc,EACd,YAAY,EACZ,kBAAkB,GACnB,GAAG,MAAM,CAAC;IAEX,MAAM,OAAO,GAA4B,EAAE,CAAC;IAE5C,IAAI,kBAAkB,GAAG,CAAC,CAAC,CAAC,4HAA4H;IAExJ,KAAK,MAAM,IAAI,IAAI,cAAc,EAAE;QACjC,uBAAuB;QACvB,MAAM,aAAa,GAAG,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,IAAI,EAAE,CAAC;QACvD,MAAM,kBAAkB,GAAG,UAAU,CAAC,QAAQ,CAAC,aAAa,CAAC,CAAC;QAC9D,IAAI,CAAC,kBAAkB,EAAE;YACvB,MAAM,OAAO,GAAG,uBAAuB,IAAI,CAAC,IAAI,kBAAkB,CAAC;YACnE,OAAO,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAC,CAAC;YACjD,SAAS;SACV;QAED,0BAA0B;QAC1B,IAAI,IAAI,CAAC,IAAI,GAAG,kBAAkB,EAAE;YAClC,MAAM,OAAO,GAAG,aAAa,IAAI,CAAC,IAAI,gDAAgD,kBAAkB,QAAQ,CAAC;YACjH,OAAO,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAC,CAAC;YACjD,SAAS;SACV;QAED,2BAA2B;QAC3B,MAAM,kBAAkB,GACtB,YAAY,CAAC,MAAM,GAAG,kBAAkB,IAAI,YAAY,CAAC;QAC3D,IAAI,kBAAkB,EAAE;YACtB,MAAM,OAAO,GAAG,mEAAmE,YAAY,GAAG,CAAC;YACnG,OAAO,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAC,CAAC;YACjD,SAAS;SACV;QAED,iCAAiC;QACjC,MAAM,WAAW,GAAG,YAAY,CAAC,IAAI,CAAC,CAAC,CAAO,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,IAAI,CAAC,IAAI,CAAC,CAAC;QACzE,IAAI,WAAW,EAAE;YACf,MAAM,OAAO,GAAG,oDAAoD,IAAI,CAAC,IAAI,EAAE,CAAC;YAChF,OAAO,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAC,CAAC;YACjD,SAAS;SACV;QAED,kDAAkD;QAClD,OAAO,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,eAAe,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC;QACjE,kBAAkB,IAAI,CAAC,CAAC;KACzB;IAED,OAAO,OAAO,CAAC;AACjB,CAAC,CAAC","sourcesContent":["import FileUploadResult from './file-upload-result.js';\n\nexport interface Config {\n currentFiles: Array<File>;\n extensions: Array<string>;\n filesToProcess: Array<File>;\n maxFileCount: number;\n maxFileSizeInBytes: number;\n}\n\nexport const processFiles = (config: Config): Array<FileUploadResult> => {\n const {\n currentFiles,\n extensions,\n filesToProcess,\n maxFileCount,\n maxFileSizeInBytes,\n } = config;\n\n const results: Array<FileUploadResult> = [];\n\n let filesToUploadCount = 0; // counter for how many files we add in the \"for\" loop below; used to know when we reach the maximum number of files allowed\n\n for (const file of filesToProcess) {\n // check file extension\n const fileExtension = file.name.split('.').pop() || '';\n const isAllowedExtension = extensions.includes(fileExtension);\n if (!isAllowedExtension) {\n const message = `File extension for \"${file.name}\" is not allowed`;\n results.push({ file, message, uploaded: false });\n continue;\n }\n\n // check for max file size\n if (file.size > maxFileSizeInBytes) {\n const message = `File size ${file.size} bytes is too large; maximum allowed size is ${maxFileSizeInBytes} bytes`;\n results.push({ file, message, uploaded: false });\n continue;\n }\n\n // check for max file count\n const noMoreFilesAllowed =\n currentFiles.length + filesToUploadCount >= maxFileCount;\n if (noMoreFilesAllowed) {\n const message = `File not uploaded; it would exceed the maximum number of files (${maxFileCount})`;\n results.push({ file, message, uploaded: false });\n continue;\n }\n\n // check for duplicate file names\n const isDuplicate = currentFiles.some((f: File) => f.name === file.name);\n if (isDuplicate) {\n const message = `File not uploaded; there is already a file named ${file.name}`;\n results.push({ file, message, uploaded: false });\n continue;\n }\n\n // The file passes all validation and can be added\n results.push({ file, message: 'File uploaded', uploaded: true });\n filesToUploadCount += 1;\n }\n\n return results;\n};\n"]}
1
+ {"version":3,"file":"process-files.js","sourceRoot":"","sources":["../../src/internal/process-files.ts"],"names":[],"mappings":"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","sourcesContent":["import FileUploadResult from './file-upload-result.js';\nimport UploaderFile from './uploader-file.js';\n\nexport interface Config {\n currentFiles: Array<UploaderFile>;\n extensions: Array<string>;\n filesToProcess: Array<File>;\n maxFileCount: number;\n maxFileSizeInBytes: number;\n allowDuplicates: boolean;\n}\n\nexport const processFiles = (config: Config): Array<FileUploadResult> => {\n const {\n currentFiles,\n extensions,\n filesToProcess,\n maxFileCount,\n maxFileSizeInBytes,\n allowDuplicates,\n } = config;\n\n const results: Array<FileUploadResult> = [];\n\n let filesToUploadCount = 0; // counter for how many files we add in the \"for\" loop below; used to know when we reach the maximum number of files allowed\n\n for (let file of filesToProcess) {\n // check file extension\n const fileExtension = file.name.split('.').pop() || '';\n const isAllowedExtension = extensions.includes(fileExtension);\n file = mapBrowserContentTypes(fileExtension, file);\n if (!isAllowedExtension) {\n const message = `File extension for \"${file.name}\" is not allowed`;\n results.push({ file, message, uploaded: false, id: crypto.randomUUID() });\n continue;\n }\n\n // check for max file size\n if (file.size > maxFileSizeInBytes) {\n const message = `File size ${file.size} bytes is too large; maximum allowed size is ${maxFileSizeInBytes} bytes`;\n results.push({ file, message, uploaded: false, id: crypto.randomUUID() });\n continue;\n }\n\n // check for max file count\n const noMoreFilesAllowed =\n currentFiles.length + filesToUploadCount >= maxFileCount;\n if (noMoreFilesAllowed) {\n const message = `File not uploaded; it would exceed the maximum number of files (${maxFileCount})`;\n results.push({ file, message, uploaded: false, id: crypto.randomUUID() });\n continue;\n }\n\n // check for duplicate file names\n if (!allowDuplicates) {\n const isDuplicate = currentFiles.some(\n (f: UploaderFile) => f.name === file.name\n );\n if (isDuplicate) {\n const message = `File not uploaded; there is already a file named ${file.name}`;\n results.push({\n file,\n message,\n uploaded: false,\n id: crypto.randomUUID(),\n });\n continue;\n }\n }\n\n // The file passes all validation and can be added\n results.push({\n file,\n message: 'File uploaded',\n uploaded: true,\n id: crypto.randomUUID(),\n });\n filesToUploadCount += 1;\n }\n\n return results;\n};\nfunction mapBrowserContentTypes(fileExtension: string, file: File) {\n if(mimeTypeMap[`${fileExtension}-${file.type}`]) {\n return new File([file], file.name, { type: mimeTypeMap[`${fileExtension}-${file.type}`]});\n }\n return file;\n}\n\n// key is source file extension and browser infered content type\nconst mimeTypeMap:{[key:string]: string} = {\n \"csv-application/vnd.ms-excel\": \"text/csv\"\n}"]}
@@ -1,2 +1,3 @@
1
- declare const sortFilesAscending: (filesToSort?: Array<File>) => Array<File>;
1
+ import UploaderFile from './uploader-file.js';
2
+ declare const sortFilesAscending: (filesToSort?: Array<UploaderFile>) => Array<UploaderFile>;
2
3
  export default sortFilesAscending;
@@ -1 +1 @@
1
- {"version":3,"file":"sort-files-ascending.js","sourceRoot":"","sources":["../../src/internal/sort-files-ascending.ts"],"names":[],"mappings":"AAAA,MAAM,kBAAkB,GAAG,CAAC,cAA2B,EAAE,EAAe,EAAE,CACxE,WAAW,CAAC,IAAI,CAAC,CAAC,KAAW,EAAE,KAAW,EAAE,EAAE;IAC5C,MAAM,SAAS,GAAG,KAAK,CAAC,IAAI,CAAC,iBAAiB,EAAE,CAAC;IACjD,MAAM,SAAS,GAAG,KAAK,CAAC,IAAI,CAAC,iBAAiB,EAAE,CAAC;IAEjD,IAAI,SAAS,GAAG,SAAS,EAAE;QACzB,OAAO,CAAC,CAAC,CAAC;KACX;IACD,IAAI,SAAS,GAAG,SAAS,EAAE;QACzB,OAAO,CAAC,CAAC;KACV;IAED,OAAO,CAAC,CAAC;AACX,CAAC,CAAC,CAAC;AAEL,eAAe,kBAAkB,CAAC","sourcesContent":["const sortFilesAscending = (filesToSort: Array<File> = []): Array<File> =>\n filesToSort.sort((file1: File, file2: File) => {\n const file1Name = file1.name.toLocaleLowerCase();\n const file2Name = file2.name.toLocaleLowerCase();\n\n if (file1Name < file2Name) {\n return -1;\n }\n if (file2Name > file1Name) {\n return 1;\n }\n\n return 0;\n });\n\nexport default sortFilesAscending;\n"]}
1
+ {"version":3,"file":"sort-files-ascending.js","sourceRoot":"","sources":["../../src/internal/sort-files-ascending.ts"],"names":[],"mappings":"AAEA,MAAM,kBAAkB,GAAG,CACzB,cAAmC,EAAE,EAChB,EAAE,CACvB,WAAW,CAAC,IAAI,CAAC,CAAC,KAAmB,EAAE,KAAmB,EAAE,EAAE;IAC5D,MAAM,SAAS,GAAG,KAAK,CAAC,IAAI,CAAC,iBAAiB,EAAE,CAAC;IACjD,MAAM,SAAS,GAAG,KAAK,CAAC,IAAI,CAAC,iBAAiB,EAAE,CAAC;IAEjD,IAAI,SAAS,GAAG,SAAS,EAAE;QACzB,OAAO,CAAC,CAAC,CAAC;KACX;IACD,IAAI,SAAS,GAAG,SAAS,EAAE;QACzB,OAAO,CAAC,CAAC;KACV;IAED,OAAO,CAAC,CAAC;AACX,CAAC,CAAC,CAAC;AAEL,eAAe,kBAAkB,CAAC","sourcesContent":["import UploaderFile from './uploader-file.js';\n\nconst sortFilesAscending = (\n filesToSort: Array<UploaderFile> = []\n): Array<UploaderFile> =>\n filesToSort.sort((file1: UploaderFile, file2: UploaderFile) => {\n const file1Name = file1.name.toLocaleLowerCase();\n const file2Name = file2.name.toLocaleLowerCase();\n\n if (file1Name < file2Name) {\n return -1;\n }\n if (file2Name > file1Name) {\n return 1;\n }\n\n return 0;\n });\n\nexport default sortFilesAscending;\n"]}
@@ -0,0 +1,4 @@
1
+ interface UploaderFile extends File {
2
+ id: string;
3
+ }
4
+ export default UploaderFile;
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=uploader-file.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"uploader-file.js","sourceRoot":"","sources":["../../src/internal/uploader-file.ts"],"names":[],"mappings":"","sourcesContent":["interface UploaderFile extends File {\n id: string;\n}\n\nexport default UploaderFile;\n"]}
@@ -1 +1 @@
1
- import{__decorate}from"tslib";import"@digital-realty/theme";import{css,LitElement,html,nothing}from"lit";import{property,state}from"lit/decorators.js";import{createRef,ref}from"lit/directives/ref.js";import"@digital-realty/ix-icon-button/ix-icon-button.js";const IxFileChipStyles=css`.file-chip{align-items:center;background:#f5f7ff;cursor:pointer;display:flex;flex:auto;padding:4px 8px}.file-chip span{margin-right:10px}`;class IxFileChip extends LitElement{onClick(){var e=new CustomEvent("on-file-click",{detail:{file:this.file}});this.dispatchEvent(e)}onDelete(){var e=new CustomEvent("on-file-delete",{detail:{file:this.file}});this.dispatchEvent(e)}render(){var e;return html`<li class="file-chip"><span @click="${this.onClick}">${null==(e=this.file)?void 0:e.name}</span><ix-icon-button @click="${this.onDelete}" name="delete-button" appearance="text" icon="delete"></ix-icon-button></li>`}}IxFileChip.styles=[IxFileChipStyles],__decorate([property({type:Object})],IxFileChip.prototype,"file",void 0),customElements.define("ix-file-chip",IxFileChip),function(e){e.B="B",e.KB="KB",e.MB="MB",e.GB="GB",e.TB="TB",e.PB="PB",e.EB="EB",e.ZB="ZB",e.YB="YB"}(DataStorageUnit=DataStorageUnit||{});var DataStorageUnit,DataStorageUnit$1=DataStorageUnit;const KB=1024,MB=1024*KB,GB=1024*MB,TB=1024*GB,PB=1024*TB,EB=1024*PB,ZB=1024*EB,YB=1024*ZB,getTotalBytes=e=>{switch(e){case DataStorageUnit$1.KB:return KB;case DataStorageUnit$1.MB:return MB;case DataStorageUnit$1.GB:return GB;case DataStorageUnit$1.TB:return TB;case DataStorageUnit$1.PB:return PB;case DataStorageUnit$1.EB:return EB;case DataStorageUnit$1.ZB:return ZB;case DataStorageUnit$1.YB:return YB;default:return 0}},processFiles=e=>{var{currentFiles:i,extensions:t,filesToProcess:e,maxFileCount:l,maxFileSizeInBytes:a}=e,o=[];let s=0;for(const n of e){var r=n.name.split(".").pop()||"";t.includes(r)?n.size>a?(r=`File size ${n.size} bytes is too large; maximum allowed size is ${a} bytes`,o.push({file:n,message:r,uploaded:!1})):i.length+s>=l?o.push({file:n,message:`File not uploaded; it would exceed the maximum number of files (${l})`,uploaded:!1}):i.some(e=>e.name===n.name)?(r="File not uploaded; there is already a file named "+n.name,o.push({file:n,message:r,uploaded:!1})):(o.push({file:n,message:"File uploaded",uploaded:!0}),s+=1):(r=`File extension for "${n.name}" is not allowed`,o.push({file:n,message:r,uploaded:!1}))}return o},sortFilesAscending=(e=[])=>e.sort((e,i)=>{e=e.name.toLocaleLowerCase(),i=i.name.toLocaleLowerCase();return e<i?-1:0}),IxFileUploaderStyles=css`.ix-file-uploader{display:flex;flex-direction:column;justify-content:center;min-width:320px}.dropzone{background:var(--Background,#f5f7ff);border:1px dashed var(--Secondary-Main,#378aca);border-radius:3px;cursor:pointer;display:flex;flex-direction:column;gap:4px;padding:16px}.ix-file-uploader__label{color:var(--Text-Dark,#092241);font-family:Red Hat Display;font-size:.75rem;font-style:normal;font-weight:700;line-height:16px;letter-spacing:1.25px;text-align:center;text-transform:uppercase}.ix-file-uploader__help-text{color:var(--Text-Dark,#092241);font-family:Red Hat Display;font-size:.75rem;text-align:center}.uploaded-file-list{display:flex;flex-wrap:wrap;gap:16px;list-style:none;margin:0;margin-top:32px;padding:0}.file-input{opacity:0;border-width:0;clip:rect(0,0,0,0);height:1px;margin:-1px;overflow:hidden;padding:0;white-space:nowrap;width:1px}`;class IxFileUploader extends LitElement{constructor(){super(...arguments),this.internals=this.attachInternals(),this.dropzoneRef=createRef(),this.fileRef=createRef(),this.allowMultipleFiles=!1,this.bodyText="",this.extensions=[],this.headerText="",this.maxFileCount=10,this.maxFileSizeUnit=DataStorageUnit$1.MB,this.maxFileSizeValue=10,this.name="ix-file-uploader",this.files=[],this.maxFileSizeInBytes=0}get form(){return this.internals.form}onDrop(e){e.preventDefault(),e.dataTransfer&&(e=Array.from(e.dataTransfer.files),this.process(e))}onFileChange(e){e=e.currentTarget.files,e=Array.from(e);this.process(e),this.fileRef.value.files=(new DataTransfer).files}process(e){e=processFiles({currentFiles:this.files,extensions:this.extensions,filesToProcess:e,maxFileCount:this.allowMultipleFiles?this.maxFileCount:1,maxFileSizeInBytes:this.maxFileSizeInBytes});this.updateState(e),this.onFilesUploaded(e)}updateState(e=[]){const i=[];e.forEach(e=>{e.uploaded&&i.push(e.file)}),this.allowMultipleFiles?this.files=[...this.files,...i]:i.length&&(e=i[0],this.files=[e])}onFilesUploaded(e){e=new CustomEvent("on-files-uploaded",{detail:{allFiles:this.files,filesUploaded:e.filter(e=>e.uploaded),filesNotUploaded:e.filter(e=>!e.uploaded)}});this.dispatchEvent(e)}onFileClick(e){e=new CustomEvent("on-file-clicked",{detail:{allFiles:this.files,file:e.detail.file}});this.dispatchEvent(e)}onFileDelete(e){const i=null==(t=e.detail.file)?void 0:t.name;this.files=[...this.files].filter(e=>e.name!==i);var t=new CustomEvent("on-file-removed",{detail:{allFiles:this.files,file:e.detail.file}});this.dispatchEvent(t)}openFileUploadDialog(){var e;null!=(e=this.fileRef.value)&&e.click()}firstUpdated(){var e=this.dropzoneRef.value,e=(e&&(e.addEventListener("dragenter",e=>e.preventDefault()),e.addEventListener("dragover",e=>e.preventDefault()),e.addEventListener("drop",this.onDrop.bind(this))),this.fileRef.value),e=(e&&e.addEventListener("change",this.onFileChange.bind(this)),getTotalBytes(this.maxFileSizeUnit));this.maxFileSizeInBytes=this.maxFileSizeValue*e}renderFileList(e=[]){e=sortFilesAscending(e).map(e=>html`<ix-file-chip .file="${e}" @on-file-click="${this.onFileClick}" @on-file-delete="${this.onFileDelete}"></ix-file-chip>`);return html`<ul class="uploaded-file-list">${e}</ul>`}updated(e){const i=new FormData;this.files.forEach(e=>{i.append(this.name+"[]",e)}),this.internals.setFormValue(i)}render(){var e=this.extensions.map(e=>"."+e).join(", ");return html`<div class="ix-file-uploader"><div class="dropzone" @click="${this.openFileUploadDialog}" @keyup="${this.openFileUploadDialog}" ${ref(this.dropzoneRef)}><div class="ix-file-uploader__label">${this.headerText}</div><div class="ix-file-uploader__help-text">${this.bodyText}</div><input accept="${e}" class="file-input" ?multiple="${this.allowMultipleFiles}" onchange="${this.onFileChange}" ${ref(this.fileRef)} type="file"></div>${this.files.length?this.renderFileList(this.files):nothing}</div>`}}IxFileUploader.styles=[IxFileUploaderStyles],IxFileUploader.formAssociated=!0,__decorate([property({type:Boolean})],IxFileUploader.prototype,"allowMultipleFiles",void 0),__decorate([property()],IxFileUploader.prototype,"bodyText",void 0),__decorate([property({type:Array})],IxFileUploader.prototype,"extensions",void 0),__decorate([property()],IxFileUploader.prototype,"headerText",void 0),__decorate([property({type:Number})],IxFileUploader.prototype,"maxFileCount",void 0),__decorate([property()],IxFileUploader.prototype,"maxFileSizeUnit",void 0),__decorate([property({type:Number})],IxFileUploader.prototype,"maxFileSizeValue",void 0),__decorate([property()],IxFileUploader.prototype,"name",void 0),__decorate([state()],IxFileUploader.prototype,"files",void 0),customElements.define("ix-file-uploader",IxFileUploader);
1
+ import{__decorate}from"tslib";import"@digital-realty/theme";import{css,LitElement,html,nothing}from"lit";import{property,state}from"lit/decorators.js";import{createRef,ref}from"lit/directives/ref.js";import"@digital-realty/ix-icon-button/ix-icon-button.js";const IxFileChipStyles=css`.file-chip{align-items:center;background:#f5f7ff;cursor:pointer;display:flex;flex:auto;padding:4px 8px}.file-chip span{margin-right:10px}`;class IxFileChip extends LitElement{onClick(){var e=new CustomEvent("on-file-click",{detail:{file:this.file}});this.dispatchEvent(e)}onDelete(){var e=new CustomEvent("on-file-delete",{detail:{file:this.file}});this.dispatchEvent(e)}render(){var e;return html`<li class="file-chip"><span @click="${this.onClick}">${null==(e=this.file)?void 0:e.name}</span><ix-icon-button @click="${this.onDelete}" name="delete-button" appearance="text" icon="delete"></ix-icon-button></li>`}}IxFileChip.styles=[IxFileChipStyles],__decorate([property({type:Object})],IxFileChip.prototype,"file",void 0),customElements.define("ix-file-chip",IxFileChip),function(e){e.B="B",e.KB="KB",e.MB="MB",e.GB="GB",e.TB="TB",e.PB="PB",e.EB="EB",e.ZB="ZB",e.YB="YB"}(DataStorageUnit=DataStorageUnit||{});var DataStorageUnit,DataStorageUnit$1=DataStorageUnit;const KB=1024,MB=1024*KB,GB=1024*MB,TB=1024*GB,PB=1024*TB,EB=1024*PB,ZB=1024*EB,YB=1024*ZB,getTotalBytes=e=>{switch(e){case DataStorageUnit$1.KB:return KB;case DataStorageUnit$1.MB:return MB;case DataStorageUnit$1.GB:return GB;case DataStorageUnit$1.TB:return TB;case DataStorageUnit$1.PB:return PB;case DataStorageUnit$1.EB:return EB;case DataStorageUnit$1.ZB:return ZB;case DataStorageUnit$1.YB:return YB;default:return 0}},processFiles=e=>{var{currentFiles:t,extensions:l,filesToProcess:e,maxFileCount:a,maxFileSizeInBytes:o,allowDuplicates:s}=e,r=[];let n=0;for(let i of e){var p=i.name.split(".").pop()||"",d=l.includes(p);if(i=mapBrowserContentTypes(p,i),d)if(i.size>o){p=`File size ${i.size} bytes is too large; maximum allowed size is ${o} bytes`;r.push({file:i,message:p,uploaded:!1,id:crypto.randomUUID()})}else if(t.length+n>=a)r.push({file:i,message:`File not uploaded; it would exceed the maximum number of files (${a})`,uploaded:!1,id:crypto.randomUUID()});else{if(!s)if(t.some(e=>e.name===i.name)){d="File not uploaded; there is already a file named "+i.name;r.push({file:i,message:d,uploaded:!1,id:crypto.randomUUID()});continue}r.push({file:i,message:"File uploaded",uploaded:!0,id:crypto.randomUUID()}),n+=1}else{p=`File extension for "${i.name}" is not allowed`;r.push({file:i,message:p,uploaded:!1,id:crypto.randomUUID()})}}return r};function mapBrowserContentTypes(e,i){return mimeTypeMap[e+"-"+i.type]?new File([i],i.name,{type:mimeTypeMap[e+"-"+i.type]}):i}const mimeTypeMap={"csv-application/vnd.ms-excel":"text/csv"},sortFilesAscending=(e=[])=>e.sort((e,i)=>{e=e.name.toLocaleLowerCase(),i=i.name.toLocaleLowerCase();return e<i?-1:0}),IxFileUploaderStyles=css`.ix-file-uploader{display:flex;flex-direction:column;justify-content:center;min-width:320px}.dropzone{background:var(--Background,#f5f7ff);border:1px dashed var(--Secondary-Main,#378aca);border-radius:3px;cursor:pointer;display:flex;flex-direction:column;gap:4px;padding:16px}.ix-file-uploader__label{color:var(--Text-Dark,#092241);font-family:Red Hat Display;font-size:.75rem;font-style:normal;font-weight:700;line-height:16px;letter-spacing:1.25px;text-align:center;text-transform:uppercase}.ix-file-uploader__help-text{color:var(--Text-Dark,#092241);font-family:Red Hat Display;font-size:.75rem;text-align:center}.uploaded-file-list{display:flex;flex-wrap:wrap;gap:16px;list-style:none;margin:0;margin-top:32px;padding:0}.file-input{opacity:0;border-width:0;clip:rect(0,0,0,0);height:1px;margin:-1px;overflow:hidden;padding:0;white-space:nowrap;width:1px}`;class IxFileUploader extends LitElement{constructor(){super(...arguments),this.internals=this.attachInternals(),this.dropzoneRef=createRef(),this.fileRef=createRef(),this.allowMultipleFiles=!1,this.allowDuplicates=!1,this.bodyText="",this.extensions=[],this.headerText="",this.maxFileCount=10,this.maxFileSizeUnit=DataStorageUnit$1.MB,this.maxFileSizeValue=10,this.name="ix-file-uploader",this.files=[],this.maxFileSizeInBytes=0}get form(){return this.internals.form}onDrop(e){e.preventDefault(),e.dataTransfer&&(e=Array.from(e.dataTransfer.files),this.process(e))}onFileChange(e){e=e.currentTarget.files,e=Array.from(e);this.process(e),this.fileRef.value.files=(new DataTransfer).files}process(e){e=processFiles({currentFiles:this.files,extensions:this.extensions,filesToProcess:e,maxFileCount:this.allowMultipleFiles?this.maxFileCount:1,maxFileSizeInBytes:this.maxFileSizeInBytes,allowDuplicates:this.allowDuplicates});this.updateState(e),this.onFilesUploaded(e)}updateState(e=[]){const i=[];e.forEach(e=>{e.uploaded&&i.push(Object.assign(e.file,{id:e.id}))}),this.allowMultipleFiles?this.files=[...this.files,...i]:i.length&&(e=i[0],this.files=[e])}onFilesUploaded(e){e=new CustomEvent("on-files-uploaded",{detail:{allFiles:this.files,filesUploaded:e.filter(e=>e.uploaded),filesNotUploaded:e.filter(e=>!e.uploaded)}});this.dispatchEvent(e)}onFileClick(e){e=new CustomEvent("on-file-clicked",{detail:{allFiles:this.files,file:e.detail.file}});this.dispatchEvent(e)}onFileDelete(e){const i=null==(t=e.detail.file)?void 0:t.id;this.files=[...this.files].filter(e=>e.id!==i);var t=new CustomEvent("on-file-removed",{detail:{allFiles:this.files,file:e.detail.file}});this.dispatchEvent(t)}openFileUploadDialog(){var e;null!=(e=this.fileRef.value)&&e.click()}firstUpdated(){var e=this.dropzoneRef.value,e=(e&&(e.addEventListener("dragenter",e=>e.preventDefault()),e.addEventListener("dragover",e=>e.preventDefault()),e.addEventListener("drop",this.onDrop.bind(this))),this.fileRef.value),e=(e&&e.addEventListener("change",this.onFileChange.bind(this)),getTotalBytes(this.maxFileSizeUnit));this.maxFileSizeInBytes=this.maxFileSizeValue*e}renderFileList(e=[]){e=sortFilesAscending(e).map(e=>html`<ix-file-chip .file="${e}" @on-file-click="${this.onFileClick}" @on-file-delete="${this.onFileDelete}"></ix-file-chip>`);return html`<ul class="uploaded-file-list">${e}</ul>`}updated(e){const i=new FormData;this.files.forEach(e=>{i.append(this.name+"[]",e)}),this.internals.setFormValue(i)}render(){var e=this.extensions.map(e=>"."+e).join(", ");return html`<div class="ix-file-uploader"><div class="dropzone" @click="${this.openFileUploadDialog}" @keyup="${this.openFileUploadDialog}" ${ref(this.dropzoneRef)}><div class="ix-file-uploader__label">${this.headerText}</div><div class="ix-file-uploader__help-text">${this.bodyText}</div><input accept="${e}" class="file-input" ?multiple="${this.allowMultipleFiles}" onchange="${this.onFileChange}" ${ref(this.fileRef)} type="file"></div>${this.files.length?this.renderFileList(this.files):nothing}</div>`}}IxFileUploader.styles=[IxFileUploaderStyles],IxFileUploader.formAssociated=!0,__decorate([property({type:Boolean})],IxFileUploader.prototype,"allowMultipleFiles",void 0),__decorate([property({type:Boolean})],IxFileUploader.prototype,"allowDuplicates",void 0),__decorate([property()],IxFileUploader.prototype,"bodyText",void 0),__decorate([property({type:Array})],IxFileUploader.prototype,"extensions",void 0),__decorate([property()],IxFileUploader.prototype,"headerText",void 0),__decorate([property({type:Number})],IxFileUploader.prototype,"maxFileCount",void 0),__decorate([property()],IxFileUploader.prototype,"maxFileSizeUnit",void 0),__decorate([property({type:Number})],IxFileUploader.prototype,"maxFileSizeValue",void 0),__decorate([property()],IxFileUploader.prototype,"name",void 0),__decorate([state()],IxFileUploader.prototype,"files",void 0),customElements.define("ix-file-uploader",IxFileUploader);
package/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "description": "Webcomponent ix-file-uploader following open-wc recommendations",
4
4
  "license": "MIT",
5
5
  "author": "Digital Realty",
6
- "version": "1.0.32",
6
+ "version": "1.0.34",
7
7
  "type": "module",
8
8
  "main": "dist/index.js",
9
9
  "module": "dist/index.js",
@@ -113,5 +113,5 @@
113
113
  "README.md",
114
114
  "LICENSE"
115
115
  ],
116
- "gitHead": "14f6504a995353e8a5c470c3e423a6da7fc332ec"
116
+ "gitHead": "d1ae79d9416a388c31319d8b88bcafd610542736"
117
117
  }