UNPKG

@nysds/nys-fileinput

Version:

The Fileinput component from the NYS Design System.

1,016 lines (988 loc) 34.4 kB
import { css as C, LitElement as D, html as h } from "lit"; /*! * ▒█▄░▒█ ▒█░░▒█ ▒█▀▀▀█ ▒█▀▀▄ ▒█▀▀▀█ * ▒█▒█▒█ ▒█▄▄▄█ ░▀▀▀▄▄ ▒█░▒█ ░▀▀▀▄▄ * ▒█░░▀█ ░░▒█░░ ▒█▄▄▄█ ▒█▄▄▀ ▒█▄▄▄█ * * Fileinput Component * Part of the New York State Design System * Repository: https://github.com/its-hcd/nysds * License: MIT */ /** * @license * Copyright 2019 Google LLC * SPDX-License-Identifier: BSD-3-Clause */ const m = globalThis, w = m.ShadowRoot && (m.ShadyCSS === void 0 || m.ShadyCSS.nativeShadow) && "adoptedStyleSheets" in Document.prototype && "replace" in CSSStyleSheet.prototype, z = Symbol(), x = /* @__PURE__ */ new WeakMap(); let U = class { constructor(e, t, i) { if (this._$cssResult$ = !0, i !== z) throw Error("CSSResult is not constructable. Use `unsafeCSS` or `css` instead."); this.cssText = e, this.t = t; } get styleSheet() { let e = this.o; const t = this.t; if (w && e === void 0) { const i = t !== void 0 && t.length === 1; i && (e = x.get(t)), e === void 0 && ((this.o = e = new CSSStyleSheet()).replaceSync(this.cssText), i && x.set(t, e)); } return e; } toString() { return this.cssText; } }; const A = (n) => new U(typeof n == "string" ? n : n + "", void 0, z), M = (n, e) => { if (w) n.adoptedStyleSheets = e.map((t) => t instanceof CSSStyleSheet ? t : t.styleSheet); else for (const t of e) { const i = document.createElement("style"), s = m.litNonce; s !== void 0 && i.setAttribute("nonce", s), i.textContent = t.cssText, n.appendChild(i); } }, P = w ? (n) => n : (n) => n instanceof CSSStyleSheet ? ((e) => { let t = ""; for (const i of e.cssRules) t += i.cssText; return A(t); })(n) : n; /** * @license * Copyright 2017 Google LLC * SPDX-License-Identifier: BSD-3-Clause */ const { is: R, defineProperty: q, getOwnPropertyDescriptor: O, getOwnPropertyNames: L, getOwnPropertySymbols: I, getPrototypeOf: T } = Object, c = globalThis, F = c.trustedTypes, V = F ? F.emptyScript : "", $ = c.reactiveElementPolyfillSupport, y = (n, e) => n, g = { toAttribute(n, e) { switch (e) { case Boolean: n = n ? V : null; break; case Object: case Array: n = n == null ? n : JSON.stringify(n); } return n; }, fromAttribute(n, e) { let t = n; switch (e) { case Boolean: t = n !== null; break; case Number: t = n === null ? null : Number(n); break; case Object: case Array: try { t = JSON.parse(n); } catch { t = null; } } return t; } }, E = (n, e) => !R(n, e), k = { attribute: !0, type: String, converter: g, reflect: !1, hasChanged: E }; Symbol.metadata ?? (Symbol.metadata = Symbol("metadata")), c.litPropertyMetadata ?? (c.litPropertyMetadata = /* @__PURE__ */ new WeakMap()); class f extends HTMLElement { static addInitializer(e) { this._$Ei(), (this.l ?? (this.l = [])).push(e); } static get observedAttributes() { return this.finalize(), this._$Eh && [...this._$Eh.keys()]; } static createProperty(e, t = k) { if (t.state && (t.attribute = !1), this._$Ei(), this.elementProperties.set(e, t), !t.noAccessor) { const i = Symbol(), s = this.getPropertyDescriptor(e, i, t); s !== void 0 && q(this.prototype, e, s); } } static getPropertyDescriptor(e, t, i) { const { get: s, set: r } = O(this.prototype, e) ?? { get() { return this[t]; }, set(o) { this[t] = o; } }; return { get() { return s == null ? void 0 : s.call(this); }, set(o) { const p = s == null ? void 0 : s.call(this); r.call(this, o), this.requestUpdate(e, p, i); }, configurable: !0, enumerable: !0 }; } static getPropertyOptions(e) { return this.elementProperties.get(e) ?? k; } static _$Ei() { if (this.hasOwnProperty(y("elementProperties"))) return; const e = T(this); e.finalize(), e.l !== void 0 && (this.l = [...e.l]), this.elementProperties = new Map(e.elementProperties); } static finalize() { if (this.hasOwnProperty(y("finalized"))) return; if (this.finalized = !0, this._$Ei(), this.hasOwnProperty(y("properties"))) { const t = this.properties, i = [...L(t), ...I(t)]; for (const s of i) this.createProperty(s, t[s]); } const e = this[Symbol.metadata]; if (e !== null) { const t = litPropertyMetadata.get(e); if (t !== void 0) for (const [i, s] of t) this.elementProperties.set(i, s); } this._$Eh = /* @__PURE__ */ new Map(); for (const [t, i] of this.elementProperties) { const s = this._$Eu(t, i); s !== void 0 && this._$Eh.set(s, t); } this.elementStyles = this.finalizeStyles(this.styles); } static finalizeStyles(e) { const t = []; if (Array.isArray(e)) { const i = new Set(e.flat(1 / 0).reverse()); for (const s of i) t.unshift(P(s)); } else e !== void 0 && t.push(P(e)); return t; } static _$Eu(e, t) { const i = t.attribute; return i === !1 ? void 0 : typeof i == "string" ? i : typeof e == "string" ? e.toLowerCase() : void 0; } constructor() { super(), this._$Ep = void 0, this.isUpdatePending = !1, this.hasUpdated = !1, this._$Em = null, this._$Ev(); } _$Ev() { var e; this._$ES = new Promise((t) => this.enableUpdating = t), this._$AL = /* @__PURE__ */ new Map(), this._$E_(), this.requestUpdate(), (e = this.constructor.l) == null || e.forEach((t) => t(this)); } addController(e) { var t; (this._$EO ?? (this._$EO = /* @__PURE__ */ new Set())).add(e), this.renderRoot !== void 0 && this.isConnected && ((t = e.hostConnected) == null || t.call(e)); } removeController(e) { var t; (t = this._$EO) == null || t.delete(e); } _$E_() { const e = /* @__PURE__ */ new Map(), t = this.constructor.elementProperties; for (const i of t.keys()) this.hasOwnProperty(i) && (e.set(i, this[i]), delete this[i]); e.size > 0 && (this._$Ep = e); } createRenderRoot() { const e = this.shadowRoot ?? this.attachShadow(this.constructor.shadowRootOptions); return M(e, this.constructor.elementStyles), e; } connectedCallback() { var e; this.renderRoot ?? (this.renderRoot = this.createRenderRoot()), this.enableUpdating(!0), (e = this._$EO) == null || e.forEach((t) => { var i; return (i = t.hostConnected) == null ? void 0 : i.call(t); }); } enableUpdating(e) { } disconnectedCallback() { var e; (e = this._$EO) == null || e.forEach((t) => { var i; return (i = t.hostDisconnected) == null ? void 0 : i.call(t); }); } attributeChangedCallback(e, t, i) { this._$AK(e, i); } _$EC(e, t) { var r; const i = this.constructor.elementProperties.get(e), s = this.constructor._$Eu(e, i); if (s !== void 0 && i.reflect === !0) { const o = (((r = i.converter) == null ? void 0 : r.toAttribute) !== void 0 ? i.converter : g).toAttribute(t, i.type); this._$Em = e, o == null ? this.removeAttribute(s) : this.setAttribute(s, o), this._$Em = null; } } _$AK(e, t) { var r; const i = this.constructor, s = i._$Eh.get(e); if (s !== void 0 && this._$Em !== s) { const o = i.getPropertyOptions(s), p = typeof o.converter == "function" ? { fromAttribute: o.converter } : ((r = o.converter) == null ? void 0 : r.fromAttribute) !== void 0 ? o.converter : g; this._$Em = s, this[s] = p.fromAttribute(t, o.type), this._$Em = null; } } requestUpdate(e, t, i) { if (e !== void 0) { if (i ?? (i = this.constructor.getPropertyOptions(e)), !(i.hasChanged ?? E)(this[e], t)) return; this.P(e, t, i); } this.isUpdatePending === !1 && (this._$ES = this._$ET()); } P(e, t, i) { this._$AL.has(e) || this._$AL.set(e, t), i.reflect === !0 && this._$Em !== e && (this._$Ej ?? (this._$Ej = /* @__PURE__ */ new Set())).add(e); } async _$ET() { this.isUpdatePending = !0; try { await this._$ES; } catch (t) { Promise.reject(t); } const e = this.scheduleUpdate(); return e != null && await e, !this.isUpdatePending; } scheduleUpdate() { return this.performUpdate(); } performUpdate() { var i; if (!this.isUpdatePending) return; if (!this.hasUpdated) { if (this.renderRoot ?? (this.renderRoot = this.createRenderRoot()), this._$Ep) { for (const [r, o] of this._$Ep) this[r] = o; this._$Ep = void 0; } const s = this.constructor.elementProperties; if (s.size > 0) for (const [r, o] of s) o.wrapped !== !0 || this._$AL.has(r) || this[r] === void 0 || this.P(r, this[r], o); } let e = !1; const t = this._$AL; try { e = this.shouldUpdate(t), e ? (this.willUpdate(t), (i = this._$EO) == null || i.forEach((s) => { var r; return (r = s.hostUpdate) == null ? void 0 : r.call(s); }), this.update(t)) : this._$EU(); } catch (s) { throw e = !1, this._$EU(), s; } e && this._$AE(t); } willUpdate(e) { } _$AE(e) { var t; (t = this._$EO) == null || t.forEach((i) => { var s; return (s = i.hostUpdated) == null ? void 0 : s.call(i); }), this.hasUpdated || (this.hasUpdated = !0, this.firstUpdated(e)), this.updated(e); } _$EU() { this._$AL = /* @__PURE__ */ new Map(), this.isUpdatePending = !1; } get updateComplete() { return this.getUpdateComplete(); } getUpdateComplete() { return this._$ES; } shouldUpdate(e) { return !0; } update(e) { this._$Ej && (this._$Ej = this._$Ej.forEach((t) => this._$EC(t, this[t]))), this._$EU(); } updated(e) { } firstUpdated(e) { } } f.elementStyles = [], f.shadowRootOptions = { mode: "open" }, f[y("elementProperties")] = /* @__PURE__ */ new Map(), f[y("finalized")] = /* @__PURE__ */ new Map(), $ == null || $({ ReactiveElement: f }), (c.reactiveElementVersions ?? (c.reactiveElementVersions = [])).push("2.0.4"); /** * @license * Copyright 2017 Google LLC * SPDX-License-Identifier: BSD-3-Clause */ const B = { attribute: !0, type: String, converter: g, reflect: !1, hasChanged: E }, j = (n = B, e, t) => { const { kind: i, metadata: s } = t; let r = globalThis.litPropertyMetadata.get(s); if (r === void 0 && globalThis.litPropertyMetadata.set(s, r = /* @__PURE__ */ new Map()), r.set(t.name, n), i === "accessor") { const { name: o } = t; return { set(p) { const b = e.get.call(this); e.set.call(this, p), this.requestUpdate(o, b, n); }, init(p) { return p !== void 0 && this.P(o, void 0, n), p; } }; } if (i === "setter") { const { name: o } = t; return function(p) { const b = this[o]; e.call(this, p), this.requestUpdate(o, b, n); }; } throw Error("Unsupported decorator location: " + i); }; function a(n) { return (e, t) => typeof t == "object" ? j(n, e, t) : ((i, s, r) => { const o = s.hasOwnProperty(r); return s.constructor.createProperty(r, o ? { ...i, wrapped: !0 } : i), o ? Object.getOwnPropertyDescriptor(s, r) : void 0; })(n, e, t); } async function N(n, e) { if (!e || e.trim() === "") return !0; const t = e.toLowerCase().split(",").map((r) => r.trim()), i = n.name.toLowerCase(), s = i.includes(".") ? i.split(".").pop() : ""; for (const r of t) if (r.startsWith(".") && r.slice(1) === s || r.endsWith("/*") && n.type.startsWith(r.slice(0, -1)) || n.type === r) return !0; return !1; } const H = C` :host { /* Global Fileinput Styles */ --_nys-fileinput-gap: var(--nys-space-100, 8px); /* Typography */ --_nys-fileinput-font-size: var(--nys-font-size-ui-md, 16px); --_nys-fileinput-font-weight: var(--nys-font-weight-semibold, 600); --_nys-fileinput-line-height: var(--nys-font-lineheight-ui-md, 24px); --_nys-fileinput-font-family: var( --nys-font-family-ui, var( --nys-font-family-sans, "Proxima Nova", "Helvetica Neue", "Helvetica", "Arial", sans-serif ) ); /* Dropzone */ --_nys-fileinput-dropzone-background: var(--nys-color-ink-reverse, #fff); --_nys-fileinput-dropzone-radius: var( --nys-radius-lg, var(--nys-space-100, 8px) ); --_nys-fileinput-dropzone-border: var(--nys-border-width-sm, 1px) dashed var(--nys-color-neutral-200, #bec0c1); --_nys-fileinput-dropzone-color: var(--nys-color-text-disabled, #bec0c1); } .nys-fileinput { display: flex; flex-direction: column; align-items: flex-start; justify-content: center; gap: var(--_nys-fileinput-gap); font-family: var(--_nys-fileinput-font-family); font-size: var(--_nys-fileinput-font-size); font-weight: var(--_nys-fileinput-font-weight); line-height: var(--_nys-fileinput-line-height); } :host([width="lg"]) .nys-fileinput { max-width: var(--nys-form-width-lg, 384px); } ul { list-style-type: none; padding: 0px; margin: 0px; width: 100%; display: flex; flex-direction: column; gap: var(--_nys-fileinput-gap); } /***** Dragzone *****/ .nys-fileinput__dropzone { display: flex; padding: var(--nys-space-400, 32px) var(--nys-space-200, 16px); justify-content: center; align-items: center; gap: 12px; align-self: stretch; border-radius: var(--_nys-fileinput-dropzone-radius); outline: var(--_nys-fileinput-dropzone-border); background: var(--_nys-fileinput-dropzone-background); transition: all 60ms ease-in-out; } .nys-fileinput__dropzone:hover { cursor: pointer; --_nys-fileinput-dropzone-border: var(--nys-border-width-md, 2px) dashed var(--nys-color-neutral-700, #4a4d4f); } .nys-fileinput__dropzone.drag-active { --_nys-fileinput-dropzone-border: var(--nys-border-width-md, 2px) solid var(--nys-color-theme, #154973); --_nys-fileinput-dropzone-background: var(--nys-color-theme-faint, #f7fafd); } .nys-fileinput__dropzone.error { --_nys-fileinput-dropzone-border: var(--nys-border-width-md, 1px) dashed var(--nys-color-danger, #b52c2c); } .nys-fileinput__dropzone.error:hover { --_nys-fileinput-dropzone-border: var(--nys-border-width-sm, 2px) dashed var(--nys-color-emergency, #721c1c); } .nys-fileinput__dropzone.disabled { cursor: not-allowed; --_nys-fileinput-dropzone-border: var(--nys-border-width-sm, 1px) dashed var(--nys-color-neutral-300, #a7a9ab); --_nys-fileinput-dropzone-background: var(--nys-color-neutral-10, #f6f6f6); color: var(--_nys-fileinput-dropzone-color); } progress { display: flex; width: 100%; height: 6px; border-radius: var(--nys-radius-round, 1776px); background: var(--_nys-fileinput-progress-background); overflow: hidden; appearance: none; border: none; } progress::-moz-progress-bar { background: var(--_nys-fileinput-progress-background); } progress::-webkit-progress-value { background: var(--_nys-fileinput-progress-background); } progress::-webkit-progress-bar { background: var(--_nys-fileinput-progress-background); } `, W = C` :host { /* Global fileitem Styles */ --_nys-fileitem-items-radius: var(--nys-radius-md, 4px); --_nys-fileitem-items-padding: var(--nys-space-100, 8px) var(--nys-space-200, 16px); --_nys-fileitem-items-background: var(--nys-color-ink-reverse, #fff); --_nys-fileitem-items-border: var(--nys-border-width-sm, 1px) solid var(--nys-color-neutral-100, #d0d0ce); --_nys-fileitem-error-color: var(--nys-color-danger, #b52c2c); /* Typography */ --_nys-fileitem-font-family: var( --nys-font-family-ui, var( --nys-font-family-sans, "Proxima Nova", "Helvetica Neue", "Helvetica", "Arial", sans-serif ) ); --_nys-fileitem-font-size: var(--nys-font-size-ui-md, 16px); --_nys-fileitem-font-weight-400: var(--nys-font-weight-regular, 400); --_nys-fileitem-line-height: var(--nys-font-lineheight-ui-md, 24px); --_nys-fileitem-letterspacing: var(--nys-font-letterspacing-ui-md, 0.044px); /* Progress Bar */ --_nys-fileitem-progress-background: var(--nys-color-neutral-50, #ededed); --_nys-fileitem-progress-fill-background: var(--nys-color-info, #004dd1); } /***** File List Item *****/ .file-item { position: relative; border-radius: var(--_nys-fileitem-items-radius); border: var(--_nys-fileitem-items-border); background: var(--_nys-fileitem-items-background); } .file-item.error { --_nys-fileitem-items-border: var(--nys-border-width-sm, 1px) solid var(--nys-color-danger, #b52c2c); } .file-item__main { display: flex; justify-items: center; align-items: center; gap: var(--_nys-fileinput-gap); padding: var(--_nys-fileitem-items-padding); height: 56px; box-sizing: border-box; } .file-item__info { display: flex; flex-direction: column; flex: 1; min-width: 0; font-family: var(--_nys-fileitem-font-family); font-size: var(--_nys-fileitem-font-size); font-style: normal; font-weight: var(--_nys-fileitem-font-weight-400); line-height: var(--_nys-fileitem-line-height); letter-spacing: var(--_nys-fileitem-letterspacing); } .file-item__info-name { display: flex; max-width: 100%; overflow: hidden; white-space: nowrap; align-items: center; } .file-item__info-name-start { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; flex-shrink: 1; min-width: 0; } .file-item p { margin: 0; } .file-item__error { color: var(--_nys-fileitem-error-color); text-overflow: ellipsis; font-weight: 700; } /**** Progress Bar ****/ progress { position: absolute; bottom: 0; display: flex; width: 100%; height: 6px; border-radius: var(--nys-radius-round, 1776px); background: var(--_nys-fileitem-progress-fill-background); overflow: hidden; appearance: none; } /* Track */ progress::-moz-progress-bar { background: var(--_nys-fileitem-progress-background); } /* Filled value (the blue bar) */ progress::-webkit-progress-value { background: var(--_nys-fileitem-progress-fill-background); } /* Firefox */ progress::-webkit-progress-bar { background: var(--_nys-fileitem-progress-background); } /**** Icon ****/ .file-icon[name="progress_activity"] { animation: spin 1s linear infinite; } .file-icon[name="error"] { color: var(--_nys-fileitem-error-color); } @keyframes spin { 0% { transform: rotate(0deg); } 100% { transform: rotate(360deg); } } `; var Y = Object.defineProperty, v = (n, e, t, i) => { for (var s = void 0, r = n.length - 1, o; r >= 0; r--) (o = n[r]) && (s = o(e, t, s) || s); return s && Y(e, t, s), s; }; const S = class S extends D { constructor() { super(...arguments), this.filename = "", this.status = "pending", this.progress = 0, this.errorMessage = ""; } _handleRemove() { this.dispatchEvent( new CustomEvent("nys-fileRemove", { detail: { filename: this.filename }, bubbles: !0, composed: !0 }) ); } splitFilename(e) { const t = e.lastIndexOf("."), i = t !== -1 ? e.slice(t) : "", s = t !== -1 ? e.slice(0, t) : e, r = s.slice(0, s.length - 3), o = s.slice(-3); return { startPart: r, endPart: o, extension: i }; } render() { const { startPart: e, endPart: t, extension: i } = this.splitFilename(this.filename); return h` <div class="file-item ${this.status}" aria-busy=${this.status === "processing" ? "true" : "false"} aria-label="You have selected ${this.filename}" > <div class="file-item__main" role="group"> <nys-icon class="file-icon" name=${this.status === "processing" ? "progress_activity" : this.status === "error" ? "error" : "attach_file"} size="2xl" ></nys-icon> <div class="file-item__info"> <div class="file-item__info-name"> <span class="file-item__info-name-start">${e}</span> <span class="file-item__info-name-end" >${t}${i}</span > </div> ${this.errorMessage ? h`<p class="file-item__error" role="alert" aria-live="assertive" aria-invalid="true" aria-errormessage=${this.errorMessage} id="${this.filename}-error" > ${this.errorMessage} </p>` : null} </div> <nys-button circle icon="close" ariaLabel="close button" size="sm" variant="ghost" .onClick=${() => this._handleRemove()} ariaLabel="Remove file: ${this.filename}" ></nys-button> </div> ${this.status === "processing" ? h`<div class="file-item__progress-container" role="progressbar" aria-valuemin="0" aria-valuemax="100" aria-valuenow="${this.progress}" aria-label="Upload progress for ${this.filename}" > <progress value=${this.progress} max="100"></progress> </div>` : null} </div> `; } }; S.styles = W; let u = S; v([ a({ type: String }) ], u.prototype, "filename"); v([ a({ type: String }) ], u.prototype, "status"); v([ a({ type: Number }) ], u.prototype, "progress"); v([ a({ type: String }) ], u.prototype, "errorMessage"); customElements.define("nys-fileitem", u); var G = Object.defineProperty, d = (n, e, t, i) => { for (var s = void 0, r = n.length - 1, o; r >= 0; r--) (o = n[r]) && (s = o(e, t, s) || s); return s && G(e, t, s), s; }; let J = 0; const _ = class _ extends D { // allows use of elementInternals' API constructor() { super(), this.id = "", this.name = "", this.label = "", this.description = "", this.multiple = !1, this.accept = "", this.disabled = !1, this.required = !1, this.optional = !1, this.showError = !1, this.errorMessage = "", this.dropzone = !1, this.width = "full", this._selectedFiles = [], this._dragActive = !1, this._internals = this.attachInternals(); } get _isDropDisabled() { return this.disabled || !this.multiple && this._selectedFiles.length > 0; } get _buttonAriaLabel() { return this._selectedFiles.length === 0 ? this.multiple ? "Choose files: " : "Choose file: " : this.multiple ? "Change files: " : "Change file: "; } get _buttonAriaDescription() { if (this._selectedFiles.length === 0) return `${this.label + " " + this.description}`; const e = this._selectedFiles.some( (s) => s.status === "error" ); let t = ""; if (this._selectedFiles.length === 1) t = `You have selected ${this._selectedFiles[0].file.name}.`; else { const s = this._selectedFiles.map((r) => r.file.name).join(", "); t = `You have selected ${this._selectedFiles.length} files: ${s}`; } return `${t}${e ? " Error: One or more files are not valid file types." : ""}`; } get _innerNysButton() { var i; const e = this.renderRoot.querySelector( '[name="file-btn"]' ); return (i = e == null ? void 0 : e.shadowRoot) == null ? void 0 : i.querySelector( "button" ); } // Generate a unique ID if one is not provided connectedCallback() { super.connectedCallback(), this.id || (this.id = `nys-fileinput-${Date.now()}-${J++}`), this.addEventListener("invalid", this._handleInvalid); } disconnectedCallback() { super.disconnectedCallback(), this.removeEventListener("invalid", this._handleInvalid); } firstUpdated() { this._setValue(); } /********************** Form Integration **********************/ _setValue() { var e; if (this.multiple) { const t = this._selectedFiles.map((i) => i.file); if (t.length > 0) { const i = new FormData(); t.forEach((s) => { i.append(this.name, s); }), this._internals.setFormValue(i); } else this._internals.setFormValue(null); } else { const t = ((e = this._selectedFiles[0]) == null ? void 0 : e.file) || null; this._internals.setFormValue(t); } this._manageRequire(); } // Called to internally set the initial internalElement required flag. _manageRequire() { var s; const e = (s = this.shadowRoot) == null ? void 0 : s.querySelector("input"); if (!e) return; const t = this.errorMessage || "Please upload a file."; this.required && this._selectedFiles.length == 0 ? (this._internals.ariaRequired = "true", this._internals.setValidity({ valueMissing: !0 }, t, e)) : (this._internals.ariaRequired = "false", this._internals.setValidity({})); } _setValidityMessage(e = "") { var i, s; const t = (i = this.shadowRoot) == null ? void 0 : i.querySelector("input"); t && (this.showError = e === (this.errorMessage || "Please upload a file."), (s = this.errorMessage) != null && s.trim() && e !== "" && (e = this.errorMessage), this._internals.setValidity( e ? { customError: !0 } : {}, e, t )); } _validate() { const e = this._selectedFiles.some( (s) => s.status === "error" ), t = this.required && this._selectedFiles.length === 0; let i = ""; t ? i = this.errorMessage || "Please upload a file." : e && (i = "One or more files are invalid."), this._setValidityMessage(i); } // This helper function is called to perform the element's native validation. checkValidity() { var t; const e = (t = this.shadowRoot) == null ? void 0 : t.querySelector("input"); return e ? e.checkValidity() : !0; } _handleInvalid(e) { e.preventDefault(), this._validate(); const t = this._innerNysButton; if (t) { const i = this._internals.form; i ? Array.from(i.elements).find( (o) => typeof o.checkValidity == "function" && !o.checkValidity() ) === this && t.focus() : t.focus(); } } /******************** Functions ********************/ // Store the files to be displayed async _saveSelectedFiles(e) { if (this._selectedFiles.some( (s) => s.file.name == e.name ) || !this.multiple && this._selectedFiles.length >= 1) return; const i = { file: e, progress: 0, status: "pending" }; this._selectedFiles.push(i), await this._processFile(i), this._setValue(), this._validate(); } // Read the contents of stored files, this will indicate loading progress of the uploaded files async _processFile(e) { e.status = "processing"; try { if (!await N(e.file, this.accept)) { e.status = "error", e.errorMsg = "File type is invalid.", this.requestUpdate(); return; } const i = new FileReader(); i.onprogress = (s) => { if (s.lengthComputable) { const r = Math.round(s.loaded * 100 / s.total); e.progress = r, this.requestUpdate(); } }, i.onload = () => { e.progress = 100, e.status = "done", this.requestUpdate(); }, i.onerror = () => { e.status = "error", e.errorMsg = "Failed to load file.", this.requestUpdate(); }, i.readAsArrayBuffer(e.file); } catch { e.status = "error", e.errorMsg = "Error validating file.", this.requestUpdate(); } } _dispatchChangeEvent() { this.dispatchEvent( new CustomEvent("nys-change", { detail: { files: this._selectedFiles }, bubbles: !0, composed: !0 }) ); } _openFileDialog() { const e = this.renderRoot.querySelector( ".hidden-file-input" ); e == null || e.click(); } _handlePostFileSelectionFocus() { if (this.multiple) { const e = this._innerNysButton; e && e.focus(); } else this._focusFirstFileItemIfSingleMode(); } async _focusFirstFileItemIfSingleMode() { var e; if (!this.multiple) { await this.updateComplete; const t = this.renderRoot.querySelector( "nys-fileitem" ), i = (e = t == null ? void 0 : t.shadowRoot) == null ? void 0 : e.querySelector( ".file-item" ); i && (i.setAttribute("tabindex", "-1"), i.focus()); } } /******************** Event Handlers ********************/ // Access the selected files & add new files to the internal list via the hidden <input type="file"> _handleFileChange(e) { const t = e.target, i = t.files; (i ? Array.from(i) : []).map((r) => { this._saveSelectedFiles(r); }), t.value = "", this.requestUpdate(), this._dispatchChangeEvent(), this._handlePostFileSelectionFocus(); } _handleFileRemove(e) { const t = e.detail.filename; this._selectedFiles = this._selectedFiles.filter( (i) => i.file.name !== t ), this._setValue(), this._validate(), this.requestUpdate(), this._dispatchChangeEvent(); } _onDragOver(e) { this.disabled || (e.stopPropagation(), e.preventDefault(), this._dragActive || (this._dragActive = !0, this.requestUpdate())); } // Mostly used for styling purpose _onDragLeave(e) { this.disabled || (e.stopPropagation(), e.preventDefault(), e.currentTarget === e.target && (this._dragActive = !1, this.requestUpdate())); } _onDrop(e) { var s; if (this.disabled) return; e.preventDefault(), this._dragActive = !1, this.requestUpdate(); const t = (s = e.dataTransfer) == null ? void 0 : s.files; if (!t) return; const i = Array.from(t); this.multiple ? i.forEach((r) => { this._saveSelectedFiles(r); }) : this._saveSelectedFiles(i[0]), this.requestUpdate(), this._dispatchChangeEvent(); } render() { return h`<div class="nys-fileinput" @nys-fileRemove=${this._handleFileRemove} > <nys-label id=${this.id} label=${this.label} description=${this.description} flag=${this.required ? "required" : this.optional ? "optional" : ""} > <slot name="description" slot="description">${this.description}</slot> </nys-label> <input class="hidden-file-input" tabindex="-1" type="file" name=${this.name} ?multiple=${this.multiple} accept=${this.accept} ?required=${this.required} ?disabled=${this.disabled || !this.multiple && this._selectedFiles.length > 0} aria-disabled="${this.disabled}" aria-hidden="true" hidden @change=${this._handleFileChange} /> ${this.dropzone ? h`<div class="nys-fileinput__dropzone ${this._dragActive ? "drag-active" : ""} ${this._isDropDisabled ? "disabled" : ""} ${this.showError && !this._isDropDisabled ? "error" : ""}" @click=${this._isDropDisabled ? null : this._openFileDialog} @keydown=${(e) => !this._isDropDisabled && (e.key === "Enter" || e.key === " ") && this._openFileDialog()} @dragover=${this._isDropDisabled ? null : this._onDragOver} @dragleave=${this._isDropDisabled ? null : this._onDragLeave} @drop=${this._isDropDisabled ? null : this._onDrop} aria-label="Drag files here or choose from folder" > ${this._dragActive ? h`<p>Drop file to upload</p>` : h` <nys-button id=${this.id} name="file-btn" label=${this.multiple ? "Choose files" : "Choose file"} variant="outline" ariaLabel=${this._buttonAriaLabel} ariaDescription=${this._buttonAriaDescription} ?disabled=${this._isDropDisabled} .onClick=${(e) => { e.stopPropagation(), this._openFileDialog(); }} ></nys-button> <p>or drag here</p>`} </div>` : h`<nys-button id=${this.id} name="file-btn" label=${this.multiple ? "Choose files" : "Choose file"} variant="outline" ariaLabel=${this._buttonAriaLabel} ariaDescription=${this._buttonAriaDescription} ?disabled=${this.disabled || !this.multiple && this._selectedFiles.length > 0} .onClick=${() => this._openFileDialog()} ></nys-button>`} ${this.showError ? h` <nys-errormessage ?showError=${this.showError} errorMessage=${this._internals.validationMessage || this.errorMessage} ></nys-errormessage> ` : null} ${this._selectedFiles.length > 0 ? h` <ul> ${this._selectedFiles.map( (e) => h`<li> <nys-fileitem filename=${e.file.name} status=${e.status} progress=${e.progress} errorMessage=${e.errorMsg || ""} ></nys-fileitem> </li>` )} </ul> ` : null} </div>`; } }; _.styles = H, _.formAssociated = !0; let l = _; d([ a({ type: String }) ], l.prototype, "id"); d([ a({ type: String, reflect: !0 }) ], l.prototype, "name"); d([ a({ type: String }) ], l.prototype, "label"); d([ a({ type: String }) ], l.prototype, "description"); d([ a({ type: Boolean }) ], l.prototype, "multiple"); d([ a({ type: String }) ], l.prototype, "accept"); d([ a({ type: Boolean, reflect: !0 }) ], l.prototype, "disabled"); d([ a({ type: Boolean, reflect: !0 }) ], l.prototype, "required"); d([ a({ type: Boolean, reflect: !0 }) ], l.prototype, "optional"); d([ a({ type: Boolean, reflect: !0 }) ], l.prototype, "showError"); d([ a({ type: String }) ], l.prototype, "errorMessage"); d([ a({ type: Boolean }) ], l.prototype, "dropzone"); d([ a({ type: String, reflect: !0 }) ], l.prototype, "width"); customElements.get("nys-fileinput") || customElements.define("nys-fileinput", l); export { l as NysFileinput }; //# sourceMappingURL=nys-fileinput.js.map