chrome-devtools-frontend 1.0.1621678 → 1.0.1624409

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 (47) hide show
  1. package/.agents/skills/foundation-test-migration/SKILL.md +171 -0
  2. package/.agents/skills/verification/SKILL.md +2 -11
  3. package/front_end/Images/src/expand.svg +1 -0
  4. package/front_end/core/common/Base64.ts +12 -2
  5. package/front_end/core/i18n/i18nImpl.ts +8 -4
  6. package/front_end/core/root/Runtime.ts +28 -9
  7. package/front_end/entrypoints/device_mode_emulation_frame/device_mode_emulation_frame.ts +1 -1
  8. package/front_end/entrypoints/greendev_floaty/FloatyEntrypoint.ts +72 -8
  9. package/front_end/entrypoints/greendev_floaty/floaty.html +1 -1
  10. package/front_end/entrypoints/shell/shell.ts +1 -1
  11. package/front_end/generated/Deprecation.ts +7 -0
  12. package/front_end/generated/InspectorBackendCommands.ts +1 -1
  13. package/front_end/generated/SupportedCSSProperties.js +6 -6
  14. package/front_end/generated/protocol.ts +1 -0
  15. package/front_end/models/ai_assistance/agents/GreenDevAgent.ts +373 -112
  16. package/front_end/models/ai_assistance/agents/NetworkAgent.snapshot.txt +57 -0
  17. package/front_end/models/ai_assistance/agents/NetworkAgent.ts +2 -1
  18. package/front_end/models/ai_assistance/agents/PerformanceAgent.ts +3 -9
  19. package/front_end/models/javascript_metadata/NativeFunctions.js +9 -4
  20. package/front_end/panels/ai_assistance/components/ChatMessage.ts +295 -45
  21. package/front_end/panels/console/ConsoleView.ts +86 -7
  22. package/front_end/panels/console/ConsoleViewMessage.ts +23 -1
  23. package/front_end/panels/console/SymbolizedErrorWidget.ts +69 -0
  24. package/front_end/panels/console/console.ts +3 -0
  25. package/front_end/panels/elements/StylePropertiesSection.ts +1 -2
  26. package/front_end/panels/elements/StylePropertyTreeElement.ts +1 -1
  27. package/front_end/panels/elements/StylesAiCodeCompletionProvider.ts +6 -2
  28. package/front_end/panels/elements/StylesSidebarPane.ts +17 -4
  29. package/front_end/panels/emulation/DeviceModeToolbar.ts +189 -132
  30. package/front_end/panels/emulation/deviceModeView.css +25 -0
  31. package/front_end/panels/greendev/GreenDevPanel.ts +30 -3
  32. package/front_end/panels/media/EventDisplayTable.ts +1 -1
  33. package/front_end/panels/mobile_throttling/NetworkThrottlingSelector.ts +48 -27
  34. package/front_end/panels/mobile_throttling/ThrottlingManager.ts +67 -38
  35. package/front_end/panels/network/NetworkConfigView.ts +1 -1
  36. package/front_end/panels/profiler/HeapSnapshotView.ts +1 -22
  37. package/front_end/panels/sources/WatchExpressionsSidebarPane.ts +12 -4
  38. package/front_end/panels/timeline/components/liveMetricsView.css +2 -2
  39. package/front_end/third_party/chromium/README.chromium +1 -1
  40. package/front_end/{core → ui}/dom_extension/DOMExtension.ts +1 -1
  41. package/front_end/ui/legacy/UIUtils.ts +26 -4
  42. package/front_end/ui/legacy/Widget.ts +1 -1
  43. package/front_end/ui/visual_logging/KnownContextValues.ts +19 -0
  44. package/package.json +1 -1
  45. package/front_end/panels/emulation/components/DeviceSizeInputElement.ts +0 -134
  46. package/front_end/panels/emulation/components/components.ts +0 -9
  47. /package/front_end/{core → ui}/dom_extension/dom_extension.ts +0 -0
@@ -10,12 +10,12 @@ import * as Host from '../../core/host/host.js';
10
10
  import * as i18n from '../../core/i18n/i18n.js';
11
11
  import * as Platform from '../../core/platform/platform.js';
12
12
  import * as EmulationModel from '../../models/emulation/emulation.js';
13
+ import * as Buttons from '../../ui/components/buttons/buttons.js';
13
14
  import * as uiI18n from '../../ui/i18n/i18n.js';
14
15
  import * as UI from '../../ui/legacy/legacy.js';
15
16
  import * as VisualLogging from '../../ui/visual_logging/visual_logging.js';
16
17
  import * as MobileThrottling from '../mobile_throttling/mobile_throttling.js';
17
18
 
