213 lines
5.2 KiB
TypeScript
213 lines
5.2 KiB
TypeScript
import {
|
|
customElement,
|
|
DeesElement,
|
|
type TemplateResult,
|
|
property,
|
|
html,
|
|
css,
|
|
unsafeCSS,
|
|
cssManager,
|
|
type CSSResult,
|
|
domtools,
|
|
} from '@design.estate/dees-element';
|
|
|
|
declare global {
|
|
interface HTMLElementTagNameMap {
|
|
'dees-input-fileupload': DeesInputFileupload;
|
|
}
|
|
}
|
|
|
|
@customElement('dees-input-fileupload')
|
|
export class DeesInputFileupload extends DeesElement {
|
|
public static demo = () => html`<dees-input-fileupload .label=${'Attachments'}></dees-input-fileupload>`;
|
|
|
|
// INSTANCE
|
|
public changeSubject = new domtools.rxjs.Subject();
|
|
|
|
@property({
|
|
type: String,
|
|
})
|
|
public label: string = null;
|
|
|
|
@property({
|
|
type: String,
|
|
reflect: true,
|
|
})
|
|
public key: string;
|
|
|
|
@property({
|
|
attribute: false,
|
|
})
|
|
public value: File[] = [];
|
|
|
|
@property()
|
|
public state: 'idle' | 'dragOver' | 'dropped' | 'uploading' | 'completed' = 'idle';
|
|
|
|
@property({
|
|
type: Boolean,
|
|
})
|
|
public required: boolean = false;
|
|
|
|
@property({
|
|
type: Boolean,
|
|
})
|
|
public disabled: boolean = false;
|
|
|
|
@property({
|
|
type: String,
|
|
})
|
|
public buttonText: string = 'Upload File...';
|
|
|
|
constructor() {
|
|
super();
|
|
}
|
|
|
|
public static styles = [
|
|
cssManager.defaultStyles,
|
|
css`
|
|
:host {
|
|
position: relative;
|
|
display: grid;
|
|
margin: 10px 0px;
|
|
margin-bottom: 24px;
|
|
}
|
|
|
|
.hidden {
|
|
display: none;
|
|
}
|
|
|
|
.maincontainer {
|
|
color: ${cssManager.bdTheme('#333', '#ccc')};
|
|
|
|
}
|
|
|
|
.label {
|
|
font-size: 14px;
|
|
margin-bottom: 5px;
|
|
}
|
|
|
|
.uploadButton {
|
|
position: relative;
|
|
cursor: pointer;
|
|
padding: 8px;
|
|
max-width: 600px;
|
|
background: ${cssManager.bdTheme('#fafafa', '#333333')};
|
|
border-radius: 3px;
|
|
text-align: center;
|
|
}
|
|
|
|
.uploadButton:hover {
|
|
color: #fff;
|
|
background: rgb(3, 155, 229);
|
|
}
|
|
|
|
.uploadButton::after {
|
|
top: 2px;
|
|
right: 2px;
|
|
left: 2px;
|
|
bottom: 2px;
|
|
transform: scale3d(0.98, 0.9, 1);
|
|
position: absolute;
|
|
content: '';
|
|
display: block;
|
|
border: 2px dashed rgba(255, 255, 255, 0);
|
|
transition: all 0.2s;
|
|
}
|
|
.uploadButton.dragOver::after {
|
|
transform: scale3d(1, 1, 1);
|
|
border: 2px dashed rgba(255, 255, 255, 0.3);
|
|
}
|
|
|
|
.uploadCandidate {
|
|
text-align: left;
|
|
border-bottom: 1px dashed #444;
|
|
color: ${cssManager.bdTheme('#666', '#ccc')};
|
|
padding: 8px;
|
|
font-family: 'Roboto', 'Inter', sans-serif;
|
|
}
|
|
|
|
.uploadButton:hover .uploadCandidate {
|
|
color: ${cssManager.bdTheme('#fff', '#fff')};
|
|
border-bottom: 1px dashed #fff;
|
|
}
|
|
|
|
.uploadCandidate:last-child {
|
|
margin-bottom: 8px;
|
|
}
|
|
`,
|
|
];
|
|
|
|
public render(): TemplateResult {
|
|
return html`
|
|
<div class="hidden">
|
|
<input type="file"></div>
|
|
</div>
|
|
<div class="maincontainer">
|
|
${this.label ? html`<div class="label">${this.label}</div>` : null}
|
|
${this.value.map((fileArg) => html` <div class="uploadCandidate">${fileArg.name} | ${fileArg.size}</div> `)}
|
|
<div class="uploadButton ${this.state === 'dragOver' ? 'dragOver' : ''}" @click=${this.openFileSelector}>
|
|
${this.buttonText}
|
|
</div>
|
|
</div>
|
|
`;
|
|
}
|
|
|
|
public async openFileSelector() {
|
|
const inputFile: HTMLInputElement = this.shadowRoot.querySelector('input[type="file"]');
|
|
inputFile.click();
|
|
this.state = 'idle';
|
|
this.buttonText = 'Upload more files...';
|
|
}
|
|
|
|
|
|
public async updateValue(eventArg: Event) {
|
|
const target: any = eventArg.target;
|
|
this.value = target.value;
|
|
this.changeSubject.next(this);
|
|
}
|
|
|
|
public firstUpdated() {
|
|
const inputFile: HTMLInputElement = this.shadowRoot.querySelector('input[type="file"]');
|
|
inputFile.addEventListener('change', (event: Event) => {
|
|
const target = event.target as HTMLInputElement;
|
|
for (const file of Array.from(target.files)) {
|
|
this.value.push(file);
|
|
}
|
|
this.requestUpdate();
|
|
console.log(`Got ${this.value.length} files!`);
|
|
// Reset the input value to allow selecting the same file again if needed
|
|
target.value = '';
|
|
});
|
|
|
|
|
|
// lets handle drag and drop
|
|
const dropArea = this.shadowRoot.querySelector('.uploadButton');
|
|
const handlerFunction = (eventArg: DragEvent) => {
|
|
eventArg.preventDefault();
|
|
switch (eventArg.type) {
|
|
case 'dragover':
|
|
this.state = 'dragOver';
|
|
this.buttonText = 'release to upload file...';
|
|
break;
|
|
case 'dragleave':
|
|
this.state = 'idle';
|
|
this.buttonText = 'Upload File...';
|
|
break;
|
|
case 'drop':
|
|
this.state = 'idle';
|
|
this.buttonText = 'Upload more files...';
|
|
}
|
|
console.log(eventArg);
|
|
for (const file of Array.from(eventArg.dataTransfer.files)) {
|
|
this.value.push(file);
|
|
this.requestUpdate();
|
|
}
|
|
console.log(`Got ${this.value.length} files!`);
|
|
};
|
|
dropArea.addEventListener('dragenter', handlerFunction, false);
|
|
dropArea.addEventListener('dragleave', handlerFunction, false);
|
|
dropArea.addEventListener('dragover', handlerFunction, false);
|
|
dropArea.addEventListener('drop', handlerFunction, false);
|
|
}
|
|
}
|