chrome-devtools-frontend 1.0.1034366 → 1.0.1034802

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.
@@ -377,4 +377,5 @@ export enum EnumeratedHistogram {
377
377
  RecordingToggled = 'DevTools.RecordingToggled',
378
378
  StyleTextCopied = 'DevTools.StyleTextCopied',
379
379
  ManifestSectionSelected = 'DevTools.ManifestSectionSelected',
380
+ CSSHintShown = 'DevTools.CSSHintShown',
380
381
  }
@@ -277,6 +277,11 @@ export class UserMetrics {
277
277
  InspectorFrontendHostInstance.recordEnumeratedHistogram(
278
278
  EnumeratedHistogram.ManifestSectionSelected, code, ManifestSectionCodes.MaxValue);
279
279
  }
280
+
281
+ cssHintShown(type: CSSHintType): void {
282
+ InspectorFrontendHostInstance.recordEnumeratedHistogram(
283
+ EnumeratedHistogram.CSSHintShown, type, CSSHintType.MaxValue);
284
+ }
280
285
  }
281
286
 
282
287
  /**
@@ -993,4 +998,22 @@ export enum ManifestSectionCodes {
993
998
  MaxValue = 5,
994
999
  }
995
1000
 
1001
+ // The names here match the CSSRuleValidator names in CSSRuleValidator.ts.
1002
+ // TODO(crbug.com/1167717): Make this a const enum again
1003
+ // eslint-disable-next-line rulesdir/const_enum
1004
+ export enum CSSHintType {
1005
+ Other = 0,
1006
+ AlignContent = 1,
1007
+ FlexItem = 2,
1008
+ FlexContainer = 3,
1009
+ GridContainer = 4,
1010
+ GridItem = 5,
1011
+ FlexGrid = 6,
1012
+ MulticolFlexGrid = 7,
1013
+ Padding = 8,
1014
+ Position = 9,
1015
+ ZIndex = 10,
1016
+ MaxValue = 11,
1017
+ }
1018
+
996
1019
  /* eslint-enable @typescript-eslint/naming-convention */
