import { property, state, query } from "lit/decorators.js"; import { msg, localized } from "@lit/localize"; import { parse as yamlToJson, stringify as yamlStringify, YAMLParseError, } from "yaml"; import LiteElement, { html } from "../utils/LiteElement"; /** * Usage example: * ```ts * * * ``` * * @event on-change */ @localized() export class ConfigEditor extends LiteElement { @property({ type: String }) value = ""; @state() errorMessage = ""; @query("#config-editor-textarea") textareaElem?: HTMLTextAreaElement; render() { return html`
${this.errorMessage ? html` ${msg("Invalid Configuration")} ` : html` ${msg("Valid Configuration")} `}
this.textareaElem?.value} >
${this.renderTextArea()}
${this.errorMessage ? html`
${this.errorMessage}
` : ""}
`; } private renderTextArea() { const lineCount = this.value.split("\n").length; return html`
${[...new Array(lineCount)].map((line, i) => html`${i + 1}
`)}
`; } private handleParseError(error: Error) { if (error instanceof YAMLParseError) { const errorMessage = error.message.replace("YAMLParseError: ", ""); this.errorMessage = errorMessage; } else { this.errorMessage = msg("Invalid YAML or JSON"); console.debug(error); } } private checkValidity(value: string) { yamlToJson(value); } private onBlur(value: string) { if (!value) { this.textareaElem?.setCustomValidity(msg("Please fill out this field")); this.textareaElem?.reportValidity(); } } private onChange(value: string) { try { this.checkValidity(value); this.textareaElem?.setCustomValidity(""); this.errorMessage = ""; this.dispatchEvent( new CustomEvent("on-change", { detail: { value: value, }, }) ); } catch (e: any) { this.textareaElem?.setCustomValidity(msg("Please fix errors")); this.handleParseError(e); } this.textareaElem?.reportValidity(); } /** * Stop propgation of sl-select events. * Prevents bug where sl-dialog closes when dropdown closes * https://github.com/shoelace-style/shoelace/issues/170 */ private stopProp(e: CustomEvent) { e.stopPropagation(); } }