const fileInput = document.createElement('template')
fileInput.innerHTML = `
`
customElements.define('file-input', class extends HTMLElement {
constructor() {
super()
this.attachShadow({
mode: 'open'
}).append(fileInput.content.cloneNode(true))
this.input = this.shadowRoot.querySelector('input')
this.fileInput = this.shadowRoot.querySelector('.file-input')
this.filesPreviewWrapper = this.shadowRoot.querySelector('.files-preview-wrapper')
this.reflectedAttributes = ['accept', 'multiple', 'capture', 'type']
this.reset = this.reset.bind(this)
this.formatBytes = this.formatBytes.bind(this)
this.createFilePreview = this.createFilePreview.bind(this)
this.handleChange = this.handleChange.bind(this)
this.handleKeyDown = this.handleKeyDown.bind(this)
}
static get observedAttributes() {
return ['accept', 'multiple', 'capture', 'type']
}
get files() {
return this.input.files
}
set accept(val) {
this.setAttribute('accept', val)
}
set multiple(val) {
if (val) {
this.setAttribute('multiple', '')
}
else {
this.removeAttribute('multiple')
}
}
set capture(val) {
this.setAttribute('capture', val)
}
set value(val) {
this.input.value = val
}
get isValid() {
return this.input.value !== ''
}
reset() {
this.input.value = ''
this.filesPreviewWrapper.innerHTML = ''
}
formatBytes(a, b = 2) { if (0 === a) return "0 Bytes"; const c = 0 > b ? 0 : b, d = Math.floor(Math.log(a) / Math.log(1024)); return parseFloat((a / Math.pow(1024, d)).toFixed(c)) + " " + ["Bytes", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"][d] }
createFilePreview(file) {
const filePreview = document.createElement('li')
const { name, size } = file
filePreview.className = 'file-preview'
filePreview.innerHTML = `
${name}
${this.formatBytes(size)}
`
return filePreview
}
handleChange(e) {
this.filesPreviewWrapper.innerHTML = ''
const frag = document.createDocumentFragment()
Array.from(e.target.files).forEach(file => {
frag.append(
this.createFilePreview(file)
)
});
this.filesPreviewWrapper.append(frag)
}
handleKeyDown(e) {
if (e.key === 'Enter' || e.key === ' ') {
e.preventDefault()
this.input.click()
}
}
connectedCallback() {
this.setAttribute('role', 'button')
this.setAttribute('aria-label', 'File upload')
this.input.addEventListener('change', this.handleChange)
this.fileInput.addEventListener('keydown', this.handleKeyDown)
}
attributeChangedCallback(name) {
if (this.reflectedAttributes.includes(name)) {
if (this.hasAttribute(name)) {
this.input.setAttribute(name, this.getAttribute(name) ? this.getAttribute(name) : '')
}
else {
this.input.removeAttribute(name)
}
}
}
disconnectedCallback() {
this.input.removeEventListener('change', this.handleChange)
this.fileInput.removeEventListener('keydown', this.handleKeyDown)
}
})