chrome-devtools-frontend 1.0.1537268 → 1.0.1538310
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/.env.template +10 -0
- package/docs/get_the_code.md +27 -0
- package/eslint.config.mjs +151 -149
- package/front_end/core/common/SettingRegistration.ts +10 -7
- package/front_end/core/common/Settings.ts +3 -0
- package/front_end/core/host/AidaClient.ts +1 -0
- package/front_end/core/host/UserMetrics.ts +3 -1
- package/front_end/core/root/Runtime.ts +8 -0
- package/front_end/core/sdk/sdk-meta.ts +8 -2
- package/front_end/entrypoints/inspector_main/RenderingOptions.ts +4 -3
- package/front_end/generated/SupportedCSSProperties.js +1 -0
- package/front_end/models/ai_assistance/agents/PerformanceAgent.ts +23 -7
- package/front_end/models/ai_assistance/data_formatters/PerformanceTraceFormatter.snapshot.txt +110 -5
- package/front_end/models/ai_assistance/data_formatters/PerformanceTraceFormatter.ts +50 -45
- package/front_end/models/ai_code_generation/AiCodeGeneration.ts +151 -0
- package/front_end/models/ai_code_generation/ai_code_generation.ts +6 -0
- package/front_end/models/ai_code_generation/debug.ts +30 -0
- package/front_end/models/cpu_profile/ProfileTreeModel.ts +7 -7
- package/front_end/models/trace_source_maps_resolver/SourceMapsResolver.ts +1 -1
- package/front_end/panels/application/PreloadingTreeElement.ts +10 -2
- package/front_end/panels/application/StorageView.ts +3 -2
- package/front_end/panels/application/components/BackForwardCacheView.ts +34 -51
- package/front_end/panels/application/components/OriginTrialTreeView.ts +141 -170
- package/front_end/panels/application/components/backForwardCacheView.css +4 -0
- package/front_end/panels/application/components/originTrialTreeView.css +37 -7
- package/front_end/panels/application/preloading/components/PreloadingGrid.ts +2 -2
- package/front_end/panels/application/preloading/components/PreloadingString.ts +30 -1
- package/front_end/panels/autofill/AutofillView.ts +1 -1
- package/front_end/panels/console/ConsoleView.ts +11 -9
- package/front_end/panels/coverage/CoverageView.ts +1 -2
- package/front_end/panels/css_overview/CSSOverviewSidebarPanel.ts +1 -1
- package/front_end/panels/developer_resources/DeveloperResourcesView.ts +1 -1
- package/front_end/panels/elements/ElementStatePaneWidget.ts +1 -1
- package/front_end/panels/elements/EventListenersWidget.ts +1 -2
- package/front_end/panels/elements/PropertiesWidget.ts +1 -1
- package/front_end/panels/emulation/components/DeviceSizeInputElement.ts +1 -0
- package/front_end/panels/network/NetworkConfigView.ts +2 -1
- package/front_end/panels/network/NetworkItemView.ts +1 -1
- package/front_end/panels/network/NetworkPanel.ts +5 -4
- package/front_end/panels/network/NetworkWaterfallColumn.ts +5 -6
- package/front_end/panels/network/RequestCookiesView.ts +2 -1
- package/front_end/panels/network/RequestTimingView.ts +404 -348
- package/front_end/panels/network/networkTimingTable.css +22 -2
- package/front_end/panels/profiler/HeapSnapshotView.ts +3 -2
- package/front_end/panels/sensors/SensorsView.ts +4 -3
- package/front_end/panels/settings/FrameworkIgnoreListSettingsTab.ts +8 -6
- package/front_end/panels/settings/KeybindsSettingsTab.ts +3 -2
- package/front_end/panels/settings/SettingsScreen.ts +2 -1
- package/front_end/panels/settings/WorkspaceSettingsTab.ts +1 -1
- package/front_end/panels/sources/AiCodeCompletionPlugin.ts +2 -1
- package/front_end/panels/sources/SourcesPanel.ts +2 -1
- package/front_end/panels/sources/sources-meta.ts +8 -1
- package/front_end/panels/timeline/TimelinePanel.ts +4 -3
- package/front_end/panels/timeline/TimelineUIUtils.ts +4 -20
- package/front_end/panels/timeline/components/LiveMetricsView.ts +1 -0
- package/front_end/panels/timeline/components/NetworkRequestTooltip.ts +42 -3
- package/front_end/panels/timeline/components/SidebarAnnotationsTab.ts +2 -0
- package/front_end/panels/timeline/components/networkRequestTooltip.css +19 -0
- package/front_end/third_party/chromium/README.chromium +1 -1
- package/front_end/ui/components/adorners/Adorner.ts +3 -1
- package/front_end/ui/components/buttons/Button.docs.ts +195 -0
- package/front_end/ui/components/icon_button/IconButton.ts +1 -0
- package/front_end/ui/components/settings/SettingCheckbox.ts +50 -14
- package/front_end/ui/components/settings/settingCheckbox.css +6 -1
- package/front_end/ui/components/spinners/Spinners.docs.ts +13 -0
- package/front_end/ui/components/tooltips/Tooltip.docs.ts +76 -0
- package/front_end/ui/legacy/FilterBar.ts +1 -2
- package/front_end/ui/legacy/RadioButton.docs.ts +41 -0
- package/front_end/ui/legacy/SelectMenu.docs.ts +98 -0
- package/front_end/ui/legacy/Toolbar.ts +4 -6
- package/front_end/ui/legacy/Treeoutline.ts +15 -0
- package/front_end/ui/legacy/UIUtils.ts +117 -1
- package/front_end/ui/legacy/Widget.ts +68 -38
- package/front_end/ui/legacy/XLink.ts +1 -0
- package/front_end/ui/legacy/components/inline_editor/Swatches.ts +1 -0
- package/front_end/ui/legacy/components/perf_ui/BrickBreaker.ts +1 -0
- package/front_end/ui/legacy/components/settings_ui/SettingsUI.ts +125 -0
- package/front_end/ui/legacy/components/settings_ui/settings_ui.ts +8 -0
- package/front_end/ui/legacy/legacy.ts +0 -2
- package/front_end/ui/legacy/popover.css +12 -11
- package/front_end/ui/visual_logging/KnownContextValues.ts +3 -0
- package/package.json +1 -1
- package/front_end/models/trace/lantern/testing/MetricTestUtils.ts +0 -62
- package/front_end/models/trace/lantern/testing/testing.ts +0 -5
- package/front_end/panels/application/components/badge.css +0 -25
- package/front_end/ui/components/docs/button/basic.html +0 -44
- package/front_end/ui/components/docs/button/basic.ts +0 -175
- package/front_end/ui/components/docs/radio_button/basic.html +0 -23
- package/front_end/ui/components/docs/radio_button/basic.ts +0 -50
- package/front_end/ui/components/docs/select_menu/basic.html +0 -19
- package/front_end/ui/components/docs/select_menu/basic.ts +0 -95
- package/front_end/ui/components/docs/select_menu/wide-option.html +0 -38
- package/front_end/ui/components/docs/select_menu/wide-option.ts +0 -43
- package/front_end/ui/components/docs/spinners/basic.html +0 -17
- package/front_end/ui/components/docs/spinners/basic.ts +0 -22
- package/front_end/ui/components/docs/tooltip/basic.html +0 -20
- package/front_end/ui/components/docs/tooltip/basic.ts +0 -82
- package/front_end/ui/legacy/SettingsUI.ts +0 -240
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
// Copyright 2021 The Chromium Authors
|
|
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 {Button, FloatingButton} from './buttons.js';
|
|
6
|
+
|
|
7
|
+
export async function render(container: HTMLElement) {
|
|
8
|
+
const style = document.createElement('style');
|
|
9
|
+
style.textContent = `
|
|
10
|
+
#container > div {
|
|
11
|
+
width: 80%;
|
|
12
|
+
padding: var(--sys-size-11);
|
|
13
|
+
display: flex;
|
|
14
|
+
align-items: center;
|
|
15
|
+
flex-wrap: wrap;
|
|
16
|
+
gap: var(--sys-size-5);
|
|
17
|
+
}
|
|
18
|
+
`;
|
|
19
|
+
container.appendChild(style);
|
|
20
|
+
|
|
21
|
+
const appendSection = (headerText: string, sectionElement: HTMLElement) => {
|
|
22
|
+
const header = document.createElement('header');
|
|
23
|
+
header.textContent = headerText;
|
|
24
|
+
container.appendChild(header);
|
|
25
|
+
container.appendChild(sectionElement);
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
const buttonsSection = document.createElement('div');
|
|
29
|
+
const primarySection = document.createElement('div');
|
|
30
|
+
const tonalSection = document.createElement('div');
|
|
31
|
+
const outlineSection = document.createElement('div');
|
|
32
|
+
const textSection = document.createElement('div');
|
|
33
|
+
const iconSection = document.createElement('div');
|
|
34
|
+
const floatingSection = document.createElement('div');
|
|
35
|
+
|
|
36
|
+
appendSection('Buttons', buttonsSection);
|
|
37
|
+
appendSection('Primary buttons', primarySection);
|
|
38
|
+
appendSection('Tonal buttons', tonalSection);
|
|
39
|
+
appendSection('Outlined buttons', outlineSection);
|
|
40
|
+
appendSection('Text buttons', textSection);
|
|
41
|
+
appendSection('Icon buttons', iconSection);
|
|
42
|
+
appendSection('Floating buttons', floatingSection);
|
|
43
|
+
|
|
44
|
+
const DEFAULT_TEXT = 'Default';
|
|
45
|
+
const WITH_ICON_TEXT = 'With icon';
|
|
46
|
+
const MICRO_TEXT = 'Micro';
|
|
47
|
+
// Buttons
|
|
48
|
+
{
|
|
49
|
+
const primaryButton = new Button.Button();
|
|
50
|
+
primaryButton.data = {
|
|
51
|
+
variant: Button.Variant.PRIMARY,
|
|
52
|
+
};
|
|
53
|
+
primaryButton.innerText = 'Primary button';
|
|
54
|
+
buttonsSection.appendChild(primaryButton);
|
|
55
|
+
|
|
56
|
+
const tonalButton = new Button.Button();
|
|
57
|
+
tonalButton.data = {
|
|
58
|
+
variant: Button.Variant.TONAL,
|
|
59
|
+
};
|
|
60
|
+
tonalButton.innerText = 'Tonal button';
|
|
61
|
+
buttonsSection.appendChild(tonalButton);
|
|
62
|
+
|
|
63
|
+
const outlinedButton = new Button.Button();
|
|
64
|
+
outlinedButton.data = {
|
|
65
|
+
variant: Button.Variant.OUTLINED,
|
|
66
|
+
};
|
|
67
|
+
outlinedButton.innerText = 'Outlined button';
|
|
68
|
+
buttonsSection.appendChild(outlinedButton);
|
|
69
|
+
|
|
70
|
+
const textButton = new Button.Button();
|
|
71
|
+
textButton.data = {
|
|
72
|
+
variant: Button.Variant.TEXT,
|
|
73
|
+
};
|
|
74
|
+
textButton.innerText = 'Text button';
|
|
75
|
+
buttonsSection.appendChild(textButton);
|
|
76
|
+
|
|
77
|
+
const iconButton = new Button.Button();
|
|
78
|
+
iconButton.data = {
|
|
79
|
+
variant: Button.Variant.ICON,
|
|
80
|
+
iconName: 'gear',
|
|
81
|
+
};
|
|
82
|
+
buttonsSection.appendChild(iconButton);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
// Primary buttons
|
|
86
|
+
{
|
|
87
|
+
const primaryDefault = new Button.Button();
|
|
88
|
+
primaryDefault.data = {
|
|
89
|
+
variant: Button.Variant.PRIMARY,
|
|
90
|
+
};
|
|
91
|
+
primaryDefault.innerText = DEFAULT_TEXT;
|
|
92
|
+
primarySection.appendChild(primaryDefault);
|
|
93
|
+
|
|
94
|
+
const primaryWithIcon = new Button.Button();
|
|
95
|
+
primaryWithIcon.innerText = WITH_ICON_TEXT;
|
|
96
|
+
primaryWithIcon.data = {
|
|
97
|
+
variant: Button.Variant.PRIMARY,
|
|
98
|
+
iconName: 'plus',
|
|
99
|
+
};
|
|
100
|
+
primarySection.appendChild(primaryWithIcon);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
// Tonal buttons
|
|
104
|
+
{
|
|
105
|
+
const tonalDefault = new Button.Button();
|
|
106
|
+
tonalDefault.data = {
|
|
107
|
+
variant: Button.Variant.TONAL,
|
|
108
|
+
};
|
|
109
|
+
tonalDefault.innerText = DEFAULT_TEXT;
|
|
110
|
+
tonalSection.appendChild(tonalDefault);
|
|
111
|
+
|
|
112
|
+
const tonalWithIcon = new Button.Button();
|
|
113
|
+
tonalWithIcon.innerText = WITH_ICON_TEXT;
|
|
114
|
+
|
|
115
|
+
tonalWithIcon.data = {
|
|
116
|
+
variant: Button.Variant.PRIMARY,
|
|
117
|
+
iconName: 'plus',
|
|
118
|
+
};
|
|
119
|
+
tonalSection.appendChild(tonalWithIcon);
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
// Outlined buttons
|
|
123
|
+
{
|
|
124
|
+
const outlinedDefault = new Button.Button();
|
|
125
|
+
outlinedDefault.data = {
|
|
126
|
+
variant: Button.Variant.OUTLINED,
|
|
127
|
+
};
|
|
128
|
+
outlinedDefault.innerText = DEFAULT_TEXT;
|
|
129
|
+
outlineSection.appendChild(outlinedDefault);
|
|
130
|
+
|
|
131
|
+
const outlinedWithIcon = new Button.Button();
|
|
132
|
+
outlinedWithIcon.innerText = WITH_ICON_TEXT;
|
|
133
|
+
outlinedWithIcon.data = {
|
|
134
|
+
variant: Button.Variant.OUTLINED,
|
|
135
|
+
iconName: 'plus',
|
|
136
|
+
};
|
|
137
|
+
outlineSection.appendChild(outlinedWithIcon);
|
|
138
|
+
|
|
139
|
+
const outlinedMicro = new Button.Button();
|
|
140
|
+
outlinedMicro.innerText = MICRO_TEXT;
|
|
141
|
+
outlinedMicro.data = {
|
|
142
|
+
variant: Button.Variant.OUTLINED,
|
|
143
|
+
size: Button.Size.MICRO,
|
|
144
|
+
};
|
|
145
|
+
outlineSection.appendChild(outlinedMicro);
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
// Text buttons
|
|
149
|
+
{
|
|
150
|
+
const textDefault = new Button.Button();
|
|
151
|
+
textDefault.innerText = DEFAULT_TEXT;
|
|
152
|
+
textDefault.data = {
|
|
153
|
+
variant: Button.Variant.TEXT,
|
|
154
|
+
};
|
|
155
|
+
textSection.appendChild(textDefault);
|
|
156
|
+
|
|
157
|
+
const textWithIcon = new Button.Button();
|
|
158
|
+
textWithIcon.innerText = WITH_ICON_TEXT;
|
|
159
|
+
|
|
160
|
+
textWithIcon.data = {
|
|
161
|
+
variant: Button.Variant.TEXT,
|
|
162
|
+
iconName: 'plus',
|
|
163
|
+
};
|
|
164
|
+
textSection.appendChild(textWithIcon);
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
// Icon buttons
|
|
168
|
+
{
|
|
169
|
+
const iconDefault = new Button.Button();
|
|
170
|
+
iconDefault.data = {
|
|
171
|
+
variant: Button.Variant.ICON,
|
|
172
|
+
iconName: 'gear',
|
|
173
|
+
};
|
|
174
|
+
iconSection.appendChild(iconDefault);
|
|
175
|
+
|
|
176
|
+
const iconToggle = new Button.Button();
|
|
177
|
+
iconToggle.data = {
|
|
178
|
+
variant: Button.Variant.ICON_TOGGLE,
|
|
179
|
+
iconName: 'gear',
|
|
180
|
+
toggledIconName: 'gear',
|
|
181
|
+
toggled: true,
|
|
182
|
+
toggleType: Button.ToggleType.PRIMARY,
|
|
183
|
+
};
|
|
184
|
+
const toggledWithLabel = document.createElement('span');
|
|
185
|
+
toggledWithLabel.textContent = '(Toggle)';
|
|
186
|
+
iconSection.appendChild(iconToggle);
|
|
187
|
+
iconSection.appendChild(toggledWithLabel);
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
// Floating buttons
|
|
191
|
+
{
|
|
192
|
+
const floatingButton = FloatingButton.create('smart-assistant', 'Ask AI!');
|
|
193
|
+
floatingSection.appendChild(floatingButton);
|
|
194
|
+
}
|
|
195
|
+
}
|
|
@@ -3,7 +3,9 @@
|
|
|
3
3
|
// found in the LICENSE file.
|
|
4
4
|
/* eslint-disable @devtools/no-lit-render-outside-of-view */
|
|
5
5
|
|
|
6
|
+
import '../tooltips/tooltips.js';
|
|
6
7
|
import './SettingDeprecationWarning.js';
|
|
8
|
+
import '../../legacy/legacy.js';
|
|
7
9
|
|
|
8
10
|
import type * as Common from '../../../core/common/common.js';
|
|
9
11
|
import * as Host from '../../../core/host/host.js';
|
|
@@ -66,23 +68,56 @@ export class SettingCheckbox extends HTMLElement {
|
|
|
66
68
|
}
|
|
67
69
|
|
|
68
70
|
const learnMore = this.#setting.learnMore();
|
|
69
|
-
if (learnMore
|
|
70
|
-
const
|
|
71
|
+
if (learnMore) {
|
|
72
|
+
const jsLogContext = `${this.#setting.name}-documentation`;
|
|
71
73
|
const data: Buttons.Button.ButtonData = {
|
|
72
|
-
iconName: '
|
|
74
|
+
iconName: 'info',
|
|
73
75
|
variant: Buttons.Button.Variant.ICON,
|
|
74
76
|
size: Buttons.Button.Size.SMALL,
|
|
75
|
-
jslogContext:
|
|
76
|
-
title: i18nString(UIStrings.learnMore),
|
|
77
|
-
};
|
|
78
|
-
const handleClick = (event: MouseEvent): void => {
|
|
79
|
-
Host.InspectorFrontendHost.InspectorFrontendHostInstance.openInNewTab(url);
|
|
80
|
-
event.consume();
|
|
77
|
+
jslogContext: jsLogContext,
|
|
81
78
|
};
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
79
|
+
|
|
80
|
+
const url = learnMore.url;
|
|
81
|
+
if (learnMore.tooltip) {
|
|
82
|
+
const id = `${this.#setting.name}-information`;
|
|
83
|
+
// clang-format off
|
|
84
|
+
return html`
|
|
85
|
+
<devtools-button
|
|
86
|
+
class="info-icon"
|
|
87
|
+
aria-details=${id}
|
|
88
|
+
.data=${data}
|
|
89
|
+
></devtools-button>
|
|
90
|
+
<devtools-tooltip id=${id} variant="rich">
|
|
91
|
+
<span>${learnMore.tooltip()}</span><br />
|
|
92
|
+
${url
|
|
93
|
+
? html`<x-link
|
|
94
|
+
href=${url}
|
|
95
|
+
class="link"
|
|
96
|
+
jslog=${VisualLogging.link(jsLogContext).track({
|
|
97
|
+
click: true,
|
|
98
|
+
})}
|
|
99
|
+
>${i18nString(UIStrings.learnMore)}</x-link
|
|
100
|
+
>`
|
|
101
|
+
: Lit.nothing}
|
|
102
|
+
</devtools-tooltip>
|
|
103
|
+
`;
|
|
104
|
+
// clang-format on
|
|
105
|
+
}
|
|
106
|
+
if (url) {
|
|
107
|
+
const handleClick = (event: MouseEvent): void => {
|
|
108
|
+
Host.InspectorFrontendHost.InspectorFrontendHostInstance.openInNewTab(url);
|
|
109
|
+
event.consume();
|
|
110
|
+
};
|
|
111
|
+
data.iconName = 'help';
|
|
112
|
+
data.title = i18nString(UIStrings.learnMore);
|
|
113
|
+
// clang-format off
|
|
114
|
+
return html`<devtools-button
|
|
115
|
+
class="info-icon"
|
|
116
|
+
@click=${handleClick}
|
|
117
|
+
.data=${data}
|
|
118
|
+
></devtools-button>`;
|
|
119
|
+
// clang-format on
|
|
120
|
+
}
|
|
86
121
|
}
|
|
87
122
|
|
|
88
123
|
return undefined;
|
|
@@ -102,7 +137,7 @@ export class SettingCheckbox extends HTMLElement {
|
|
|
102
137
|
}
|
|
103
138
|
|
|
104
139
|
const icon = this.icon();
|
|
105
|
-
const title = `${this.#setting.learnMore() ? this.#setting.learnMore()?.tooltip() : ''}`;
|
|
140
|
+
const title = `${this.#setting.learnMore() ? this.#setting.learnMore()?.tooltip?.() : ''}`;
|
|
106
141
|
const disabledReasons = this.#setting.disabledReasons();
|
|
107
142
|
const reason = disabledReasons.length ?
|
|
108
143
|
html`
|
|
@@ -141,6 +176,7 @@ export class SettingCheckbox extends HTMLElement {
|
|
|
141
176
|
}
|
|
142
177
|
}
|
|
143
178
|
|
|
179
|
+
// eslint-disable-next-line @devtools/enforce-custom-element-prefix
|
|
144
180
|
customElements.define('setting-checkbox', SettingCheckbox);
|
|
145
181
|
|
|
146
182
|
declare global {
|
|
@@ -35,7 +35,7 @@ p {
|
|
|
35
35
|
height: var(--sys-size-9);
|
|
36
36
|
}
|
|
37
37
|
|
|
38
|
-
.
|
|
38
|
+
.info-icon {
|
|
39
39
|
cursor: pointer;
|
|
40
40
|
position: relative;
|
|
41
41
|
margin-left: var(--sys-size-2);
|
|
@@ -43,3 +43,8 @@ p {
|
|
|
43
43
|
width: var(--sys-size-9);
|
|
44
44
|
height: var(--sys-size-9);
|
|
45
45
|
}
|
|
46
|
+
|
|
47
|
+
.link {
|
|
48
|
+
color: var(--text-link);
|
|
49
|
+
text-decoration: underline;
|
|
50
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
// Copyright 2025 The Chromium Authors
|
|
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 './spinners.js';
|
|
6
|
+
|
|
7
|
+
import * as Lit from '../../lit/lit.js';
|
|
8
|
+
|
|
9
|
+
const {html} = Lit;
|
|
10
|
+
|
|
11
|
+
export async function render(container: HTMLElement) {
|
|
12
|
+
Lit.render(html`<devtools-spinner></devtools-spinner>`, container);
|
|
13
|
+
}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
// Copyright 2025 The Chromium Authors
|
|
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 Lit from '../../lit/lit.js';
|
|
6
|
+
|
|
7
|
+
import {Tooltip} from './Tooltip.js';
|
|
8
|
+
|
|
9
|
+
const {html} = Lit;
|
|
10
|
+
|
|
11
|
+
export async function render(container: HTMLElement) {
|
|
12
|
+
Lit.render(
|
|
13
|
+
html`
|
|
14
|
+
<div style="position: relative; z-index: 0;">
|
|
15
|
+
<button aria-describedby="simple-tooltip" style="position: absolute; left: 16px; top: 16px;">
|
|
16
|
+
Simple
|
|
17
|
+
</button>
|
|
18
|
+
<devtools-tooltip id="simple-tooltip">Simple content</devtools-tooltip>
|
|
19
|
+
</div>
|
|
20
|
+
<div style="position: relative; z-index: 0;">
|
|
21
|
+
<span
|
|
22
|
+
aria-details="rich-tooltip"
|
|
23
|
+
style="position: absolute; left: 16px; top: 116px; border: 1px solid black;"
|
|
24
|
+
>
|
|
25
|
+
Non-button click trigger
|
|
26
|
+
</span>
|
|
27
|
+
<devtools-tooltip id="rich-tooltip" variant="rich" use-click>
|
|
28
|
+
<p>Rich tooltip</p>
|
|
29
|
+
<button>Action</button>
|
|
30
|
+
</devtools-tooltip>
|
|
31
|
+
</div>
|
|
32
|
+
<div style="position: relative; z-index: 0;">
|
|
33
|
+
<button
|
|
34
|
+
id="removable"
|
|
35
|
+
@click=${() => document.getElementById('removable')?.remove()}
|
|
36
|
+
class="anchor"
|
|
37
|
+
aria-details="programatic"
|
|
38
|
+
style="position: absolute; left: 16px; top: 216px;"
|
|
39
|
+
>
|
|
40
|
+
Click to remove anchor
|
|
41
|
+
</button>
|
|
42
|
+
</div>
|
|
43
|
+
`,
|
|
44
|
+
container);
|
|
45
|
+
|
|
46
|
+
const anchor = container.querySelector('.anchor') as HTMLElement;
|
|
47
|
+
const programmaticTooltip = new Tooltip({id: 'programatic', variant: 'rich', anchor});
|
|
48
|
+
programmaticTooltip.append('Text content');
|
|
49
|
+
anchor.insertAdjacentElement('afterend', programmaticTooltip);
|
|
50
|
+
|
|
51
|
+
// Make the buttons draggable, so that we can experiment with the position of the tooltip.
|
|
52
|
+
container.querySelectorAll('button,span').forEach(anchor => draggable(anchor as HTMLElement));
|
|
53
|
+
function draggable(element: HTMLElement|null): void {
|
|
54
|
+
if (!element) {
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
element.addEventListener('mousedown', event => {
|
|
58
|
+
const target = event.target as HTMLElement;
|
|
59
|
+
const offsetX = event.clientX - target.getBoundingClientRect().left + container.getBoundingClientRect().left;
|
|
60
|
+
const offsetY = event.clientY - target.getBoundingClientRect().top + container.getBoundingClientRect().top;
|
|
61
|
+
|
|
62
|
+
function onMouseMove(event: MouseEvent) {
|
|
63
|
+
target.style.left = `${event.clientX - offsetX}px`;
|
|
64
|
+
target.style.top = `${event.clientY - offsetY}px`;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
function onMouseUp() {
|
|
68
|
+
document.removeEventListener('mousemove', onMouseMove);
|
|
69
|
+
document.removeEventListener('mouseup', onMouseUp);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
document.addEventListener('mousemove', onMouseMove);
|
|
73
|
+
document.addEventListener('mouseup', onMouseUp);
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
}
|
|
@@ -15,11 +15,10 @@ import * as VisualLogging from '../../ui/visual_logging/visual_logging.js';
|
|
|
15
15
|
import * as ARIAUtils from './ARIAUtils.js';
|
|
16
16
|
import filterStyles from './filter.css.js';
|
|
17
17
|
import {KeyboardShortcut, Modifiers} from './KeyboardShortcut.js';
|
|
18
|
-
import {bindCheckbox} from './SettingsUI.js';
|
|
19
18
|
import type {Suggestions} from './SuggestBox.js';
|
|
20
19
|
import {type ToolbarButton, ToolbarFilter, ToolbarInput, ToolbarSettingToggle} from './Toolbar.js';
|
|
21
20
|
import {Tooltip} from './Tooltip.js';
|
|
22
|
-
import {CheckboxLabel, createTextChild} from './UIUtils.js';
|
|
21
|
+
import {bindCheckbox, CheckboxLabel, createTextChild} from './UIUtils.js';
|
|
23
22
|
import {HBox} from './Widget.js';
|
|
24
23
|
|
|
25
24
|
const UIStrings = {
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
// Copyright 2024 The Chromium Authors
|
|
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 {UIUtils} from './legacy.js';
|
|
6
|
+
|
|
7
|
+
export async function render(container: HTMLElement) {
|
|
8
|
+
const styleElement = document.createElement('style');
|
|
9
|
+
styleElement.textContent = 'fieldset { label { display: block; } }';
|
|
10
|
+
container.appendChild(styleElement);
|
|
11
|
+
|
|
12
|
+
function radioExample({name, tabbable, disabled}: {
|
|
13
|
+
name: string,
|
|
14
|
+
tabbable: boolean,
|
|
15
|
+
disabled: boolean,
|
|
16
|
+
}): HTMLElement {
|
|
17
|
+
const example = document.createElement('fieldset');
|
|
18
|
+
example.style.marginTop = '20px';
|
|
19
|
+
const legend = document.createElement('legend');
|
|
20
|
+
legend.textContent = name;
|
|
21
|
+
const list = document.createElement('div');
|
|
22
|
+
for (let i = 0; i < 3; ++i) {
|
|
23
|
+
const {label, radio} = UIUtils.createRadioButton(name, `Option #${i + 1}`, name);
|
|
24
|
+
radio.tabIndex = tabbable ? 0 : -1;
|
|
25
|
+
radio.disabled = disabled;
|
|
26
|
+
radio.checked = i === 0;
|
|
27
|
+
list.append(label);
|
|
28
|
+
}
|
|
29
|
+
example.append(legend, list);
|
|
30
|
+
return example;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// Basic
|
|
34
|
+
container.appendChild(radioExample({name: 'basic', tabbable: true, disabled: false}));
|
|
35
|
+
|
|
36
|
+
// Not tab reachable
|
|
37
|
+
container.appendChild(radioExample({name: 'not-table-reachable', tabbable: false, disabled: false}));
|
|
38
|
+
|
|
39
|
+
// Disabled
|
|
40
|
+
container.appendChild(radioExample({name: 'disabled', tabbable: true, disabled: true}));
|
|
41
|
+
}
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
// Copyright 2023 The Chromium Authors
|
|
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 Lit from '../lit/lit.js';
|
|
6
|
+
import * as VisualLogging from '../visual_logging/visual_logging.js';
|
|
7
|
+
|
|
8
|
+
import {UIUtils} from './legacy.js';
|
|
9
|
+
|
|
10
|
+
const {html} = Lit;
|
|
11
|
+
|
|
12
|
+
export async function render(container: HTMLElement) {
|
|
13
|
+
function createDivWithP(text: string): HTMLDivElement {
|
|
14
|
+
const div = document.createElement('div');
|
|
15
|
+
div.style.paddingLeft = '25px';
|
|
16
|
+
const p = document.createElement('p');
|
|
17
|
+
p.style.marginLeft = '-25px';
|
|
18
|
+
p.textContent = text;
|
|
19
|
+
div.appendChild(p);
|
|
20
|
+
container.appendChild(div);
|
|
21
|
+
return div;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
function onChange(event: Event): void {
|
|
25
|
+
const menu = event.target;
|
|
26
|
+
if (menu instanceof HTMLSelectElement) {
|
|
27
|
+
// eslint-disable-next-line no-console
|
|
28
|
+
console.log('Option selected: ', menu.value);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
{
|
|
33
|
+
const simpleMenuHTML = createDivWithP('Simple item select with lit-html');
|
|
34
|
+
Lit.render(
|
|
35
|
+
html`<select id="menu" aria-label="Select an option"
|
|
36
|
+
@change=${onChange}>
|
|
37
|
+
<option hidden>Select an option</option>
|
|
38
|
+
<option id="option-1" jslog=${VisualLogging.item('option-1').track({
|
|
39
|
+
click: true
|
|
40
|
+
})}
|
|
41
|
+
value="Option1">Option 1</option>
|
|
42
|
+
<option jslog=${VisualLogging.item('option-2').track({
|
|
43
|
+
click: true
|
|
44
|
+
})}
|
|
45
|
+
value="Option2">Option 2</option>
|
|
46
|
+
<option disabled jslog=${VisualLogging.item('option-3').track({
|
|
47
|
+
click: true
|
|
48
|
+
})}
|
|
49
|
+
value="Option3">Option 3</option>
|
|
50
|
+
</select>`,
|
|
51
|
+
simpleMenuHTML);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
{
|
|
55
|
+
const groupMenuHTML = createDivWithP('Select with groups with lit-html');
|
|
56
|
+
Lit.render(
|
|
57
|
+
html`<select aria-label="Select an option"
|
|
58
|
+
@change=${onChange}>
|
|
59
|
+
<optgroup label="Group 1">
|
|
60
|
+
<option jslog=${VisualLogging.item('option-1').track({
|
|
61
|
+
click: true
|
|
62
|
+
})}
|
|
63
|
+
value="Option1">Option 1</option>
|
|
64
|
+
</optgroup>
|
|
65
|
+
<optgroup label="Group 2">
|
|
66
|
+
<option jslog=${VisualLogging.item('option-2').track({
|
|
67
|
+
click: true
|
|
68
|
+
})}
|
|
69
|
+
value="Option2">Option 2</option>
|
|
70
|
+
<option jslog=${VisualLogging.item('option-3').track({
|
|
71
|
+
click: true
|
|
72
|
+
})}
|
|
73
|
+
value="Option3">Option 3</option>
|
|
74
|
+
</optgroup>
|
|
75
|
+
</select>`,
|
|
76
|
+
groupMenuHTML);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
{
|
|
80
|
+
const simpleMenuImperative = createDivWithP('Simple item select with imperative API');
|
|
81
|
+
const simpleSelect = UIUtils.createSelect('Select an option', [
|
|
82
|
+
'Option 1',
|
|
83
|
+
'Option 2',
|
|
84
|
+
'Option 3',
|
|
85
|
+
]);
|
|
86
|
+
simpleSelect.addEventListener('change', event => onChange(event));
|
|
87
|
+
simpleMenuImperative.appendChild(simpleSelect);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
{
|
|
91
|
+
const groupMenuImperative = createDivWithP('Select with groups with imperative API');
|
|
92
|
+
const group1 = new Map<string, string[]>([['Group 1', ['Option 1']]]);
|
|
93
|
+
const group2 = new Map<string, string[]>([['Group 2', ['Option 2', 'Option 3']]]);
|
|
94
|
+
const groupSelect = UIUtils.createSelect('Select an option', [group1, group2]);
|
|
95
|
+
groupSelect.addEventListener('change', event => onChange(event));
|
|
96
|
+
groupMenuImperative.appendChild(groupSelect);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
@@ -10,7 +10,6 @@ import * as Platform from '../../core/platform/platform.js';
|
|
|
10
10
|
import * as Root from '../../core/root/root.js';
|
|
11
11
|
import * as Buttons from '../../ui/components/buttons/buttons.js';
|
|
12
12
|
import * as VisualLogging from '../../ui/visual_logging/visual_logging.js';
|
|
13
|
-
import type * as Adorners from '../components/adorners/adorners.js';
|
|
14
13
|
import * as IconButton from '../components/icon_button/icon_button.js';
|
|
15
14
|
|
|
16
15
|
import {type Action, Events as ActionEvents} from './ActionRegistration.js';
|
|
@@ -18,12 +17,11 @@ import {ActionRegistry} from './ActionRegistry.js';
|
|
|
18
17
|
import * as ARIAUtils from './ARIAUtils.js';
|
|
19
18
|
import {ContextMenu} from './ContextMenu.js';
|
|
20
19
|
import {GlassPane, PointerEventsBehavior} from './GlassPane.js';
|
|
21
|
-
import {bindCheckbox} from './SettingsUI.js';
|
|
22
20
|
import type {Suggestion} from './SuggestBox.js';
|
|
23
21
|
import {Events as TextPromptEvents, TextPrompt} from './TextPrompt.js';
|
|
24
22
|
import toolbarStyles from './toolbar.css.js';
|
|
25
23
|
import {Tooltip} from './Tooltip.js';
|
|
26
|
-
import {CheckboxLabel, LongClickController} from './UIUtils.js';
|
|
24
|
+
import {bindCheckbox, CheckboxLabel, LongClickController} from './UIUtils.js';
|
|
27
25
|
|
|
28
26
|
const UIStrings = {
|
|
29
27
|
/**
|
|
@@ -643,7 +641,7 @@ export class ToolbarButton extends ToolbarItem<ToolbarButton.EventTypes, Buttons
|
|
|
643
641
|
this.text = text;
|
|
644
642
|
}
|
|
645
643
|
|
|
646
|
-
setAdorner(adorner:
|
|
644
|
+
setAdorner(adorner: HTMLElement): void {
|
|
647
645
|
if (this.adorner) {
|
|
648
646
|
this.adorner.replaceWith(adorner);
|
|
649
647
|
} else {
|
|
@@ -971,7 +969,7 @@ export class ToolbarMenuButton extends ToolbarItem<ToolbarButton.EventTypes> {
|
|
|
971
969
|
private textElement?: HTMLElement;
|
|
972
970
|
private text?: string;
|
|
973
971
|
private iconName?: string;
|
|
974
|
-
private adorner?:
|
|
972
|
+
private adorner?: HTMLElement;
|
|
975
973
|
private readonly contextMenuHandler: (arg0: ContextMenu) => void;
|
|
976
974
|
private readonly useSoftMenu: boolean;
|
|
977
975
|
private readonly keepOpen: boolean;
|
|
@@ -1028,7 +1026,7 @@ export class ToolbarMenuButton extends ToolbarItem<ToolbarButton.EventTypes> {
|
|
|
1028
1026
|
this.text = text;
|
|
1029
1027
|
}
|
|
1030
1028
|
|
|
1031
|
-
setAdorner(adorner:
|
|
1029
|
+
setAdorner(adorner: HTMLElement): void {
|
|
1032
1030
|
if (this.iconName) {
|
|
1033
1031
|
return;
|
|
1034
1032
|
}
|
|
@@ -1604,6 +1604,18 @@ function getTreeNodes(nodeList: NodeList|Node[]): HTMLLIElement[] {
|
|
|
1604
1604
|
.toArray();
|
|
1605
1605
|
}
|
|
1606
1606
|
|
|
1607
|
+
function getStyleElements(nodes: NodeList|Node[]): HTMLElement[] {
|
|
1608
|
+
return [...nodes].flatMap(node => {
|
|
1609
|
+
if (node instanceof HTMLStyleElement) {
|
|
1610
|
+
return [node];
|
|
1611
|
+
}
|
|
1612
|
+
if (node instanceof HTMLElement) {
|
|
1613
|
+
return [...node.querySelectorAll<HTMLStyleElement>('style')];
|
|
1614
|
+
}
|
|
1615
|
+
return [] as HTMLElement[];
|
|
1616
|
+
});
|
|
1617
|
+
}
|
|
1618
|
+
|
|
1607
1619
|
/**
|
|
1608
1620
|
* A tree element that can be used as progressive enhancement over a <ul> element. A `template` IDL attribute allows
|
|
1609
1621
|
* additionally to insert the <ul> into a <template>, avoiding rendering anything into light DOM, which is recommended.
|
|
@@ -1763,6 +1775,9 @@ export class TreeViewElement extends HTMLElementWithLightDOMTemplate {
|
|
|
1763
1775
|
parent.treeElement.expand();
|
|
1764
1776
|
}
|
|
1765
1777
|
}
|
|
1778
|
+
for (const element of getStyleElements(nodes)) {
|
|
1779
|
+
this.#treeOutline.shadowRoot.appendChild(element.cloneNode(true));
|
|
1780
|
+
}
|
|
1766
1781
|
}
|
|
1767
1782
|
|
|
1768
1783
|
protected override removeNodes(nodes: NodeList): void {
|