kemet-ui 1.2.0 → 1.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/custom-elements.json +1383 -349
- package/dist/components/kemet-combo/kemet-combo.js +7 -3
- package/dist/components/kemet-modal/kemet-modal.js +1 -1
- package/dist/components/kemet-sortable/kemet-sortable-item.js +42 -0
- package/dist/components/kemet-sortable/kemet-sortable.js +93 -0
- package/dist/components/kemet-upload/kemet-upload-file.js +167 -0
- package/dist/components/kemet-upload/kemet-upload-file.loaders.styles.js +53 -0
- package/dist/components/kemet-upload/kemet-upload.js +260 -0
- package/dist/kemet-components.cjs +2004 -1381
- package/dist/kemet-components.js +2004 -1382
- package/dist/kemet-components.min.js +532 -320
- package/package.json +19 -15
|
@@ -84,7 +84,7 @@ export default class KemetCombo extends LitElement {
|
|
|
84
84
|
this.input = this.field.querySelector('[slot="input"]');
|
|
85
85
|
|
|
86
86
|
// managed properties
|
|
87
|
-
this.slug = this.field.slug;
|
|
87
|
+
this.slug = this.field.slug || 'slug';
|
|
88
88
|
|
|
89
89
|
// events listeners
|
|
90
90
|
this.input.addEventListener('kemet-input-input', this.handleInput.bind(this));
|
|
@@ -99,7 +99,7 @@ export default class KemetCombo extends LitElement {
|
|
|
99
99
|
aria-controls="${this.slug}-listbox"
|
|
100
100
|
aria-haspopup="listbox"
|
|
101
101
|
id="${this.slug}-combobox"
|
|
102
|
-
aria-label="${this.field
|
|
102
|
+
aria-label="${this.field?.label}"
|
|
103
103
|
>
|
|
104
104
|
<ul role="listbox" aria-labelledby="${this.slug}-label" id="${this.slug}-listbox">
|
|
105
105
|
${this.makeOptions()}
|
|
@@ -154,7 +154,11 @@ export default class KemetCombo extends LitElement {
|
|
|
154
154
|
new CustomEvent('kemet-combo-selection', {
|
|
155
155
|
bubbles: true,
|
|
156
156
|
composed: true,
|
|
157
|
-
detail:
|
|
157
|
+
detail: {
|
|
158
|
+
element: event.target,
|
|
159
|
+
text: event.target.innerText,
|
|
160
|
+
id: event.target.getAttribute('id'),
|
|
161
|
+
},
|
|
158
162
|
}),
|
|
159
163
|
);
|
|
160
164
|
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { html, css, LitElement } from 'lit';
|
|
2
|
+
|
|
3
|
+
export default class KemetSortableItem extends LitElement {
|
|
4
|
+
static get styles() {
|
|
5
|
+
return [
|
|
6
|
+
css`
|
|
7
|
+
:host {
|
|
8
|
+
cursor: grab;
|
|
9
|
+
display: block;
|
|
10
|
+
padding: 1rem;
|
|
11
|
+
border: 1px solid var(--kemet-color-primary);
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
:host([ghost]) {
|
|
15
|
+
opacity: 0.5;
|
|
16
|
+
border-style: dashed;
|
|
17
|
+
}
|
|
18
|
+
`,
|
|
19
|
+
];
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
static get properties() {
|
|
23
|
+
return {
|
|
24
|
+
/* Automatically set to true when an item is dragged to a new spot */
|
|
25
|
+
ghost: {
|
|
26
|
+
type: Boolean,
|
|
27
|
+
reflect: true,
|
|
28
|
+
},
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
firstUpdated() {
|
|
33
|
+
this.draggable = true;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
render() {
|
|
37
|
+
return html`<slot></slot>`;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// eslint-disable-next-line no-unused-expressions
|
|
42
|
+
customElements.get('kemet-sortable-item') || customElements.define('kemet-sortable-item', KemetSortableItem);
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import { html, css, LitElement } from 'lit';
|
|
2
|
+
import { polyfill } from 'mobile-drag-drop';
|
|
3
|
+
|
|
4
|
+
const getMouseOffset = (event) => {
|
|
5
|
+
const targetRect = event.target.getBoundingClientRect();
|
|
6
|
+
const offset = {
|
|
7
|
+
x: event.pageX - targetRect.left,
|
|
8
|
+
y: event.pageY - targetRect.top,
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
return offset;
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
const getElementVerticalCenter = (element) => {
|
|
15
|
+
const rect = element.getBoundingClientRect();
|
|
16
|
+
return (rect.bottom - rect.top) / 2;
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
export default class KemetSortable extends LitElement {
|
|
20
|
+
static get styles() {
|
|
21
|
+
return [
|
|
22
|
+
css`
|
|
23
|
+
:host {
|
|
24
|
+
display: flex;
|
|
25
|
+
gap: 1rem;
|
|
26
|
+
flex-direction: column;
|
|
27
|
+
}
|
|
28
|
+
`,
|
|
29
|
+
];
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
firstUpdated() {
|
|
33
|
+
polyfill();
|
|
34
|
+
|
|
35
|
+
this.addEventListener('dragstart', event => this.handleDragStart(event), false);
|
|
36
|
+
this.addEventListener('dragenter', (event) => { event.preventDefault(); });
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
render() {
|
|
40
|
+
return html`<slot></slot>`;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
handleDragStart(event) {
|
|
44
|
+
this.sortableItem = event.target;
|
|
45
|
+
|
|
46
|
+
this.addEventListener('dragover', dragOverEvent => this.handleDragOver(dragOverEvent), false);
|
|
47
|
+
this.addEventListener('dragend', dragEndEvent => this.handleDragEnd(dragEndEvent), false);
|
|
48
|
+
|
|
49
|
+
setTimeout(() => {
|
|
50
|
+
this.sortableItem.ghost = true;
|
|
51
|
+
}, 0);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
handleDragOver(event) {
|
|
55
|
+
event.preventDefault();
|
|
56
|
+
|
|
57
|
+
const { target } = event;
|
|
58
|
+
|
|
59
|
+
if (target && target.tagName === 'KEMET-SORTABLE-ITEM') {
|
|
60
|
+
const offset = getMouseOffset(event);
|
|
61
|
+
const middleY = getElementVerticalCenter(event.target);
|
|
62
|
+
|
|
63
|
+
if (offset.y > middleY) {
|
|
64
|
+
this.insertBefore(this.sortableItem, target.nextSibling);
|
|
65
|
+
} else {
|
|
66
|
+
this.insertBefore(this.sortableItem, target);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
handleDragEnd(event) {
|
|
72
|
+
event.preventDefault();
|
|
73
|
+
this.sortableItem.ghost = false;
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Fires when an item has been moved to a new spot
|
|
77
|
+
*/
|
|
78
|
+
this.dispatchEvent(
|
|
79
|
+
new CustomEvent('kemet-sortable-drag-end', {
|
|
80
|
+
bubbles: true,
|
|
81
|
+
composed: true,
|
|
82
|
+
detail: {
|
|
83
|
+
event,
|
|
84
|
+
current: this.sortableItem,
|
|
85
|
+
all: this.querySelectorAll('kemet-sortable-item'),
|
|
86
|
+
},
|
|
87
|
+
}),
|
|
88
|
+
);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
// eslint-disable-next-line no-unused-expressions
|
|
93
|
+
customElements.get('kemet-sortable') || customElements.define('kemet-sortable', KemetSortable);
|
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
import { html, css, LitElement } from 'lit';
|
|
2
|
+
import { stylesLoaders } from './kemet-upload-file.loaders.styles.js';
|
|
3
|
+
|
|
4
|
+
const formatBytes = (bytes, decimals = 2) => {
|
|
5
|
+
if (bytes === 0) return '0 Bytes';
|
|
6
|
+
|
|
7
|
+
const k = 1024;
|
|
8
|
+
const dm = decimals < 0 ? 0 : decimals;
|
|
9
|
+
const sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'];
|
|
10
|
+
|
|
11
|
+
const i = Math.floor(Math.log(bytes) / Math.log(k));
|
|
12
|
+
|
|
13
|
+
// eslint-disable-next-line no-restricted-properties
|
|
14
|
+
return `${parseFloat((bytes / Math.pow(k, i)).toFixed(dm))} ${sizes[i]}`;
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
export default class KemetUploadFile extends LitElement {
|
|
18
|
+
static get styles() {
|
|
19
|
+
return [
|
|
20
|
+
css`
|
|
21
|
+
:host {
|
|
22
|
+
--kemet-upload-file-ripple-color: var(--kemet-color-primary);
|
|
23
|
+
|
|
24
|
+
color: var(--kemet-upload-file-color, var(--kemet-color-gray7));
|
|
25
|
+
display: grid;
|
|
26
|
+
gap: 1rem;
|
|
27
|
+
grid-template-columns: auto 1fr auto;
|
|
28
|
+
align-items: center;
|
|
29
|
+
padding: var(--kemet-upload-file-padding, 0.5rem 1rem);
|
|
30
|
+
border: var(--kemet-upload-file-border, 1px solid var(--kemet-color-primary));
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
:host([status='error']) {
|
|
34
|
+
border: 1px solid var(--kemet-color-error);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
:host([status='complete']) {
|
|
38
|
+
border: 1px solid var(--kemet-color-success);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
h3 {
|
|
42
|
+
margin: 0;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
.percentage {
|
|
46
|
+
font-size: clamp(2rem, 3vw, 2.5rem);
|
|
47
|
+
align-self: center;
|
|
48
|
+
justify-self: center;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
.indicator {
|
|
52
|
+
transform: scale(0.8);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
:host([status='complete']) .message,
|
|
56
|
+
:host([status='complete']) .indicator {
|
|
57
|
+
color: var(--kemet-color-success);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
:host([status='error']) .message,
|
|
61
|
+
:host([status='error']) .indicator {
|
|
62
|
+
color: var(--kemet-color-error);
|
|
63
|
+
}
|
|
64
|
+
`,
|
|
65
|
+
stylesLoaders,
|
|
66
|
+
];
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
static get properties() {
|
|
70
|
+
return {
|
|
71
|
+
/**
|
|
72
|
+
* The name of the file
|
|
73
|
+
*/
|
|
74
|
+
name: {
|
|
75
|
+
type: String,
|
|
76
|
+
},
|
|
77
|
+
/**
|
|
78
|
+
* The number of bytes loaded
|
|
79
|
+
*/
|
|
80
|
+
loaded: {
|
|
81
|
+
type: Number,
|
|
82
|
+
},
|
|
83
|
+
/**
|
|
84
|
+
* The file size in bytes
|
|
85
|
+
*/
|
|
86
|
+
size: {
|
|
87
|
+
type: Number,
|
|
88
|
+
},
|
|
89
|
+
/**
|
|
90
|
+
* The file type
|
|
91
|
+
*/
|
|
92
|
+
type: {
|
|
93
|
+
type: String,
|
|
94
|
+
},
|
|
95
|
+
/**
|
|
96
|
+
* The status of the file. Values are complete | uploading | error.
|
|
97
|
+
*/
|
|
98
|
+
status: {
|
|
99
|
+
type: String,
|
|
100
|
+
reflect: true,
|
|
101
|
+
},
|
|
102
|
+
/**
|
|
103
|
+
* A percentage of file completion that's calculated by the loaded property
|
|
104
|
+
*/
|
|
105
|
+
percent: {
|
|
106
|
+
type: Number,
|
|
107
|
+
},
|
|
108
|
+
/**
|
|
109
|
+
* An error message to give to users
|
|
110
|
+
*/
|
|
111
|
+
message: {
|
|
112
|
+
type: String,
|
|
113
|
+
},
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
constructor() {
|
|
118
|
+
super();
|
|
119
|
+
this.loaded = 0;
|
|
120
|
+
this.size = 0;
|
|
121
|
+
this.percent = 0;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
updated() {
|
|
125
|
+
this.percent = this.calculatePercent();
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
render() {
|
|
129
|
+
return html`
|
|
130
|
+
<div class="percentage" part="percentage">
|
|
131
|
+
<span>${this.percent}%</span>
|
|
132
|
+
</div>
|
|
133
|
+
<div>
|
|
134
|
+
<h3 part="filename">${this.name}</h3>
|
|
135
|
+
<span part="loaded">${formatBytes(this.loaded)} / ${formatBytes(this.size)}</span>
|
|
136
|
+
${this.message ? html`<div class="message" part="message">${this.message}</div>` : null}
|
|
137
|
+
</div>
|
|
138
|
+
<div class="indicator" part="indicator">
|
|
139
|
+
${this.getStatusIcon()}
|
|
140
|
+
</div>
|
|
141
|
+
`;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
calculatePercent() {
|
|
145
|
+
const percent = Math.round((this.loaded * 100.0) / this.size);
|
|
146
|
+
return percent > 100 ? 100 : percent;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
getStatusIcon() {
|
|
150
|
+
if (this.status === 'uploading') {
|
|
151
|
+
return html`<div class="lds-ripple"><div></div><div></div></div>`;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
if (this.status === 'complete') {
|
|
155
|
+
return html`<kemet-icon icon="check-circle" size="48"></kemet-icon>`;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
if (this.status === 'error') {
|
|
159
|
+
return html`<kemet-icon icon="exclamation-circle" size="48"></kemet-icon>`;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
return null;
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
// eslint-disable-next-line no-unused-expressions
|
|
167
|
+
customElements.get('kemet-upload-file') || customElements.define('kemet-upload-file', KemetUploadFile);
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { css } from 'lit';
|
|
2
|
+
|
|
3
|
+
export const stylesLoaders = css`
|
|
4
|
+
.lds-ripple {
|
|
5
|
+
display: inline-block;
|
|
6
|
+
position: relative;
|
|
7
|
+
width: 80px;
|
|
8
|
+
height: 80px;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
.lds-ripple div {
|
|
12
|
+
position: absolute;
|
|
13
|
+
border: 4px solid var(--kemet-upload-file-ripple-color);
|
|
14
|
+
opacity: 1;
|
|
15
|
+
border-radius: 50%;
|
|
16
|
+
animation: lds-ripple 1s cubic-bezier(0, 0.2, 0.8, 1) infinite;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
.lds-ripple div:nth-child(2) {
|
|
20
|
+
animation-delay: -0.5s;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
@keyframes lds-ripple {
|
|
24
|
+
0% {
|
|
25
|
+
top: 36px;
|
|
26
|
+
left: 36px;
|
|
27
|
+
width: 0;
|
|
28
|
+
height: 0;
|
|
29
|
+
opacity: 0;
|
|
30
|
+
}
|
|
31
|
+
4.9% {
|
|
32
|
+
top: 36px;
|
|
33
|
+
left: 36px;
|
|
34
|
+
width: 0;
|
|
35
|
+
height: 0;
|
|
36
|
+
opacity: 0;
|
|
37
|
+
}
|
|
38
|
+
5% {
|
|
39
|
+
top: 36px;
|
|
40
|
+
left: 36px;
|
|
41
|
+
width: 0;
|
|
42
|
+
height: 0;
|
|
43
|
+
opacity: 1;
|
|
44
|
+
}
|
|
45
|
+
100% {
|
|
46
|
+
top: 0px;
|
|
47
|
+
left: 0px;
|
|
48
|
+
width: 72px;
|
|
49
|
+
height: 72px;
|
|
50
|
+
opacity: 0;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
`;
|
|
@@ -0,0 +1,260 @@
|
|
|
1
|
+
import { html, css, LitElement } from 'lit';
|
|
2
|
+
import { ifDefined } from 'lit/directives/if-defined.js';
|
|
3
|
+
|
|
4
|
+
const preventDefaults = (event) => {
|
|
5
|
+
event.preventDefault();
|
|
6
|
+
event.stopPropagation();
|
|
7
|
+
};
|
|
8
|
+
|
|
9
|
+
export default class KemetUpload extends LitElement {
|
|
10
|
+
static get styles() {
|
|
11
|
+
return [
|
|
12
|
+
css`
|
|
13
|
+
:host {
|
|
14
|
+
color: var(--kemet-upload-color, var(--kemet-color-white));
|
|
15
|
+
display: grid;
|
|
16
|
+
grid-template-columns: 1fr 1fr;
|
|
17
|
+
height: var(--kemet-upload-height, 364px);
|
|
18
|
+
border: var(--kemet-upload-border, 1rem solid var(--kemet-color-white));
|
|
19
|
+
background-color: var(--kemet-upload-background-color, var(--kemet-color-primary));
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
:host([mobile]) {
|
|
23
|
+
display: block;
|
|
24
|
+
height: auto;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
input {
|
|
28
|
+
display: none;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
.button {
|
|
32
|
+
cursor: pointer;
|
|
33
|
+
font-size: 1rem;
|
|
34
|
+
display: block;
|
|
35
|
+
color: var(--kemet-color-white);
|
|
36
|
+
padding: 0.5rem 1rem;
|
|
37
|
+
border: 1px solid var(--kemet-color-white);
|
|
38
|
+
background-color: transparent;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
.upload {
|
|
42
|
+
display: flex;
|
|
43
|
+
align-items: center;
|
|
44
|
+
justify-content: center;
|
|
45
|
+
margin: 1rem;
|
|
46
|
+
flex-direction: column;
|
|
47
|
+
border: 2px dashed var(--kemet-color-white);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
:host([over]) .upload {
|
|
51
|
+
background-color: green;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
:host([mobile]) .upload {
|
|
55
|
+
height: 280px;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
.files {
|
|
59
|
+
display: flex;
|
|
60
|
+
gap: 1rem;
|
|
61
|
+
flex-direction: column;
|
|
62
|
+
padding: 0 1rem;
|
|
63
|
+
overflow: auto;
|
|
64
|
+
background-color: var(--kemet-color-white);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
:host([mobile]) .files {
|
|
68
|
+
padding: 0;
|
|
69
|
+
max-height: 280px;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
.heading {
|
|
73
|
+
font-size: 1.25rem;
|
|
74
|
+
margin: 0 0 2rem 0;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
:host([no-drag-drop]) .heading {
|
|
78
|
+
display: none;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
::slotted(:first-child) {
|
|
82
|
+
margin-top: 1rem;
|
|
83
|
+
}
|
|
84
|
+
`,
|
|
85
|
+
];
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
static get properties() {
|
|
89
|
+
return {
|
|
90
|
+
/**
|
|
91
|
+
* A unique identifier for the component
|
|
92
|
+
*/
|
|
93
|
+
slug: {
|
|
94
|
+
type: String,
|
|
95
|
+
},
|
|
96
|
+
/**
|
|
97
|
+
* Determines what file types are accepted
|
|
98
|
+
*/
|
|
99
|
+
accept: {
|
|
100
|
+
type: String,
|
|
101
|
+
},
|
|
102
|
+
/**
|
|
103
|
+
* Allows for multiple files
|
|
104
|
+
*/
|
|
105
|
+
multiple: {
|
|
106
|
+
type: Boolean,
|
|
107
|
+
},
|
|
108
|
+
/**
|
|
109
|
+
* Automatically is true when a file is being dragged over the upload area
|
|
110
|
+
*/
|
|
111
|
+
over: {
|
|
112
|
+
type: Boolean,
|
|
113
|
+
reflect: true,
|
|
114
|
+
},
|
|
115
|
+
/**
|
|
116
|
+
* Descriptive text for the upload area
|
|
117
|
+
*/
|
|
118
|
+
heading: {
|
|
119
|
+
type: String,
|
|
120
|
+
},
|
|
121
|
+
/**
|
|
122
|
+
* Displays the component in a mobile context
|
|
123
|
+
*/
|
|
124
|
+
mobile: {
|
|
125
|
+
type: Boolean,
|
|
126
|
+
reflect: true,
|
|
127
|
+
},
|
|
128
|
+
/**
|
|
129
|
+
* Controls the point at which the component is considered mobile
|
|
130
|
+
*/
|
|
131
|
+
breakpoint: {
|
|
132
|
+
type: String,
|
|
133
|
+
reflect: true,
|
|
134
|
+
},
|
|
135
|
+
/**
|
|
136
|
+
* If true if drag and drop support is not detected
|
|
137
|
+
*/
|
|
138
|
+
noDragDrop: {
|
|
139
|
+
type: Boolean,
|
|
140
|
+
reflect: true,
|
|
141
|
+
attribute: 'no-drag-drop',
|
|
142
|
+
},
|
|
143
|
+
/**
|
|
144
|
+
* The maximum file size for uploads
|
|
145
|
+
*/
|
|
146
|
+
maxSize: {
|
|
147
|
+
type: Number,
|
|
148
|
+
attribute: 'max-size',
|
|
149
|
+
},
|
|
150
|
+
/**
|
|
151
|
+
* The browse files button text
|
|
152
|
+
*/
|
|
153
|
+
buttonLabel: {
|
|
154
|
+
type: String,
|
|
155
|
+
attribute: 'button-label',
|
|
156
|
+
},
|
|
157
|
+
};
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
constructor() {
|
|
161
|
+
super();
|
|
162
|
+
this.slug = 'upload';
|
|
163
|
+
this.breakpoint = '600px';
|
|
164
|
+
this.buttonLabel = 'Browse Files';
|
|
165
|
+
this.heading = 'Drag & Drop Files';
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
firstUpdated() {
|
|
169
|
+
this.fileInputElement = this.shadowRoot.querySelector('[type="file"]');
|
|
170
|
+
this.upload = this.shadowRoot.querySelector('.upload');
|
|
171
|
+
|
|
172
|
+
['dragenter', 'dragover', 'dragleave', 'drop'].forEach((eventName) => {
|
|
173
|
+
this.upload.addEventListener(eventName, event => preventDefaults(event), false);
|
|
174
|
+
});
|
|
175
|
+
|
|
176
|
+
['dragenter', 'dragover'].forEach((eventName) => {
|
|
177
|
+
this.upload.addEventListener(eventName, () => { this.over = true; }, false);
|
|
178
|
+
});
|
|
179
|
+
|
|
180
|
+
['dragleave', 'drop'].forEach((eventName) => {
|
|
181
|
+
this.upload.addEventListener(eventName, () => { this.over = false; }, false);
|
|
182
|
+
});
|
|
183
|
+
|
|
184
|
+
this.isMobile();
|
|
185
|
+
this.hasDragDrop();
|
|
186
|
+
|
|
187
|
+
window.addEventListener('resize', () => { this.isMobile(); });
|
|
188
|
+
this.upload.addEventListener('drop', event => this.handleDrop(event), false);
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
render() {
|
|
192
|
+
return html`
|
|
193
|
+
<div class="upload" part="upload">
|
|
194
|
+
<kemet-icon icon="cloud-arrow-up" size="128"></kemet-icon>
|
|
195
|
+
<input
|
|
196
|
+
type="file"
|
|
197
|
+
id=${this.slug}
|
|
198
|
+
?multiple=${this.multiple}
|
|
199
|
+
accept=${ifDefined(this.accept) ? this.accept : null}
|
|
200
|
+
@change=${event => this.handleChange(event)}
|
|
201
|
+
/>
|
|
202
|
+
<h3 class="heading" part="heading">${this.heading}</h3>
|
|
203
|
+
<label class="button" part="button" for=${this.slug}>${this.buttonLabel}</label>
|
|
204
|
+
</div>
|
|
205
|
+
<div class="files" part="files">
|
|
206
|
+
<slot></slot>
|
|
207
|
+
</div>
|
|
208
|
+
`;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
handleChange(event) {
|
|
212
|
+
/**
|
|
213
|
+
* Fires when files have been added
|
|
214
|
+
*/
|
|
215
|
+
this.dispatchEvent(
|
|
216
|
+
new CustomEvent('kemet-upload-change', {
|
|
217
|
+
bubbles: true,
|
|
218
|
+
composed: true,
|
|
219
|
+
detail: {
|
|
220
|
+
event,
|
|
221
|
+
files: this.fileInputElement.files,
|
|
222
|
+
fileElement: this.fileInputElement,
|
|
223
|
+
},
|
|
224
|
+
}),
|
|
225
|
+
);
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
handleDrop(event) {
|
|
229
|
+
/**
|
|
230
|
+
* Fires when files have been added
|
|
231
|
+
*/
|
|
232
|
+
this.dispatchEvent(
|
|
233
|
+
new CustomEvent('kemet-upload-change', {
|
|
234
|
+
bubbles: true,
|
|
235
|
+
composed: true,
|
|
236
|
+
detail: {
|
|
237
|
+
event,
|
|
238
|
+
files: event?.dataTransfer.files || [],
|
|
239
|
+
fileElement: this.fileInputElement,
|
|
240
|
+
},
|
|
241
|
+
}),
|
|
242
|
+
);
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
isMobile() {
|
|
246
|
+
const mediaQuery = window.matchMedia(`(max-width: ${this.breakpoint})`);
|
|
247
|
+
this.mobile = mediaQuery.matches;
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
hasDragDrop() {
|
|
251
|
+
if ('draggable' in document.createElement('span')) {
|
|
252
|
+
this.noDragDrop = false;
|
|
253
|
+
} else {
|
|
254
|
+
this.noDragDrop = true;
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
// eslint-disable-next-line no-unused-expressions
|
|
260
|
+
customElements.get('kemet-upload') || customElements.define('kemet-upload', KemetUpload);
|