dees-catalog/ts_web/elements/dees-input-fileupload.ts

267 lines
6.8 KiB
TypeScript
Raw Normal View History

2024-01-18 01:08:19 +00:00
import * as colors from './00colors.js';
import * as plugins from './00plugins.js';
import { DeesContextmenu } from './dees-contextmenu.js';
2021-05-05 20:55:49 +00:00
import {
customElement,
DeesElement,
2023-08-07 18:02:18 +00:00
type TemplateResult,
2021-05-05 20:55:49 +00:00
property,
html,
css,
unsafeCSS,
cssManager,
2023-08-07 18:02:18 +00:00
type CSSResult,
2023-10-23 14:13:02 +00:00
domtools,
2023-08-07 17:13:29 +00:00
} from '@design.estate/dees-element';
2021-05-05 20:55:49 +00:00
declare global {
interface HTMLElementTagNameMap {
'dees-input-fileupload': DeesInputFileupload;
}
}
@customElement('dees-input-fileupload')
export class DeesInputFileupload extends DeesElement {
2024-01-18 01:08:19 +00:00
public static demo = () =>
html`<dees-input-fileupload .label=${'Attachments'}></dees-input-fileupload>`;
2021-05-05 20:55:49 +00:00
2021-08-19 22:25:14 +00:00
// INSTANCE
2023-10-23 15:26:03 +00:00
public changeSubject = new domtools.plugins.smartrx.rxjs.Subject();
2021-08-19 22:25:14 +00:00
2021-05-05 20:55:49 +00:00
@property({
type: String,
})
public label: string = null;
@property({
type: String,
2023-08-28 07:49:51 +00:00
reflect: true,
2021-05-05 20:55:49 +00:00
})
public key: string;
@property({
attribute: false,
})
public value: File[] = [];
@property()
public state: 'idle' | 'dragOver' | 'dropped' | 'uploading' | 'completed' = 'idle';
2021-08-25 11:51:55 +00:00
@property({
type: Boolean,
})
public required: boolean = false;
2021-08-26 19:30:35 +00:00
@property({
2022-12-06 12:11:06 +00:00
type: Boolean,
2021-08-26 19:30:35 +00:00
})
public disabled: boolean = false;
2022-12-06 12:11:06 +00:00
@property({
type: String,
})
public buttonText: string = 'Upload File...';
2021-08-25 11:51:55 +00:00
constructor() {
2022-12-06 12:11:06 +00:00
super();
2021-08-25 11:51:55 +00:00
}
2021-05-05 20:55:49 +00:00
public static styles = [
cssManager.defaultStyles,
css`
:host {
position: relative;
display: grid;
margin: 10px 0px;
margin-bottom: 24px;
2024-01-18 01:08:19 +00:00
color: ${cssManager.bdTheme('#333', '#ccc')};
2021-05-05 20:55:49 +00:00
}
2022-12-11 16:24:12 +00:00
.hidden {
display: none;
}
2021-05-05 20:55:49 +00:00
.maincontainer {
2024-01-18 01:08:19 +00:00
position: relative;
border-radius: 3px;
padding: 8px;
background: ${cssManager.bdTheme('#fafafa', '#222222')};
2021-05-05 20:55:49 +00:00
color: ${cssManager.bdTheme('#333', '#ccc')};
2024-01-18 01:08:19 +00:00
border-top: 1px solid #ffffff10;
}
.maincontainer::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;
pointer-events: none;
background: #00000000;
}
.maincontainer.dragOver::after {
transform: scale3d(1, 1, 1);
border: 2px dashed rgba(255, 255, 255, 0.3);
background: #00000080;
2021-05-05 20:55:49 +00:00
}
.label {
font-size: 14px;
2024-01-18 01:08:19 +00:00
margin-bottom: 8px;
2021-05-05 20:55:49 +00:00
}
.uploadButton {
position: relative;
2022-12-06 12:11:06 +00:00
padding: 8px;
max-width: 600px;
2021-05-05 20:55:49 +00:00
background: ${cssManager.bdTheme('#fafafa', '#333333')};
border-radius: 3px;
text-align: center;
2024-01-18 01:08:19 +00:00
font-size: 14px;
cursor: default;
2021-05-05 20:55:49 +00:00
}
2022-12-06 13:07:12 +00:00
.uploadButton:hover {
color: #fff;
2024-01-18 01:08:19 +00:00
background: ${unsafeCSS(colors.dark.blue)};
2022-12-06 12:11:06 +00:00
}
.uploadCandidate {
2024-01-18 01:08:19 +00:00
display: grid;
grid-template-columns: 48px auto;
background: #333;
padding: 8px 8px 8px 0px;
margin-bottom: 8px;
2022-12-06 12:11:06 +00:00
text-align: left;
2024-01-18 01:08:19 +00:00
border-radius: 3px;
2022-12-06 13:07:12 +00:00
color: ${cssManager.bdTheme('#666', '#ccc')};
font-family: 'Geist Sans', sans-serif;
2024-01-18 01:08:19 +00:00
cursor: default;
transition: all 0.2s;
border-top: 1px solid #ffffff10;
2022-12-06 13:07:12 +00:00
}
2022-12-06 12:11:06 +00:00
.uploadCandidate:last-child {
margin-bottom: 8px;
2021-05-05 20:55:49 +00:00
}
2024-01-18 01:08:19 +00:00
.uploadCandidate .icon {
display: flex;
align-items: center;
justify-content: center;
font-size: 16px;
}
.uploadCandidate:hover {
background: #393939;
}
.uploadCandidate .description {
font-size: 14px;
border-left: 1px solid #ffffff10;
padding-left: 8px;
}
2021-05-05 20:55:49 +00:00
`,
];
public render(): TemplateResult {
return html`
2022-12-11 16:24:12 +00:00
<div class="hidden">
<input type="file"></div>
</div>
2024-01-18 01:08:19 +00:00
${this.label ? html`<div class="label">${this.label}</div>` : null}
<div class="maincontainer ${this.state === 'dragOver' ? 'dragOver' : ''}">
${this.value.map(
(fileArg) => html`
<div class="uploadCandidate" @contextmenu=${eventArg => {
DeesContextmenu.openContextMenuWithOptions(eventArg, [{
iconName: 'trash',
name: 'Remove',
action: async () => {
this.value.splice(this.value.indexOf(fileArg), 1);
this.requestUpdate();
}
}]);
}}>
<div class="icon">
<dees-icon .iconFA=${'paperclip'}></dees-icon>
</div>
<div class="description">
<span style="font-weight: 600">${fileArg.name}</span><br />
<span style="font-weight: 400">${fileArg.size}</span>
</div>
</div> `
)}
<div class="uploadButton" @click=${
this.openFileSelector
}>
2022-12-06 12:11:06 +00:00
${this.buttonText}
</div>
2021-05-05 20:55:49 +00:00
</div>
`;
}
2022-12-11 16:24:12 +00:00
public async openFileSelector() {
const inputFile: HTMLInputElement = this.shadowRoot.querySelector('input[type="file"]');
inputFile.click();
2023-08-19 09:47:45 +00:00
this.state = 'idle';
this.buttonText = 'Upload more files...';
2022-12-11 16:24:12 +00:00
}
2021-05-05 20:55:49 +00:00
public async updateValue(eventArg: Event) {
const target: any = eventArg.target;
this.value = target.value;
2021-08-19 22:25:14 +00:00
this.changeSubject.next(this);
2021-05-05 20:55:49 +00:00
}
public firstUpdated() {
2023-08-19 09:47:45 +00:00
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
2024-01-18 01:08:19 +00:00
const dropArea = this.shadowRoot.querySelector('.maincontainer');
2021-05-05 20:55:49 +00:00
const handlerFunction = (eventArg: DragEvent) => {
eventArg.preventDefault();
2022-12-06 12:11:06 +00:00
switch (eventArg.type) {
2021-05-05 20:55:49 +00:00
case 'dragover':
this.state = 'dragOver';
2022-12-06 12:11:06 +00:00
this.buttonText = 'release to upload file...';
2021-05-05 20:55:49 +00:00
break;
case 'dragleave':
this.state = 'idle';
2022-12-06 12:11:06 +00:00
this.buttonText = 'Upload File...';
2021-05-05 20:55:49 +00:00
break;
2022-12-06 12:11:06 +00:00
case 'drop':
this.state = 'idle';
this.buttonText = 'Upload more files...';
2021-05-05 20:55:49 +00:00
}
console.log(eventArg);
for (const file of Array.from(eventArg.dataTransfer.files)) {
this.value.push(file);
2022-12-06 12:11:06 +00:00
this.requestUpdate();
}
2021-05-05 20:55:49 +00:00
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);
}
}