UNPKG

@synergy-design-system/components

Version:

This package provides the base of the Synergy Design System as native web components. It uses [lit](https://www.lit.dev) and parts of [shoelace](https://shoelace.style/). Synergy officially supports the latest two versions of all major browsers (as define

538 lines (532 loc) 15.7 kB
import { file_styles_default } from "./chunk.CW2Q7KG6.js"; import { defaultValue } from "./chunk.3NXKLKWH.js"; import { form_control_custom_styles_default, form_control_styles_default } from "./chunk.G4URZQCL.js"; import { SynButton } from "./chunk.YYEPGTYW.js"; import { FormControlController } from "./chunk.HP2LEQRU.js"; import { animateTo } from "./chunk.G6ITZTTW.js"; import { getAnimation, setDefaultAnimation } from "./chunk.7JGKUB4A.js"; import { SynIcon } from "./chunk.WFJVDRQR.js"; import { LocalizeController } from "./chunk.OAQRCZOO.js"; import { HasSlotController } from "./chunk.WVVQK5TE.js"; import { enableDefaultSettings } from "./chunk.E5UUNP6E.js"; import { watch } from "./chunk.BVZQ6QSY.js"; import { component_styles_default } from "./chunk.NLYVOJGK.js"; import { SynergyElement } from "./chunk.3AZFEB6D.js"; import { __decorateClass } from "./chunk.Z4XV3SMG.js"; // src/components/file/file.component.ts import { classMap } from "lit/directives/class-map.js"; import { property, query, state } from "lit/decorators.js"; import { html } from "lit"; import { ifDefined } from "lit/directives/if-defined.js"; var SynFile = class extends SynergyElement { constructor() { super(...arguments); this.formControlController = new FormControlController(this, { assumeInteractionOn: ["syn-change"], // This makes sure the value sent in formdata events is always the files object // @see internals/form.ts #handleFormData for more information value: (el) => el.files }); this.hasSlotController = new HasSlotController(this, "help-text", "label"); this.localize = new LocalizeController(this); this.userIsDragging = false; this.name = ""; this.defaultValue = ""; this.size = "medium"; this.label = ""; this.helpText = ""; this.disabled = false; this.droparea = false; this.accept = ""; this.multiple = false; this.webkitdirectory = false; this.form = ""; this.required = false; this.hideValue = false; } set files(v) { if (this.input) { this.input.files = v; } } get files() { var _a; return (_a = this.input) == null ? void 0 : _a.files; } set value(v) { if (this.input) { this.input.value = v; } } get value() { var _a; return (_a = this.input) == null ? void 0 : _a.value; } /** Gets the validity state object */ get validity() { return this.input.validity; } /** Gets the validation message */ get validationMessage() { return this.input.validationMessage; } /** * Checks for validity but does not show a validation message. * Returns `true` when valid and `false` when invalid. */ checkValidity() { return this.input.checkValidity(); } /** Gets the associated form, if one exists. */ getForm() { return this.formControlController.getForm(); } /** Checks for validity and shows the browser's validation message if the control is invalid. */ reportValidity() { return this.input.reportValidity(); } /** Sets a custom validation message. Pass an empty string to restore validity. */ setCustomValidity(message) { this.input.setCustomValidity(message); this.formControlController.updateValidity(); } handleDisabledChange() { this.formControlController.setValidity(this.disabled); } async handleValueChange() { await this.updateComplete; this.formControlController.updateValidity(); } /** Sets focus on the button or droparea. */ focus(options) { var _a, _b; if (this.droparea) { (_a = this.dropareaWrapper) == null ? void 0 : _a.focus(options); return; } (_b = this.button) == null ? void 0 : _b.focus(options); } /** Removes focus from the button or droparea. */ blur() { var _a, _b; if (this.droparea) { (_a = this.dropareaWrapper) == null ? void 0 : _a.blur(); return; } (_b = this.button) == null ? void 0 : _b.blur(); } handleInvalid(event) { this.formControlController.setValidity(false); this.formControlController.emitInvalidEvent(event); } handleFiles(files) { if (!files) { this.value = ""; return; } this.files = files; } async handleTransferItems(items) { if (!items) { this.value = ""; return new Promise((_resolve, reject) => { reject(new Error("No proper items found")); }); } const entries = Array.from(items).map((item) => item.webkitGetAsEntry()); const filesPromises = entries.map((entry) => this.getFilesFromEntry(entry)); const filesArray = await Promise.all(filesPromises); const files = filesArray.flat(); const dataTransfer = new DataTransfer(); Array.from(files).forEach((f) => dataTransfer.items.add(f)); return dataTransfer.files; } async getFilesFromEntry(entry) { if (!entry) { return []; } if (entry.isFile) { return new Promise((resolve, reject) => { entry.file((file) => resolve([file]), reject); }); } if (entry.isDirectory) { return new Promise((resolve, reject) => { const dirReader = entry.createReader(); dirReader.readEntries((entries) => { Promise.all(entries.map((e) => this.getFilesFromEntry(e))).then((files) => { resolve(files.flat()); }).catch(reject); }); }); } return []; } handleClick(e) { e.preventDefault(); this.input.click(); } /** Handles the change event of the native input */ handleChange(e) { e.preventDefault(); e.stopPropagation(); this.emit("syn-input"); this.emit("syn-change"); } handleDragOver(e) { e.preventDefault(); e.stopPropagation(); this.userIsDragging = true; } handleDragLeave(e) { e.preventDefault(); e.stopPropagation(); this.userIsDragging = false; } // eslint-disable-next-line complexity async handleDrop(e) { var _a; e.preventDefault(); e.stopPropagation(); if (!e.dataTransfer) { return; } const files = await this.handleTransferItems((_a = e.dataTransfer) == null ? void 0 : _a.items); this.userIsDragging = false; if (!files) { return; } if (!this.multiple && !this.webkitdirectory && files.length > 1) { this.emit("syn-error"); return; } const hasTrigger = this.hasSlotController.test("trigger"); if (!hasTrigger) { const disappearAnimation = getAnimation(this.inputChosen, "file.text.disappear", { dir: this.localize.dir() }); const appearAnimation = getAnimation(this.inputChosen, "file.text.appear", { dir: this.localize.dir() }); if (this.droparea) { const dropIconAnimation = getAnimation(this.dropareaIcon, "file.iconDrop", { dir: this.localize.dir() }); animateTo(this.dropareaIcon, dropIconAnimation.keyframes, dropIconAnimation.options); } await animateTo(this.inputChosen, disappearAnimation.keyframes, disappearAnimation.options); this.handleFiles(files); await animateTo(this.inputChosen, appearAnimation.keyframes, appearAnimation.options); } else { this.handleFiles(files); } this.input.dispatchEvent(new Event("change")); } /** * Handle the focus of the droparea and emit focus event */ handleFocus() { this.emit("syn-focus"); } /** * Handle the blur of the droparea and emit blur event */ handleBlur() { this.emit("syn-blur"); } renderValue() { var _a; let hasFiles = false; let fileChosenLabel = this.localize.term("numFilesSelected", 0, this.webkitdirectory); if (this.files && ((_a = this.files) == null ? void 0 : _a.length) > 0) { hasFiles = true; fileChosenLabel = this.files.length === 1 ? this.files[0].name : this.localize.term("numFilesSelected", this.files.length, this.webkitdirectory); } return html` <span class=${classMap({ input__value: true, "input__value--hidden": this.hideValue, "input__value--placeholder": !hasFiles })} part="value" > ${fileChosenLabel} </span> `; } /* eslint-disable @typescript-eslint/unbound-method */ renderDroparea() { return html` <div class="droparea" @click=${this.handleClick} @keypress=${this.handleClick} @focus=${this.handleFocus} @blur=${this.handleBlur} tabindex=${this.disabled ? -1 : 0} part="droparea" > <div class="droparea__background" part="droparea-background" > <span part="droparea-icon" class="droparea__icon"> <slot name="droparea-icon"> <syn-icon name="upload-file" library="system" ></syn-icon> </slot> </span> <p class="droparea__text" part="droparea-value" > <strong>${this.localize.term(this.webkitdirectory ? "folderDragDrop" : "fileDragDrop")}</strong> ${this.renderValue()} </p> </div> </div> `; } /* eslint-enable @typescript-eslint/unbound-method */ /* eslint-disable @typescript-eslint/unbound-method */ renderButton() { let buttonText = this.localize.term("fileButtonText"); if (this.multiple) { buttonText = this.localize.term("fileButtonTextMultiple"); } if (this.webkitdirectory) { buttonText = this.localize.term("folderButtonText"); } return html` <div class="button__wrapper" part="button-wrapper" > <syn-button class="button" @click=${this.handleClick} ?disabled=${this.disabled} exportparts="base:button__base" part="button" size=${this.size} variant="outline" > ${buttonText} </syn-button> ${this.renderValue()} </div> `; } /* eslint-enable @typescript-eslint/unbound-method */ /* eslint-disable @typescript-eslint/unbound-method */ // eslint-disable-next-line complexity render() { const hasLabel = this.label || !!this.hasSlotController.test("label"); const hasHelpText = this.helpText ? true : !!this.hasSlotController.test("help-text"); const hasTrigger = !!this.hasSlotController.test("trigger"); return html` <div class=${classMap({ "form-control": true, "form-control--droparea": this.droparea, "form-control--has-help-text": hasHelpText, "form-control--has-label": hasLabel, "form-control--large": this.size === "large", "form-control--medium": this.size === "medium", "form-control--small": this.size === "small", "form-control--user-dragging": this.userIsDragging })} @dragenter=${this.handleDragOver} @dragleave=${this.handleDragLeave} @dragover=${this.handleDragOver} @drop=${this.handleDrop} part="form-control" > ${hasTrigger ? html` <slot @click=${this.handleClick} @keypress=${this.handleClick} name="trigger" part="trigger" ></slot> ` : html` <label aria-hidden=${hasLabel ? "false" : "true"} class="form-control__label" for="input" part="form-control-label" > <slot name="label">${this.label}</slot> </label> <div class="form-control-input" part="form-control-input" > ${this.droparea ? this.renderDroparea() : this.renderButton()} </div> <div aria-hidden=${hasHelpText ? "false" : "true"} class="form-control__help-text" id="help-text" part="form-control-help-text" > <slot name="help-text">${this.helpText}</slot> </div> `} <input accept=${this.accept} aria-describedby="help-text" @change=${this.handleChange} class="input__control" ?disabled=${this.disabled} id="input" @invalid=${this.handleInvalid} ?multiple=${this.multiple} name=${ifDefined(this.name)} ?required=${this.required} type="file" tabindex="-1" ?webkitdirectory=${this.webkitdirectory} > </div> `; } /* eslint-enable @typescript-eslint/unbound-method */ }; SynFile.styles = [ component_styles_default, form_control_styles_default, form_control_custom_styles_default, file_styles_default ]; SynFile.dependencies = { "syn-button": SynButton, "syn-icon": SynIcon }; __decorateClass([ state() ], SynFile.prototype, "userIsDragging", 2); __decorateClass([ property({ type: Object }) ], SynFile.prototype, "files", 1); __decorateClass([ property({ type: String }) ], SynFile.prototype, "name", 2); __decorateClass([ property({ type: String }) ], SynFile.prototype, "value", 1); __decorateClass([ defaultValue() ], SynFile.prototype, "defaultValue", 2); __decorateClass([ property({ reflect: true }) ], SynFile.prototype, "size", 2); __decorateClass([ property() ], SynFile.prototype, "label", 2); __decorateClass([ property({ attribute: "help-text" }) ], SynFile.prototype, "helpText", 2); __decorateClass([ property({ reflect: true, type: Boolean }) ], SynFile.prototype, "disabled", 2); __decorateClass([ property({ type: Boolean }) ], SynFile.prototype, "droparea", 2); __decorateClass([ property({ type: String }) ], SynFile.prototype, "accept", 2); __decorateClass([ property({ type: String }) ], SynFile.prototype, "capture", 2); __decorateClass([ property({ reflect: true, type: Boolean }) ], SynFile.prototype, "multiple", 2); __decorateClass([ property({ reflect: true, type: Boolean }) ], SynFile.prototype, "webkitdirectory", 2); __decorateClass([ property({ reflect: true }) ], SynFile.prototype, "form", 2); __decorateClass([ property({ reflect: true, type: Boolean }) ], SynFile.prototype, "required", 2); __decorateClass([ property({ attribute: "hide-value", type: Boolean }) ], SynFile.prototype, "hideValue", 2); __decorateClass([ query(".input__control") ], SynFile.prototype, "input", 2); __decorateClass([ query(".button") ], SynFile.prototype, "button", 2); __decorateClass([ query(".droparea") ], SynFile.prototype, "dropareaWrapper", 2); __decorateClass([ query(".droparea__icon") ], SynFile.prototype, "dropareaIcon", 2); __decorateClass([ query(".input__value") ], SynFile.prototype, "inputChosen", 2); __decorateClass([ watch("disabled", { waitUntilFirstUpdate: true }) ], SynFile.prototype, "handleDisabledChange", 1); __decorateClass([ watch("value", { waitUntilFirstUpdate: true }) ], SynFile.prototype, "handleValueChange", 1); SynFile = __decorateClass([ enableDefaultSettings("SynFile") ], SynFile); setDefaultAnimation("file.iconDrop", { keyframes: [ { scale: 1 }, { scale: 0.7 }, { scale: 1 } ], options: { duration: 600, easing: "ease-out" } }); setDefaultAnimation("file.text.disappear", { keyframes: [ { opacity: 1 }, { opacity: 0, transform: "translateY(-40%)" } ], options: { duration: 300, easing: "cubic-bezier(0.45, 1.45, 0.8, 1)" } }); setDefaultAnimation("file.text.appear", { keyframes: [ { opacity: 0, transform: "translateY(40%)" }, { opacity: 1 } ], options: { duration: 300, easing: "cubic-bezier(0.45, 1.45, 0.8, 1)" } }); export { SynFile }; //# sourceMappingURL=chunk.Z2DUHMF5.js.map