import { ComponentId } from '../dataModels'; import { ComponentBase, ComponentState } from './componentBase'; import { hijackLinkElement } from '../utils'; import { applyIcon } from '../designApplication'; export type LinkState = ComponentState & { _type_: 'Link-builtin'; child_text?: string | null; child_component?: ComponentId | null; icon?: string | null; open_in_new_tab?: boolean; targetUrl: string; }; export class LinkComponent extends ComponentBase { state: Required; createElement(): HTMLElement { let element = document.createElement('a'); element.classList.add('rio-link'); hijackLinkElement(element); return element; } removeHtmlChild(latentComponents: Set) { /// If `element` has a child, remove it. There mustn't be more than one. // Components need special consideration, since they're tracked if (this.state.child_component !== null) { this.replaceOnlyChild(latentComponents, null); return; } // Plain HTML elements can be removed directly if (this.state.child_text !== null) { let element = this.element as HTMLAnchorElement; while (element.firstChild) { element.removeChild(element.firstChild); } } // There should be no children left console.assert(this.element.childElementCount === 0); } updateElement( deltaState: LinkState, latentComponents: Set ): void { super.updateElement(deltaState, latentComponents); let element = this.element as HTMLAnchorElement; // Child Text? if ( (deltaState.child_text !== undefined && deltaState.child_text !== null) || (this.state.child_text !== null && deltaState.icon !== undefined) ) { // Clear any existing children this.removeHtmlChild(latentComponents); // Add the icon, if any console.debug(deltaState.icon, this.state.icon); let icon = deltaState.icon ?? this.state.icon; if (icon !== null) { let iconElement = document.createElement('div'); iconElement.classList.add('rio-text-link-icon'); element.appendChild(iconElement); applyIcon(iconElement, icon, 'currentColor'); } // Add the new text let child_text = deltaState.child_text ?? this.state.child_text; let textElement = document.createElement('div'); textElement.classList.add('rio-text-link-text'); element.appendChild(textElement); textElement.textContent = child_text; // Update the CSS classes element.classList.add('rio-text-link'); } // Child Component? if ( deltaState.child_component !== undefined && deltaState.child_component !== null ) { // Clear any existing children this.removeHtmlChild(latentComponents); // Add the new component this.replaceOnlyChild(latentComponents, deltaState.child_component); // Update the CSS classes element.classList.remove('rio-text-link'); } // Target URL? if (deltaState.targetUrl !== undefined) { element.href = deltaState.targetUrl; } // Open in new tab? if (deltaState.open_in_new_tab === true) { element.target = '_blank'; } else if (deltaState.open_in_new_tab === false) { element.target = ''; } } }