import { uuid } from '@lion/ui/core.js'; import { LionValidationFeedback } from '@lion/ui/form-core.js'; import { LocalizeMixin } from '@lion/ui/localize.js'; import { ScopedElementsMixin } from '@open-wc/scoped-elements'; import { css, html, LitElement, nothing } from 'lit'; import { ifDefined } from 'lit/directives/if-defined.js'; import { repeat } from 'lit/directives/repeat.js'; import { localizeNamespaceLoader } from './localizeNamespaceLoader.js'; /** * @typedef {import('lit').TemplateResult} TemplateResult * @typedef {import('../types/input-file.js').InputFile} InputFile * @typedef {import('../types/input-file.js').SystemFile} SystemFile */ export class LionSelectedFileList extends LocalizeMixin(ScopedElementsMixin(LitElement)) { static get scopedElements() { return { // @ts-expect-error [external] fix types scopedElements ...super.scopedElements, 'lion-validation-feedback': LionValidationFeedback, }; } static get properties() { return { fileList: { type: Array }, multiple: { type: Boolean }, }; } static localizeNamespaces = [ { 'lion-input-file': localizeNamespaceLoader }, ...super.localizeNamespaces, ]; constructor() { super(); /** * @type {InputFile[]} */ this.fileList = []; this.multiple = false; } /** * @param {import('lit').PropertyValues} changedProperties */ updated(changedProperties) { super.updated(changedProperties); if (changedProperties.has('fileList')) { this._enhanceLightDomA11y(); } } _enhanceLightDomA11y() { const fileFeedbackElementList = this.shadowRoot?.querySelectorAll('[id^="file-feedback"]'); // TODO: this will break as soon as a Subclasser changes the template ... const inputFileNode = this.parentNode?.parentNode; fileFeedbackElementList?.forEach(feedbackEl => { // Generic focus/blur handling that works for both Fields/FormGroups inputFileNode?.addEventListener('focusin', () => { feedbackEl.setAttribute('aria-live', 'polite'); }); inputFileNode?.addEventListener('focusout', () => { feedbackEl.setAttribute('aria-live', 'assertive'); }); }); } /** * @protected * @param {InputFile} removedFile */ _removeFile(removedFile) { this.dispatchEvent( new CustomEvent('file-remove-requested', { detail: { removedFile, status: removedFile.status, uploadResponse: removedFile.response, }, }), ); } /** * @protected * @param {Array} validationFeedback * @param {string} fileUuid * @return {TemplateResult} */ // eslint-disable-next-line class-methods-use-this _validationFeedbackTemplate(validationFeedback, fileUuid) { return html` `; } /** * @protected * @param {InputFile} file * @return {TemplateResult|nothing} */ // eslint-disable-next-line class-methods-use-this, no-unused-vars _listItemBeforeTemplate(file) { return nothing; } /** * @protected * @param {InputFile} file * @param {string} fileUuid * @return {TemplateResult} */ // eslint-disable-next-line no-unused-vars _listItemAfterTemplate(file, fileUuid) { return html` `; } /** * @protected * @return {TemplateResult} */ // eslint-disable-next-line class-methods-use-this _removeButtonContentTemplate() { return html`✖️`; } /** * @protected * @param {InputFile} file * @return {TemplateResult} */ _selectedListItemTemplate(file) { const fileUuid = uuid(); return html`
${this._listItemBeforeTemplate(file)} ${this.msgLit('lion-input-file:fileNameDescriptionLabel')} ${file.downloadUrl && file.status !== 'LOADING' ? html` ${file.systemFile?.name} ` : file.systemFile?.name} ${this._listItemAfterTemplate(file, fileUuid)}
${file.status === 'FAIL' && file.validationFeedback ? html` ${repeat( file.validationFeedback, validationFeedback => html` ${this._validationFeedbackTemplate([validationFeedback], fileUuid)} `, )} ` : nothing}
`; } render() { return this.fileList?.length ? html` ${this.multiple ? html` ` : html` ${this._selectedListItemTemplate(this.fileList[0])} `} ` : nothing; } static get styles() { return [ css` .selected__list { list-style-type: none; margin-block-start: 0; margin-block-end: 0; padding-inline-start: 0; } .sr-only { position: absolute; top: 0; width: 1px; height: 1px; overflow: hidden; clip-path: inset(100%); clip: rect(1px, 1px, 1px, 1px); white-space: nowrap; border: 0; margin: 0; padding: 0; } `, ]; } }