18
- import * as EmulationComponents from './components/components.js';
19
19
  const UIStrings = {
20
20
  /**
21
21
  * @description Title of the device dimensions selection item in the Device Mode Toolbar.
@@ -194,9 +194,13 @@ const i18nString = i18n.i18n.getLocalizedString.bind(undefined, str_);
194
194
  * than in the DevTools panel itself. Therefore, we need to fall back to using the
195
195
  * built-in tooltip by setting the title attribute on the button's element.
196
196
  */
197
- function setTitleForButton(button: UI.Toolbar.ToolbarButton|UI.Toolbar.ToolbarMenuButton, title: string): void {
198
- button.setTitle(title);
199
- button.element.title = title;
197
+ function setTitleForButton(button: Buttons.Button.Button|UI.Toolbar.ToolbarMenuButton, title: string): void {
198
+ if (button instanceof UI.Toolbar.ToolbarMenuButton) {
199
+ button.setTitle(title);
200
+ button.element.title = title;
201
+ } else {
202
+ button.title = title;
203
+ }
200
204
  }
201
205
 
202
206
  export class DeviceModeToolbar {
@@ -211,19 +215,19 @@ export class DeviceModeToolbar {
211
215
  readonly #element: HTMLDivElement;
212
216
  private readonly emulatedDevicesList: EmulationModel.EmulatedDevices.EmulatedDevicesList;
213
217
  private readonly persistenceSetting: Common.Settings.Setting<{device: string, orientation: string, mode: string}>;
214
- private spanButton!: UI.Toolbar.ToolbarButton;
215
- private postureItem!: UI.Toolbar.ToolbarComboBox;
216
- private modeButton!: UI.Toolbar.ToolbarButton;
217
- private widthInput: EmulationComponents.DeviceSizeInputElement.SizeInputElement;
218
- private heightInput: EmulationComponents.DeviceSizeInputElement.SizeInputElement;
219
- private deviceScaleItem!: UI.Toolbar.ToolbarComboBox;
220
- private deviceScaleItems: UI.Toolbar.ToolbarItem[] = [];
221
- private deviceSelectItem!: UI.Toolbar.ToolbarComboBox;
222
- private scaleItem!: UI.Toolbar.ToolbarComboBox;
223
- private uaItem!: UI.Toolbar.ToolbarComboBox;
218
+ private spanButton!: Buttons.Button.Button;
219
+ private postureItem!: HTMLSelectElement;
220
+ private modeButton!: Buttons.Button.Button;
221
+ private widthInput: HTMLInputElement;
222
+ private heightInput: HTMLInputElement;
223
+ private deviceScaleItem!: HTMLSelectElement;
224
+ private deviceScaleItems: HTMLElement[] = [];
225
+ private deviceSelectItem!: HTMLSelectElement;
226
+ private scaleItem!: HTMLSelectElement;
227
+ private uaItem!: HTMLSelectElement;
224
228
  private cachedDeviceScale!: number|null;
225
229
  private cachedUaType!: string|null;
226
- private xItem?: UI.Toolbar.ToolbarItem;
230
+ private xItem?: HTMLElement;
227
231
  private cachedModelType?: EmulationModel.DeviceModeModel.Type;
228
232
  private cachedScale?: number;
229
233
  private cachedModelDevice?: EmulationModel.EmulatedDevices.EmulatedDevice|null;
@@ -250,10 +254,9 @@ export class DeviceModeToolbar {
250
254
  Common.Settings.Settings.instance().createSetting('emulation.auto-adjust-scale', true);
251
255
 
252
256
  this.lastMode = new Map();
253
- this.widthInput = new EmulationComponents.DeviceSizeInputElement.SizeInputElement(
254
- i18nString(UIStrings.width), {jslogContext: 'width'});
255
- this.heightInput = new EmulationComponents.DeviceSizeInputElement.SizeInputElement(
256
- i18nString(UIStrings.heightLeaveEmptyForFull), {jslogContext: 'height'});
257
+
258
+ this.widthInput = this.createSizeInput(i18nString(UIStrings.width), 'width');
259
+ this.heightInput = this.createSizeInput(i18nString(UIStrings.heightLeaveEmptyForFull), 'height');
257
260
 
258
261
  this.#element = document.createElement('div');
259
262
  this.#element.classList.add('device-mode-toolbar');
@@ -287,98 +290,158 @@ export class DeviceModeToolbar {
287
290
  }
288
291
  }
289
292
 
293
+ private appendOption(parentElement: HTMLElement, title: string, value: string, jslogContext: string): void {
294
+ const option = document.createElement('option');
295
+ option.text = title;
296
+ option.value = value;
297
+ option.setAttribute('jslog', `${VisualLogging.item(jslogContext).track({click: true})}`);
298
+ parentElement.appendChild(option);
299
+ }
300
+
290
301
  private createEmptyToolbarElement(): HTMLDivElement {
291
302
  const element = document.createElement('div');
292
303
  element.classList.add('device-mode-empty-toolbar-element');
293
304
  return element;
294
305
  }
295
306
 
307
+ private createSizeInput(title: string, jslogContext: string): HTMLInputElement {
308
+ const input = document.createElement('input');
309
+ input.type = 'number';
310
+ input.max = String(EmulationModel.DeviceModeModel.MaxDeviceSize);
311
+ input.min = String(EmulationModel.DeviceModeModel.MinDeviceSize);
312
+ input.title = title;
313
+ input.classList.add('device-mode-size-input');
314
+ input.setAttribute('jslog', `${VisualLogging.textField().track({change: true}).context(jslogContext)}`);
315
+
316
+ input.addEventListener('keydown', (event: Event) => {
317
+ let modifiedValue = UI.UIUtils.modifiedFloatNumber(Number(input.value), event);
318
+ if (modifiedValue === null) {
319
+ return;
320
+ }
321
+ modifiedValue = Math.min(modifiedValue, EmulationModel.DeviceModeModel.MaxDeviceSize);
322
+ modifiedValue = Math.max(modifiedValue, EmulationModel.DeviceModeModel.MinDeviceSize);
323
+
324
+ event.preventDefault();
325
+ input.value = String(modifiedValue);
326
+ input.dispatchEvent(new Event('change'));
327
+ });
328
+ return input;
329
+ }
330
+
296
331
  private createMainToolbar(): UI.Toolbar.Toolbar {
297
332
  const mainToolbar = this.#element.createChild('devtools-toolbar', 'main-toolbar');
298
333
 
299
- mainToolbar.appendToolbarItem(new UI.Toolbar.ToolbarItem(this.createEmptyToolbarElement()));
300
- this.deviceSelectItem = new UI.Toolbar.ToolbarComboBox(
301
- this.onDeviceChange.bind(this), i18nString(UIStrings.deviceType), 'dark-text', 'device');
302
- this.deviceSelectItem.turnShrinkable();
303
- const dimensionsSpan =
304
- uiI18n.getFormatLocalizedString(str_, UIStrings.dimensions, {PH1: this.deviceSelectItem.element});
334
+ mainToolbar.append(this.createEmptyToolbarElement());
335
+ this.deviceSelectItem = document.createElement('select');
336
+ this.deviceSelectItem.classList.add('dark-text', 'toolbar-has-dropdown-shrinkable');
337
+ this.deviceSelectItem.title = i18nString(UIStrings.deviceType);
338
+ UI.ARIAUtils.setLabel(this.deviceSelectItem, i18nString(UIStrings.deviceType));
339
+ this.deviceSelectItem.addEventListener('change', this.onDeviceChange.bind(this));
340
+ this.deviceSelectItem.setAttribute('jslog', `${VisualLogging.dropDown().track({change: true}).context('device')}`);
341
+ const dimensionsSpan = uiI18n.getFormatLocalizedString(str_, UIStrings.dimensions, {PH1: this.deviceSelectItem});
305
342
  mainToolbar.append(...dimensionsSpan.childNodes);
306
- mainToolbar.appendToolbarItem(this.deviceSelectItem);
343
+ mainToolbar.append(this.deviceSelectItem);
307
344
 
308
- this.widthInput.addEventListener('sizechanged', ({size: width}) => {
345
+ this.widthInput.addEventListener('change', () => {
346
+ const width = Number(this.widthInput.value);
309
347
  if (this.autoAdjustScaleSetting.get()) {
310
348
  this.model.setWidthAndScaleToFit(width);
311
349
  } else {
312
350
  this.model.setWidth(width);
313
351
  }
314
352
  });
315
- this.heightInput.addEventListener('sizechanged', ({size: height}) => {
353
+ this.heightInput.addEventListener('change', () => {
354
+ const height = Number(this.heightInput.value);
316
355
  if (this.autoAdjustScaleSetting.get()) {
317
356
  this.model.setHeightAndScaleToFit(height);
318
357
  } else {
319
358
  this.model.setHeight(height);
320
359
  }
321
360
  });
322
- mainToolbar.appendToolbarItem(new UI.Toolbar.ToolbarItem(this.widthInput));
323
- const xElement = document.createElement('div');
324
- xElement.classList.add('device-mode-x');
325
- xElement.textContent = '×';
326
- this.xItem = new UI.Toolbar.ToolbarItem(xElement);
327
- mainToolbar.appendToolbarItem(this.xItem);
328
- mainToolbar.appendToolbarItem(new UI.Toolbar.ToolbarItem(this.heightInput));
329
-
330
- mainToolbar.appendToolbarItem(new UI.Toolbar.ToolbarItem(this.createEmptyToolbarElement()));
331
- this.scaleItem =
332
- new UI.Toolbar.ToolbarComboBox(this.onScaleChange.bind(this), i18nString(UIStrings.zoom), 'dark-text', 'scale');
333
- this.scaleItem.turnShrinkable();
334
- mainToolbar.appendToolbarItem(this.scaleItem);
361
+ mainToolbar.append(this.widthInput);
362
+ this.xItem = document.createElement('div');
363
+ this.xItem.classList.add('device-mode-x');
364
+ this.xItem.textContent = '×';
365
+ mainToolbar.append(this.xItem);
366
+ mainToolbar.append(this.heightInput);
367
+
368
+ mainToolbar.append(this.createEmptyToolbarElement());
369
+ this.scaleItem = document.createElement('select');
370
+ this.scaleItem.classList.add('dark-text', 'toolbar-has-dropdown-shrinkable');
371
+ this.scaleItem.title = i18nString(UIStrings.zoom);
372
+ UI.ARIAUtils.setLabel(this.scaleItem, i18nString(UIStrings.zoom));
373
+ this.scaleItem.addEventListener('change', this.onScaleChange.bind(this));
374
+ this.scaleItem.setAttribute('jslog', `${VisualLogging.dropDown().track({change: true}).context('scale')}`);
375
+ mainToolbar.append(this.scaleItem);
335
376
 
336
377
  const autoAdjustScaleButton = new UI.Toolbar.ToolbarSettingToggle(
337
378
  this.autoAdjustScaleSetting, 'center-focus-weak', i18nString(UIStrings.autoadjustZoom));
338
379
  mainToolbar.appendToolbarItem(autoAdjustScaleButton);
339
380
 
340
- mainToolbar.appendToolbarItem(new UI.Toolbar.ToolbarItem(this.createEmptyToolbarElement()));
381
+ mainToolbar.append(this.createEmptyToolbarElement());
341
382
 
342
- this.deviceScaleItem = new UI.Toolbar.ToolbarComboBox(
343
- this.onDeviceScaleChange.bind(this), i18nString(UIStrings.devicePixelRatio), 'dark-text', 'device-pixel-ratio');
344
- this.deviceScaleItem.turnShrinkable();
345
- const deviceScaleSpan = uiI18n.getFormatLocalizedString(str_, UIStrings.dpr, {PH1: this.deviceScaleItem.element});
383
+ this.deviceScaleItem = document.createElement('select');
384
+ this.deviceScaleItem.classList.add('dark-text', 'toolbar-has-dropdown-shrinkable');
385
+ this.deviceScaleItem.title = i18nString(UIStrings.devicePixelRatio);
386
+ UI.ARIAUtils.setLabel(this.deviceScaleItem, i18nString(UIStrings.devicePixelRatio));
387
+ this.deviceScaleItem.addEventListener('change', this.onDeviceScaleChange.bind(this));
388
+ this.deviceScaleItem.setAttribute(
389
+ 'jslog', `${VisualLogging.dropDown().track({change: true}).context('device-pixel-ratio')}`);
390
+ const deviceScaleSpan = uiI18n.getFormatLocalizedString(str_, UIStrings.dpr, {PH1: this.deviceScaleItem});
346
391
  for (const node of Array.from(deviceScaleSpan.childNodes)) {
347
- const item = node === this.deviceScaleItem.element ? this.deviceScaleItem :
348
- new UI.Toolbar.ToolbarText(node.textContent || '');
349
- item.setVisible(this.showDeviceScaleFactorSetting.get());
350
- this.deviceScaleItems.push(item);
351
- mainToolbar.appendToolbarItem(item);
392
+ if (node === this.deviceScaleItem) {
393
+ this.deviceScaleItem.classList.toggle('hidden', !this.showDeviceScaleFactorSetting.get());
394
+ this.deviceScaleItems.push(this.deviceScaleItem);
395
+ mainToolbar.append(this.deviceScaleItem);
396
+ } else {
397
+ const item = new UI.Toolbar.ToolbarText(node.textContent || '');
398
+ item.setVisible(this.showDeviceScaleFactorSetting.get());
399
+ this.deviceScaleItems.push(item.element);
400
+ mainToolbar.appendToolbarItem(item);
401
+ }
352
402
  }
353
- mainToolbar.appendToolbarItem(new UI.Toolbar.ToolbarItem(this.createEmptyToolbarElement()));
354
- this.uaItem = new UI.Toolbar.ToolbarComboBox(
355
- this.onUAChange.bind(this), i18nString(UIStrings.deviceType), 'dark-text', 'device-type');
356
- this.uaItem.turnShrinkable();
357
- this.uaItem.setVisible(this.showUserAgentTypeSetting.get());
358
- mainToolbar.appendToolbarItem(this.uaItem);
403
+ mainToolbar.append(this.createEmptyToolbarElement());
404
+ this.uaItem = document.createElement('select');
405
+ this.uaItem.classList.add('dark-text', 'toolbar-has-dropdown-shrinkable');
406
+ this.uaItem.title = i18nString(UIStrings.deviceType);
407
+ UI.ARIAUtils.setLabel(this.uaItem, i18nString(UIStrings.deviceType));
408
+ this.uaItem.addEventListener('change', this.onUAChange.bind(this));
409
+ this.uaItem.setAttribute('jslog', `${VisualLogging.dropDown().track({change: true}).context('device-type')}`);
410
+ this.uaItem.classList.toggle('hidden', !this.showUserAgentTypeSetting.get());
411
+ mainToolbar.append(this.uaItem);
359
412
 
360
413
  MobileThrottling.NetworkThrottlingSelector.NetworkThrottlingSelect.createForGlobalConditions(
361
414
  mainToolbar, i18nString(UIStrings.throttling));
362
415
  const saveDataItem = MobileThrottling.ThrottlingManager.throttlingManager().createSaveDataOverrideSelector();
363
- saveDataItem.turnShrinkable();
364
- mainToolbar.appendToolbarItem(saveDataItem);
416
+ saveDataItem.classList.add('dark-text', 'toolbar-has-dropdown-shrinkable');
417
+ mainToolbar.append(saveDataItem);
365
418
 
366
- mainToolbar.appendToolbarItem(new UI.Toolbar.ToolbarItem(this.createEmptyToolbarElement()));
367
- this.modeButton = new UI.Toolbar.ToolbarButton('', 'screen-rotation', undefined, 'screen-rotation');
368
- this.modeButton.addEventListener(UI.Toolbar.ToolbarButton.Events.CLICK, this.modeMenuClicked, this);
369
- mainToolbar.appendToolbarItem(this.modeButton);
419
+ mainToolbar.append(this.createEmptyToolbarElement());
420
+ this.modeButton = new Buttons.Button.Button();
421
+ this.modeButton.classList.add('toolbar-button');
422
+ this.modeButton.data = {variant: Buttons.Button.Variant.ICON, iconName: 'screen-rotation'};
423
+ this.modeButton.setAttribute('jslog', `${VisualLogging.action('screen-rotation').track({click: true})}`);
424
+ this.modeButton.addEventListener('click', this.modeMenuClicked.bind(this));
425
+ mainToolbar.append(this.modeButton);
370
426
 
371
427
  // Show dual screen toolbar.
372
- this.spanButton = new UI.Toolbar.ToolbarButton('', 'device-fold', undefined, 'device-fold');
373
- this.spanButton.addEventListener(UI.Toolbar.ToolbarButton.Events.CLICK, this.spanClicked, this);
374
- mainToolbar.appendToolbarItem(this.spanButton);
428
+ this.spanButton = new Buttons.Button.Button();
429
+ this.spanButton.classList.add('toolbar-button');
430
+ this.spanButton.data = {variant: Buttons.Button.Variant.ICON, iconName: 'device-fold'};
431
+ this.spanButton.setAttribute('jslog', `${VisualLogging.action('device-fold').track({click: true})}`);
432
+ this.spanButton.addEventListener('click', this.spanClicked.bind(this));
433
+ mainToolbar.append(this.spanButton);
375
434
 
376
435
  // Show posture toolbar menu for foldable devices.
377
- mainToolbar.appendToolbarItem(new UI.Toolbar.ToolbarItem(this.createEmptyToolbarElement()));
378
- this.postureItem = new UI.Toolbar.ToolbarComboBox(
379
- this.onPostureChange.bind(this), i18nString(UIStrings.devicePosture), 'dark-text', 'device-posture');
380
- this.postureItem.turnShrinkable();
381
- mainToolbar.appendToolbarItem(this.postureItem);
436
+ mainToolbar.append(this.createEmptyToolbarElement());
437
+ this.postureItem = document.createElement('select');
438
+ this.postureItem.classList.add('dark-text', 'toolbar-has-dropdown-shrinkable');
439
+ this.postureItem.title = i18nString(UIStrings.devicePosture);
440
+ UI.ARIAUtils.setLabel(this.postureItem, i18nString(UIStrings.devicePosture));
441
+ this.postureItem.addEventListener('change', this.onPostureChange.bind(this));
442
+ this.postureItem.setAttribute(
443
+ 'jslog', `${VisualLogging.dropDown().track({change: true}).context('device-posture')}`);
444
+ mainToolbar.append(this.postureItem);
382
445
 
383
446
  return mainToolbar;
384
447
  }
@@ -400,19 +463,19 @@ export class DeviceModeToolbar {
400
463
  }
401
464
 
402
465
  private updateDevicePostureItems(): void {
403
- this.postureItem.removeOptions();
466
+ this.postureItem.replaceChildren();
404
467
  for (const option of this.getDevicePostureOptions()) {
405
- this.postureItem.createOption(option.title, option.value, option.title.toLowerCase());
468
+ this.appendOption(this.postureItem, option.title, option.value, option.title.toLowerCase());
406
469
  }
407
470
  const currentPosture = this.currentDevicePosture();
408
- if (this.postureItem.element.value !== currentPosture) {
409
- this.postureItem.element.value = currentPosture;
471
+ if (this.postureItem.value !== currentPosture) {
472
+ this.postureItem.value = currentPosture;
410
473
  }
411
474
  this.resizeItem(this.postureItem);
412
475
  }
413
476
 
414
477
  private onPostureChange(): void {
415
- const value = this.postureItem.element.value;
478
+ const value = this.postureItem.value;
416
479
  if (value !== this.currentDevicePosture()) {
417
480
  this.spanClicked();
418
481
  }
@@ -461,20 +524,20 @@ export class DeviceModeToolbar {
461
524
  }
462
525
 
463
526
  private updateScaleMenuItems(): void {
464
- this.scaleItem.removeOptions();
527
+ this.scaleItem.replaceChildren();
465
528
  const options = this.getScaleOptions();
466
529
  for (const option of options) {
467
- this.scaleItem.createOption(option.title, String(option.value), option.jslogContext);
530
+ this.appendOption(this.scaleItem, option.title, String(option.value), option.jslogContext);
468
531
  }
469
532
  const selected = options.find(o => o.selected);
470
533
  if (selected) {
471
- this.scaleItem.element.value = String(selected.value);
534
+ this.scaleItem.value = String(selected.value);
472
535
  }
473
536
  this.resizeItem(this.scaleItem, true);
474
537
  }
475
538
 
476
539
  private onScaleChange(): void {
477
- const value = Number(this.scaleItem.selectedOption()?.value);
540
+ const value = Number(this.scaleItem.value);
478
541
  this.model.scaleSetting().set(value);
479
542
  }
480
543
 
@@ -509,20 +572,20 @@ export class DeviceModeToolbar {
509
572
  }
510
573
 
511
574
  private updateDeviceScaleMenuItems(): void {
512
- this.deviceScaleItem.removeOptions();
575
+ this.deviceScaleItem.replaceChildren();
513
576
  const options = this.getDeviceScaleFactorOptions();
514
577
  for (const option of options) {
515
- this.deviceScaleItem.createOption(option.title, String(option.value), option.jslogContext);
578
+ this.appendOption(this.deviceScaleItem, option.title, String(option.value), option.jslogContext);
516
579
  }
517
580
  const selected = options.find(o => o.selected);
518
581
  if (selected) {
519
- this.deviceScaleItem.element.value = String(selected.value);
582
+ this.deviceScaleItem.value = String(selected.value);
520
583
  }
521
584
  this.resizeItem(this.deviceScaleItem, true);
522
585
  }
523
586
 
524
587
  private onDeviceScaleChange(): void {
525
- const value = Number(this.deviceScaleItem.selectedOption()?.value);
588
+ const value = Number(this.deviceScaleItem.value);
526
589
  this.model.deviceScaleFactorSetting().set(value);
527
590
  }
528
591
 
@@ -544,20 +607,20 @@ export class DeviceModeToolbar {
544
607
  }
545
608
 
546
609
  private updateUserAgentMenuItems(): void {
547
- this.uaItem.removeOptions();
610
+ this.uaItem.replaceChildren();
548
611
  const options = this.getUserAgentOptions();
549
612
  for (const option of options) {
550
- this.uaItem.createOption(option.title, option.value, option.jslogContext);
613
+ this.appendOption(this.uaItem, option.title, option.value, option.jslogContext);
551
614
  }
552
615
  const selected = options.find(o => o.selected);
553
616
  if (selected) {
554
- this.uaItem.element.value = selected.value;
617
+ this.uaItem.value = selected.value;
555
618
  }
556
619
  this.resizeItem(this.uaItem);
557
620
  }
558
621
 
559
622
  private onUAChange(): void {
560
- const value = this.uaItem.selectedOption()?.value as EmulationModel.DeviceModeModel.UA;
623
+ const value = this.uaItem.value as EmulationModel.DeviceModeModel.UA;
561
624
  this.model.uaSetting().set(value);
562
625
  this.resizeItem(this.uaItem);
563
626
  }
@@ -685,15 +748,15 @@ export class DeviceModeToolbar {
685
748
  }
686
749
 
687
750
  private updateDeviceMenuItems(): void {
688
- this.deviceSelectItem.removeOptions();
751
+ this.deviceSelectItem.replaceChildren();
689
752
  const options = this.getDeviceModeOptions();
690
753
 
691
- this.deviceSelectItem.createOption(options.responsive.title, 'Responsive', options.responsive.jslogContext);
754
+ this.appendOption(this.deviceSelectItem, options.responsive.title, 'Responsive', options.responsive.jslogContext);
692
755
 
693
756
  appendGroup.call(this, options.standard, 'Standard');
694
757
  appendGroup.call(this, options.custom, 'Custom');
695
758
 
696
- this.deviceSelectItem.createOption(options.edit.title, 'Edit', options.edit.jslogContext);
759
+ this.appendOption(this.deviceSelectItem, options.edit.title, 'Edit', options.edit.jslogContext);
697
760
 
698
761
  this.updateDeviceSelection();
699
762
 
@@ -705,28 +768,24 @@ export class DeviceModeToolbar {
705
768
  const optGroup = document.createElement('optgroup');
706
769
  optGroup.label = label;
707
770
  for (const item of group) {
708
- const option = document.createElement('option');
709
- option.value = item.title;
710
- option.text = item.title;
711
- option.setAttribute('jslog', `${VisualLogging.item(item.jslogContext).track({click: true})}`);
712
- optGroup.appendChild(option);
771
+ this.appendOption(optGroup, item.title, item.title, item.jslogContext);
713
772
  }
714
- this.deviceSelectItem.addOption(optGroup);
773
+ this.deviceSelectItem.appendChild(optGroup);
715
774
  }
716
775
  }
717
776
 
718
777
  private updateDeviceSelection(): void {
719
778
  const device = this.model.device();
720
779
  if (this.model.type() === EmulationModel.DeviceModeModel.Type.Responsive) {
721
- this.deviceSelectItem.element.value = 'Responsive';
780
+ this.deviceSelectItem.value = 'Responsive';
722
781
  } else if (device) {
723
- this.deviceSelectItem.element.value = device.title;
782
+ this.deviceSelectItem.value = device.title;
724
783
  }
725
784
  this.resizeItem(this.deviceSelectItem);
726
785
  }
727
786
 
728
787
  private onDeviceChange(): void {
729
- const value = this.deviceSelectItem.selectedOption()?.value;
788
+ const value = this.deviceSelectItem.value;
730
789
  if (value === 'Edit') {
731
790
  this.emulatedDevicesList.revealCustomSetting();
732
791
  this.updateDeviceSelection();
@@ -764,9 +823,9 @@ export class DeviceModeToolbar {
764
823
  private updateDeviceScaleFactorVisibility(): void {
765
824
  if (this.deviceScaleItem) {
766
825
  const visible = this.showDeviceScaleFactorSetting.get();
767
- this.deviceScaleItem.setVisible(visible);
826
+ this.deviceScaleItem.classList.toggle('hidden', !visible);
768
827
  for (const item of this.deviceScaleItems) {
769
- item.setVisible(visible);
828
+ item.classList.toggle('hidden', !visible);
770
829
  }
771
830
  }
772
831
  }
@@ -774,7 +833,7 @@ export class DeviceModeToolbar {
774
833
  private updateUserAgentTypeVisibility(): void {
775
834
  if (this.uaItem) {
776
835
  const visible = this.showUserAgentTypeSetting.get();
777
- this.uaItem.setVisible(visible);
836
+ this.uaItem.classList.toggle('hidden', !visible);
778
837
  if (visible) {
779
838
  this.resizeItem(this.uaItem);
780
839
  }
@@ -802,9 +861,7 @@ export class DeviceModeToolbar {
802
861
  return;
803
862
  }
804
863
 
805
- private modeMenuClicked(event: {
806
- data: Event,
807
- }): void {
864
+ private modeMenuClicked(event: Event): void {
808
865
  if (this.model.isScreenOrientationLocked()) {
809
866
  return;
810
867
  }
@@ -847,9 +904,9 @@ export class DeviceModeToolbar {
847
904
  return;
848
905
  }
849
906
 
850
- const contextMenu = new UI.ContextMenu.ContextMenu(event.data, {
851
- x: this.modeButton.element.getBoundingClientRect().left,
852
- y: this.modeButton.element.getBoundingClientRect().top + (this.modeButton.element as HTMLElement).offsetHeight,
907
+ const contextMenu = new UI.ContextMenu.ContextMenu(event, {
908
+ x: this.modeButton.getBoundingClientRect().left,
909
+ y: this.modeButton.getBoundingClientRect().top + this.modeButton.offsetHeight,
853
910
  });
854
911
  addOrientation(EmulationModel.EmulatedDevices.Vertical, i18nString(UIStrings.portrait));
855
912
  addOrientation(EmulationModel.EmulatedDevices.Horizontal, i18nString(UIStrings.landscape));
@@ -902,20 +959,20 @@ export class DeviceModeToolbar {
902
959
  this.widthInput.disabled = this.model.type() !== EmulationModel.DeviceModeModel.Type.Responsive;
903
960
 
904
961
  this.heightInput.disabled = this.model.type() !== EmulationModel.DeviceModeModel.Type.Responsive;
905
- this.deviceScaleItem.setEnabled(this.model.type() === EmulationModel.DeviceModeModel.Type.Responsive);
906
- this.uaItem.setEnabled(this.model.type() === EmulationModel.DeviceModeModel.Type.Responsive);
962
+ this.deviceScaleItem.disabled = this.model.type() !== EmulationModel.DeviceModeModel.Type.Responsive;
963
+ this.uaItem.disabled = this.model.type() !== EmulationModel.DeviceModeModel.Type.Responsive;
907
964
 
908
965
  if (this.model.type() === EmulationModel.DeviceModeModel.Type.Responsive) {
909
- this.modeButton.setEnabled(true);
966
+ this.modeButton.disabled = false;
910
967
  setTitleForButton(this.modeButton, i18nString(UIStrings.rotate));
911
968
  } else {
912
- this.modeButton.setEnabled(false);
969
+ this.modeButton.disabled = true;
913
970
  }
914
971
  }
915
972
 
916
973
  const size = this.model.appliedDeviceSize();
917
- this.widthInput.size = String(size.width);
918
- this.heightInput.size =
974
+ this.widthInput.value = String(size.width);
975
+ this.heightInput.value =
919
976
  this.model.type() === EmulationModel.DeviceModeModel.Type.Responsive && this.model.isFullHeight() ?
920
977
  '' :
921
978
  String(size.height);
@@ -928,14 +985,14 @@ export class DeviceModeToolbar {
928
985
 
929
986
  const deviceScale = this.model.appliedDeviceScaleFactor();
930
987
  if (deviceScale !== this.cachedDeviceScale) {
931
- this.deviceScaleItem.element.value = String(deviceScale);
988
+ this.deviceScaleItem.value = String(deviceScale);
932
989
  this.cachedDeviceScale = deviceScale;
933
990
  this.resizeItem(this.deviceScaleItem, true);
934
991
  }
935
992
 
936
993
  const uaType = this.model.appliedUserAgentType();
937
994
  if (uaType !== this.cachedUaType) {
938
- this.uaItem.element.value = uaType;
995
+ this.uaItem.value = uaType;
939
996
  this.cachedUaType = uaType;
940
997
  this.updateDeviceScaleMenuItems();
941
998
  this.resizeItem(this.uaItem);
@@ -948,7 +1005,7 @@ export class DeviceModeToolbar {
948
1005
  const device = this.model.device();
949
1006
  if (device) {
950
1007
  const modeCount = device ? device.modes.length : 0;
951
- this.modeButton.setEnabled(modeCount >= 2);
1008
+ this.modeButton.disabled = modeCount < 2;
952
1009
  setTitleForButton(
953
1010
  this.modeButton,
954
1011
  modeCount === 2 ? i18nString(UIStrings.rotate) : i18nString(UIStrings.screenOrientationOptions));
@@ -957,15 +1014,15 @@ export class DeviceModeToolbar {
957
1014
  }
958
1015
 
959
1016
  if (device?.isDualScreen) {
960
- this.spanButton.setVisible(true);
961
- this.postureItem.setVisible(false);
1017
+ this.spanButton.classList.toggle('hidden', false);
1018
+ this.postureItem.classList.toggle('hidden', true);
962
1019
  } else if (device?.isFoldableScreen) {
963
- this.spanButton.setVisible(false);
964
- this.postureItem.setVisible(true);
1020
+ this.spanButton.classList.toggle('hidden', true);
1021
+ this.postureItem.classList.toggle('hidden', false);
965
1022
  this.updateDevicePostureItems();
966
1023
  } else {
967
- this.spanButton.setVisible(false);
968
- this.postureItem.setVisible(false);
1024
+ this.spanButton.classList.toggle('hidden', true);
1025
+ this.postureItem.classList.toggle('hidden', true);
969
1026
  }
970
1027
  setTitleForButton(this.spanButton, i18nString(UIStrings.toggleDualscreenMode));
971
1028
 
@@ -996,16 +1053,16 @@ export class DeviceModeToolbar {
996
1053
  // disable the rotate button to prevent user-initiated rotation.
997
1054
  // When unlocked, restore the button to its normal state.
998
1055
  if (this.model.isScreenOrientationLocked()) {
999
- this.modeButton.setEnabled(false);
1056
+ this.modeButton.disabled = true;
1000
1057
  setTitleForButton(this.modeButton, i18nString(UIStrings.screenOrientationLocked));
1001
1058
  } else if (this.cachedModelDevice) {
1002
1059
  const modeCount = this.cachedModelDevice.modes.length;
1003
- this.modeButton.setEnabled(modeCount >= 2);
1060
+ this.modeButton.disabled = modeCount < 2;
1004
1061
  setTitleForButton(
1005
1062
  this.modeButton,
1006
1063
  modeCount === 2 ? i18nString(UIStrings.rotate) : i18nString(UIStrings.screenOrientationOptions));
1007
1064
  } else if (this.model.type() === EmulationModel.DeviceModeModel.Type.Responsive) {
1008
- this.modeButton.setEnabled(true);
1065
+ this.modeButton.disabled = false;
1009
1066
  setTitleForButton(this.modeButton, i18nString(UIStrings.rotate));
1010
1067
  }
1011
1068
  }
@@ -1027,13 +1084,13 @@ export class DeviceModeToolbar {
1027
1084
  this.model.emulate(EmulationModel.DeviceModeModel.Type.Responsive, null, null);
1028
1085
  }
1029
1086
 
1030
- private resizeItem(item: UI.Toolbar.ToolbarComboBox, stripParens = false): void {
1031
- const selectedOption = item.selectedOption();
1087
+ private resizeItem(item: HTMLSelectElement, stripParens = false): void {
1088
+ const selectedOption = item.options[item.selectedIndex];
1032
1089
  if (!selectedOption) {
1033
1090
  return;
1034
1091
  }
1035
1092
 
1036
- const dummySelect = item.element.cloneNode(false) as HTMLSelectElement;
1093
+ const dummySelect = item.cloneNode(false) as HTMLSelectElement;
1037
1094
  const dummyOption = selectedOption.cloneNode(true) as HTMLOptionElement;
1038
1095
 
1039
1096
  if (stripParens) {
@@ -1049,8 +1106,8 @@ export class DeviceModeToolbar {
1049
1106
  dummySelect.style.visibility = 'hidden';
1050
1107
  dummySelect.style.pointerEvents = 'none';
1051
1108
 
1052
- item.element.parentElement?.appendChild(dummySelect);
1053
- item.element.style.width = dummySelect.offsetWidth + 'px';
1109
+ item.parentElement?.appendChild(dummySelect);
1110
+ item.style.width = dummySelect.offsetWidth + 'px';
1054
1111
  dummySelect.remove();
1055
1112
  }
1056
1113
  }
@@ -25,6 +25,31 @@
25
25
  font-size: 16px;
26
26
  }
27
27
 
28
+ .device-mode-size-input {
29
+ /*
30
+ * 4 characters for the maximum size of the value,
31
+ * 2 characters for the width of the step-buttons,
32
+ * 2 pixels padding between the characters and the
33
+ * step-buttons.
34
+ */
35
+ width: calc(4ch + 2ch + 2px);
36
+ max-height: 18px;
37
+ border: var(--sys-color-neutral-outline);
38
+ border-radius: 4px;
39
+ margin: 0 2px;
40
+ text-align: center;
41
+ font-size: inherit;
42
+ font-family: inherit;
43
+ }
44
+
45
+ .device-mode-size-input:disabled {
46
+ user-select: none;
47
+ }
48
+
49
+ .device-mode-size-input:focus::-webkit-input-placeholder {
50
+ color: transparent;
51
+ }
52
+
28
53
  .device-mode-empty-toolbar-element {
29
54
  width: 0;
30
55
  }