UNPKG

chrome-devtools-frontend

Version:
97 lines (80 loc) 2.87 kB
// Copyright 2022 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. /* eslint-disable rulesdir/no-lit-render-outside-of-view */ import * as ComponentHelpers from '../../../ui/components/helpers/helpers.js'; import {html, render} from '../../../ui/lit/lit.js'; import * as VisualLogging from '../../../ui/visual_logging/visual_logging.js'; import editableSpanStyles from './EditableSpan.css.js'; export interface EditableSpanData { value: string; } export class EditableSpan extends HTMLElement { readonly #shadow = this.attachShadow({mode: 'open'}); #value = ''; connectedCallback(): void { this.#shadow.addEventListener('focusin', this.#selectAllText.bind(this)); this.#shadow.addEventListener('keydown', this.#onKeyDown.bind(this)); this.#shadow.addEventListener('input', this.#onInput.bind(this)); } set data(data: EditableSpanData) { this.#value = data.value; void ComponentHelpers.ScheduledRender.scheduleRender(this, this.#render); } get value(): string { return this.#shadow.querySelector<HTMLSpanElement>('span')?.innerText || ''; } set value(value: string) { this.#value = value; const span = this.#shadow.querySelector<HTMLSpanElement>('span'); if (span) { span.innerText = value; } } #onKeyDown(event: Event): void { if ((event as KeyboardEvent).key === 'Enter') { event.preventDefault(); (event.target as HTMLElement)?.blur(); } } #onInput(event: Event): void { this.#value = (event.target as HTMLElement).innerText; } #selectAllText(event: Event): void { const target = event.target as HTMLElement; const selection = window.getSelection(); const range = document.createRange(); range.selectNodeContents(target); selection?.removeAllRanges(); selection?.addRange(range); } #render(): void { if (!ComponentHelpers.ScheduledRender.isScheduledRender(this)) { throw new Error('HeaderSectionRow render was not scheduled'); } // Disabled until https://crbug.com/1079231 is fixed. // clang-format off render(html` <style>${editableSpanStyles}</style> <span contenteditable="plaintext-only" class="editable" tabindex="0" .innerText=${this.#value} jslog=${VisualLogging.value('header-editor').track({change: true, keydown: 'Enter|Escape'})} </span>`, this.#shadow, {host: this}); // clang-format on } override focus(): void { requestAnimationFrame(() => { const span = this.#shadow.querySelector<HTMLElement>('.editable'); span?.focus(); }); } } customElements.define('devtools-editable-span', EditableSpan); declare global { interface HTMLElementTagNameMap { 'devtools-editable-span': EditableSpan; } }