TS-componentize Computed tab's style property and style trace elements

This also helps future work, for example, Computed style grouping,
to be TS-componentized as well.

Bug: chromium:1106251, chromium:1096230
Change-Id: I2f8a977f4e3f701905354cb4edb15702cb8cd2a3
Reviewed-on: https://chromium-review.googlesource.com/c/devtools/devtools-frontend/+/2336723
Commit-Queue: Changhao Han <[email protected]>
Reviewed-by: Paul Lewis <[email protected]>
Reviewed-by: Jack Franklin <[email protected]>
Reviewed-by: Mathias Bynens <[email protected]>
Reviewed-by: Alex Rudenko <[email protected]>
diff --git a/front_end/elements/BUILD.gn b/front_end/elements/BUILD.gn
index 7e145ef..678bc9d 100644
--- a/front_end/elements/BUILD.gn
+++ b/front_end/elements/BUILD.gn
@@ -12,6 +12,10 @@
     "ClassesPaneWidget.js",
     "ColorSwatchPopoverIcon.js",
     "ComputedStyleModel.js",
+    "ComputedStyleProperty.ts",
+    "ComputedStyleProperty_bridge.js",
+    "ComputedStyleTrace.ts",
+    "ComputedStyleTrace_bridge.js",
     "ComputedStyleWidget.js",
     "DOMLinkifier.js",
     "DOMPath.js",
