/** * Copyright Aquera Inc 2023 * * This source code is licensed under the BSD-3-Clause license found in the * LICENSE file in the root directory of this source tree. */ import { LitElement, html, CSSResultArray, TemplateResult, } from 'lit'; import { customElement, property } from 'lit/decorators.js'; import { styles } from './nile-inline-edit.css'; import NileElement from '../internal/nile-element'; import { getDisplayValue, updateSlottedElementValue, handleDocumentFocusIn, handleDocumentMouseDown, } from './nile-inline-edit-utils'; /** * Nile inline-edit component. * * @tag nile-inline-edit * */ @customElement('nile-inline-edit') export class NileInlineEdit extends NileElement { /** * The styles for nile-inline-edit * @remarks If you are extending this class you can extend the base styles with super. Eg `return [super(), myCustomStyles]` */ public static get styles(): CSSResultArray { return [styles]; } /** Gives the label to the Inline Edit */ @property({ type: String, reflect: true }) label = ''; /** Gives the Placeholder to the Inline Edit */ @property({ type: String, reflect: true }) placeholder = ''; /** Open prop for displaying default slot in Inline Edit */ @property({ type: Boolean, reflect: true }) open = false; /** Gives the Value to the Inline Edit */ @property({ type: String, reflect: true }) value = ''; /** Maximum length for the placeholder value. Values longer than this will be truncated */ @property({ type: Number, attribute: 'max-placeholder-length' }) maxPlaceholderLength: number = 25; /** Enables automatic closing when focus moves outside the component or when clicking outside */ @property({ type: Boolean, attribute: 'auto-close' }) autoClose: boolean = false; /** Disables the inline edit, preventing it from being opened */ @property({ type: Boolean, reflect: true}) disabled: boolean = false; /* #endregion */ /* #region Methods */ /** * Render method * @slot This is a slot test */ private handleCloseResult(result: { shouldClose: boolean; newValue: string | null }) { if (result.shouldClose) { if (result.newValue !== null) { this.value = result.newValue; } this.open = false; } } private handleDocumentFocusInWrapper = (event: FocusEvent) => { const result = handleDocumentFocusIn(event, this, this.open); this.handleCloseResult(result); }; private handleDocumentMouseDownWrapper = (event: MouseEvent) => { const result = handleDocumentMouseDown(event, this, this.open); this.handleCloseResult(result); }; connectedCallback() { super.connectedCallback(); } updated(changedProperties: Map) { super.updated(changedProperties); if (changedProperties.has('open') && this.autoClose) { if (this.open) { updateSlottedElementValue(this.updateComplete, this.shadowRoot, this.value); document.addEventListener('focusin', this.handleDocumentFocusInWrapper, true); document.addEventListener('mousedown', this.handleDocumentMouseDownWrapper, true); } else { document.removeEventListener('focusin', this.handleDocumentFocusInWrapper, true); document.removeEventListener('mousedown', this.handleDocumentMouseDownWrapper, true); } } } disconnectedCallback() { super.disconnectedCallback(); document.removeEventListener('focusin', this.handleDocumentFocusInWrapper, true); document.removeEventListener('mousedown', this.handleDocumentMouseDownWrapper, true); } private handleClick() { if (this.disabled) return; this.open = true; } public render(): TemplateResult { // Use truncated value for display, or placeholder if empty const displayValue = this.autoClose ? getDisplayValue(this.value, this.maxPlaceholderLength) : this.value; const textInsideContainer = displayValue || this.placeholder; return html`
${this.label}
${this.open ? html` ` : html`
${textInsideContainer}
`} `; } /* #endregion */ } export default NileInlineEdit; declare global { interface HTMLElementTagNameMap { 'nile-inline-edit': NileInlineEdit; } }