@@ -222,25 +222,36 @@ async function fetchLocaleData(locales: string[]): Promise<string|void> {
222
222
  */
223
223
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
224
224
  function notifyFrontendViaWorkerMessage(action: string, args: any): void {
225
- self.postMessage(JSON.stringify({action, args}));
225
+ self.postMessage({action, args});
226
226
  }
227
227
 
228
228
  async function onFrontendMessage(event: MessageEvent): Promise<void> {
229
- const messageFromFrontend = JSON.parse(event.data);
229
+ const messageFromFrontend = event.data;
230
230
  switch (messageFromFrontend.action) {
231
231
  case 'startTimespan':
232
232
  case 'endTimespan':
233
233
  case 'snapshot':
234
234
  case 'navigation': {
235
235
  const result = await invokeLH(messageFromFrontend.action, messageFromFrontend.args);
236
- self.postMessage(JSON.stringify({id: messageFromFrontend.id, result}));
236
+ if (result && typeof result === 'object') {
237
+ // Report isn't used upstream.
238
+ if ('report' in result) {
239
+ // @ts-expect-error
240
+ delete result.report;
241
+ }
242
+
243
+ // Logger PerformanceTiming objects cannot be cloned by this worker's `postMessage` function.
244
+ if ('artifacts' in result) {
245
+ // @ts-expect-error
246
+ result.artifacts.Timing = JSON.parse(JSON.stringify(result.artifacts.Timing));
247
+ }
248
+ }
249
+ self.postMessage({id: messageFromFrontend.id, result});
237
250
  break;
238
251
  }
239
252
  case 'dispatchProtocolMessage': {
240
- cdpConnection?.onMessage?.(
241
- JSON.parse(messageFromFrontend.args.message),
242
- );
243
- legacyPort.onMessage?.(messageFromFrontend.args.message);
253
+ cdpConnection?.onMessage?.(messageFromFrontend.args.message);
254
+ legacyPort.onMessage?.(JSON.stringify(messageFromFrontend.args.message));
244
255
  break;
245
256
  }
246
257
  default: {
@@ -2,11 +2,12 @@
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 Host from '../../core/host/host.js';
5
6
  import * as i18n from '../../core/i18n/i18n.js';
6
7
 
7
8
  import {
8
- buildStyledPropertyText,
9
- buildStyledRuleText,
9
+ buildPropertyDefinitionText,
10
+ buildPropertyText,
10
11
  isFlexContainer,
11
12
  isGridContainer,
12
13
  isMulticolContainer,
@@ -58,35 +59,34 @@ const UIStrings = {
58
59
  const str_ = i18n.i18n.registerUIStrings('panels/elements/CSSRuleValidator.ts', UIStrings);
59
60
  const i18nString = i18n.i18n.getLocalizedString.bind(undefined, str_);
60
61
 
61
- export const enum AuthoringHintType {
62
+ export const enum HintType {
62
63
  INACTIVE_PROPERTY = 'ruleValidation',
63
64
  DEPRECATED_PROPERTY = 'deprecatedProperty',
64
65
  }
65
66
 
66
- export class AuthoringHint {
67
- readonly #hintType: AuthoringHintType;
67
+ export class Hint {
68
+ readonly #hintType: HintType;
68
69
  readonly #hintMessage: string;
69
70
  readonly #possibleFixMessage: string|null;
70
71
  readonly #learnMoreLink: string|undefined;
71
72
 
72
- constructor(
73
- hintType: AuthoringHintType, hintMessage: string, possibleFixMessage: string|null, learnMoreLink?: string) {
73
+ constructor(hintType: HintType, hintMessage: string, possibleFixMessage: string|null, learnMoreLink?: string) {
74
74
  this.#hintType = hintType;
75
75
  this.#hintMessage = hintMessage;
76
76
  this.#possibleFixMessage = possibleFixMessage;
77
77
  this.#learnMoreLink = learnMoreLink;
78
78
  }
79
79
 
80
- getHintPrefix(): string {
80
+ getPrefix(): string {
81
81
  switch (this.#hintType) {
82
- case AuthoringHintType.INACTIVE_PROPERTY:
82
+ case HintType.INACTIVE_PROPERTY:
83
83
  return i18nString(UIStrings.inactivePropertyHintPrefix);
84
- case AuthoringHintType.DEPRECATED_PROPERTY:
84
+ case HintType.DEPRECATED_PROPERTY:
85
85
  return i18nString(UIStrings.deprecatedPropertyHintPrefix);
86
86
  }
87
87
  }
88
88
 
89
- getHintMessage(): string {
89
+ getMessage(): string {
90
90
  return this.#hintMessage;
91
91
  }
92
92
 
@@ -100,25 +100,23 @@ export class AuthoringHint {
100
100
  }
101
101
 
102
102
  export abstract class CSSRuleValidator {
103
+ getMetricType(): Host.UserMetrics.CSSHintType {
104
+ return Host.UserMetrics.CSSHintType.Other;
105
+ }
106
+
103
107
  readonly #affectedProperties: string[];
104
108
 
105
109
  constructor(affectedProperties: string[]) {
106
110
  this.#affectedProperties = affectedProperties;
107
111
  }
108
112
 
109
- /**
110
- * If `isRuleValid` returns false, it means there is a hint to be shown. The hint is retrieved by invoking `getAuthoringHint`.
111
- */
112
- abstract isRuleValid(computedStyles: Map<String, String>|null, parentsComputedStyles?: Map<String, String>|null):
113
- boolean;
114
-
115
- getAffectedProperties(): string[] {
113
+ getApplicableProperties(): string[] {
116
114
  return this.#affectedProperties;
117
115
  }
118
116
 
119
- abstract getAuthoringHint(
120
- propertyName: string, computedStyles: Map<String, String>|null,
121
- parentComputedStyles: Map<String, String>|null): AuthoringHint;
117
+ abstract getHint(
118
+ propertyName: string, computedStyles?: Map<string, string>, parentComputedStyles?: Map<string, string>): Hint
119
+ |undefined;
122
120
  }
123
121
 
124
122
  export class AlignContentValidator extends CSSRuleValidator {
@@ -126,7 +124,11 @@ export class AlignContentValidator extends CSSRuleValidator {
126
124
  super(['align-content']);
127
125
  }
128
126
 
129
- isRuleValid(computedStyles: Map<String, String>|null): boolean {
127
+ getMetricType(): Host.UserMetrics.CSSHintType {
128
+ return Host.UserMetrics.CSSHintType.AlignContent;
129
+ }
130
+
131
+ #isRuleValid(computedStyles?: Map<string, string>): boolean {
130
132
  if (computedStyles === null || computedStyles === undefined) {
131
133
  return true;
132
134
  }
@@ -136,12 +138,15 @@ export class AlignContentValidator extends CSSRuleValidator {
136
138
  return computedStyles.get('flex-wrap') !== 'nowrap';
137
139
  }
138
140
 
139
- getAuthoringHint(): AuthoringHint {
140
- const reasonPropertyDeclaration = buildStyledPropertyText('flex-wrap');
141
- const affectedPropertyDeclarationCode = buildStyledPropertyText('align-content');
141
+ getHint(_propertyName: string, computedStyles?: Map<string, string>): Hint|undefined {
142
+ if (this.#isRuleValid(computedStyles)) {
143
+ return;
144
+ }
145
+ const reasonPropertyDeclaration = buildPropertyText('flex-wrap');
146
+ const affectedPropertyDeclarationCode = buildPropertyText('align-content');
142
147
 
143
- return new AuthoringHint(
144
- AuthoringHintType.INACTIVE_PROPERTY,
148
+ return new Hint(
149
+ HintType.INACTIVE_PROPERTY,
145
150
  i18nString(UIStrings.ruleViolatedBySameElementRuleReason, {
146
151
  'REASON_PROPERTY_DECLARATION_CODE': reasonPropertyDeclaration,
147
152
  'AFFECTED_PROPERTY_DECLARATION_CODE': affectedPropertyDeclarationCode,
@@ -158,22 +163,28 @@ export class FlexItemValidator extends CSSRuleValidator {
158
163
  super(['flex', 'flex-basis', 'flex-grow', 'flex-shrink']);
159
164
  }
160
165
 
161
- isRuleValid(computedStyles: Map<String, String>|null, parentsComputedStyles: Map<String, String>|null): boolean {
162
- if (parentsComputedStyles === null) {
166
+ getMetricType(): Host.UserMetrics.CSSHintType {
167
+ return Host.UserMetrics.CSSHintType.FlexItem;
168
+ }
169
+
170
+ #isRuleValid(computedStyles?: Map<string, string>, parentComputedStyles?: Map<string, string>): boolean {
171
+ if (parentComputedStyles === null) {
163
172
  return true;
164
173
  }
165
- return isFlexContainer(parentsComputedStyles);
174
+ return isFlexContainer(parentComputedStyles);
166
175
  }
167
176
 
168
- getAuthoringHint(
169
- property: string, computedStyles: Map<String, String>|null,
170
- parentsComputedStyles: Map<String, String>|null): AuthoringHint {
171
- const reasonPropertyDeclaration = buildStyledRuleText('display', parentsComputedStyles?.get('display'));
172
- const affectedPropertyDeclarationCode = buildStyledPropertyText(property);
173
- const targeParentPropertyDeclaration = buildStyledRuleText('display', 'flex');
177
+ getHint(propertyName: string, computedStyles?: Map<string, string>, parentComputedStyles?: Map<string, string>): Hint
178
+ |undefined {
179
+ if (this.#isRuleValid(computedStyles, parentComputedStyles)) {
180
+ return;
181
+ }
182
+ const reasonPropertyDeclaration = buildPropertyDefinitionText('display', parentComputedStyles?.get('display'));
183
+ const affectedPropertyDeclarationCode = buildPropertyText(propertyName);
184
+ const targeParentPropertyDeclaration = buildPropertyDefinitionText('display', 'flex');
174
185
 
175
- return new AuthoringHint(
176
- AuthoringHintType.INACTIVE_PROPERTY,
186
+ return new Hint(
187
+ HintType.INACTIVE_PROPERTY,
177
188
  i18nString(UIStrings.ruleViolatedByParentElementRuleReason, {
178
189
  'REASON_PROPERTY_DECLARATION_CODE': reasonPropertyDeclaration,
179
190
  'AFFECTED_PROPERTY_DECLARATION_CODE': affectedPropertyDeclarationCode,
@@ -191,20 +202,27 @@ export class FlexContainerValidator extends CSSRuleValidator {
191
202
  super(['flex-direction', 'flex-flow', 'flex-wrap', 'justify-content']);
192
203
  }
193
204
 
194
- isRuleValid(computedStyles: Map<String, String>|null): boolean {
205
+ getMetricType(): Host.UserMetrics.CSSHintType {
206
+ return Host.UserMetrics.CSSHintType.FlexContainer;
207
+ }
208
+
209
+ #isRuleValid(computedStyles?: Map<string, string>): boolean {
195
210
  if (computedStyles === null) {
196
211
  return true;
197
212
  }
198
213
  return isFlexContainer(computedStyles);
199
214
  }
200
215
 
201
- getAuthoringHint(property: string, computedStyles: Map<String, String>|null): AuthoringHint {
202
- const reasonPropertyDeclaration = buildStyledRuleText('display', computedStyles?.get('display'));
203
- const targetRuleCode = buildStyledRuleText('display', 'flex');
204
- const affectedPropertyDeclarationCode = buildStyledPropertyText(property);
216
+ getHint(propertyName: string, computedStyles?: Map<string, string>): Hint|undefined {
217
+ if (this.#isRuleValid(computedStyles)) {
218
+ return;
219
+ }
220
+ const reasonPropertyDeclaration = buildPropertyDefinitionText('display', computedStyles?.get('display'));
221
+ const targetRuleCode = buildPropertyDefinitionText('display', 'flex');
222
+ const affectedPropertyDeclarationCode = buildPropertyText(propertyName);
205
223
 
206
- return new AuthoringHint(
207
- AuthoringHintType.INACTIVE_PROPERTY,
224
+ return new Hint(
225
+ HintType.INACTIVE_PROPERTY,
208
226
  i18nString(UIStrings.ruleViolatedBySameElementRuleReason, {
209
227
  'REASON_PROPERTY_DECLARATION_CODE': reasonPropertyDeclaration,
210
228
  'AFFECTED_PROPERTY_DECLARATION_CODE': affectedPropertyDeclarationCode,
@@ -231,20 +249,24 @@ export class GridContainerValidator extends CSSRuleValidator {
231
249
  ]);
232
250
  }
233
251
 
234
- isRuleValid(computedStyles: Map<String, String>|null): boolean {
235
- if (computedStyles === null) {
236
- return true;
237
- }
252
+ getMetricType(): Host.UserMetrics.CSSHintType {
253
+ return Host.UserMetrics.CSSHintType.GridContainer;
254
+ }
255
+
256
+ #isRuleValid(computedStyles?: Map<string, string>): boolean {
238
257
  return isGridContainer(computedStyles);
239
258
  }
240
259
 
241
- getAuthoringHint(property: string, computedStyles: Map<String, String>|null): AuthoringHint {
242
- const reasonPropertyDeclaration = buildStyledRuleText('display', computedStyles?.get('display'));
243
- const targetRuleCode = buildStyledRuleText('display', 'grid');
244
- const affectedPropertyDeclarationCode = buildStyledPropertyText(property);
260
+ getHint(propertyName: string, computedStyles?: Map<string, string>): Hint|undefined {
261
+ if (this.#isRuleValid(computedStyles)) {
262
+ return;
263
+ }
264
+ const reasonPropertyDeclaration = buildPropertyDefinitionText('display', computedStyles?.get('display'));
265
+ const targetRuleCode = buildPropertyDefinitionText('display', 'grid');
266
+ const affectedPropertyDeclarationCode = buildPropertyText(propertyName);
245
267
 
246
- return new AuthoringHint(
247
- AuthoringHintType.INACTIVE_PROPERTY,
268
+ return new Hint(
269
+ HintType.INACTIVE_PROPERTY,
248
270
  i18nString(UIStrings.ruleViolatedBySameElementRuleReason, {
249
271
  'REASON_PROPERTY_DECLARATION_CODE': reasonPropertyDeclaration,
250
272
  'AFFECTED_PROPERTY_DECLARATION_CODE': affectedPropertyDeclarationCode,
@@ -268,22 +290,28 @@ export class GridItemValidator extends CSSRuleValidator {
268
290
  ]);
269
291
  }
270
292
 
271
- isRuleValid(computedStyles: Map<String, String>|null, parentComputedStyles: Map<String, String>|null): boolean {
272
- if (parentComputedStyles === null) {
293
+ getMetricType(): Host.UserMetrics.CSSHintType {
294
+ return Host.UserMetrics.CSSHintType.GridItem;
295
+ }
296
+
297
+ #isRuleValid(computedStyles?: Map<string, string>, parentComputedStyles?: Map<string, string>): boolean {
298
+ if (!parentComputedStyles) {
273
299
  return true;
274
300
  }
275
301
  return isGridContainer(parentComputedStyles);
276
302
  }
277
303
 
278
- getAuthoringHint(
279
- property: string, computedStyles: Map<String, String>|null,
280
- parentComputedStyles: Map<String, String>|null): AuthoringHint {
281
- const reasonPropertyDeclaration = buildStyledRuleText('display', parentComputedStyles?.get('display'));
282
- const targeParentPropertyDeclaration = buildStyledRuleText('display', 'grid');
283
- const affectedPropertyDeclarationCode = buildStyledPropertyText(property);
304
+ getHint(propertyName: string, computedStyles?: Map<string, string>, parentComputedStyles?: Map<string, string>): Hint
305
+ |undefined {
306
+ if (this.#isRuleValid(computedStyles, parentComputedStyles)) {
307
+ return;
308
+ }
309
+ const reasonPropertyDeclaration = buildPropertyDefinitionText('display', parentComputedStyles?.get('display'));
310
+ const targeParentPropertyDeclaration = buildPropertyDefinitionText('display', 'grid');
311
+ const affectedPropertyDeclarationCode = buildPropertyText(propertyName);
284
312
 
285
- return new AuthoringHint(
286
- AuthoringHintType.INACTIVE_PROPERTY,
313
+ return new Hint(
314
+ HintType.INACTIVE_PROPERTY,
287
315
  i18nString(UIStrings.ruleViolatedByParentElementRuleReason, {
288
316
  'REASON_PROPERTY_DECLARATION_CODE': reasonPropertyDeclaration,
289
317
  'AFFECTED_PROPERTY_DECLARATION_CODE': affectedPropertyDeclarationCode,
@@ -306,19 +334,27 @@ export class FlexGridValidator extends CSSRuleValidator {
306
334
  ]);
307
335
  }
308
336
 
309
- isRuleValid(computedStyles: Map<String, String>|null): boolean {
337
+ getMetricType(): Host.UserMetrics.CSSHintType {
338
+ return Host.UserMetrics.CSSHintType.FlexGrid;
339
+ }
340
+
341
+ #isRuleValid(computedStyles?: Map<string, string>): boolean {
310
342
  if (computedStyles === null) {
311
343
  return true;
312
344
  }
313
345
  return isFlexContainer(computedStyles) || isGridContainer(computedStyles);
314
346
  }
315
347
 
316
- getAuthoringHint(property: string, computedStyles: Map<String, String>|null): AuthoringHint {
317
- const reasonPropertyDeclaration = buildStyledRuleText('display', computedStyles?.get('display'));
318
- const affectedPropertyDeclarationCode = buildStyledPropertyText(property);
348
+ getHint(propertyName: string, computedStyles?: Map<string, string>): Hint|undefined {
349
+ if (this.#isRuleValid(computedStyles)) {
350
+ return;
351
+ }
352
+
353
+ const reasonPropertyDeclaration = buildPropertyDefinitionText('display', computedStyles?.get('display'));
354
+ const affectedPropertyDeclarationCode = buildPropertyText(propertyName);
319
355
 
320
- return new AuthoringHint(
321
- AuthoringHintType.INACTIVE_PROPERTY,
356
+ return new Hint(
357
+ HintType.INACTIVE_PROPERTY,
322
358
  i18nString(UIStrings.ruleViolatedBySameElementRuleReason, {
323
359
  'REASON_PROPERTY_DECLARATION_CODE': reasonPropertyDeclaration,
324
360
  'AFFECTED_PROPERTY_DECLARATION_CODE': affectedPropertyDeclarationCode,
@@ -343,19 +379,27 @@ export class MulticolFlexGridValidator extends CSSRuleValidator {
343
379
  ]);
344
380
  }
345
381
 
346
- isRuleValid(computedStyles: Map<String, String>|null): boolean {
382
+ getMetricType(): Host.UserMetrics.CSSHintType {
383
+ return Host.UserMetrics.CSSHintType.MulticolFlexGrid;
384
+ }
385
+
386
+ #isRuleValid(computedStyles?: Map<string, string>): boolean {
347
387
  if (computedStyles === null) {
348
388
  return true;
349
389
  }
350
390
  return isMulticolContainer(computedStyles) || isFlexContainer(computedStyles) || isGridContainer(computedStyles);
351
391
  }
352
392
 
353
- getAuthoringHint(property: string, computedStyles: Map<String, String>|null): AuthoringHint {
354
- const reasonPropertyDeclaration = buildStyledRuleText('display', computedStyles?.get('display'));
355
- const affectedPropertyDeclarationCode = buildStyledPropertyText(property);
393
+ getHint(propertyName: string, computedStyles?: Map<string, string>): Hint|undefined {
394
+ if (this.#isRuleValid(computedStyles)) {
395
+ return;
396
+ }
356
397
 
357
- return new AuthoringHint(
358
- AuthoringHintType.INACTIVE_PROPERTY,
398
+ const reasonPropertyDeclaration = buildPropertyDefinitionText('display', computedStyles?.get('display'));
399
+ const affectedPropertyDeclarationCode = buildPropertyText(propertyName);
400
+
401
+ return new Hint(
402
+ HintType.INACTIVE_PROPERTY,
359
403
  i18nString(UIStrings.ruleViolatedBySameElementRuleReason, {
360
404
  'REASON_PROPERTY_DECLARATION_CODE': reasonPropertyDeclaration,
361
405
  'AFFECTED_PROPERTY_DECLARATION_CODE': affectedPropertyDeclarationCode,
@@ -378,7 +422,11 @@ export class PaddingValidator extends CSSRuleValidator {
378
422
  ]);
379
423
  }
380
424
 
381
- isRuleValid(computedStyles: Map<String, String>|null): boolean {
425
+ getMetricType(): Host.UserMetrics.CSSHintType {
426
+ return Host.UserMetrics.CSSHintType.Padding;
427
+ }
428
+
429
+ #isRuleValid(computedStyles?: Map<string, string>): boolean {
382
430
  const display = computedStyles?.get('display');
383
431
  if (display === null || display === undefined) {
384
432
  return true;
@@ -388,12 +436,16 @@ export class PaddingValidator extends CSSRuleValidator {
388
436
  .includes(display as string);
389
437
  }
390
438
 
391
- getAuthoringHint(property: string, computedStyles: Map<String, String>|null): AuthoringHint {
392
- const reasonPropertyDeclaration = buildStyledRuleText('display', computedStyles?.get('display'));
393
- const affectedPropertyDeclarationCode = buildStyledPropertyText(property);
439
+ getHint(propertyName: string, computedStyles?: Map<string, string>): Hint|undefined {
440
+ if (this.#isRuleValid(computedStyles)) {
441
+ return;
442
+ }
443
+
444
+ const reasonPropertyDeclaration = buildPropertyDefinitionText('display', computedStyles?.get('display'));
445
+ const affectedPropertyDeclarationCode = buildPropertyText(propertyName);
394
446
 
395
- return new AuthoringHint(
396
- AuthoringHintType.INACTIVE_PROPERTY,
447
+ return new Hint(
448
+ HintType.INACTIVE_PROPERTY,
397
449
  i18nString(UIStrings.ruleViolatedBySameElementRuleReason, {
398
450
  'REASON_PROPERTY_DECLARATION_CODE': reasonPropertyDeclaration,
399
451
  'AFFECTED_PROPERTY_DECLARATION_CODE': affectedPropertyDeclarationCode,
@@ -415,7 +467,11 @@ export class PositionValidator extends CSSRuleValidator {
415
467
  ]);
416
468
  }
417
469
 
418
- isRuleValid(computedStyles: Map<String, String>|null): boolean {
470
+ getMetricType(): Host.UserMetrics.CSSHintType {
471
+ return Host.UserMetrics.CSSHintType.Position;
472
+ }
473
+
474
+ #isRuleValid(computedStyles?: Map<string, string>): boolean {
419
475
  const position = computedStyles?.get('position');
420
476
  if (position === null || position === undefined) {
421
477
  return true;
@@ -423,12 +479,16 @@ export class PositionValidator extends CSSRuleValidator {
423
479
  return position !== 'static';
424
480
  }
425
481
 
426
- getAuthoringHint(property: string, computedStyles: Map<String, String>|null): AuthoringHint {
427
- const reasonPropertyDeclaration = buildStyledRuleText('position', computedStyles?.get('position'));
428
- const affectedPropertyDeclarationCode = buildStyledPropertyText(property);
482
+ getHint(propertyName: string, computedStyles?: Map<string, string>): Hint|undefined {
483
+ if (this.#isRuleValid(computedStyles)) {
484
+ return;
485
+ }
429
486
 
430
- return new AuthoringHint(
431
- AuthoringHintType.INACTIVE_PROPERTY,
487
+ const reasonPropertyDeclaration = buildPropertyDefinitionText('position', computedStyles?.get('position'));
488
+ const affectedPropertyDeclarationCode = buildPropertyText(propertyName);
489
+
490
+ return new Hint(
491
+ HintType.INACTIVE_PROPERTY,
432
492
  i18nString(UIStrings.ruleViolatedBySameElementRuleReason, {
433
493
  'REASON_PROPERTY_DECLARATION_CODE': reasonPropertyDeclaration,
434
494
  'AFFECTED_PROPERTY_DECLARATION_CODE': affectedPropertyDeclarationCode,
@@ -447,21 +507,29 @@ export class ZIndexValidator extends CSSRuleValidator {
447
507
  ]);
448
508
  }
449
509
 
450
- isRuleValid(computedStyles: Map<String, String>|null, parentComputedStyles: Map<String, String>|null): boolean {
510
+ getMetricType(): Host.UserMetrics.CSSHintType {
511
+ return Host.UserMetrics.CSSHintType.ZIndex;
512
+ }
513
+
514
+ #isRuleValid(computedStyles?: Map<string, string>, parentComputedStyles?: Map<string, string>): boolean {
451
515
  const position = computedStyles?.get('position');
452
516
  if (position === null || position === undefined) {
453
517
  return true;
454
518
  }
455
- return ['absolute', 'relative', 'fixed', 'sticky'].includes(position as string) ||
456
- isFlexContainer(parentComputedStyles);
519
+ return ['absolute', 'relative', 'fixed', 'sticky'].includes(position) || isFlexContainer(parentComputedStyles);
457
520
  }
458
521
 
459
- getAuthoringHint(property: string, computedStyles: Map<String, String>|null): AuthoringHint {
460
- const reasonPropertyDeclaration = buildStyledRuleText('position', computedStyles?.get('position'));
461
- const affectedPropertyDeclarationCode = buildStyledPropertyText(property);
522
+ getHint(propertyName: string, computedStyles?: Map<string, string>, parentComputedStyles?: Map<string, string>): Hint
523
+ |undefined {
524
+ if (this.#isRuleValid(computedStyles, parentComputedStyles)) {
525
+ return;
526
+ }
527
+
528
+ const reasonPropertyDeclaration = buildPropertyDefinitionText('position', computedStyles?.get('position'));
529
+ const affectedPropertyDeclarationCode = buildPropertyText(propertyName);
462
530
 
463
- return new AuthoringHint(
464
- AuthoringHintType.INACTIVE_PROPERTY,
531
+ return new Hint(
532
+ HintType.INACTIVE_PROPERTY,
465
533
  i18nString(UIStrings.ruleViolatedBySameElementRuleReason, {
466
534
  'REASON_PROPERTY_DECLARATION_CODE': reasonPropertyDeclaration,
467
535
  'AFFECTED_PROPERTY_DECLARATION_CODE': affectedPropertyDeclarationCode,
@@ -486,11 +554,11 @@ const CSS_RULE_VALIDATORS = [
486
554
  ZIndexValidator,
487
555
  ];
488
556
 
489
- const setupCSSRulesValidators = (): Map<String, CSSRuleValidator[]> => {
490
- const validatorsMap = new Map<String, CSSRuleValidator[]>();
557
+ const setupCSSRulesValidators = (): Map<string, CSSRuleValidator[]> => {
558
+ const validatorsMap = new Map<string, CSSRuleValidator[]>();
491
559
  for (const validatorClass of CSS_RULE_VALIDATORS) {
492
560
  const validator = new validatorClass();
493
- const affectedProperties = validator.getAffectedProperties();
561
+ const affectedProperties = validator.getApplicableProperties();
494
562
 
495
563
  for (const affectedProperty of affectedProperties) {
496
564
  let propertyValidators = validatorsMap.get(affectedProperty);
@@ -505,4 +573,4 @@ const setupCSSRulesValidators = (): Map<String, CSSRuleValidator[]> => {
505
573
  return validatorsMap;
506
574
  };
507
575
 
508
- export const cssRuleValidatorsMap: Map<String, CSSRuleValidator[]> = setupCSSRulesValidators();
576
+ export const cssRuleValidatorsMap: Map<string, CSSRuleValidator[]> = setupCSSRulesValidators();
@@ -2,31 +2,37 @@
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
- export const buildStyledRuleText = (property: String, value: String|undefined): string => {
5
+ export const buildPropertyDefinitionText = (property: string, value?: string): string => {
6
6
  if (value === undefined) {
7
- return buildStyledPropertyText(property);
7
+ return buildPropertyText(property);
8
8
  }
9
9
  return '<code class="unbreakable-text"><span class="property">' + property + '</span>: ' + value + '</code>';
10
10
  };
11
11
 
12
- export const buildStyledPropertyText = (property: String): string => {
12
+ export const buildPropertyText = (property: string): string => {
13
13
  return '<code class="unbreakable-text"><span class="property">' + property + '</span></code>';
14
14
  };
15
15
 
16
- export const isFlexContainer = (computedStyles: Map<String, String>|null): boolean => {
17
- if (computedStyles === null) {
16
+ export const isFlexContainer = (computedStyles?: Map<string, string>): boolean => {
17
+ if (!computedStyles) {
18
18
  return false;
19
19
  }
20
20
  const display = computedStyles.get('display');
21
21
  return display === 'flex' || display === 'inline-flex';
22
22
  };
23
23
 
24
- export const isGridContainer = (computedStyles: Map<String, String>): boolean => {
24
+ export const isGridContainer = (computedStyles?: Map<string, string>): boolean => {
25
+ if (!computedStyles) {
26
+ return false;
27
+ }
25
28
  const display = computedStyles.get('display');
26
29
  return display === 'grid' || display === 'inline-grid';
27
30
  };
28
31
 
29
- export const isMulticolContainer = (computedStyles: Map<String, String>): boolean => {
32
+ export const isMulticolContainer = (computedStyles?: Map<string, string>): boolean => {
33
+ if (!computedStyles) {
34
+ return false;
35
+ }
30
36
  const columnWidth = computedStyles.get('column-width');
31
37
  const columnCount = computedStyles.get('column-count');
32
38
 
@@ -290,6 +290,14 @@ export class StylePropertiesSection {
290
290
  this.onpopulate();
291
291
  }
292
292
 
293
+ setComputedStyles(computedStyles: Map<string, string>|null): void {
294
+ this.computedStyles = computedStyles;
295
+ }
296
+
297
+ setParentsComputedStyles(parentsComputedStyles: Map<string, string>|null): void {
298
+ this.parentsComputedStyles = parentsComputedStyles;
299
+ }
300
+
293
301
  setSectionIdx(sectionIdx: number): void {
294
302
  this.sectionIdx = sectionIdx;
295
303
  this.onpopulate();
@@ -21,12 +21,12 @@ import {StyleEditorWidget} from './StyleEditorWidget.js';
21
21
  import {type StylePropertiesSection} from './StylePropertiesSection.js';
22
22
  import {CSSPropertyPrompt, StylesSidebarPane, StylesSidebarPropertyRenderer} from './StylesSidebarPane.js';
23
23
  import {getCssDeclarationAsJavascriptProperty} from './StylePropertyUtils.js';
24
- import {cssRuleValidatorsMap, type AuthoringHint} from './CSSRuleValidator.js';
24
+ import {cssRuleValidatorsMap, type Hint} from './CSSRuleValidator.js';
25
25
 
26
26
  const FlexboxEditor = ElementsComponents.StylePropertyEditor.FlexboxEditor;
27
27
  const GridEditor = ElementsComponents.StylePropertyEditor.GridEditor;
28
28
 
29
- export const activeHints = new WeakMap<Element, AuthoringHint>();
29
+ export const activeHints = new WeakMap<Element, Hint>();
30
30
 
31
31
  const UIStrings = {
32
32
  /**
@@ -717,23 +717,16 @@ export class StylePropertyTreeElement extends UI.TreeOutline.TreeElement {
717
717
  }
718
718
  }
719
719
 
720
- const authoringHint = this.getAuthoringHint(this.computedStyles, this.parentsComputedStyles);
721
- const showAuthoringHint = authoringHint !== null && this.property.parsedOk;
722
- if (showAuthoringHint) {
723
- const hintIcon = UI.Icon.Icon.create('mediumicon-info', 'hint');
724
- activeHints.set(hintIcon, authoringHint);
725
- this.listItemElement.append(hintIcon);
726
- }
727
-
728
- if (!this.property.parsedOk) {
720
+ if (this.property.parsedOk) {
721
+ void this.updateFontVariationSettingsWarning();
722
+ this.updateAuthoringHint();
723
+ } else {
729
724
  // Avoid having longhands under an invalid shorthand.
730
725
  this.listItemElement.classList.add('not-parsed-ok');
731
726
 
732
727
  // Add a separate exclamation mark IMG element with a tooltip.
733
728
  this.listItemElement.insertBefore(
734
729
  StylesSidebarPane.createExclamationMark(this.property, null), this.listItemElement.firstChild);
735
- } else {
736
- void this.updateFontVariationSettingsWarning();
737
730
  }
738
731
 
739
732
  if (!this.property.activeInStyle()) {
@@ -768,6 +761,35 @@ export class StylePropertyTreeElement extends UI.TreeOutline.TreeElement {
768
761
  }
769
762
  }
770
763
 
764
+ private updateAuthoringHint(): void {
765
+ if (!Root.Runtime.experiments.isEnabled(Root.Runtime.ExperimentName.CSS_AUTHORING_HINTS)) {
766
+ return;
767
+ }
768
+
769
+ const existingElement = this.listItemElement.querySelector('.hint');
770
+ if (existingElement) {
771
+ activeHints.delete(existingElement);
772
+ existingElement.parentElement?.removeChild(existingElement);
773
+ }
774
+ const propertyName = this.property.name;
775
+
776
+ if (!cssRuleValidatorsMap.has(propertyName)) {
777
+ return;
778
+ }
779
+
780
+ for (const validator of cssRuleValidatorsMap.get(propertyName) || []) {
781
+ const hint =
782
+ validator.getHint(propertyName, this.computedStyles || undefined, this.parentsComputedStyles || undefined);
783
+ if (hint) {
784
+ Host.userMetrics.cssHintShown(validator.getMetricType());
785
+ const hintIcon = UI.Icon.Icon.create('mediumicon-info', 'hint');
786
+ activeHints.set(hintIcon, hint);
787
+ this.listItemElement.append(hintIcon);
788
+ break;
789
+ }
790
+ }
791
+ }
792
+
771
793
  private async updateFontVariationSettingsWarning(): Promise<void> {
772
794
  if (this.property.name !== 'font-variation-settings') {
773
795
  return;
@@ -816,24 +838,6 @@ export class StylePropertyTreeElement extends UI.TreeOutline.TreeElement {
816
838
  StylesSidebarPane.createExclamationMark(this.property, warnings.join(' ')), this.listItemElement.firstChild);
817
839
  }
818
840
 
819
- private getAuthoringHint(computedStyles: Map<string, string>|null, parentComputedStyles: Map<string, string>|null):
820
- AuthoringHint|null {
821
- const propertyName = this.property.name;
822
-
823
- if (!Root.Runtime.experiments.isEnabled(Root.Runtime.ExperimentName.CSS_AUTHORING_HINTS) ||
824
- !cssRuleValidatorsMap.has(propertyName)) {
825
- return null;
826
- }
827
-
828
- for (const validator of cssRuleValidatorsMap.get(propertyName) || []) {
829
- if (!validator.isRuleValid(computedStyles, parentComputedStyles)) {
830
- return validator.getAuthoringHint(propertyName, this.computedStyles, this.parentsComputedStyles);
831
- }
832
- }
833
-
834
- return null;
835
- }
836
-
837
841
  private mouseUp(event: MouseEvent): void {
838
842
  const activeTreeElement = parentMap.get(this.parentPaneInternal);
839
843
  parentMap.delete(this.parentPaneInternal);
@@ -218,6 +218,7 @@ export class StylesSidebarPane extends Common.ObjectWrapper.eventMixin<EventType
218
218
  #urlToChangeTracker: Map<Platform.DevToolsPath.UrlString, ChangeTracker> = new Map();
219
219
  #copyChangesButton?: UI.Toolbar.ToolbarButton;
220
220
  #updateAbortController?: AbortController;
221
+ #updateComputedStylesAbortController?: AbortController;
221
222
 
222
223
  static instance(): StylesSidebarPane {
223
224
  if (!stylesSidebarPaneInstance) {
@@ -753,10 +754,12 @@ export class StylesSidebarPane extends Common.ObjectWrapper.eventMixin<EventType
753
754
  for (const section of this.allSections()) {
754
755
  section.styleSheetEdited(edit);
755
756
  }
757
+ void this.refreshComputedStyles();
756
758
  return;
757
759
  }
758
760
 
759
761
  if (this.userOperation || this.isEditingStyle) {
762
+ void this.refreshComputedStyles();
760
763
  return;
761
764
  }
762
765
 
@@ -764,6 +767,27 @@ export class StylesSidebarPane extends Common.ObjectWrapper.eventMixin<EventType
764
767
  this.update();
765
768
  }
766
769
 
770
+ async refreshComputedStyles(): Promise<void> {
771
+ this.#updateComputedStylesAbortController?.abort();
772
+ this.#updateAbortController = new AbortController();
773
+ const signal = this.#updateAbortController.signal;
774
+ const matchedStyles = await this.fetchMatchedCascade();
775
+ const nodeId = this.node()?.id;
776
+ const parentNodeId = matchedStyles?.getParentLayoutNodeId();
777
+
778
+ const [computedStyles, parentsComputedStyles] =
779
+ await Promise.all([this.fetchComputedStylesFor(nodeId), this.fetchComputedStylesFor(parentNodeId)]);
780
+
781
+ if (signal.aborted) {
782
+ return;
783
+ }
784
+
785
+ for (const section of this.allSections()) {
786
+ section.setComputedStyles(computedStyles);
787
+ section.setParentsComputedStyles(parentsComputedStyles);
788
+ }
789
+ }
790
+
767
791
  focusedSectionIndex(): number {
768
792
  let index = 0;
769
793
  for (const block of this.sectionBlocks) {
@@ -20,10 +20,10 @@ const i18nString = i18n.i18n.getLocalizedString.bind(undefined, str_);
20
20
  const {render, html, Directives} = LitHtml;
21
21
 
22
22
  interface Hint {
23
- getHintPrefix(): string;
24
- getHintMessage(): string;
25
- getPossibleFixMessage(): string|null;
26
- getLearnMoreLink(): string|undefined;
23
+ getPrefix(): string;
24
+ getMessage(): string;
25
+ getPossibleFixMessage(): string|null;
26
+ getLearnMoreLink(): string|undefined;
27
27
  }
28
28
 
29
29
  export class CSSHintDetailsView extends HTMLElement {
@@ -44,7 +44,7 @@ export class CSSHintDetailsView extends HTMLElement {
44
44
  render(html`
45
45
  <div class="hint-popup-wrapper">
46
46
  <div class="hint-popup-reason">
47
- <strong>${this.#authoringHint.getHintPrefix()}:</strong> ${Directives.unsafeHTML(this.#authoringHint.getHintMessage())}
47
+ <strong>${this.#authoringHint.getPrefix()}:</strong> ${Directives.unsafeHTML(this.#authoringHint.getMessage())}
48
48
  </div>
49
49
  ${this.#authoringHint.getPossibleFixMessage() ? html`
50
50
  <div class="hint-popup-possible-fix">
@@ -267,7 +267,7 @@ export class LayoutPane extends HTMLElement {
267
267
  } as NodeText.NodeText.NodeTextData}></${NodeText.NodeText.NodeText.litTagName}>
268
268
  </span>
269
269
  </label>
270
- <label @keyup=${onColorLabelKeyUp} @keydown=${onColorLabelKeyDown} tabindex="0" title=${i18nString(UIStrings.chooseElementOverlayColor)} class="color-picker-label" style="background: ${element.color};">
270
+ <label @keyup=${onColorLabelKeyUp} @keydown=${onColorLabelKeyDown} tabindex="0" title=${i18nString(UIStrings.chooseElementOverlayColor)} aria-label=${i18nString(UIStrings.chooseElementOverlayColor)} class="color-picker-label" style="background: ${element.color};">
271
271
  <input @change=${onColorChange} @input=${onColorChange} tabindex="-1" class="color-picker" type="color" value=${element.color} />
272
272
  </label>
273
273
  <button tabindex="0" @click=${onElementClick} title=${i18nString(UIStrings.showElementInTheElementsPanel)} class="show-element"></button>
@@ -181,7 +181,7 @@ export class ProtocolService {
181
181
  method?: string,
182
182
  };
183
183
  if (protocolMessage.sessionId || (protocolMessage.method && protocolMessage.method.startsWith('Target'))) {
184
- void this.send('dispatchProtocolMessage', {message: JSON.stringify(message)});
184
+ void this.send('dispatchProtocolMessage', {message});
185
185
  }
186
186
  }
187
187
 
@@ -218,7 +218,7 @@ export class ProtocolService {
218
218
  }
219
219
 
220
220
  private onWorkerMessage(event: MessageEvent): void {
221
- const lighthouseMessage = JSON.parse(event.data);
221
+ const lighthouseMessage = event.data;
222
222
 
223
223
  if (lighthouseMessage.action === 'statusUpdate') {
224
224
  if (this.lighthouseMessageUpdateCallback && lighthouseMessage.args && 'message' in lighthouseMessage.args) {
@@ -240,7 +240,7 @@ export class ProtocolService {
240
240
  private async send(action: string, args: {[x: string]: string|string[]|Object} = {}): Promise<void> {
241
241
  const worker = await this.ensureWorkerExists();
242
242
  const messageId = lastId++;
243
- worker.postMessage(JSON.stringify({id: messageId, action, args: {...args, id: messageId}}));
243
+ worker.postMessage({id: messageId, action, args: {...args, id: messageId}});
244
244
  }
245
245
 
246
246
  /** sendWithResponse currently only handles the original startLighthouse request and LHR-filled response. */
@@ -250,7 +250,7 @@ export class ProtocolService {
250
250
  const messageId = lastId++;
251
251
  const messageResult = new Promise<ReportRenderer.RunnerResult>(resolve => {
252
252
  const workerListener = (event: MessageEvent): void => {
253
- const lighthouseMessage = JSON.parse(event.data);
253
+ const lighthouseMessage = event.data;
254
254
 
255
255
  if (lighthouseMessage.id === messageId) {
256
256
  worker.removeEventListener('message', workerListener);
@@ -259,7 +259,7 @@ export class ProtocolService {
259
259
  };
260
260
  worker.addEventListener('message', workerListener);
261
261
  });
262
- worker.postMessage(JSON.stringify({id: messageId, action, args: {...args, id: messageId}}));
262
+ worker.postMessage({id: messageId, action, args: {...args, id: messageId}});
263
263
 
264
264
  return messageResult;
265
265
  }
package/package.json CHANGED
@@ -56,5 +56,5 @@
56
56
  "unittest": "scripts/test/run_unittests.py --no-text-coverage",
57
57
  "watch": "vpython third_party/node/node.py --output scripts/watch_build.js"
58
58
  },
59
- "version": "1.0.1034366"
59
+ "version": "1.0.1034802"
60
60
  }