@nysds/nys-fileinput
Version:
The Fileinput component from the NYS Design System.
1,016 lines (988 loc) • 34.4 kB
JavaScript
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