@@ -65,6 +69,8 @@
   ]
 
   visibility = [
+    "../component_docs/computed_style_property",
+    "../component_docs/computed_style_trace",
     "../component_docs/elements_breadcrumbs",
     "../component_docs/layout_pane",
     "../../test/unittests/front_end/elements",
diff --git a/front_end/elements/ComputedStyleProperty.ts b/front_end/elements/ComputedStyleProperty.ts
new file mode 100644
index 0000000..207fbd4
--- /dev/null
+++ b/front_end/elements/ComputedStyleProperty.ts
@@ -0,0 +1,210 @@
+// Copyright (c) 2020 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.
+
+import * as LitHtml from '../third_party/lit-html/lit-html.js';
+
+const {render, html} = LitHtml;
+
+export interface ComputedStylePropertyData {
+  inherited: boolean;
+  expanded: boolean;
+  onNavigateToSource: (event?: Event) => void;
+}
+
+export class ComputedStyleProperty extends HTMLElement {
+  private readonly shadow = this.attachShadow({mode: 'open'});
+
+  private inherited = false;
+  private expanded = false;
+  private onNavigateToSource: ((event?: Event) => void) = () => {};
+
+  set data(data: ComputedStylePropertyData) {
+    this.inherited = data.inherited;
+    this.expanded = data.expanded;
+    this.onNavigateToSource = data.onNavigateToSource;
+    this.render();
+  }
+
+  isExpanded(): boolean {
+    return this.expanded;
+  }
+
+  private onSummaryClick(event: Event) {
+    event.preventDefault();
+    this.expanded = !this.expanded;
+    this.render();
+  }
+
+  private renderStyle() {
+    return html`
+      <style>
+        :host {
+          position: relative;
+          overflow: hidden;
+          flex: auto;
+          text-overflow: ellipsis;
+        }
+
+        summary {
+          outline: none;
+        }
+
+        summary::-webkit-details-marker {
+          position: absolute;
+          top: 4.5px;
+          left: 4px;
+          color: var(--active-control-bg-color, #727272);
+        }
+
+        .computed-style-property {
+          min-height: 16px;
+          padding-left: 1.4em;
+          box-sizing: border-box;
+          padding-top: 2px;
+          white-space: nowrap;
+        }
+
+        .computed-style-property:hover,
+        summary:focus .computed-style-property {
+          background-color: var(--focus-bg-color);
+          cursor: pointer;
+        }
+
+        .computed-style-property.inherited {
+          opacity: 50%;
+        }
+
+        slot[name="property-name"],
+        slot[name="property-value"] {
+          overflow: hidden;
+          text-overflow: ellipsis;
+        }
+
+        slot[name="property-name"] {
+          width: 16em;
+          max-width: 52%;
+          display: inline-block;
+          vertical-align: text-top;
+        }
+
+        slot[name="property-value"] {
+          margin-left: 2em;
+        }
+
+        .goto {
+          --size: 16px;
+          display: none;
+          position: absolute;
+          width: var(--size);
+          height: var(--size);
+          margin: -1px 0 0 calc(-1 * var(--size));
+          -webkit-mask-image: url(Images/mediumIcons.svg);
+          -webkit-mask-position: -32px 48px;
+          background-color: var(--active-control-bg-color);
+        }
+
+        .computed-style-property:hover .goto {
+          display: inline-block;
+        }
+
+        .hidden {
+          display: none;
+        }
+
+        ::slotted([slot="property-traces"]) {
+          margin-left: 16px;
+        }
+
+        /* narrowed styles */
+        :host-context(.computed-narrow) .computed-style-property {
+          white-space: normal;
+        }
+
+        :host-context(.computed-narrow) slot[name="property-name"],
+        :host-context(.computed-narrow) slot[name="property-value"] {
+          display: inline-block;
+          width: 100%;
+          max-width: 100%;
+          margin-left: 0;
+          white-space: nowrap;
+        }
+
+        :host-context(.computed-narrow) .goto {
+          display: none;
+        }
+
+        /* high-contrast styles */
+        @media (forced-colors: active) {
+          .computed-style-property.inherited {
+            opacity: 100%;
+          }
+
+          :host-context(.monospace.computed-properties) .computed-style-property:hover,
+          :host-context(.monospace.computed-properties) summary:focus .computed-style-property {
+            forced-color-adjust: none;
+            background-color: Highlight;
+          }
+
+          :host-context(.monospace.computed-properties) .computed-style-property:hover *,
+          :host-context(.monospace.computed-properties) summary:focus .computed-style-property *,
+          :host-context(.monospace.computed-properties) details[open] > summary:hover::-webkit-details-marker {
+            color: HighlightText;
+          }
+
+          :host-context(.monospace.computed-properties) .goto {
+            background-color: HighlightText;
+          }
+        }
+      </style>
+    `;
+  }
+
+  private renderProperty() {
+    return html`
+      <div class="computed-style-property ${this.inherited ? 'inherited' : ''}">
+        <slot name="property-name"></slot>
+        <span class="hidden" aria-hidden="false">: </span>
+        ${this.inherited ? null : html`
+          <span class="goto" @click=${this.onNavigateToSource}></span>
+        `}
+        <slot name="property-value"></slot>
+        <span class="hidden" aria-hidden="false">;</span>
+      </div>
+    `;
+  }
+
+  private render() {
+    // Disabled until https://crbug.com/1079231 is fixed.
+    // clang-format off
+    if (this.inherited) {
+      render(html`
+        ${this.renderStyle()}
+        ${this.renderProperty()}
+      `, this.shadow, {
+        eventContext: this,
+      });
+    } else {
+      render(html`
+        ${this.renderStyle()}
+        <details ?open=${this.expanded}>
+          <summary @click=${this.onSummaryClick}>
+            ${this.renderProperty()}
+          </summary>
+          <slot name="property-traces"></slot>
+        </details>
+      `, this.shadow, {
+        eventContext: this,
+      });
+    }
+    // clang-format on
+  }
+}
+
+customElements.define('devtools-computed-style-property', ComputedStyleProperty);
+
+declare global {
+  interface HTMLElementTagNameMap {
+    'devtools-computed-style-property': ComputedStyleProperty;
+  }
+}
diff --git a/front_end/elements/ComputedStyleProperty_bridge.js b/front_end/elements/ComputedStyleProperty_bridge.js
new file mode 100644
index 0000000..f941999
--- /dev/null
+++ b/front_end/elements/ComputedStyleProperty_bridge.js
@@ -0,0 +1,40 @@
+// Copyright 2020 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.
+
+/**
+* WARNING: do not modify this file by hand!
+* it was automatically generated by the bridge generator
+* if you made changes to the source code and need to update this file, run:
+*  npm run generate-bridge-file front_end/elements/ComputedStyleProperty.ts
+*/
+
+import './ComputedStyleProperty.js';
+/**
+* @typedef {{
+* inherited:boolean,
+* expanded:boolean,
+* onNavigateToSource:function(Event): void,
+* }}
+*/
+// @ts-ignore we export this for Closure not TS
+export let ComputedStylePropertyData;
+// eslint-disable-next-line no-unused-vars
+export class ComputedStylePropertyClosureInterface extends HTMLElement {
+  /**
+  */
+  isExpanded() {
+  }
+  /**
+  * @param {!ComputedStylePropertyData} data
+  */
+  set data(data) {
+  }
+}
+/**
+* @return {!ComputedStylePropertyClosureInterface}
+*/
+export function createComputedStyleProperty() {
+  return /** @type {!ComputedStylePropertyClosureInterface} */ (
+      document.createElement('devtools-computed-style-property'));
+}
diff --git a/front_end/elements/ComputedStyleTrace.ts b/front_end/elements/ComputedStyleTrace.ts
new file mode 100644
index 0000000..c912d96
--- /dev/null
+++ b/front_end/elements/ComputedStyleTrace.ts
@@ -0,0 +1,123 @@
+// Copyright (c) 2020 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.
+
+import * as LitHtml from '../third_party/lit-html/lit-html.js';
+
+const {render, html} = LitHtml;
+
+export interface ComputedStyleTraceData {
+  selector: string;
+  active: boolean;
+  onNavigateToSource: (event?: Event) => void;
+}
+
+export class ComputedStyleTrace extends HTMLElement {
+  private readonly shadow = this.attachShadow({mode: 'open'});
+
+  private selector = '';
+  private active = false;
+  private onNavigateToSource: ((event?: Event) => void) = () => {};
+
+  set data(data: ComputedStyleTraceData) {
+    this.selector = data.selector;
+    this.active = data.active;
+    this.onNavigateToSource = data.onNavigateToSource;
+    this.render();
+  }
+
+  private render() {
+    // Disabled until https://crbug.com/1079231 is fixed.
+    // clang-format off
+    render(html`
+      <style>
+        :host {
+          text-overflow: ellipsis;
+          overflow: hidden;
+          flex-grow: 1;
+        }
+
+        .computed-style-trace {
+          margin-left: 16px;
+        }
+
+        .computed-style-trace:hover {
+          background-color: var(--focus-bg-color);
+          cursor: pointer;
+        }
+
+        .goto {
+          /* TODO: reuse with ComputedStyleProperty */
+          --size: 16px;
+          display: none;
+          position: absolute;
+          width: var(--size);
+          height: var(--size);
+          margin: -1px 0 0 calc(-1 * var(--size));
+          -webkit-mask-image: url(Images/mediumIcons.svg);
+          -webkit-mask-position: -32px 48px;
+          background-color: var(--active-control-bg-color);
+        }
+
+        .computed-style-trace:hover .goto {
+          display: inline-block;
+        }
+
+        .trace-value {
+          margin-left: 16px;
+        }
+
+        .computed-style-trace.inactive slot[name="trace-value"] {
+          text-decoration: line-through;
+        }
+
+        .trace-selector {
+          color: gray;
+          padding-left: 2em;
+        }
+
+        ::slotted([slot="trace-link"]) {
+          user-select: none;
+          float: right;
+          padding-left: 1em;
+          position: relative;
+          z-index: 1;
+        }
+
+        /* high-contrast styles */
+        @media (forced-colors: active) {
+          :host-context(.monospace.computed-properties) .computed-style-trace:hover {
+            forced-color-adjust: none;
+            background-color: Highlight;
+          }
+
+          :host-context(.monospace.computed-properties) .goto {
+            background-color: HighlightText;
+          }
+
+          :host-context(.monospace.computed-properties) .computed-style-trace:hover * {
+            color: HighlightText;
+          }
+        }
+      </style>
+
+      <div class="computed-style-trace ${this.active ? 'active' : 'inactive'}">
+        <span class="goto" @click=${this.onNavigateToSource}></span>
+        <slot name="trace-value" @click=${this.onNavigateToSource}></slot>
+        <span class="trace-selector">${this.selector}</span>
+        <slot name="trace-link"></slot>
+      </div>
+    `, this.shadow, {
+      eventContext: this,
+    });
+    // clang-format on
+  }
+}
+
+customElements.define('devtools-computed-style-trace', ComputedStyleTrace);
+
+declare global {
+  interface HTMLElementTagNameMap {
+    'devtools-computed-style-trace': ComputedStyleTrace;
+  }
+}
diff --git a/front_end/elements/ComputedStyleTrace_bridge.js b/front_end/elements/ComputedStyleTrace_bridge.js
new file mode 100644
index 0000000..c19f7c7
--- /dev/null
+++ b/front_end/elements/ComputedStyleTrace_bridge.js
@@ -0,0 +1,35 @@
+// Copyright 2020 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.
+
+/**
+* WARNING: do not modify this file by hand!
+* it was automatically generated by the bridge generator
+* if you made changes to the source code and need to update this file, run:
+*  npm run generate-bridge-file front_end/elements/ComputedStyleTrace.ts
+*/
+
+import './ComputedStyleTrace.js';
+/**
+* @typedef {{
+* selector:string,
+* active:boolean,
+* onNavigateToSource:function(Event): void,
+* }}
+*/
+// @ts-ignore we export this for Closure not TS
+export let ComputedStyleTraceData;
+// eslint-disable-next-line no-unused-vars
+export class ComputedStyleTraceClosureInterface extends HTMLElement {
+  /**
+  * @param {!ComputedStyleTraceData} data
+  */
+  set data(data) {
+  }
+}
+/**
+* @return {!ComputedStyleTraceClosureInterface}
+*/
+export function createComputedStyleTrace() {
+  return /** @type {!ComputedStyleTraceClosureInterface} */ (document.createElement('devtools-computed-style-trace'));
+}
diff --git a/front_end/elements/ComputedStyleWidget.js b/front_end/elements/ComputedStyleWidget.js
index d7675ac..7293cea 100644
--- a/front_end/elements/ComputedStyleWidget.js
+++ b/front_end/elements/ComputedStyleWidget.js
@@ -37,6 +37,8 @@
 import * as UI from '../ui/ui.js';
 
 import {ComputedStyle, ComputedStyleModel, Events} from './ComputedStyleModel.js';  // eslint-disable-line no-unused-vars
+import {ComputedStylePropertyData, createComputedStyleProperty} from './ComputedStyleProperty_bridge.js';  // eslint-disable-line no-unused-vars
+import {createComputedStyleTrace} from './ComputedStyleTrace_bridge.js';
 import {ImagePreviewPopover} from './ImagePreviewPopover.js';
 import {PlatformFontsWidget} from './PlatformFontsWidget.js';
 import {IdleCallbackManager, StylePropertiesSection, StylesSidebarPane, StylesSidebarPropertyRenderer} from './StylesSidebarPane.js';
@@ -45,36 +47,25 @@
  * @param {!SDK.DOMModel.DOMNode} node
  * @param {string} propertyName
  * @param {string | undefined} propertyValue
- * @param {boolean} isInherited
+ * @param {!ComputedStylePropertyData} propertyData
  */
-const createPropertyElement = (node, propertyName, propertyValue, isInherited) => {
-  const propertyElement = document.createElement('div');
-  propertyElement.classList.add('computed-style-property');
-  propertyElement.classList.toggle('computed-style-property-inherited', isInherited);
+const createPropertyElement = (node, propertyName, propertyValue, propertyData) => {
+  const propertyElement = createComputedStyleProperty();
 
   const renderer = new StylesSidebarPropertyRenderer(null, node, propertyName, /** @type {string} */ (propertyValue));
   renderer.setColorHandler(processComputedColor);
+
   const propertyNameElement = renderer.renderName();
-  propertyNameElement.classList.add('property-name');
+  propertyNameElement.slot = 'property-name';
   propertyElement.appendChild(propertyNameElement);
 
-  const colon = document.createElement('span');
-  colon.classList.add('delimiter');
-  colon.textContent = ': ';
-  propertyNameElement.appendChild(colon);
+  const propertyValueElement = renderer.renderValue();
+  propertyValueElement.slot = 'property-value';
+  propertyElement.appendChild(propertyValueElement);
 
-  const propertyValueElement = propertyElement.createChild('span', 'property-value');
+  propertyElement.data = propertyData;
 
-  const propertyValueText = renderer.renderValue();
-  propertyValueText.classList.add('property-value-text');
-  propertyValueElement.appendChild(propertyValueText);
-
-  const semicolon = document.createElement('span');
-  semicolon.classList.add('delimiter');
-  semicolon.textContent = ';';
-  propertyValueElement.appendChild(semicolon);
-
-  return {propertyElement, propertyValueElement};
+  return propertyElement;
 };
 
 /**
@@ -85,33 +76,28 @@
  * @param {!Components.Linkifier.Linkifier} linkifier
  */
 const createTraceElement = (node, property, isPropertyOverloaded, matchedStyles, linkifier) => {
-  const trace = document.createElement('div');
-  trace.classList.add('property-trace');
-  if (isPropertyOverloaded) {
-    trace.classList.add('property-trace-inactive');
-  }
+  const trace = createComputedStyleTrace();
 
   const renderer = new StylesSidebarPropertyRenderer(null, node, property.name, /** @type {string} */ (property.value));
   renderer.setColorHandler(processColor);
   const valueElement = renderer.renderValue();
-  valueElement.classList.add('property-trace-value');
-  valueElement.addEventListener('click', navigateToSource.bind(null, property), false);
-  const gotoSourceElement = UI.Icon.Icon.create('mediumicon-arrow-in-circle', 'goto-source-icon');
-  gotoSourceElement.addEventListener('click', navigateToSource.bind(null, property));
-  valueElement.insertBefore(gotoSourceElement, valueElement.firstChild);
-
+  valueElement.slot = 'trace-value';
   trace.appendChild(valueElement);
 
   const rule = property.ownerStyle.parentRule;
-  const selectorElement = trace.createChild('span', 'property-trace-selector');
-  selectorElement.textContent = rule ? rule.selectorText() : 'element.style';
-  selectorElement.title = selectorElement.textContent;
-
   if (rule) {
-    const linkSpan = trace.createChild('span', 'trace-link');
+    const linkSpan = document.createElement('span');
     linkSpan.appendChild(StylePropertiesSection.createRuleOriginNode(matchedStyles, linkifier, rule));
+    linkSpan.slot = 'trace-link';
+    trace.appendChild(linkSpan);
   }
 
+  trace.data = {
+    selector: rule ? rule.selectorText() : 'element.style',
+    active: !isPropertyOverloaded,
+    onNavigateToSource: /** @type {function(?Event):void} */ (navigateToSource.bind(null, property)),
+  };
+
   return trace;
 };
 
@@ -285,9 +271,12 @@
     /** @type {!Set<string>} */
     const expandedProperties = new Set();
     for (const treeElement of this._propertiesOutline.rootElement().children()) {
-      if (!treeElement.expanded) {
+      const computedStylePropertyElement =
+          treeElement.listItemElement.querySelector('devtools-computed-style-property');
+      if (!computedStylePropertyElement || !(computedStylePropertyElement.isExpanded() || treeElement.expanded)) {
         continue;
       }
+
       const propertyName = treeElement[_propertySymbol].name;
       expandedProperties.add(propertyName);
     }
@@ -313,6 +302,7 @@
     for (const propertyName of uniqueProperties) {
       const propertyValue = nodeStyle.computedStyle.get(propertyName);
       const canonicalName = SDK.CSSMetadata.cssMetadata().canonicalPropertyName(propertyName);
+      // TODO(changhaohan): refactor this variable to make the legacy "inherited" logic clear
       const isInherited = !inheritedProperties.has(canonicalName);
       if (!showInherited && isInherited && !_alwaysShownComputedProperties.has(propertyName)) {
         continue;
@@ -339,19 +329,16 @@
 
       this._idleCallbackManager.schedule(() => {
         for (const {propertyName, propertyValue, isInherited} of currentBatch) {
-          const {propertyElement, propertyValueElement} =
-              createPropertyElement(node, propertyName, propertyValue, isInherited);
           const treeElement = new UI.TreeOutline.TreeElement();
-          treeElement.title = propertyElement;
-          treeElement[_propertySymbol] = {name: propertyName, value: propertyValue};
-          if (!this._propertiesOutline.selectedTreeElement) {
-            treeElement.select(!hadFocus);
-          }
-
           const trace = propertyTraces.get(propertyName);
+          /** @type {function(?Event):void} */
+          let navigate = () => {};
+          const traceContainer = document.createElement('div');
+          traceContainer.slot = 'property-traces';
           if (trace) {
             const activeProperty = this._renderPropertyTrace(
-                /** @type {!SDK.CSSMatchedStyles.CSSMatchedStyles} */ (matchedStyles), node, treeElement, trace);
+                /** @type {!SDK.CSSMatchedStyles.CSSMatchedStyles} */ (matchedStyles), node, traceContainer, trace);
+            treeElement.setExpandable(true);
             treeElement.listItemElement.addEventListener('mousedown', e => e.consume(), false);
             treeElement.listItemElement.addEventListener('dblclick', e => e.consume(), false);
             treeElement.listItemElement.addEventListener('click', handleClick.bind(null, treeElement), false);
@@ -359,12 +346,24 @@
                 'contextmenu',
                 this._handleContextMenuEvent.bind(
                     this, /** @type {!SDK.CSSMatchedStyles.CSSMatchedStyles} */ (matchedStyles), activeProperty));
-            const gotoSourceElement = UI.Icon.Icon.create('mediumicon-arrow-in-circle', 'goto-source-icon');
-            gotoSourceElement.addEventListener('click', navigateToSource.bind(this, activeProperty));
-            propertyValueElement.appendChild(gotoSourceElement);
-            if (expandedProperties.has(propertyName)) {
-              treeElement.expand();
-            }
+            navigate = /** @type {function(?Event):void} */ (navigateToSource.bind(this, activeProperty));
+          }
+
+          const isExpanded = expandedProperties.has(propertyName);
+          if (isExpanded) {
+            treeElement.expand();
+          }
+          const propertyElement = createPropertyElement(node, propertyName, propertyValue, {
+            inherited: isInherited,
+            expanded: isExpanded,
+            onNavigateToSource: navigate,
+          });
+          propertyElement.appendChild(traceContainer);
+
+          treeElement.title = propertyElement;
+          treeElement[_propertySymbol] = {name: propertyName, value: propertyValue};
+          if (!this._propertiesOutline.selectedTreeElement) {
+            treeElement.select(!hadFocus);
           }
 
           this._propertiesOutline.appendChild(treeElement);
@@ -414,11 +413,11 @@
   /**
    * @param {!SDK.CSSMatchedStyles.CSSMatchedStyles} matchedStyles
    * @param {!SDK.DOMModel.DOMNode} node
-   * @param {!UI.TreeOutline.TreeElement} rootTreeElement
+   * @param {!Element} rootElement
    * @param {!Array<!SDK.CSSProperty.CSSProperty>} tracedProperties
    * @return {!SDK.CSSProperty.CSSProperty}
    */
-  _renderPropertyTrace(matchedStyles, node, rootTreeElement, tracedProperties) {
+  _renderPropertyTrace(matchedStyles, node, rootElement, tracedProperties) {
     let activeProperty = null;
     for (const property of tracedProperties) {
       const isPropertyOverloaded =
@@ -427,13 +426,8 @@
         activeProperty = property;
       }
       const trace = createTraceElement(node, property, isPropertyOverloaded, matchedStyles, this._linkifier);
-
-      const traceTreeElement = new UI.TreeOutline.TreeElement();
-      traceTreeElement.title = trace;
-
-      traceTreeElement.listItemElement.addEventListener(
-          'contextmenu', this._handleContextMenuEvent.bind(this, matchedStyles, property));
-      rootTreeElement.appendChild(traceTreeElement);
+      trace.addEventListener('contextmenu', this._handleContextMenuEvent.bind(this, matchedStyles, property));
+      rootElement.appendChild(trace);
     }
     return /** @type {!SDK.CSSProperty.CSSProperty} */ (activeProperty);
   }
diff --git a/front_end/elements/computedStyleWidgetTree.css b/front_end/elements/computedStyleWidgetTree.css
index 02da103..59b5425 100644
--- a/front_end/elements/computedStyleWidgetTree.css
+++ b/front_end/elements/computedStyleWidgetTree.css
@@ -4,85 +4,8 @@
  * found in the LICENSE file.
  */
 
-.computed-style-property {
-  overflow: hidden;
-  flex: auto;
-  text-overflow: ellipsis;
-}
-
-.computed-style-property .property-name {
-  width: 16em;
-  text-overflow: ellipsis;
-  overflow: hidden;
-  max-width: 52%;
-  display: inline-block;
-  vertical-align: text-top;
-}
-
-.computed-style-property .property-value {
-  margin-left: 2em;
-  position: relative;
-}
-
-.computed-style-property .property-value-text {
-  overflow: hidden;
-  text-overflow: ellipsis;
-}
-
-.goto-source-icon {
-  background-color: #5a5a5a;
-  display: none;
-  position: absolute;
-  left: -16px;
-  top: 0;
-}
-
-.goto-source-icon:hover {
-  background-color: #333;
-}
-
-.tree-outline li:hover .goto-source-icon {
-  display: block;
-  margin-top: -2px;
-}
-
-.computed-style-property-inherited {
-  opacity: 50%;
-}
-
-.trace-link {
-  user-select: none;
-  float: right;
-  padding-left: 1em;
-  position: relative;
-  z-index: 1;
-}
-
-.property-trace {
-  text-overflow: ellipsis;
-  overflow: hidden;
-  flex-grow: 1;
-}
-
-.property-trace-selector {
-  color: gray;
-  padding-left: 2em;
-}
-
-.property-trace-value {
-  position: relative;
-  display: inline-block;
-  margin-left: 16px;
-}
-
-.property-trace-inactive .property-trace-value::before {
-  position: absolute;
-  content: ".";
-  border-bottom: 1px solid rgb(0 0 0 / 35%);
-  top: 0;
-  bottom: 5px;
-  left: 0;
-  right: 0;
+.tree-outline li::before {
+  content: none;
 }
 
 .tree-outline li.even-row {
@@ -94,65 +17,3 @@
 .tree-outline ol {
   padding-left: 0;
 }
-
-.tree-outline li:hover {
-  background-color: rgb(235 242 252);
-  cursor: pointer;
-}
-
-.tree-outline li::before {
-  margin-left: 4px;
-}
-
-.delimiter {
-  color: transparent;
-}
-
-.delimiter::selection {
-  color: transparent;
-}
-
-.computed-narrow .computed-style-property .property-name,
-.computed-narrow .computed-style-property .property-value {
-  display: inline-block;
-  width: 100%;
-  max-width: 100%;
-  margin-left: 0;
-  white-space: nowrap;
-}
-
-.computed-narrow .computed-style-property {
-  padding: 2px 0;
-  display: block;
-  white-space: normal;
-}
-
-.computed-narrow.tree-outline li::before {
-  margin-top: -14px;
-}
-
-@media (forced-colors: active) {
-  .computed-style-property-inherited {
-    opacity: 100%;
-  }
-
-  :host-context(.monospace.computed-properties) .tree-outline li:hover {
-    forced-color-adjust: none;
-    background-color: Highlight;
-  }
-
-  :host-context(.monospace.computed-properties) .tree-outline:not(.hide-selection-when-blurred) li.parent:hover.selected::before,
-  :host-context(.monospace.computed-properties) .tree-outline-disclosure li.parent:hover::before,
-  :host-context(.monospace.computed-properties) .tree-outline li:hover .goto-source-icon {
-    background-color: HighlightText;
-  }
-
-  :host-context(.monospace.computed-properties) .tree-outline li:hover * {
-    color: HighlightText;
-  }
-
-  .property-trace-inactive .property-trace-value::before {
-    content: "";
-    border-bottom-color: HighlightText !important;
-  }
-}
diff --git a/front_end/elements/module.json b/front_end/elements/module.json
index 18a1feb..830ba8a 100644
--- a/front_end/elements/module.json
+++ b/front_end/elements/module.json
@@ -331,6 +331,8 @@
     "StylesSidebarPane.js",
     "StylePropertyTreeElement.js",
     "ComputedStyleWidget.js",
+    "ComputedStyleProperty_bridge.js",
+    "ComputedStyleTrace_bridge.js",
     "ElementsPanel.js",
     "ClassesPaneWidget.js",
     "ElementStatePaneWidget.js",