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.
Files changed (98) hide show
  1. package/.env.template +10 -0
  2. package/docs/get_the_code.md +27 -0
  3. package/eslint.config.mjs +151 -149
  4. package/front_end/core/common/SettingRegistration.ts +10 -7
  5. package/front_end/core/common/Settings.ts +3 -0
  6. package/front_end/core/host/AidaClient.ts +1 -0
  7. package/front_end/core/host/UserMetrics.ts +3 -1
  8. package/front_end/core/root/Runtime.ts +8 -0
  9. package/front_end/core/sdk/sdk-meta.ts +8 -2
  10. package/front_end/entrypoints/inspector_main/RenderingOptions.ts +4 -3
  11. package/front_end/generated/SupportedCSSProperties.js +1 -0
  12. package/front_end/models/ai_assistance/agents/PerformanceAgent.ts +23 -7
  13. package/front_end/models/ai_assistance/data_formatters/PerformanceTraceFormatter.snapshot.txt +110 -5
  14. package/front_end/models/ai_assistance/data_formatters/PerformanceTraceFormatter.ts +50 -45
  15. package/front_end/models/ai_code_generation/AiCodeGeneration.ts +151 -0
  16. package/front_end/models/ai_code_generation/ai_code_generation.ts +6 -0
  17. package/front_end/models/ai_code_generation/debug.ts +30 -0
  18. package/front_end/models/cpu_profile/ProfileTreeModel.ts +7 -7
  19. package/front_end/models/trace_source_maps_resolver/SourceMapsResolver.ts +1 -1
  20. package/front_end/panels/application/PreloadingTreeElement.ts +10 -2
  21. package/front_end/panels/application/StorageView.ts +3 -2
  22. package/front_end/panels/application/components/BackForwardCacheView.ts +34 -51
  23. package/front_end/panels/application/components/OriginTrialTreeView.ts +141 -170
  24. package/front_end/panels/application/components/backForwardCacheView.css +4 -0
  25. package/front_end/panels/application/components/originTrialTreeView.css +37 -7
  26. package/front_end/panels/application/preloading/components/PreloadingGrid.ts +2 -2
  27. package/front_end/panels/application/preloading/components/PreloadingString.ts +30 -1
  28. package/front_end/panels/autofill/AutofillView.ts +1 -1
  29. package/front_end/panels/console/ConsoleView.ts +11 -9
  30. package/front_end/panels/coverage/CoverageView.ts +1 -2
  31. package/front_end/panels/css_overview/CSSOverviewSidebarPanel.ts +1 -1
  32. package/front_end/panels/developer_resources/DeveloperResourcesView.ts +1 -1
  33. package/front_end/panels/elements/ElementStatePaneWidget.ts +1 -1
  34. package/front_end/panels/elements/EventListenersWidget.ts +1 -2
  35. package/front_end/panels/elements/PropertiesWidget.ts +1 -1
  36. package/front_end/panels/emulation/components/DeviceSizeInputElement.ts +1 -0
  37. package/front_end/panels/network/NetworkConfigView.ts +2 -1
  38. package/front_end/panels/network/NetworkItemView.ts +1 -1
  39. package/front_end/panels/network/NetworkPanel.ts +5 -4
  40. package/front_end/panels/network/NetworkWaterfallColumn.ts +5 -6
  41. package/front_end/panels/network/RequestCookiesView.ts +2 -1
  42. package/front_end/panels/network/RequestTimingView.ts +404 -348
  43. package/front_end/panels/network/networkTimingTable.css +22 -2
  44. package/front_end/panels/profiler/HeapSnapshotView.ts +3 -2
  45. package/front_end/panels/sensors/SensorsView.ts +4 -3
  46. package/front_end/panels/settings/FrameworkIgnoreListSettingsTab.ts +8 -6
  47. package/front_end/panels/settings/KeybindsSettingsTab.ts +3 -2
  48. package/front_end/panels/settings/SettingsScreen.ts +2 -1
  49. package/front_end/panels/settings/WorkspaceSettingsTab.ts +1 -1
  50. package/front_end/panels/sources/AiCodeCompletionPlugin.ts +2 -1
  51. package/front_end/panels/sources/SourcesPanel.ts +2 -1
  52. package/front_end/panels/sources/sources-meta.ts +8 -1
  53. package/front_end/panels/timeline/TimelinePanel.ts +4 -3
  54. package/front_end/panels/timeline/TimelineUIUtils.ts +4 -20
  55. package/front_end/panels/timeline/components/LiveMetricsView.ts +1 -0
  56. package/front_end/panels/timeline/components/NetworkRequestTooltip.ts +42 -3
  57. package/front_end/panels/timeline/components/SidebarAnnotationsTab.ts +2 -0
  58. package/front_end/panels/timeline/components/networkRequestTooltip.css +19 -0
  59. package/front_end/third_party/chromium/README.chromium +1 -1
  60. package/front_end/ui/components/adorners/Adorner.ts +3 -1
  61. package/front_end/ui/components/buttons/Button.docs.ts +195 -0
  62. package/front_end/ui/components/icon_button/IconButton.ts +1 -0
  63. package/front_end/ui/components/settings/SettingCheckbox.ts +50 -14
  64. package/front_end/ui/components/settings/settingCheckbox.css +6 -1
  65. package/front_end/ui/components/spinners/Spinners.docs.ts +13 -0
  66. package/front_end/ui/components/tooltips/Tooltip.docs.ts +76 -0
  67. package/front_end/ui/legacy/FilterBar.ts +1 -2
  68. package/front_end/ui/legacy/RadioButton.docs.ts +41 -0
  69. package/front_end/ui/legacy/SelectMenu.docs.ts +98 -0
  70. package/front_end/ui/legacy/Toolbar.ts +4 -6
  71. package/front_end/ui/legacy/Treeoutline.ts +15 -0
  72. package/front_end/ui/legacy/UIUtils.ts +117 -1
  73. package/front_end/ui/legacy/Widget.ts +68 -38
  74. package/front_end/ui/legacy/XLink.ts +1 -0
  75. package/front_end/ui/legacy/components/inline_editor/Swatches.ts +1 -0
  76. package/front_end/ui/legacy/components/perf_ui/BrickBreaker.ts +1 -0
  77. package/front_end/ui/legacy/components/settings_ui/SettingsUI.ts +125 -0
  78. package/front_end/ui/legacy/components/settings_ui/settings_ui.ts +8 -0
  79. package/front_end/ui/legacy/legacy.ts +0 -2
  80. package/front_end/ui/legacy/popover.css +12 -11
  81. package/front_end/ui/visual_logging/KnownContextValues.ts +3 -0
  82. package/package.json +1 -1
  83. package/front_end/models/trace/lantern/testing/MetricTestUtils.ts +0 -62
  84. package/front_end/models/trace/lantern/testing/testing.ts +0 -5
  85. package/front_end/panels/application/components/badge.css +0 -25
  86. package/front_end/ui/components/docs/button/basic.html +0 -44
  87. package/front_end/ui/components/docs/button/basic.ts +0 -175
  88. package/front_end/ui/components/docs/radio_button/basic.html +0 -23
  89. package/front_end/ui/components/docs/radio_button/basic.ts +0 -50
  90. package/front_end/ui/components/docs/select_menu/basic.html +0 -19
  91. package/front_end/ui/components/docs/select_menu/basic.ts +0 -95
  92. package/front_end/ui/components/docs/select_menu/wide-option.html +0 -38
  93. package/front_end/ui/components/docs/select_menu/wide-option.ts +0 -43
  94. package/front_end/ui/components/docs/spinners/basic.html +0 -17
  95. package/front_end/ui/components/docs/spinners/basic.ts +0 -22
  96. package/front_end/ui/components/docs/tooltip/basic.html +0 -20
  97. package/front_end/ui/components/docs/tooltip/basic.ts +0 -82
  98. 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
+ }
@@ -93,6 +93,7 @@ export class IconButton extends HTMLElement {
93
93
  }
94
94
  }
95
95
 
96
+ // eslint-disable-next-line @devtools/enforce-custom-element-prefix
96
97
  customElements.define('icon-button', IconButton);
97
98
 
98
99
  declare global {
@@ -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?.url) {
70
- const url = learnMore.url;
71
+ if (learnMore) {
72
+ const jsLogContext = `${this.#setting.name}-documentation`;
71
73
  const data: Buttons.Button.ButtonData = {
72
- iconName: 'help',
74
+ iconName: 'info',
73
75
  variant: Buttons.Button.Variant.ICON,
74
76
  size: Buttons.Button.Size.SMALL,
75
- jslogContext: `${this.#setting.name}-documentation`,
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
- return html`<devtools-button
83
- class=learn-more
84
- @click=${handleClick}
85
- .data=${data}></devtools-button>`;
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
- .learn-more {
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: Adorners.Adorner.Adorner): void {
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?: Adorners.Adorner.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: Adorners.Adorner.Adorner): void {
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 {