chrome-devtools-frontend 1.0.1567721 → 1.0.1568864
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/front_end/Images/src/grid-direction.svg +6 -0
- package/front_end/generated/InspectorBackendCommands.ts +6 -6
- package/front_end/generated/protocol.ts +0 -18
- package/front_end/models/ai_assistance/injected.ts +7 -22
- package/front_end/models/javascript_metadata/NativeFunctions.js +12 -0
- package/front_end/models/trace/insights/NetworkDependencyTree.ts +3 -4
- package/front_end/panels/application/preloading/PreloadingView.ts +1 -3
- package/front_end/panels/application/preloading/components/UsedPreloadingView.ts +315 -258
- package/front_end/panels/common/AiCodeCompletionTeaser.ts +58 -15
- package/front_end/panels/elements/ElementsSidebarPane.ts +2 -26
- package/front_end/panels/elements/MetricsSidebarPane.ts +83 -106
- package/front_end/panels/elements/StylesSidebarPane.ts +5 -5
- package/front_end/panels/elements/components/CSSPropertyIconResolver.ts +57 -4
- package/front_end/panels/elements/components/StylePropertyEditor.ts +93 -1
- package/front_end/third_party/chromium/README.chromium +1 -1
- package/front_end/ui/components/menus/Menu.ts +3 -1
- package/front_end/ui/visual_logging/KnownContextValues.ts +2 -0
- package/mcp/mcp.ts +1 -0
- package/package.json +1 -1
|
@@ -6,9 +6,10 @@ import * as Common from '../../core/common/common.js';
|
|
|
6
6
|
import * as Host from '../../core/host/host.js';
|
|
7
7
|
import * as i18n from '../../core/i18n/i18n.js';
|
|
8
8
|
import * as Root from '../../core/root/root.js';
|
|
9
|
+
import * as AiCodeGeneration from '../../models/ai_code_generation/ai_code_generation.js';
|
|
9
10
|
import * as Snackbars from '../../ui/components/snackbars/snackbars.js';
|
|
10
11
|
import * as UI from '../../ui/legacy/legacy.js';
|
|
11
|
-
import {html, nothing, render} from '../../ui/lit/lit.js';
|
|
12
|
+
import {html, type LitTemplate, nothing, render} from '../../ui/lit/lit.js';
|
|
12
13
|
import * as VisualLogging from '../../ui/visual_logging/visual_logging.js';
|
|
13
14
|
|
|
14
15
|
import styles from './aiCodeCompletionTeaser.css.js';
|
|
@@ -61,17 +62,32 @@ const UIStringsNotTranslate = {
|
|
|
61
62
|
*/
|
|
62
63
|
freDisclaimerTextAiWontAlwaysGetItRight: 'This feature uses AI and won’t always get it right',
|
|
63
64
|
/**
|
|
64
|
-
* @description
|
|
65
|
+
* @description Code completion disclaimer item text for the fre dialog.
|
|
66
|
+
*/
|
|
67
|
+
freDisclaimerTextAsYouType:
|
|
68
|
+
'As you type, relevant data is being send to Google to generate code suggestions. Press Tab to accept.',
|
|
69
|
+
/**
|
|
70
|
+
* @description Code generation disclaimer item text for the fre dialog.
|
|
71
|
+
*/
|
|
72
|
+
freDisclaimerDescribeCodeInComment:
|
|
73
|
+
'In Console or Sources, describe the code you need in a comment, then press Ctrl+I to generate it.',
|
|
74
|
+
/**
|
|
75
|
+
* @description Code generation disclaimer item text for the fre dialog.
|
|
76
|
+
*/
|
|
77
|
+
freDisclaimerDescribeCodeInCommentForMacOs:
|
|
78
|
+
'In Console or Sources, describe the code you need in a comment, then press Cmd+I to generate it.',
|
|
79
|
+
/**
|
|
80
|
+
* @description Privacy disclaimer item text for the fre dialog.
|
|
65
81
|
*/
|
|
66
82
|
freDisclaimerTextPrivacy:
|
|
67
83
|
'To generate code suggestions, your console input, the history of your current console session, the currently inspected CSS, and the contents of the currently open file are shared with Google. This data may be seen by human reviewers to improve this feature.',
|
|
68
84
|
/**
|
|
69
|
-
* @description
|
|
85
|
+
* @description Privacy disclaimer item text for the fre dialog when enterprise logging is off.
|
|
70
86
|
*/
|
|
71
87
|
freDisclaimerTextPrivacyNoLogging:
|
|
72
88
|
'To generate code suggestions, your console input, the history of your current console session, the currently inspected CSS, and the contents of the currently open file are shared with Google. This data will not be used to improve Google’s AI models. Your organization may change these settings at any time.',
|
|
73
89
|
/**
|
|
74
|
-
* @description
|
|
90
|
+
* @description Last disclaimer item text for the fre dialog.
|
|
75
91
|
*/
|
|
76
92
|
freDisclaimerTextUseWithCaution: 'Use generated code snippets with caution',
|
|
77
93
|
/**
|
|
@@ -192,15 +208,34 @@ export class AiCodeCompletionTeaser extends UI.Widget.Widget {
|
|
|
192
208
|
}
|
|
193
209
|
}
|
|
194
210
|
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
211
|
+
#createReminderItems(): Array<{
|
|
212
|
+
iconName: string,
|
|
213
|
+
content: Common.UIString.LocalizedString|LitTemplate,
|
|
214
|
+
}> {
|
|
215
|
+
const reminderItems: Array<{
|
|
216
|
+
iconName: string,
|
|
217
|
+
content: Common.UIString.LocalizedString | LitTemplate,
|
|
218
|
+
}> = [{
|
|
219
|
+
iconName: 'psychiatry',
|
|
220
|
+
content: lockedString(UIStringsNotTranslate.freDisclaimerTextAiWontAlwaysGetItRight),
|
|
221
|
+
}];
|
|
222
|
+
|
|
223
|
+
const devtoolsLocale = i18n.DevToolsLocale.DevToolsLocale.instance();
|
|
224
|
+
if (AiCodeGeneration.AiCodeGeneration.AiCodeGeneration.isAiCodeGenerationEnabled(devtoolsLocale.locale)) {
|
|
225
|
+
reminderItems.push(
|
|
226
|
+
{
|
|
227
|
+
iconName: 'code',
|
|
228
|
+
content: lockedString(UIStringsNotTranslate.freDisclaimerTextAsYouType),
|
|
229
|
+
},
|
|
230
|
+
{
|
|
231
|
+
iconName: 'text-analysis',
|
|
232
|
+
content: Host.Platform.isMac() ?
|
|
233
|
+
lockedString(UIStringsNotTranslate.freDisclaimerDescribeCodeInCommentForMacOs) :
|
|
234
|
+
lockedString(UIStringsNotTranslate.freDisclaimerDescribeCodeInComment),
|
|
235
|
+
});
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
reminderItems.push(
|
|
204
239
|
{
|
|
205
240
|
iconName: 'google',
|
|
206
241
|
content: this.#noLogging ? lockedString(UIStringsNotTranslate.freDisclaimerTextPrivacyNoLogging) :
|
|
@@ -217,8 +252,16 @@ export class AiCodeCompletionTeaser extends UI.Widget.Widget {
|
|
|
217
252
|
})}
|
|
218
253
|
>${lockedString(UIStringsNotTranslate.freDisclaimerTextUseWithCaution)}</x-link>`,
|
|
219
254
|
// clang-format on
|
|
220
|
-
}
|
|
221
|
-
|
|
255
|
+
});
|
|
256
|
+
return reminderItems;
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
onAction = async(event: Event): Promise<void> => {
|
|
260
|
+
event.preventDefault();
|
|
261
|
+
|
|
262
|
+
const result = await FreDialog.show({
|
|
263
|
+
header: {iconName: 'smart-assistant', text: lockedString(UIStringsNotTranslate.freDisclaimerHeader)},
|
|
264
|
+
reminderItems: this.#createReminderItems(),
|
|
222
265
|
onLearnMoreClick: () => {
|
|
223
266
|
void UI.ViewManager.ViewManager.instance().showView('chrome-ai');
|
|
224
267
|
},
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
// Use of this source code is governed by a BSD-style license that can be
|
|
3
3
|
// found in the LICENSE file.
|
|
4
4
|
|
|
5
|
-
import * as Common from '../../core/common/common.js';
|
|
5
|
+
import type * as Common from '../../core/common/common.js';
|
|
6
6
|
import type * as SDK from '../../core/sdk/sdk.js';
|
|
7
7
|
import * as UI from '../../ui/legacy/legacy.js';
|
|
8
8
|
|
|
@@ -10,16 +10,11 @@ import {type ComputedStyleModel, type CSSModelChangedEvent, Events} from './Comp
|
|
|
10
10
|
|
|
11
11
|
export class ElementsSidebarPane extends UI.Widget.VBox {
|
|
12
12
|
protected computedStyleModelInternal: ComputedStyleModel;
|
|
13
|
-
private readonly updateThrottler: Common.Throttler.Throttler;
|
|
14
|
-
private updateWhenVisible: boolean;
|
|
15
13
|
constructor(computedStyleModel: ComputedStyleModel, delegatesFocus?: boolean) {
|
|
16
14
|
super({useShadowDom: true, delegatesFocus, classes: ['flex-none']});
|
|
17
15
|
this.computedStyleModelInternal = computedStyleModel;
|
|
18
16
|
this.computedStyleModelInternal.addEventListener(Events.CSS_MODEL_CHANGED, this.onCSSModelChanged, this);
|
|
19
17
|
this.computedStyleModelInternal.addEventListener(Events.COMPUTED_STYLE_CHANGED, this.onComputedStyleChanged, this);
|
|
20
|
-
|
|
21
|
-
this.updateThrottler = new Common.Throttler.Throttler(100);
|
|
22
|
-
this.updateWhenVisible = false;
|
|
23
18
|
}
|
|
24
19
|
|
|
25
20
|
node(): SDK.DOMModel.DOMNode|null {
|
|
@@ -34,29 +29,10 @@ export class ElementsSidebarPane extends UI.Widget.VBox {
|
|
|
34
29
|
return this.computedStyleModelInternal;
|
|
35
30
|
}
|
|
36
31
|
|
|
37
|
-
async
|
|
32
|
+
override async performUpdate(): Promise<void> {
|
|
38
33
|
return;
|
|
39
34
|
}
|
|
40
35
|
|
|
41
|
-
update(): void {
|
|
42
|
-
this.updateWhenVisible = !this.isShowing();
|
|
43
|
-
if (this.updateWhenVisible) {
|
|
44
|
-
return;
|
|
45
|
-
}
|
|
46
|
-
void this.updateThrottler.schedule(innerUpdate.bind(this));
|
|
47
|
-
|
|
48
|
-
function innerUpdate(this: ElementsSidebarPane): Promise<void> {
|
|
49
|
-
return this.isShowing() ? this.doUpdate() : Promise.resolve();
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
override wasShown(): void {
|
|
54
|
-
super.wasShown();
|
|
55
|
-
if (this.updateWhenVisible) {
|
|
56
|
-
this.update();
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
|
|
60
36
|
onCSSModelChanged(_event: Common.EventTarget.EventTargetEvent<CSSModelChangedEvent|null>): void {
|
|
61
37
|
}
|
|
62
38
|
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
// Use of this source code is governed by a BSD-style license that can be
|
|
3
3
|
// found in the LICENSE file.
|
|
4
4
|
/* eslint-disable @devtools/no-imperative-dom-api */
|
|
5
|
+
/* eslint-disable @devtools/no-lit-render-outside-of-view */
|
|
5
6
|
|
|
6
7
|
/*
|
|
7
8
|
* Copyright (C) 2007 Apple Inc. All rights reserved.
|
|
@@ -35,22 +36,21 @@ import * as Common from '../../core/common/common.js';
|
|
|
35
36
|
import * as Platform from '../../core/platform/platform.js';
|
|
36
37
|
import * as SDK from '../../core/sdk/sdk.js';
|
|
37
38
|
import * as UI from '../../ui/legacy/legacy.js';
|
|
39
|
+
import {Directives, html, type LitTemplate, nothing, render} from '../../ui/lit/lit.js';
|
|
38
40
|
import * as VisualLogging from '../../ui/visual_logging/visual_logging.js';
|
|
39
41
|
|
|
40
42
|
import type {ComputedStyleModel} from './ComputedStyleModel.js';
|
|
41
43
|
import {ElementsSidebarPane} from './ElementsSidebarPane.js';
|
|
42
44
|
import metricsSidebarPaneStyles from './metricsSidebarPane.css.js';
|
|
43
45
|
|
|
46
|
+
const {live} = Directives;
|
|
47
|
+
|
|
44
48
|
export class MetricsSidebarPane extends ElementsSidebarPane {
|
|
45
49
|
originalPropertyData: SDK.CSSProperty.CSSProperty|null;
|
|
46
50
|
previousPropertyDataCandidate: SDK.CSSProperty.CSSProperty|null;
|
|
47
51
|
private inlineStyle: SDK.CSSStyleDeclaration.CSSStyleDeclaration|null;
|
|
48
52
|
private highlightMode: string;
|
|
49
|
-
private
|
|
50
|
-
element: HTMLElement,
|
|
51
|
-
name: string,
|
|
52
|
-
backgroundColor: string,
|
|
53
|
-
}>;
|
|
53
|
+
private computedStyle: Map<string, string>|null;
|
|
54
54
|
private isEditingMetrics?: boolean;
|
|
55
55
|
|
|
56
56
|
constructor(computedStyleModel: ComputedStyleModel) {
|
|
@@ -61,15 +61,15 @@ export class MetricsSidebarPane extends ElementsSidebarPane {
|
|
|
61
61
|
this.previousPropertyDataCandidate = null;
|
|
62
62
|
this.inlineStyle = null;
|
|
63
63
|
this.highlightMode = '';
|
|
64
|
-
this.
|
|
64
|
+
this.computedStyle = null;
|
|
65
65
|
this.contentElement.setAttribute('jslog', `${VisualLogging.pane('styles-metrics')}`);
|
|
66
66
|
}
|
|
67
67
|
|
|
68
|
-
override
|
|
68
|
+
override async performUpdate(): Promise<void> {
|
|
69
69
|
// "style" attribute might have changed. Update metrics unless they are being edited
|
|
70
70
|
// (if a CSS property is added, a StyleSheetChanged event is dispatched).
|
|
71
71
|
if (this.isEditingMetrics) {
|
|
72
|
-
return Promise.resolve();
|
|
72
|
+
return await Promise.resolve();
|
|
73
73
|
}
|
|
74
74
|
|
|
75
75
|
// FIXME: avoid updates of a collapsed pane.
|
|
@@ -78,18 +78,20 @@ export class MetricsSidebarPane extends ElementsSidebarPane {
|
|
|
78
78
|
if (!node || node.nodeType() !== Node.ELEMENT_NODE || !cssModel) {
|
|
79
79
|
this.contentElement.removeChildren();
|
|
80
80
|
this.element.classList.add('collapsed');
|
|
81
|
-
return Promise.resolve();
|
|
81
|
+
return await Promise.resolve();
|
|
82
82
|
}
|
|
83
83
|
|
|
84
84
|
function callback(this: MetricsSidebarPane, style: Map<string, string>|null): void {
|
|
85
85
|
if (!style || this.node() !== node) {
|
|
86
|
+
this.computedStyle = null;
|
|
86
87
|
return;
|
|
87
88
|
}
|
|
89
|
+
this.computedStyle = style;
|
|
88
90
|
this.updateMetrics(style);
|
|
89
91
|
}
|
|
90
92
|
|
|
91
93
|
if (!node.id) {
|
|
92
|
-
return Promise.resolve();
|
|
94
|
+
return await Promise.resolve();
|
|
93
95
|
}
|
|
94
96
|
|
|
95
97
|
const promises = [
|
|
@@ -100,11 +102,11 @@ export class MetricsSidebarPane extends ElementsSidebarPane {
|
|
|
100
102
|
}
|
|
101
103
|
}),
|
|
102
104
|
];
|
|
103
|
-
return Promise.all(promises) as unknown as Promise<void
|
|
105
|
+
return await (Promise.all(promises) as unknown as Promise<void>);
|
|
104
106
|
}
|
|
105
107
|
|
|
106
108
|
override onCSSModelChanged(): void {
|
|
107
|
-
this.
|
|
109
|
+
this.requestUpdate();
|
|
108
110
|
}
|
|
109
111
|
|
|
110
112
|
/**
|
|
@@ -153,47 +155,35 @@ export class MetricsSidebarPane extends ElementsSidebarPane {
|
|
|
153
155
|
SDK.OverlayModel.OverlayModel.hideDOMNodeHighlight();
|
|
154
156
|
}
|
|
155
157
|
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
element.style.backgroundColor = shouldHighlight ? backgroundColor : '';
|
|
159
|
-
element.classList.toggle('highlighted', shouldHighlight);
|
|
158
|
+
if (this.computedStyle) {
|
|
159
|
+
this.updateMetrics(this.computedStyle, mode);
|
|
160
160
|
}
|
|
161
161
|
}
|
|
162
162
|
|
|
163
|
-
private updateMetrics(style: Map<string, string
|
|
163
|
+
private updateMetrics(style: Map<string, string>, highlightedMode = 'all'): void {
|
|
164
164
|
// Updating with computed style.
|
|
165
|
-
const metricsElement = document.createElement('div');
|
|
166
|
-
metricsElement.className = 'metrics';
|
|
167
165
|
const self = this;
|
|
168
166
|
|
|
169
167
|
function createBoxPartElement(
|
|
170
|
-
this: MetricsSidebarPane, style: Map<string, string>, name: string, side: string,
|
|
171
|
-
suffix: string): HTMLDivElement {
|
|
172
|
-
const element = document.createElement('div');
|
|
173
|
-
element.className = side;
|
|
174
|
-
|
|
168
|
+
this: MetricsSidebarPane, style: Map<string, string>, name: string, side: string, suffix: string): LitTemplate {
|
|
175
169
|
const propertyName = (name !== 'position' ? name + '-' : '') + side + suffix;
|
|
176
170
|
let value = style.get(propertyName);
|
|
177
|
-
if (value === undefined) {
|
|
178
|
-
return element;
|
|
179
|
-
}
|
|
180
171
|
|
|
181
172
|
if (value === '' || (name !== 'position' && value === 'unset')) {
|
|
182
173
|
value = '\u2012';
|
|
183
174
|
} else if (name === 'position' && value === 'auto') {
|
|
184
175
|
value = '\u2012';
|
|
185
176
|
}
|
|
186
|
-
value = value
|
|
187
|
-
value = Platform.NumberUtilities.toFixedIfFloating(value);
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
return element;
|
|
177
|
+
value = value?.replace(/px$/, '');
|
|
178
|
+
value = value ? Platform.NumberUtilities.toFixedIfFloating(value) : value;
|
|
179
|
+
// clang-format off
|
|
180
|
+
return html`<div class=${side} jslog=${VisualLogging.value(propertyName).track({
|
|
181
|
+
dblclick: true, keydown: 'Enter|Escape|ArrowUp|ArrowDown|PageUp|PageDown', change: true,
|
|
182
|
+
})}
|
|
183
|
+
@dblclick=${(e: Event) => this.startEditing(e.currentTarget, name, propertyName, style)}
|
|
184
|
+
.innerText=${live(value ?? '')}>
|
|
185
|
+
</div>`;
|
|
186
|
+
// clang-format on
|
|
197
187
|
}
|
|
198
188
|
|
|
199
189
|
function getContentAreaWidthPx(style: Map<string, string>): string {
|
|
@@ -263,8 +253,7 @@ export class MetricsSidebarPane extends ElementsSidebarPane {
|
|
|
263
253
|
Common.Color.Legacy.fromRGBA([0, 0, 0, 0]),
|
|
264
254
|
];
|
|
265
255
|
const boxLabels = ['content', 'padding', 'border', 'margin', 'position'];
|
|
266
|
-
let previousBox:
|
|
267
|
-
this.boxElements = [];
|
|
256
|
+
let previousBox: LitTemplate = nothing;
|
|
268
257
|
for (let i = 0; i < boxes.length; ++i) {
|
|
269
258
|
const name = boxes[i];
|
|
270
259
|
const display = style.get('display');
|
|
@@ -282,76 +271,64 @@ export class MetricsSidebarPane extends ElementsSidebarPane {
|
|
|
282
271
|
continue;
|
|
283
272
|
}
|
|
284
273
|
|
|
285
|
-
const
|
|
286
|
-
|
|
274
|
+
const node = this.node();
|
|
275
|
+
const shouldHighlight = !node || highlightedMode === 'all' || name === highlightedMode;
|
|
287
276
|
const backgroundColor = boxColors[i].asString(Common.Color.Format.RGBA) || '';
|
|
288
|
-
boxElement.style.backgroundColor = backgroundColor;
|
|
289
|
-
boxElement.setAttribute('jslog', `${VisualLogging.metricsBox().context(name).track({hover: true})}`);
|
|
290
|
-
boxElement.addEventListener(
|
|
291
|
-
'mouseover', this.highlightDOMNode.bind(this, true, name === 'position' ? 'all' : name), false);
|
|
292
|
-
this.boxElements.push({element: boxElement, name, backgroundColor});
|
|
293
|
-
|
|
294
|
-
if (name === 'content') {
|
|
295
|
-
const widthElement = document.createElement('span');
|
|
296
|
-
widthElement.textContent = getContentAreaWidthPx(style);
|
|
297
|
-
widthElement.addEventListener(
|
|
298
|
-
'dblclick', this.startEditing.bind(this, widthElement, 'width', 'width', style), false);
|
|
299
|
-
widthElement.setAttribute('jslog', `${VisualLogging.value('width').track({
|
|
300
|
-
dblclick: true,
|
|
301
|
-
keydown: 'Enter|Escape|ArrowUp|ArrowDown|PageUp|PageDown',
|
|
302
|
-
change: true,
|
|
303
|
-
})}`);
|
|
304
|
-
|
|
305
|
-
const heightElement = document.createElement('span');
|
|
306
|
-
heightElement.textContent = getContentAreaHeightPx(style);
|
|
307
|
-
heightElement.addEventListener(
|
|
308
|
-
'dblclick', this.startEditing.bind(this, heightElement, 'height', 'height', style), false);
|
|
309
|
-
heightElement.setAttribute('jslog', `${VisualLogging.value('height').track({
|
|
310
|
-
dblclick: true,
|
|
311
|
-
keydown: 'Enter|Escape|ArrowUp|ArrowDown|PageUp|PageDown',
|
|
312
|
-
change: true,
|
|
313
|
-
})}`);
|
|
314
|
-
|
|
315
|
-
const timesElement = document.createElement('span');
|
|
316
|
-
timesElement.textContent = ' × ';
|
|
317
|
-
|
|
318
|
-
boxElement.appendChild(widthElement);
|
|
319
|
-
boxElement.appendChild(timesElement);
|
|
320
|
-
boxElement.appendChild(heightElement);
|
|
321
|
-
} else {
|
|
322
|
-
const suffix = (name === 'border' ? '-width' : '');
|
|
323
277
|
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
278
|
+
const suffix = (name === 'border' ? '-width' : '');
|
|
279
|
+
// clang-format off
|
|
280
|
+
const box: LitTemplate = html`
|
|
281
|
+
<div
|
|
282
|
+
class="${name} ${shouldHighlight ? 'highlighted' : ''}"
|
|
283
|
+
style="background-color: ${shouldHighlight ? backgroundColor : ''}"
|
|
284
|
+
jslog=${VisualLogging.metricsBox().context(name).track({hover: true})}
|
|
285
|
+
@mouseover=${this.highlightDOMNode.bind(this, true, name === 'position' ? 'all' : name)}>
|
|
286
|
+
${name === 'content' ? html`
|
|
287
|
+
<span jslog=${VisualLogging.value('width').track({
|
|
288
|
+
dblclick: true,
|
|
289
|
+
keydown: 'Enter|Escape|ArrowUp|ArrowDown|PageUp|PageDown',
|
|
290
|
+
change: true,
|
|
291
|
+
})}
|
|
292
|
+
@dblclick=${(e: Event) => this.startEditing(e.currentTarget, 'width', 'width', style)}
|
|
293
|
+
.innerText=${live(getContentAreaWidthPx(style))}>
|
|
294
|
+
</span>
|
|
295
|
+
<span> × </span>
|
|
296
|
+
<span jslog=${VisualLogging.value('height').track({
|
|
297
|
+
dblclick: true,
|
|
298
|
+
keydown: 'Enter|Escape|ArrowUp|ArrowDown|PageUp|PageDown',
|
|
299
|
+
change: true,
|
|
300
|
+
})}
|
|
301
|
+
@dblclick=${(e: Event) => this.startEditing(e.currentTarget, 'height', 'height', style)}
|
|
302
|
+
.innerText=${live(getContentAreaHeightPx(style))}>
|
|
303
|
+
</span>` : html`
|
|
304
|
+
<div class="label">${boxLabels[i]}</div>
|
|
305
|
+
${createBoxPartElement.call(this, style, name, 'top', suffix)}
|
|
306
|
+
<br>
|
|
307
|
+
${createBoxPartElement.call(this, style, name, 'left', suffix)}
|
|
308
|
+
${previousBox}
|
|
309
|
+
${createBoxPartElement.call(this, style, name, 'right', suffix)}
|
|
310
|
+
<br>
|
|
311
|
+
${createBoxPartElement.call(this, style, name, 'bottom', suffix)}`}
|
|
312
|
+
</div>`;
|
|
313
|
+
// clang-format on
|
|
314
|
+
|
|
315
|
+
previousBox = box;
|
|
343
316
|
}
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
317
|
+
// clang-format off
|
|
318
|
+
render(html`
|
|
319
|
+
<div class="metrics" @mouseover=${this.highlightDOMNode.bind(this, false, 'all')}
|
|
320
|
+
@mouseleave=${this.highlightDOMNode.bind(this, false, 'all')}>
|
|
321
|
+
${previousBox}
|
|
322
|
+
</div>`, this.contentElement);
|
|
323
|
+
// clang-format on
|
|
351
324
|
this.element.classList.remove('collapsed');
|
|
352
325
|
}
|
|
353
326
|
|
|
354
|
-
startEditing(
|
|
327
|
+
startEditing(target: EventTarget|null, box: string, styleProperty: string, computedStyle: Map<string, string>): void {
|
|
328
|
+
if (!(target instanceof Element)) {
|
|
329
|
+
return;
|
|
330
|
+
}
|
|
331
|
+
const targetElement = target as Element;
|
|
355
332
|
if (UI.UIUtils.isBeingEdited(targetElement)) {
|
|
356
333
|
return;
|
|
357
334
|
}
|
|
@@ -429,7 +406,7 @@ export class MetricsSidebarPane extends ElementsSidebarPane {
|
|
|
429
406
|
}
|
|
430
407
|
}
|
|
431
408
|
this.editingEnded(element, context);
|
|
432
|
-
this.
|
|
409
|
+
this.requestUpdate();
|
|
433
410
|
}
|
|
434
411
|
|
|
435
412
|
private applyUserInput(
|
|
@@ -519,7 +496,7 @@ export class MetricsSidebarPane extends ElementsSidebarPane {
|
|
|
519
496
|
}
|
|
520
497
|
|
|
521
498
|
if (commitEditor) {
|
|
522
|
-
this.
|
|
499
|
+
this.requestUpdate();
|
|
523
500
|
}
|
|
524
501
|
}
|
|
525
502
|
}
|
|
@@ -208,7 +208,7 @@ export class StylesSidebarPane extends Common.ObjectWrapper.eventMixin<EventType
|
|
|
208
208
|
super(computedStyleModel, true /* delegatesFocus */);
|
|
209
209
|
this.setMinimumSize(96, 26);
|
|
210
210
|
this.registerRequiredCSS(stylesSidebarPaneStyles);
|
|
211
|
-
Common.Settings.Settings.instance().moduleSetting('text-editor-indent').addChangeListener(this.
|
|
211
|
+
Common.Settings.Settings.instance().moduleSetting('text-editor-indent').addChangeListener(this.requestUpdate, this);
|
|
212
212
|
this.toolbarPaneElement = this.createStylesSidebarToolbar();
|
|
213
213
|
this.noMatchesElement = this.contentElement.createChild('div', 'gray-info-message hidden');
|
|
214
214
|
this.noMatchesElement.textContent = i18nString(UIStrings.noMatchingSelectorOrStyle);
|
|
@@ -330,7 +330,7 @@ export class StylesSidebarPane extends Common.ObjectWrapper.eventMixin<EventType
|
|
|
330
330
|
revealProperty(cssProperty: SDK.CSSProperty.CSSProperty): void {
|
|
331
331
|
void this.decorator.highlightProperty(cssProperty);
|
|
332
332
|
this.lastRevealedProperty = cssProperty;
|
|
333
|
-
this.
|
|
333
|
+
this.requestUpdate();
|
|
334
334
|
}
|
|
335
335
|
|
|
336
336
|
jumpToProperty(propertyName: string, sectionName?: string, blockName?: string): boolean {
|
|
@@ -366,7 +366,7 @@ export class StylesSidebarPane extends Common.ObjectWrapper.eventMixin<EventType
|
|
|
366
366
|
this.#swatchPopoverHelper.hide();
|
|
367
367
|
this.#updateAbortController?.abort();
|
|
368
368
|
this.resetCache();
|
|
369
|
-
this.
|
|
369
|
+
this.requestUpdate();
|
|
370
370
|
}
|
|
371
371
|
|
|
372
372
|
private sectionsContainerKeyDown(event: Event): void {
|
|
@@ -534,7 +534,7 @@ export class StylesSidebarPane extends Common.ObjectWrapper.eventMixin<EventType
|
|
|
534
534
|
this.nodeStylesUpdatedForTest(node, false);
|
|
535
535
|
}
|
|
536
536
|
|
|
537
|
-
override async
|
|
537
|
+
override async performUpdate(): Promise<void> {
|
|
538
538
|
this.#updateAbortController?.abort();
|
|
539
539
|
this.#updateAbortController = new AbortController();
|
|
540
540
|
await this.#innerDoUpdate(this.#updateAbortController.signal);
|
|
@@ -745,7 +745,7 @@ export class StylesSidebarPane extends Common.ObjectWrapper.eventMixin<EventType
|
|
|
745
745
|
}
|
|
746
746
|
|
|
747
747
|
this.resetCache();
|
|
748
|
-
this.
|
|
748
|
+
this.requestUpdate();
|
|
749
749
|
}
|
|
750
750
|
|
|
751
751
|
#scheduleResetUpdateIfNotEditing(): void {
|
|
@@ -108,6 +108,41 @@ export function rotateFlexDirectionIcon(direction: PhysicalDirection): IconInfo
|
|
|
108
108
|
};
|
|
109
109
|
}
|
|
110
110
|
|
|
111
|
+
/**
|
|
112
|
+
* Rotates the grid direction icon in such way that it indicates
|
|
113
|
+
* the desired `direction` and the arrow in the icon is always at the bottom
|
|
114
|
+
* or at the right.
|
|
115
|
+
*
|
|
116
|
+
* By default, the icon is pointing top-down with the arrow on the right-hand side.
|
|
117
|
+
*/
|
|
118
|
+
export function rotateGridDirectionIcon(direction: PhysicalDirection): IconInfo {
|
|
119
|
+
// Default to LTR.
|
|
120
|
+
let flipX = true;
|
|
121
|
+
let flipY = false;
|
|
122
|
+
let rotate = -90;
|
|
123
|
+
|
|
124
|
+
if (direction === PhysicalDirection.RIGHT_TO_LEFT) {
|
|
125
|
+
rotate = 90;
|
|
126
|
+
flipY = false;
|
|
127
|
+
flipX = false;
|
|
128
|
+
} else if (direction === PhysicalDirection.TOP_TO_BOTTOM) {
|
|
129
|
+
rotate = 0;
|
|
130
|
+
flipX = false;
|
|
131
|
+
flipY = false;
|
|
132
|
+
} else if (direction === PhysicalDirection.BOTTOM_TO_TOP) {
|
|
133
|
+
rotate = 0;
|
|
134
|
+
flipX = false;
|
|
135
|
+
flipY = true;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
return {
|
|
139
|
+
iconName: 'grid-direction',
|
|
140
|
+
rotate,
|
|
141
|
+
scaleX: flipX ? -1 : 1,
|
|
142
|
+
scaleY: flipY ? -1 : 1,
|
|
143
|
+
};
|
|
144
|
+
}
|
|
145
|
+
|
|
111
146
|
export function rotateAlignContentIcon(iconName: string, direction: PhysicalDirection): IconInfo {
|
|
112
147
|
return {
|
|
113
148
|
iconName,
|
|
@@ -156,6 +191,14 @@ function flexDirectionIcon(value: string): (styles: ComputedStyles) => IconInfo
|
|
|
156
191
|
return getIcon;
|
|
157
192
|
}
|
|
158
193
|
|
|
194
|
+
function gridDirectionIcon(value: string): (styles: ComputedStyles) => IconInfo {
|
|
195
|
+
function getIcon(computedStyles: ComputedStyles): IconInfo {
|
|
196
|
+
const directions = getPhysicalDirections(computedStyles);
|
|
197
|
+
return rotateGridDirectionIcon(directions[value]);
|
|
198
|
+
}
|
|
199
|
+
return getIcon;
|
|
200
|
+
}
|
|
201
|
+
|
|
159
202
|
function flexAlignContentIcon(iconName: string): (styles: ComputedStyles) => IconInfo {
|
|
160
203
|
function getIcon(computedStyles: ComputedStyles): IconInfo {
|
|
161
204
|
const directions = getPhysicalDirections(computedStyles);
|
|
@@ -178,7 +221,9 @@ function flexAlignContentIcon(iconName: string): (styles: ComputedStyles) => Ico
|
|
|
178
221
|
function gridAlignContentIcon(iconName: string): (styles: ComputedStyles) => IconInfo {
|
|
179
222
|
function getIcon(computedStyles: ComputedStyles): IconInfo {
|
|
180
223
|
const directions = getPhysicalDirections(computedStyles);
|
|
181
|
-
|
|
224
|
+
const gridAutoFlow = computedStyles.get('grid-auto-flow') || 'row';
|
|
225
|
+
const direction = gridAutoFlow.includes('column') ? directions.row : directions.column;
|
|
226
|
+
return rotateAlignContentIcon(iconName, direction);
|
|
182
227
|
}
|
|
183
228
|
return getIcon;
|
|
184
229
|
}
|
|
@@ -194,7 +239,9 @@ function flexJustifyContentIcon(iconName: string): (styles: ComputedStyles) => I
|
|
|
194
239
|
function gridJustifyContentIcon(iconName: string): (styles: ComputedStyles) => IconInfo {
|
|
195
240
|
function getIcon(computedStyles: ComputedStyles): IconInfo {
|
|
196
241
|
const directions = getPhysicalDirections(computedStyles);
|
|
197
|
-
|
|
242
|
+
const gridAutoFlow = computedStyles.get('grid-auto-flow') || 'row';
|
|
243
|
+
const direction = gridAutoFlow.includes('column') ? directions.column : directions.row;
|
|
244
|
+
return rotateJustifyContentIcon(iconName, direction);
|
|
198
245
|
}
|
|
199
246
|
return getIcon;
|
|
200
247
|
}
|
|
@@ -202,7 +249,9 @@ function gridJustifyContentIcon(iconName: string): (styles: ComputedStyles) => I
|
|
|
202
249
|
function gridJustifyItemsIcon(iconName: string): (styles: ComputedStyles) => IconInfo {
|
|
203
250
|
function getIcon(computedStyles: ComputedStyles): IconInfo {
|
|
204
251
|
const directions = getPhysicalDirections(computedStyles);
|
|
205
|
-
|
|
252
|
+
const gridAutoFlow = computedStyles.get('grid-auto-flow') || 'row';
|
|
253
|
+
const direction = gridAutoFlow.includes('column') ? directions.column : directions.row;
|
|
254
|
+
return rotateJustifyItemsIcon(iconName, direction);
|
|
206
255
|
}
|
|
207
256
|
return getIcon;
|
|
208
257
|
}
|
|
@@ -229,7 +278,9 @@ function flexAlignItemsIcon(iconName: string): (styles: ComputedStyles) => IconI
|
|
|
229
278
|
function gridAlignItemsIcon(iconName: string): (styles: ComputedStyles) => IconInfo {
|
|
230
279
|
function getIcon(computedStyles: ComputedStyles): IconInfo {
|
|
231
280
|
const directions = getPhysicalDirections(computedStyles);
|
|
232
|
-
|
|
281
|
+
const gridAutoFlow = computedStyles.get('grid-auto-flow') || 'row';
|
|
282
|
+
const direction = gridAutoFlow.includes('column') ? directions.row : directions.column;
|
|
283
|
+
return rotateAlignItemsIcon(iconName, direction);
|
|
233
284
|
}
|
|
234
285
|
return getIcon;
|
|
235
286
|
}
|
|
@@ -338,6 +389,8 @@ const flexItemIcons = new Map([
|
|
|
338
389
|
]);
|
|
339
390
|
|
|
340
391
|
const gridContainerIcons = new Map([
|
|
392
|
+
['grid-auto-flow: row', gridDirectionIcon('row')],
|
|
393
|
+
['grid-auto-flow: column', gridDirectionIcon('column')],
|
|
341
394
|
['align-content: center', gridAlignContentIcon('align-content-center')],
|
|
342
395
|
['align-content: space-around', gridAlignContentIcon('align-content-space-around')],
|
|
343
396
|
['align-content: space-between', gridAlignContentIcon('align-content-space-between')],
|