@umbraco-ui/uui-file-dropzone 0.1.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.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2020 uui-app
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,31 @@
1
+ # uui-file-dropzone
2
+
3
+ ![npm](https://img.shields.io/npm/v/@umbraco-ui/uui-file-dropzone?logoColor=%231B264F)
4
+
5
+ Umbraco style file-dropzone component.
6
+
7
+ ## Installation
8
+
9
+ ### ES imports
10
+
11
+ ```zsh
12
+ npm i @umbraco-ui/uui-file-dropzone
13
+ ```
14
+
15
+ Import the registration of `<uui-file-dropzone>` via:
16
+
17
+ ```javascript
18
+ import '@umbraco-ui/uui-file-dropzone';
19
+ ```
20
+
21
+ When looking to leverage the `UUIFileDropzoneElement` base class as a type and/or for extension purposes, do so via:
22
+
23
+ ```javascript
24
+ import { UUIFileDropzoneElement } from '@umbraco-ui/uui-file-dropzone';
25
+ ```
26
+
27
+ ## Usage
28
+
29
+ ```html
30
+ <uui-file-dropzone></uui-file-dropzone>
31
+ ```
@@ -0,0 +1,67 @@
1
+ {
2
+ "version": "experimental",
3
+ "tags": [
4
+ {
5
+ "name": "uui-file-dropzone",
6
+ "path": "./lib/uui-file-dropzone.element.ts",
7
+ "attributes": [
8
+ {
9
+ "name": "accept",
10
+ "description": "Accepted filetypes. Will allow all types if empty.",
11
+ "type": "string",
12
+ "default": "\"false\""
13
+ },
14
+ {
15
+ "name": "multiple",
16
+ "description": "Allows for multiple files to be selected.",
17
+ "type": "boolean",
18
+ "default": "\"false\""
19
+ },
20
+ {
21
+ "name": "label",
22
+ "description": "Label to be used for aria-label and eventually as visual label",
23
+ "type": "string"
24
+ }
25
+ ],
26
+ "properties": [
27
+ {
28
+ "name": "styles",
29
+ "type": "CSSResult[]",
30
+ "default": "[null]"
31
+ },
32
+ {
33
+ "name": "accept",
34
+ "attribute": "accept",
35
+ "description": "Accepted filetypes. Will allow all types if empty.",
36
+ "type": "string",
37
+ "default": "\"false\""
38
+ },
39
+ {
40
+ "name": "multiple",
41
+ "attribute": "multiple",
42
+ "description": "Allows for multiple files to be selected.",
43
+ "type": "boolean",
44
+ "default": "\"false\""
45
+ },
46
+ {
47
+ "name": "label",
48
+ "attribute": "label",
49
+ "description": "Label to be used for aria-label and eventually as visual label",
50
+ "type": "string"
51
+ }
52
+ ],
53
+ "events": [
54
+ {
55
+ "name": "file-change",
56
+ "description": "fires when the a file has been selected."
57
+ }
58
+ ],
59
+ "slots": [
60
+ {
61
+ "name": "",
62
+ "description": "For the content of the dropzone"
63
+ }
64
+ ]
65
+ }
66
+ ]
67
+ }
@@ -0,0 +1,7 @@
1
+ import { UUIEvent } from '@umbraco-ui/uui-base/lib/events';
2
+ import { UUIFileDropzoneElement } from './uui-file-dropzone.element';
3
+ export declare class UUIFileDropzoneEvent extends UUIEvent<{
4
+ files: File[];
5
+ }, UUIFileDropzoneElement> {
6
+ static readonly FILE_CHANGE: string;
7
+ }
package/lib/index.d.ts ADDED
@@ -0,0 +1 @@
1
+ export * from './uui-file-dropzone.element';
package/lib/index.js ADDED
@@ -0,0 +1,223 @@
1
+ import { defineElement } from '@umbraco-ui/uui-base/lib/registration';
2
+ import { LitElement, html, css } from 'lit';
3
+ import { query, property } from 'lit/decorators.js';
4
+ import { UUIEvent } from '@umbraco-ui/uui-base/lib/events';
5
+ import { LabelMixin } from '@umbraco-ui/uui-base/lib/mixins';
6
+ import { demandCustomElement } from '@umbraco-ui/uui-base/lib/utils';
7
+
8
+ class UUIFileDropzoneEvent extends UUIEvent {
9
+ }
10
+ UUIFileDropzoneEvent.FILE_CHANGE = "file-change";
11
+
12
+ var __defProp = Object.defineProperty;
13
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
14
+ var __decorateClass = (decorators, target, key, kind) => {
15
+ var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc(target, key) : target;
16
+ for (var i = decorators.length - 1, decorator; i >= 0; i--)
17
+ if (decorator = decorators[i])
18
+ result = (kind ? decorator(target, key, result) : decorator(result)) || result;
19
+ if (kind && result)
20
+ __defProp(target, key, result);
21
+ return result;
22
+ };
23
+ let UUIFileDropzoneElement = class extends LabelMixin("", LitElement) {
24
+ constructor() {
25
+ super();
26
+ this.accept = "";
27
+ this.multiple = false;
28
+ this.addEventListener("dragenter", this._onDragEnter, false);
29
+ this.addEventListener("dragleave", this._onDragLeave, false);
30
+ this.addEventListener("dragover", this._onDragOver, false);
31
+ this.addEventListener("drop", this._onDrop, false);
32
+ }
33
+ browse() {
34
+ this._input.click();
35
+ }
36
+ connectedCallback() {
37
+ super.connectedCallback();
38
+ demandCustomElement(this, "uui-symbol-file-dropzone");
39
+ }
40
+ _checkIsItDirectory(dtItem) {
41
+ return !dtItem.type ? dtItem.webkitGetAsEntry().isDirectory : false;
42
+ }
43
+ async _getAllFileEntries(dataTransferItemList) {
44
+ const fileEntries = [];
45
+ const queue = [];
46
+ for (let i = 0; i < dataTransferItemList.length; i++) {
47
+ queue.push(dataTransferItemList[i].webkitGetAsEntry());
48
+ }
49
+ if (this.accept) {
50
+ const acceptList = [];
51
+ const wildcards = [];
52
+ this.accept.split(",").forEach((item) => {
53
+ if (item.includes("*")) {
54
+ wildcards.push(item.split("*")[0].trim().toLowerCase());
55
+ } else {
56
+ acceptList.push(item.trim().toLowerCase());
57
+ }
58
+ });
59
+ while (queue.length > 0) {
60
+ const entry = queue.shift();
61
+ if (entry.isFile && await this._isAccepted(acceptList, wildcards, entry)) {
62
+ fileEntries.push(entry);
63
+ } else if (entry.isDirectory) {
64
+ fileEntries.push(entry);
65
+ queue.push(...await this._readAllDirectoryEntries(entry.createReader()));
66
+ }
67
+ }
68
+ } else {
69
+ while (queue.length > 0) {
70
+ const entry = queue.shift();
71
+ if (entry.isFile) {
72
+ fileEntries.push(entry);
73
+ } else if (entry.isDirectory) {
74
+ fileEntries.push(entry);
75
+ queue.push(...await this._readAllDirectoryEntries(entry.createReader()));
76
+ }
77
+ }
78
+ }
79
+ return fileEntries;
80
+ }
81
+ async _readAllDirectoryEntries(directoryReader) {
82
+ const entries = [];
83
+ let readEntries = await this._readEntriesPromise(directoryReader);
84
+ while (readEntries.length > 0) {
85
+ entries.push(...readEntries);
86
+ readEntries = await this._readEntriesPromise(directoryReader);
87
+ }
88
+ return entries;
89
+ }
90
+ async _readEntriesPromise(directoryReader) {
91
+ try {
92
+ return await new Promise((resolve, reject) => {
93
+ directoryReader.readEntries(resolve, reject);
94
+ });
95
+ } catch (err) {
96
+ console.log(err);
97
+ }
98
+ }
99
+ async _getFile(fileEntry) {
100
+ return await new Promise((resolve, reject) => fileEntry.file(resolve, reject));
101
+ }
102
+ async _isAccepted(acceptList, wildcards, entry) {
103
+ const file = await this._getFile(entry);
104
+ const fileType = file.type.toLowerCase();
105
+ const fileExtension = "." + file.name.split(".")[1].toLowerCase();
106
+ if (acceptList.includes(fileExtension)) {
107
+ return true;
108
+ }
109
+ if (acceptList.includes(fileType)) {
110
+ return true;
111
+ }
112
+ if (wildcards.some((wildcard) => fileType.startsWith(wildcard))) {
113
+ return true;
114
+ }
115
+ return false;
116
+ }
117
+ async _onDrop(e) {
118
+ var _a;
119
+ e.preventDefault();
120
+ this._dropzone.classList.remove("hover");
121
+ const items = (_a = e.dataTransfer) == null ? void 0 : _a.items;
122
+ if (items) {
123
+ let result = await this._getAllFileEntries(items);
124
+ if (this.multiple === false && result.length > 0) {
125
+ result = [result[0]];
126
+ }
127
+ this.dispatchEvent(new UUIFileDropzoneEvent(UUIFileDropzoneEvent.FILE_CHANGE, {
128
+ detail: { files: result }
129
+ }));
130
+ }
131
+ }
132
+ _onDragOver(e) {
133
+ e.preventDefault();
134
+ }
135
+ _onDragEnter(e) {
136
+ this._dropzone.classList.add("hover");
137
+ e.preventDefault();
138
+ }
139
+ _onDragLeave(e) {
140
+ this._dropzone.classList.remove("hover");
141
+ e.preventDefault();
142
+ }
143
+ _onFileInputChange() {
144
+ const files = this._input.files ? Array.from(this._input.files) : [];
145
+ this.dispatchEvent(new UUIFileDropzoneEvent(UUIFileDropzoneEvent.FILE_CHANGE, {
146
+ detail: { files }
147
+ }));
148
+ }
149
+ render() {
150
+ return html`
151
+ <div id="dropzone">
152
+ <uui-symbol-file-dropzone id="symbol"></uui-symbol-file-dropzone>
153
+ ${this.renderLabel()}
154
+ <input
155
+ @click=${(e) => e.stopImmediatePropagation()}
156
+ id="input"
157
+ type="file"
158
+ accept=${this.accept}
159
+ ?multiple=${this.multiple}
160
+ @change=${this._onFileInputChange}
161
+ aria-label="${this.label}" />
162
+ </div>
163
+ `;
164
+ }
165
+ };
166
+ UUIFileDropzoneElement.styles = [
167
+ css`
168
+ #dropzone {
169
+ display: flex;
170
+ flex-direction: column;
171
+ align-items: center;
172
+ justify-content: center;
173
+ position: relative;
174
+ box-sizing: border-box;
175
+ width: 100%;
176
+ height: 100%;
177
+ padding: var(--uui-size-4,12px);
178
+ border: 3px solid transparent;
179
+ margin: -3px;
180
+ backdrop-filter: blur(2px);
181
+ }
182
+ #dropzone.hover {
183
+ border-color: var(--uui-color-primary,#3544b1);
184
+ }
185
+ #dropzone.hover::before {
186
+ content: '';
187
+ position: absolute;
188
+ inset: 0;
189
+ opacity: 0.2;
190
+ border-color: var(--uui-color-primary,#3544b1);
191
+ background-color: var(--uui-color-primary,#3544b1);
192
+ }
193
+ #symbol {
194
+ color: var(--uui-color-primary,#3544b1);
195
+ max-width: 100%;
196
+ max-height: 100%;
197
+ }
198
+ #input {
199
+ position: absolute;
200
+ width: 0px;
201
+ height: 0px;
202
+ opacity: 0;
203
+ display: none;
204
+ }
205
+ `
206
+ ];
207
+ __decorateClass([
208
+ query("#input")
209
+ ], UUIFileDropzoneElement.prototype, "_input", 2);
210
+ __decorateClass([
211
+ query("#dropzone")
212
+ ], UUIFileDropzoneElement.prototype, "_dropzone", 2);
213
+ __decorateClass([
214
+ property({ type: String })
215
+ ], UUIFileDropzoneElement.prototype, "accept", 2);
216
+ __decorateClass([
217
+ property({ type: Boolean })
218
+ ], UUIFileDropzoneElement.prototype, "multiple", 2);
219
+ UUIFileDropzoneElement = __decorateClass([
220
+ defineElement("uui-file-dropzone")
221
+ ], UUIFileDropzoneElement);
222
+
223
+ export { UUIFileDropzoneElement };
@@ -0,0 +1,52 @@
1
+ import { LitElement } from 'lit';
2
+ declare const UUIFileDropzoneElement_base: (new (...args: any[]) => import("@umbraco-ui/uui-base/lib/mixins").LabelMixinInterface) & typeof LitElement;
3
+ /**
4
+ * @element uui-file-dropzone
5
+ * @fires {UUIFileDropzoneEvent} file-change - fires when the a file has been selected.
6
+ * @slot - For the content of the dropzone
7
+ * @description - Dropzone for file upload. Supports native browsing and drag n drop.
8
+ */
9
+ export declare class UUIFileDropzoneElement extends UUIFileDropzoneElement_base {
10
+ static styles: import("lit").CSSResult[];
11
+ private _input;
12
+ private _dropzone;
13
+ /**
14
+ * Accepted filetypes. Will allow all types if empty.
15
+ * @type {string}
16
+ * @attr
17
+ * @default false
18
+ */
19
+ accept: string;
20
+ /**
21
+ * Allows for multiple files to be selected.
22
+ * @type {boolean}
23
+ * @attr
24
+ * @default false
25
+ */
26
+ multiple: boolean;
27
+ /**
28
+ * Opens the native file picker to select a file.
29
+ * @method browse
30
+ */
31
+ browse(): void;
32
+ constructor();
33
+ connectedCallback(): void;
34
+ protected _checkIsItDirectory(dtItem: DataTransferItem): boolean;
35
+ private _getAllFileEntries;
36
+ private _readAllDirectoryEntries;
37
+ private _readEntriesPromise;
38
+ private _getFile;
39
+ private _isAccepted;
40
+ private _onDrop;
41
+ private _onDragOver;
42
+ private _onDragEnter;
43
+ private _onDragLeave;
44
+ private _onFileInputChange;
45
+ render(): import("lit-html").TemplateResult<1>;
46
+ }
47
+ declare global {
48
+ interface HTMLElementTagNameMap {
49
+ 'uui-file-dropzone': UUIFileDropzoneElement;
50
+ }
51
+ }
52
+ export {};
package/package.json ADDED
@@ -0,0 +1,46 @@
1
+ {
2
+ "name": "@umbraco-ui/uui-file-dropzone",
3
+ "version": "0.1.0",
4
+ "license": "MIT",
5
+ "keywords": [
6
+ "Umbraco",
7
+ "Custom elements",
8
+ "Web components",
9
+ "UI",
10
+ "Lit",
11
+ "File Dropzone"
12
+ ],
13
+ "description": "Umbraco UI file-dropzone component.",
14
+ "repository": {
15
+ "type": "git",
16
+ "url": "https://github.com/umbraco/Umbraco.UI.git",
17
+ "directory": "packages/uui-file-dropzone"
18
+ },
19
+ "bugs": {
20
+ "url": "https://github.com/umbraco/Umbraco.UI/issues"
21
+ },
22
+ "main": "./lib/index.js",
23
+ "module": "./lib/index.js",
24
+ "types": "./lib/index.d.ts",
25
+ "type": "module",
26
+ "customElements": "custom-elements.json",
27
+ "files": [
28
+ "lib/**/*.d.ts",
29
+ "lib/**/*.js",
30
+ "custom-elements.json"
31
+ ],
32
+ "dependencies": {
33
+ "@umbraco-ui/uui-base": "0.2.0",
34
+ "@umbraco-ui/uui-symbol-file-dropzone": "0.1.0"
35
+ },
36
+ "scripts": {
37
+ "build": "npm run analyze && tsc --build --force && rollup -c rollup.config.js",
38
+ "clean": "tsc --build --clean && rimraf dist lib/*.js lib/**/*.js custom-elements.json",
39
+ "analyze": "web-component-analyzer **/*.element.ts --outFile custom-elements.json"
40
+ },
41
+ "publishConfig": {
42
+ "access": "public"
43
+ },
44
+ "homepage": "https://uui.umbraco.com/?path=/story/uui-file-dropzone",
45
+ "gitHead": "5494b55e03c9fb3ba8f160e693d3ce59c02d21cd"
46
+ }