Repository: microsoft/playwright
File: packages/injected/src/highlight.ts (TypeScript)

Code before:
    this._glassPaneElement.style.padding = '0';
    this._glassPaneElement.style.margin = '0';
    this._glassPaneElement.style.border = 'none';
    this._glassPaneElement.style.overflow = 'visible';
    this._glassPaneElement.style.pointerEvents = 'none';
    this._glassPaneElement.style.display = 'flex';
    this._glassPaneElement.style.backgroundColor = 'transparent';
    this._actionPointElement = document.createElement('x-pw-action-point');
    this._actionPointElement.setAttribute('hidden', 'true');
    this._glassPaneShadow = this._glassPaneElement.attachShadow({ mode: this._isUnderTest ? 'open' : 'closed' });
    // workaround for firefox: when taking screenshots, it complains adoptedStyleSheets.push
    // is not a function, so we fallback to style injection
    if (typeof this._glassPaneShadow.adoptedStyleSheets.push === 'function') {
      const sheet = new this._injectedScript.window.CSSStyleSheet();
      sheet.replaceSync(highlightCSS);
      this._glassPaneShadow.adoptedStyleSheets.push(sheet);
    } else {
      const styleElement = this._injectedScript.document.createElement('style');
      styleElement.textContent = highlightCSS;
      this._glassPaneShadow.appendChild(styleElement);
    }
    this._glassPaneShadow.appendChild(this._actionPointElement);

    this._injectedScript.document.addEventListener('toggle', this._onTopLayerChange, true);
    this._dialogObserver = new injectedScript.window.MutationObserver(this._onOpenMutation);
    this._dialogObserver.observe(this._injectedScript.document, { subtree: true, attributes: true, attributeFilter: ['open'] });
  }

  private _onOpenMutation = (mutations: MutationRecord[]) => {
    for (const mutation of mutations) {
      if (mutation.type === 'attributes' &&
            mutation.attributeName === 'open' &&
            mutation.target instanceof this._injectedScript.window.HTMLDialogElement &&
            mutation.target.hasAttribute('open')) {
        this._bringToFront();
        return;
      }
    }
  };

  private _onTopLayerChange = (e: ToggleEvent) => {
    if (e.target === this._glassPaneElement)
      return;
    if (e.newState !== 'open')
      return;
    this._bringToFront();
  };

  private _bringToFront() {
    if (!this._glassPaneElement.matches(':popover-open'))
      return;

Review comment (suggestion):
This needs to be done in `install()`, and all observers/listeners should be reset. See `Recorder.installListeners()` for an example.

Code after:
    this._glassPaneElement.style.margin = '0';
    this._glassPaneElement.style.border = 'none';
    this._glassPaneElement.style.overflow = 'visible';
    this._glassPaneElement.style.pointerEvents = 'none';
    this._glassPaneElement.style.display = 'flex';
    this._glassPaneElement.style.backgroundColor = 'transparent';
    this._actionPointElement = document.createElement('x-pw-action-point');
    this._actionPointElement.setAttribute('hidden', 'true');
    this._glassPaneShadow = this._glassPaneElement.attachShadow({ mode: this._isUnderTest ? 'open' : 'closed' });
    // workaround for firefox: when taking screenshots, it complains adoptedStyleSheets.push
    // is not a function, so we fallback to style injection
    if (typeof this._glassPaneShadow.adoptedStyleSheets.push === 'function') {
      const sheet = new this._injectedScript.window.CSSStyleSheet();
      sheet.replaceSync(highlightCSS);
      this._glassPaneShadow.adoptedStyleSheets.push(sheet);
    } else {
      const styleElement = this._injectedScript.document.createElement('style');
      styleElement.textContent = highlightCSS;
      this._glassPaneShadow.appendChild(styleElement);
    }
    this._glassPaneShadow.appendChild(this._actionPointElement);
  }

  install() {
    // NOTE: document.documentElement can be null: https://github.com/microsoft/TypeScript/issues/50078
    if (!this._injectedScript.document.documentElement)
      return;
    if (!this._injectedScript.document.documentElement.contains(this._glassPaneElement) || this._glassPaneElement.nextElementSibling)
      this._injectedScript.document.documentElement.appendChild(this._glassPaneElement);
    this._bringToFront();
  }

  private _bringToFront() {
    this._glassPaneElement.hidePopover();
    this._glassPaneElement.showPopover();
  }

  setLanguage(language: Language) {
    this._language = language;
  }

  runHighlightOnRaf(selector: ParsedSelector) {
    if (this._rafRequest)
      this._injectedScript.utils.builtins.cancelAnimationFrame(this._rafRequest);
    const elements = this._injectedScript.querySelectorAll(selector, this._injectedScript.document.documentElement);
    const locator = asLocator(this._language, stringifySelector(selector));
    const color = elements.length > 1 ? '#f6b26b7f' : '#6fa8dc7f';
    this.updateHighlight(elements.map((element, index) => {
      const suffix = elements.length > 1 ? ` [${index + 1} of ${elements.length}]` : '';
      return { element, color, tooltipText: locator + suffix };
    }));