chrome-devtools-frontend 1.0.975541 → 1.0.976570
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AUTHORS +1 -0
- package/config/gni/devtools_grd_files.gni +5 -0
- package/config/gni/devtools_image_files.gni +2 -0
- package/front_end/Images/src/minus_icon.svg +3 -0
- package/front_end/Images/src/plus_icon.svg +3 -0
- package/front_end/core/sdk/CSSModel.ts +4 -0
- package/front_end/generated/InspectorBackendCommands.js +1 -1
- package/front_end/generated/protocol.ts +1 -0
- package/front_end/panels/elements/LayersWidget.ts +3 -2
- package/front_end/panels/elements/StylesSidebarPane.ts +8 -5
- package/front_end/panels/settings/components/SyncSection.ts +5 -17
- package/front_end/panels/sources/CSSPlugin.ts +77 -22
- package/front_end/ui/components/chrome_link/ChromeLink.ts +62 -0
- package/front_end/ui/components/chrome_link/chromeLink.css +12 -0
- package/front_end/ui/components/chrome_link/chrome_link.ts +9 -0
- package/package.json +1 -1
package/AUTHORS
CHANGED
@@ -29,6 +29,7 @@ Feng Lu <lufengd3@gmail.com>
|
|
29
29
|
Gabriel Luong <gabriel.luong@gmail.com>
|
30
30
|
Gautham Banasandra <gautham.bangalore@gmail.com>
|
31
31
|
Jake Mulhern <mulherje@gmail.com>
|
32
|
+
Jan Keitel <jan.keitel@gmail.com>
|
32
33
|
Jeffrey Chen <jeffreyca16@gmail.com>
|
33
34
|
Jesper van den Ende <jespertheend@gmail.com>
|
34
35
|
Juba Borgohain <chromiumjuba@gmail.com>
|
@@ -114,12 +114,14 @@ grd_files_release_sources = [
|
|
114
114
|
"front_end/Images/lighthouse_logo.svg",
|
115
115
|
"front_end/Images/link_icon.svg",
|
116
116
|
"front_end/Images/mediumIcons.svg",
|
117
|
+
"front_end/Images/minus_icon.svg",
|
117
118
|
"front_end/Images/navigationControls.png",
|
118
119
|
"front_end/Images/navigationControls_2x.png",
|
119
120
|
"front_end/Images/network_conditions_icon.svg",
|
120
121
|
"front_end/Images/network_panel_icon.svg",
|
121
122
|
"front_end/Images/nodeIcon.avif",
|
122
123
|
"front_end/Images/node_search_icon.svg",
|
124
|
+
"front_end/Images/plus_icon.svg",
|
123
125
|
"front_end/Images/popoverArrows.png",
|
124
126
|
"front_end/Images/preview_feature_video_thumbnail.svg",
|
125
127
|
"front_end/Images/profileGroupIcon.png",
|
@@ -480,6 +482,7 @@ grd_files_release_sources = [
|
|
480
482
|
"front_end/third_party/wasmparser/wasmparser.js",
|
481
483
|
"front_end/ui/components/adorners/adorners.js",
|
482
484
|
"front_end/ui/components/buttons/buttons.js",
|
485
|
+
"front_end/ui/components/chrome_link/chrome_link.js",
|
483
486
|
"front_end/ui/components/code_highlighter/code_highlighter.js",
|
484
487
|
"front_end/ui/components/data_grid/data_grid.js",
|
485
488
|
"front_end/ui/components/diff_view/diff_view.js",
|
@@ -1400,6 +1403,8 @@ grd_files_debug_sources = [
|
|
1400
1403
|
"front_end/ui/components/adorners/adorner.css.js",
|
1401
1404
|
"front_end/ui/components/buttons/Button.js",
|
1402
1405
|
"front_end/ui/components/buttons/button.css.js",
|
1406
|
+
"front_end/ui/components/chrome_link/ChromeLink.js",
|
1407
|
+
"front_end/ui/components/chrome_link/chromeLink.css.js",
|
1403
1408
|
"front_end/ui/components/code_highlighter/CodeHighlighter.js",
|
1404
1409
|
"front_end/ui/components/code_highlighter/codeHighlighter.css.js",
|
1405
1410
|
"front_end/ui/components/data_grid/DataGrid.js",
|
@@ -124,9 +124,11 @@ devtools_svg_sources = [
|
|
124
124
|
"lighthouse_logo.svg",
|
125
125
|
"link_icon.svg",
|
126
126
|
"mediumIcons.svg",
|
127
|
+
"minus_icon.svg",
|
127
128
|
"network_conditions_icon.svg",
|
128
129
|
"network_panel_icon.svg",
|
129
130
|
"node_search_icon.svg",
|
131
|
+
"plus_icon.svg",
|
130
132
|
"preview_feature_video_thumbnail.svg",
|
131
133
|
"refresh_12x12_icon.svg",
|
132
134
|
"resizeDiagonal.svg",
|
@@ -150,6 +150,10 @@ export class CSSModel extends SDKModel<EventTypes> {
|
|
150
150
|
return this.#sourceMapManager;
|
151
151
|
}
|
152
152
|
|
153
|
+
static readableLayerName(text: string): string {
|
154
|
+
return text || '<anonymous>';
|
155
|
+
}
|
156
|
+
|
153
157
|
static trimSourceURL(text: string): string {
|
154
158
|
let sourceURLIndex = text.lastIndexOf('/*# sourceURL=');
|
155
159
|
if (sourceURLIndex === -1) {
|
@@ -1877,7 +1877,7 @@ export function registerCommands(inspectorBackend) {
|
|
1877
1877
|
// Overlay.
|
1878
1878
|
inspectorBackend.registerEnum('Overlay.LineStylePattern', {Dashed: 'dashed', Dotted: 'dotted'});
|
1879
1879
|
inspectorBackend.registerEnum('Overlay.ContrastAlgorithm', {Aa: 'aa', Aaa: 'aaa', Apca: 'apca'});
|
1880
|
-
inspectorBackend.registerEnum('Overlay.ColorFormat', {Rgb: 'rgb', Hsl: 'hsl', Hex: 'hex'});
|
1880
|
+
inspectorBackend.registerEnum('Overlay.ColorFormat', {Rgb: 'rgb', Hsl: 'hsl', Hwb: 'hwb', Hex: 'hex'});
|
1881
1881
|
inspectorBackend.registerEnum('Overlay.InspectMode', {
|
1882
1882
|
SearchForNode: 'searchForNode',
|
1883
1883
|
SearchForUAShadowDOM: 'searchForUAShadowDOM',
|
@@ -84,8 +84,9 @@ export class LayersWidget extends UI.Widget.Widget {
|
|
84
84
|
const makeTreeNode = (parentId: string) =>
|
85
85
|
(layer: Protocol.CSS.CSSLayerData): TreeOutline.TreeOutlineUtils.TreeNode<string> => {
|
86
86
|
const subLayers = layer.subLayers;
|
87
|
-
const
|
88
|
-
const
|
87
|
+
const name = SDK.CSSModel.CSSModel.readableLayerName(layer.name);
|
88
|
+
const treeNodeData = layer.order + ': ' + name;
|
89
|
+
const id = parentId ? parentId + '.' + name : name;
|
89
90
|
if (!subLayers) {
|
90
91
|
return {treeNodeData, id};
|
91
92
|
}
|
@@ -875,7 +875,7 @@ export class StylesSidebarPane extends Common.ObjectWrapper.eventMixin<EventType
|
|
875
875
|
if (parentRule instanceof SDK.CSSRule.CSSStyleRule) {
|
876
876
|
const layers = parentRule.layers;
|
877
877
|
if ((layers.length || lastLayers) && lastLayers !== layers) {
|
878
|
-
const block = SectionBlock.createLayerBlock(
|
878
|
+
const block = SectionBlock.createLayerBlock(parentRule);
|
879
879
|
blocks.push(block);
|
880
880
|
sawLayers = true;
|
881
881
|
lastLayers = layers;
|
@@ -1430,18 +1430,21 @@ export class SectionBlock {
|
|
1430
1430
|
return new SectionBlock(separatorElement);
|
1431
1431
|
}
|
1432
1432
|
|
1433
|
-
static createLayerBlock(
|
1433
|
+
static createLayerBlock(rule: SDK.CSSRule.CSSStyleRule): SectionBlock {
|
1434
1434
|
const separatorElement = document.createElement('div');
|
1435
1435
|
separatorElement.className = 'sidebar-separator layer-separator';
|
1436
1436
|
UI.UIUtils.createTextChild(separatorElement.createChild('div'), i18nString(UIStrings.layer));
|
1437
|
-
|
1438
|
-
|
1437
|
+
const layers = rule.layers;
|
1438
|
+
if (!layers.length && rule.origin === Protocol.CSS.StyleSheetOrigin.UserAgent) {
|
1439
|
+
const name = rule.origin === Protocol.CSS.StyleSheetOrigin.UserAgent ? '\xa0user\xa0agent\xa0stylesheet' :
|
1440
|
+
'\xa0implicit\xa0outer\xa0layer';
|
1441
|
+
UI.UIUtils.createTextChild(separatorElement.createChild('div'), name);
|
1439
1442
|
return new SectionBlock(separatorElement);
|
1440
1443
|
}
|
1441
1444
|
const layerLink = separatorElement.createChild('button') as HTMLButtonElement;
|
1442
1445
|
layerLink.className = 'link';
|
1443
1446
|
layerLink.title = i18nString(UIStrings.clickToRevealLayer);
|
1444
|
-
const name = layers.map(layer => layer.text
|
1447
|
+
const name = layers.map(layer => SDK.CSSModel.CSSModel.readableLayerName(layer.text)).join('.');
|
1445
1448
|
layerLink.textContent = name;
|
1446
1449
|
layerLink.onclick = (): Promise<void> => LayersWidget.LayersWidget.instance().revealLayer(name);
|
1447
1450
|
return new SectionBlock(separatorElement);
|
@@ -8,7 +8,7 @@ import type * as Host from '../../../core/host/host.js';
|
|
8
8
|
import * as i18n from '../../../core/i18n/i18n.js';
|
9
9
|
import * as LitHtml from '../../../ui/lit-html/lit-html.js';
|
10
10
|
import * as Settings from '../../../ui/components/settings/settings.js';
|
11
|
-
import * as
|
11
|
+
import * as ChromeLink from '../../../ui/components/chrome_link/chrome_link.js';
|
12
12
|
|
13
13
|
import syncSectionStyles from './syncSection.css.js';
|
14
14
|
|
@@ -92,9 +92,8 @@ function renderAccountInfoOrWarning(syncInfo: Host.InspectorFrontendHostAPI.Sync
|
|
92
92
|
// clang-format off
|
93
93
|
return LitHtml.html`
|
94
94
|
<span class="warning">
|
95
|
-
${i18nString(UIStrings.syncDisabled)}
|
96
|
-
|
97
|
-
@keydown=${(e: Event): void => openSettingsTab(link, e)}>${i18nString(UIStrings.settings)}</x-link>
|
95
|
+
${i18nString(UIStrings.syncDisabled)}
|
96
|
+
<${ChromeLink.ChromeLink.ChromeLink.litTagName} .href=${link}>${i18nString(UIStrings.settings)}</${ChromeLink.ChromeLink.ChromeLink.litTagName}>
|
98
97
|
</span>`;
|
99
98
|
// clang-format on
|
100
99
|
}
|
@@ -104,9 +103,8 @@ function renderAccountInfoOrWarning(syncInfo: Host.InspectorFrontendHostAPI.Sync
|
|
104
103
|
// clang-format off
|
105
104
|
return LitHtml.html`
|
106
105
|
<span class="warning">
|
107
|
-
${i18nString(UIStrings.preferencesSyncDisabled)}
|
108
|
-
|
109
|
-
@keydown=${(e: Event): void => openSettingsTab(link, e)}>${i18nString(UIStrings.settings)}</x-link>
|
106
|
+
${i18nString(UIStrings.preferencesSyncDisabled)}
|
107
|
+
<${ChromeLink.ChromeLink.ChromeLink.litTagName} .href=${link}>${i18nString(UIStrings.settings)}</${ChromeLink.ChromeLink.ChromeLink.litTagName}>
|
110
108
|
</span>`;
|
111
109
|
// clang-format on
|
112
110
|
}
|
@@ -120,16 +118,6 @@ function renderAccountInfoOrWarning(syncInfo: Host.InspectorFrontendHostAPI.Sync
|
|
120
118
|
</div>`;
|
121
119
|
}
|
122
120
|
|
123
|
-
// Navigating to a chrome:// link via a normal anchor doesn't work, so we "navigate"
|
124
|
-
// there using CDP.
|
125
|
-
function openSettingsTab(url: string, event: Event): void {
|
126
|
-
if (event.type === 'click' || (event.type === 'keydown' && self.isEnterOrSpaceKey(event))) {
|
127
|
-
const mainTarget = SDK.TargetManager.TargetManager.instance().mainTarget();
|
128
|
-
mainTarget && mainTarget.targetAgent().invoke_createTarget({url});
|
129
|
-
event.consume(true);
|
130
|
-
}
|
131
|
-
}
|
132
|
-
|
133
121
|
ComponentHelpers.CustomElements.defineComponent('devtools-sync-section', SyncSection);
|
134
122
|
|
135
123
|
declare global {
|
@@ -4,13 +4,17 @@
|
|
4
4
|
|
5
5
|
import * as Common from '../../core/common/common.js';
|
6
6
|
import * as i18n from '../../core/i18n/i18n.js';
|
7
|
+
import * as Platform from '../../core/platform/platform.js';
|
7
8
|
import * as SDK from '../../core/sdk/sdk.js';
|
9
|
+
import type * as Protocol from '../../generated/protocol.js';
|
8
10
|
import type * as Workspace from '../../models/workspace/workspace.js';
|
9
11
|
import * as ColorPicker from '../../ui/legacy/components/color_picker/color_picker.js';
|
10
12
|
import * as InlineEditor from '../../ui/legacy/components/inline_editor/inline_editor.js';
|
11
13
|
import * as CodeMirror from '../../third_party/codemirror.next/codemirror.next.js';
|
14
|
+
import type * as SourceFrame from '../../ui/legacy/components/source_frame/source_frame.js';
|
12
15
|
import * as UI from '../../ui/legacy/legacy.js';
|
13
16
|
|
17
|
+
import {assertNotNullOrUndefined} from '../../core/platform/platform.js';
|
14
18
|
import {Plugin} from './Plugin.js';
|
15
19
|
|
16
20
|
// Plugin to add CSS completion, shortcuts, and color/curve swatches
|
@@ -29,17 +33,6 @@ const UIStrings = {
|
|
29
33
|
const str_ = i18n.i18n.registerUIStrings('panels/sources/CSSPlugin.ts', UIStrings);
|
30
34
|
const i18nString = i18n.i18n.getLocalizedString.bind(undefined, str_);
|
31
35
|
|
32
|
-
export function completion(): CodeMirror.Extension {
|
33
|
-
const {cssCompletionSource} = CodeMirror.css;
|
34
|
-
return CodeMirror.autocompletion({
|
35
|
-
override:
|
36
|
-
[async(cx: CodeMirror.CompletionContext):
|
37
|
-
Promise<CodeMirror.CompletionResult|null> => {
|
38
|
-
return (await specificCssCompletion(cx)) || cssCompletionSource(cx);
|
39
|
-
}],
|
40
|
-
});
|
41
|
-
}
|
42
|
-
|
43
36
|
const dontCompleteIn = new Set(['ColorLiteral', 'NumberLiteral', 'StringLiteral', 'Comment', 'Important']);
|
44
37
|
|
45
38
|
function findPropertyAt(node: CodeMirror.SyntaxNode, pos: number): CodeMirror.SyntaxNode|null {
|
@@ -57,18 +50,43 @@ function findPropertyAt(node: CodeMirror.SyntaxNode, pos: number): CodeMirror.Sy
|
|
57
50
|
return null;
|
58
51
|
}
|
59
52
|
|
60
|
-
function
|
53
|
+
function getCurrentStyleSheet(
|
54
|
+
url: Platform.DevToolsPath.UrlString, cssModel: SDK.CSSModel.CSSModel): Protocol.CSS.StyleSheetId {
|
55
|
+
const currentStyleSheet = cssModel.getStyleSheetIdsForURL(url);
|
56
|
+
if (currentStyleSheet.length === 0) {
|
57
|
+
Platform.DCHECK(() => currentStyleSheet.length !== 0, 'Can\'t find style sheet ID for current URL');
|
58
|
+
}
|
59
|
+
|
60
|
+
return currentStyleSheet[0];
|
61
|
+
}
|
62
|
+
|
63
|
+
async function specificCssCompletion(
|
64
|
+
cx: CodeMirror.CompletionContext, uiSourceCode: Workspace.UISourceCode.UISourceCode,
|
65
|
+
cssModel: SDK.CSSModel.CSSModel|undefined): Promise<CodeMirror.CompletionResult|null> {
|
61
66
|
const node = CodeMirror.syntaxTree(cx.state).resolveInner(cx.pos, -1);
|
67
|
+
if (node.name === 'ClassName') {
|
68
|
+
// Should never happen, but let's code defensively here
|
69
|
+
assertNotNullOrUndefined(cssModel);
|
70
|
+
|
71
|
+
const currentStyleSheet = getCurrentStyleSheet(uiSourceCode.url(), cssModel);
|
72
|
+
const existingClassNames = await cssModel.classNamesPromise(currentStyleSheet);
|
73
|
+
|
74
|
+
return {
|
75
|
+
from: node.from,
|
76
|
+
options: existingClassNames.map(value => ({type: 'constant', label: value})),
|
77
|
+
};
|
78
|
+
}
|
62
79
|
const property = findPropertyAt(node, cx.pos);
|
63
|
-
if (
|
64
|
-
|
80
|
+
if (property) {
|
81
|
+
const propertyValues =
|
82
|
+
SDK.CSSMetadata.cssMetadata().getPropertyValues(cx.state.sliceDoc(property.from, property.to));
|
83
|
+
return {
|
84
|
+
from: node.name === 'ValueName' ? node.from : cx.pos,
|
85
|
+
options: propertyValues.map(value => ({type: 'constant', label: value})),
|
86
|
+
span: /^[\w\P{ASCII}\-]+$/u,
|
87
|
+
};
|
65
88
|
}
|
66
|
-
|
67
|
-
return {
|
68
|
-
from: node.name === 'ValueName' ? node.from : cx.pos,
|
69
|
-
options: propertyValues.map(value => ({type: 'constant', label: value})),
|
70
|
-
span: /^[\w\P{ASCII}\-]+$/u,
|
71
|
-
};
|
89
|
+
return null;
|
72
90
|
}
|
73
91
|
|
74
92
|
function findColorsAndCurves(
|
@@ -380,12 +398,49 @@ export function cssBindings(): CodeMirror.Extension {
|
|
380
398
|
});
|
381
399
|
}
|
382
400
|
|
383
|
-
export class CSSPlugin extends Plugin {
|
401
|
+
export class CSSPlugin extends Plugin implements SDK.TargetManager.SDKModelObserver<SDK.CSSModel.CSSModel> {
|
402
|
+
#cssModel?: SDK.CSSModel.CSSModel;
|
403
|
+
|
404
|
+
constructor(uiSourceCode: Workspace.UISourceCode.UISourceCode, _transformer?: SourceFrame.SourceFrame.Transformer) {
|
405
|
+
super(uiSourceCode, _transformer);
|
406
|
+
SDK.TargetManager.TargetManager.instance().observeModels(SDK.CSSModel.CSSModel, this);
|
407
|
+
}
|
408
|
+
|
384
409
|
static accepts(uiSourceCode: Workspace.UISourceCode.UISourceCode): boolean {
|
385
410
|
return uiSourceCode.contentType().isStyleSheet();
|
386
411
|
}
|
387
412
|
|
413
|
+
modelAdded(cssModel: SDK.CSSModel.CSSModel): void {
|
414
|
+
if (this.#cssModel) {
|
415
|
+
return;
|
416
|
+
}
|
417
|
+
this.#cssModel = cssModel;
|
418
|
+
}
|
419
|
+
modelRemoved(cssModel: SDK.CSSModel.CSSModel): void {
|
420
|
+
if (this.#cssModel === cssModel) {
|
421
|
+
this.#cssModel = undefined;
|
422
|
+
}
|
423
|
+
}
|
424
|
+
|
388
425
|
editorExtension(): CodeMirror.Extension {
|
389
|
-
return [cssBindings(),
|
426
|
+
return [cssBindings(), this.#cssCompletion(), cssSwatches()];
|
427
|
+
}
|
428
|
+
|
429
|
+
#cssCompletion(): CodeMirror.Extension {
|
430
|
+
const {cssCompletionSource} = CodeMirror.css;
|
431
|
+
|
432
|
+
// CodeMirror binds the function below to the state object.
|
433
|
+
// Therefore, we can't access `this` and retrieve the following properties.
|
434
|
+
// Instead, retrieve them up front to bind them to the correct closure.
|
435
|
+
const uiSourceCode = this.uiSourceCode;
|
436
|
+
const cssModel = this.#cssModel;
|
437
|
+
|
438
|
+
return CodeMirror.autocompletion({
|
439
|
+
override:
|
440
|
+
[async(cx: CodeMirror.CompletionContext):
|
441
|
+
Promise<CodeMirror.CompletionResult|null> => {
|
442
|
+
return (await specificCssCompletion(cx, uiSourceCode, cssModel)) || cssCompletionSource(cx);
|
443
|
+
}],
|
444
|
+
});
|
390
445
|
}
|
391
446
|
}
|
@@ -0,0 +1,62 @@
|
|
1
|
+
// Copyright 2022 The Chromium Authors. All rights reserved.
|
2
|
+
// Use of this source code is governed by a BSD-style license that can be
|
3
|
+
// found in the LICENSE file.
|
4
|
+
|
5
|
+
import * as SDK from '../../../core/sdk/sdk.js';
|
6
|
+
import * as LitHtml from '../../lit-html/lit-html.js';
|
7
|
+
import * as ComponentHelpers from '../helpers/helpers.js';
|
8
|
+
|
9
|
+
import chromeLinkStyles from './chromeLink.css.js';
|
10
|
+
|
11
|
+
declare global {
|
12
|
+
interface HTMLElementTagNameMap {
|
13
|
+
'devtools-chrome-link': ChromeLink;
|
14
|
+
}
|
15
|
+
}
|
16
|
+
|
17
|
+
// Use this component to render links to 'chrome://...'-URLs
|
18
|
+
// (for which regular <x-link>s do not work).
|
19
|
+
export class ChromeLink extends HTMLElement {
|
20
|
+
static readonly litTagName = LitHtml.literal`devtools-chrome-link`;
|
21
|
+
readonly #shadow = this.attachShadow({mode: 'open'});
|
22
|
+
readonly #boundRender = this.#render.bind(this);
|
23
|
+
#href: string = '';
|
24
|
+
|
25
|
+
connectedCallback(): void {
|
26
|
+
this.#shadow.adoptedStyleSheets = [chromeLinkStyles];
|
27
|
+
void ComponentHelpers.ScheduledRender.scheduleRender(this, this.#boundRender);
|
28
|
+
}
|
29
|
+
|
30
|
+
set href(href: string) {
|
31
|
+
if (!href.startsWith('chrome://')) {
|
32
|
+
throw new Error('ChromeLink href needs to start with \'chrome://\'');
|
33
|
+
}
|
34
|
+
this.#href = href;
|
35
|
+
void ComponentHelpers.ScheduledRender.scheduleRender(this, this.#boundRender);
|
36
|
+
}
|
37
|
+
|
38
|
+
// Navigating to a chrome:// link via a normal anchor doesn't work, so we "navigate"
|
39
|
+
// there using CDP.
|
40
|
+
openSettingsTab(event: Event): void {
|
41
|
+
if (event.type === 'click' || (event.type === 'keydown' && self.isEnterOrSpaceKey(event))) {
|
42
|
+
const mainTarget = SDK.TargetManager.TargetManager.instance().mainTarget();
|
43
|
+
mainTarget && mainTarget.targetAgent().invoke_createTarget({url: this.#href});
|
44
|
+
event.consume(true);
|
45
|
+
}
|
46
|
+
}
|
47
|
+
|
48
|
+
#render(): void {
|
49
|
+
// clang-format off
|
50
|
+
LitHtml.render(
|
51
|
+
/* x-link doesn't work with custom click/keydown handlers */
|
52
|
+
/* eslint-disable rulesdir/ban_a_tags_in_lit_html */
|
53
|
+
LitHtml.html`
|
54
|
+
<a href=${this.#href} class="link" target="_blank"
|
55
|
+
@click=${this.openSettingsTab}
|
56
|
+
@keydown=${this.openSettingsTab}><slot></slot></a>
|
57
|
+
`, this.#shadow, {host: this});
|
58
|
+
// clang-format on
|
59
|
+
}
|
60
|
+
}
|
61
|
+
|
62
|
+
ComponentHelpers.CustomElements.defineComponent('devtools-chrome-link', ChromeLink);
|
@@ -0,0 +1,12 @@
|
|
1
|
+
/*
|
2
|
+
* Copyright 2022 The Chromium Authors. All rights reserved.
|
3
|
+
* Use of this source code is governed by a BSD-style license that can be
|
4
|
+
* found in the LICENSE file.
|
5
|
+
*/
|
6
|
+
|
7
|
+
.link {
|
8
|
+
color: var(--color-link);
|
9
|
+
text-decoration: underline;
|
10
|
+
cursor: pointer;
|
11
|
+
padding: 2px 0; /* adjust focus ring size */
|
12
|
+
}
|
package/package.json
CHANGED