chrome-devtools-frontend 1.0.1516909 → 1.0.1519267
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/config/owner/COMMON_OWNERS +2 -2
- package/docs/checklist/README.md +2 -2
- package/docs/checklist/javascript.md +1 -1
- package/docs/contributing/README.md +1 -1
- package/docs/contributing/settings-experiments-features.md +9 -8
- package/docs/cookbook/devtools_on_devtools.md +2 -2
- package/docs/cookbook/localization.md +10 -10
- package/docs/devtools-protocol.md +9 -8
- package/docs/ecosystem/automatic_workspace_folders.md +3 -3
- package/docs/get_the_code.md +0 -2
- package/docs/styleguide/ux/components.md +166 -85
- package/docs/styleguide/ux/numbers.md +3 -4
- package/eslint.config.mjs +1 -0
- package/front_end/core/common/README.md +13 -12
- package/front_end/core/host/GdpClient.ts +16 -1
- package/front_end/core/host/UserMetrics.ts +4 -2
- package/front_end/core/root/Runtime.ts +13 -0
- package/front_end/core/sdk/CSSMatchedStyles.ts +5 -1
- package/front_end/core/sdk/EnhancedTracesParser.ts +5 -5
- package/front_end/core/sdk/RehydratingConnection.snapshot.txt +211 -0
- package/front_end/core/sdk/TargetManager.ts +4 -0
- package/front_end/entrypoints/main/MainImpl.ts +6 -3
- package/front_end/generated/InspectorBackendCommands.js +10 -7
- package/front_end/generated/SupportedCSSProperties.js +40 -11
- package/front_end/generated/protocol-mapping.d.ts +16 -1
- package/front_end/generated/protocol-proxy-api.d.ts +13 -1
- package/front_end/generated/protocol.ts +95 -0
- package/front_end/models/ai_assistance/agents/AiAgent.ts +57 -10
- package/front_end/models/ai_assistance/agents/PerformanceAgent.ts +119 -51
- package/front_end/models/ai_assistance/agents/StylingAgent.ts +0 -31
- package/front_end/models/ai_assistance/data_formatters/PerformanceInsightFormatter.snapshot.txt +14 -181
- package/front_end/models/ai_assistance/data_formatters/PerformanceInsightFormatter.ts +19 -315
- package/front_end/models/ai_assistance/data_formatters/PerformanceTraceFormatter.snapshot.txt +224 -50
- package/front_end/models/ai_assistance/data_formatters/PerformanceTraceFormatter.ts +310 -11
- package/front_end/models/ai_assistance/performance/AIContext.ts +15 -2
- package/front_end/models/ai_code_completion/AiCodeCompletion.ts +22 -11
- package/front_end/models/badges/AiExplorerBadge.ts +19 -3
- package/front_end/models/badges/Badge.ts +10 -3
- package/front_end/models/badges/CodeWhispererBadge.ts +3 -4
- package/front_end/models/badges/DOMDetectiveBadge.ts +1 -0
- package/front_end/models/badges/SpeedsterBadge.ts +1 -0
- package/front_end/models/badges/StarterBadge.ts +3 -2
- package/front_end/models/badges/UserBadges.ts +21 -3
- package/front_end/models/badges/badges.ts +1 -0
- package/front_end/models/javascript_metadata/NativeFunctions.js +2 -2
- package/front_end/models/trace/EventsSerializer.ts +4 -3
- package/front_end/models/trace/README.md +28 -1
- package/front_end/models/trace/handlers/UserInteractionsHandler.ts +101 -73
- package/front_end/models/trace/handlers/UserTimingsHandler.ts +1 -1
- package/front_end/models/trace/helpers/Timing.ts +1 -1
- package/front_end/models/trace/helpers/Trace.ts +99 -43
- package/front_end/models/trace/types/TraceEvents.ts +9 -0
- package/front_end/panels/accessibility/ARIAAttributesView.ts +113 -191
- package/front_end/panels/accessibility/AccessibilityNodeView.ts +9 -9
- package/front_end/panels/accessibility/AccessibilitySubPane.ts +6 -4
- package/front_end/panels/accessibility/accessibilityProperties.css +2 -0
- package/front_end/panels/ai_assistance/AiAssistancePanel.ts +20 -3
- package/front_end/panels/ai_assistance/components/ChatView.ts +9 -10
- package/front_end/panels/ai_assistance/components/PerformanceAgentMarkdownRenderer.ts +44 -0
- package/front_end/panels/application/components/BounceTrackingMitigationsView.ts +2 -2
- package/front_end/panels/common/AiCodeCompletionDisclaimer.ts +32 -9
- package/front_end/panels/common/AiCodeCompletionSummaryToolbar.ts +7 -1
- package/front_end/panels/common/BadgeNotification.ts +21 -5
- package/front_end/panels/common/GdpSignUpDialog.ts +20 -12
- package/front_end/panels/console/ConsolePrompt.ts +1 -1
- package/front_end/panels/console/ConsoleView.ts +6 -2
- package/front_end/panels/css_overview/CSSOverviewCompletedView.ts +5 -5
- package/front_end/panels/elements/ElementsPanel.ts +4 -0
- package/front_end/panels/elements/ElementsTreeElement.ts +18 -0
- package/front_end/panels/elements/ElementsTreeOutline.ts +13 -0
- package/front_end/panels/elements/StylePropertyTreeElement.ts +21 -6
- package/front_end/panels/media/TickingFlameChart.ts +1 -1
- package/front_end/panels/profiler/HeapSnapshotView.ts +34 -19
- package/front_end/panels/recorder/components/RecordingView.ts +2 -2
- package/front_end/panels/search/SearchResultsPane.ts +167 -152
- package/front_end/panels/search/SearchView.ts +36 -26
- package/front_end/panels/search/searchResultsPane.css +9 -0
- package/front_end/panels/security/CookieControlsView.ts +2 -1
- package/front_end/panels/settings/AISettingsTab.ts +6 -3
- package/front_end/panels/settings/components/SyncSection.ts +39 -17
- package/front_end/panels/settings/emulation/components/UserAgentClientHintsForm.ts +1 -1
- package/front_end/panels/sources/AiCodeCompletionPlugin.ts +9 -1
- package/front_end/panels/sources/SourcesPanel.ts +4 -1
- package/front_end/panels/sources/sourcesView.css +6 -1
- package/front_end/panels/timeline/AppenderUtils.ts +2 -2
- package/front_end/panels/timeline/ExtensionTrackAppender.ts +13 -4
- package/front_end/panels/timeline/GPUTrackAppender.ts +2 -1
- package/front_end/panels/timeline/InteractionsTrackAppender.ts +5 -1
- package/front_end/panels/timeline/LayoutShiftsTrackAppender.ts +2 -1
- package/front_end/panels/timeline/ThreadAppender.ts +12 -3
- package/front_end/panels/timeline/TimelineFlameChartDataProvider.ts +9 -4
- package/front_end/panels/timeline/TimelinePanel.ts +3 -2
- package/front_end/panels/timeline/TimelineUIUtils.ts +5 -4
- package/front_end/panels/timeline/TimingsTrackAppender.ts +6 -1
- package/front_end/panels/timeline/components/CPUThrottlingSelector.ts +95 -82
- package/front_end/panels/timeline/components/LayoutShiftDetails.ts +1 -1
- package/front_end/panels/timeline/components/LiveMetricsView.ts +2 -2
- package/front_end/panels/timeline/components/NetworkRequestDetails.ts +1 -1
- package/front_end/panels/timeline/components/RelatedInsightChips.ts +1 -1
- package/front_end/panels/timeline/components/SidebarSingleInsightSet.ts +1 -1
- package/front_end/panels/timeline/components/cpuThrottlingSelector.css +17 -15
- package/front_end/panels/timeline/components/insights/BaseInsightComponent.ts +3 -0
- package/front_end/third_party/chromium/README.chromium +1 -1
- package/front_end/third_party/codemirror.next/chunk/codemirror.js +1 -1
- package/front_end/third_party/codemirror.next/chunk/codemirror.js.map +1 -1
- package/front_end/third_party/codemirror.next/codemirror.next.d.ts +6 -9
- package/front_end/third_party/codemirror.next/package.json +2 -1
- package/front_end/third_party/diff/README.chromium +1 -0
- package/front_end/third_party/puppeteer/README.chromium +2 -2
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/bidi/core/Realm.d.ts +2 -2
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/generated/injected.d.ts +1 -1
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/generated/injected.js +1 -1
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/generated/version.d.ts +1 -1
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/generated/version.js +1 -1
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/injected/injected.d.ts +1 -1
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/node/ChromeLauncher.d.ts.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/node/ChromeLauncher.js +1 -0
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/node/ChromeLauncher.js.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/revisions.d.ts +3 -3
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/revisions.js +3 -3
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/revisions.js.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/util/Function.d.ts.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/util/Function.js +16 -25
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/util/Function.js.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/util/Mutex.d.ts +2 -2
- package/front_end/third_party/puppeteer/package/lib/es5-iife/puppeteer-core-browser.js +19 -28
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/generated/injected.d.ts +1 -1
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/generated/injected.js +1 -1
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/generated/version.d.ts +1 -1
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/generated/version.js +1 -1
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/node/ChromeLauncher.d.ts.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/node/ChromeLauncher.js +1 -0
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/node/ChromeLauncher.js.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/revisions.d.ts +3 -3
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/revisions.js +3 -3
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/revisions.js.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/util/Function.d.ts.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/util/Function.js +16 -25
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/util/Function.js.map +1 -1
- package/front_end/third_party/puppeteer/package/package.json +10 -3
- package/front_end/third_party/puppeteer/package/src/generated/injected.ts +1 -1
- package/front_end/third_party/puppeteer/package/src/generated/version.ts +1 -1
- package/front_end/third_party/puppeteer/package/src/node/ChromeLauncher.ts +1 -0
- package/front_end/third_party/puppeteer/package/src/revisions.ts +3 -3
- package/front_end/third_party/puppeteer/package/src/util/Function.ts +22 -30
- package/front_end/ui/components/dialogs/Dialog.ts +1 -1
- package/front_end/ui/components/markdown_view/MarkdownImage.ts +4 -5
- package/front_end/ui/components/switch/SwitchImpl.ts +12 -1
- package/front_end/ui/components/text_editor/config.ts +22 -9
- package/front_end/ui/components/tooltips/Tooltip.ts +70 -31
- package/front_end/ui/legacy/README.md +33 -24
- package/front_end/ui/legacy/SearchableView.ts +19 -26
- package/front_end/ui/legacy/TextPrompt.ts +166 -1
- package/front_end/ui/legacy/Treeoutline.ts +19 -3
- package/front_end/ui/legacy/UIUtils.ts +15 -2
- package/front_end/ui/legacy/XElement.ts +0 -43
- package/front_end/ui/legacy/components/perf_ui/FlameChart.ts +20 -4
- package/front_end/ui/legacy/components/source_frame/XMLView.ts +12 -11
- package/front_end/ui/lit/i18n-template.ts +5 -2
- package/front_end/ui/visual_logging/KnownContextValues.ts +23 -6
- package/front_end/ui/visual_logging/README.md +43 -27
- package/package.json +1 -1
@@ -1,14 +1,15 @@
|
|
1
1
|
// Copyright 2016 The Chromium Authors
|
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
|
-
/* eslint-disable rulesdir/no-imperative-dom-api */
|
5
4
|
|
6
5
|
import * as i18n from '../../core/i18n/i18n.js';
|
7
6
|
import * as Platform from '../../core/platform/platform.js';
|
8
7
|
import * as SDK from '../../core/sdk/sdk.js';
|
9
8
|
import * as UI from '../../ui/legacy/legacy.js';
|
9
|
+
import * as Lit from '../../ui/lit/lit.js';
|
10
10
|
import * as VisualLogging from '../../ui/visual_logging/visual_logging.js';
|
11
11
|
|
12
|
+
import accessibilityPropertiesStyles from './accessibilityProperties.css.js';
|
12
13
|
import {AccessibilitySubPane} from './AccessibilitySubPane.js';
|
13
14
|
import {ariaMetadata} from './ARIAMetadata.js';
|
14
15
|
|
@@ -24,214 +25,135 @@ const UIStrings = {
|
|
24
25
|
} as const;
|
25
26
|
const str_ = i18n.i18n.registerUIStrings('panels/accessibility/ARIAAttributesView.ts', UIStrings);
|
26
27
|
const i18nString = i18n.i18n.getLocalizedString.bind(undefined, str_);
|
28
|
+
const {render, html} = Lit;
|
29
|
+
|
30
|
+
interface ViewInput {
|
31
|
+
propertyCompletions: Map<SDK.DOMModel.Attribute, string[]>;
|
32
|
+
onStartEditing: (attribute: SDK.DOMModel.Attribute) => void;
|
33
|
+
onCommitEditing: (attribute: SDK.DOMModel.Attribute, result: string) => void;
|
34
|
+
onCancelEditing: (attribute: SDK.DOMModel.Attribute) => void;
|
35
|
+
attributeBeingEdited: SDK.DOMModel.Attribute|null;
|
36
|
+
attributes: SDK.DOMModel.Attribute[];
|
37
|
+
}
|
38
|
+
|
39
|
+
type View = (input: ViewInput, output: object, target: HTMLElement) => void;
|
40
|
+
export const DEFAULT_VIEW: View = (input, output, target) => {
|
41
|
+
const MAX_CONTENT_LENGTH = 10000;
|
42
|
+
|
43
|
+
const onStartEditing = (attribute: SDK.DOMModel.Attribute, e: MouseEvent): void => {
|
44
|
+
e.consume(true);
|
45
|
+
input.onStartEditing(attribute);
|
46
|
+
};
|
47
|
+
|
48
|
+
const propertyCompletions = (attribute: SDK.DOMModel.Attribute): Lit.LitTemplate => {
|
49
|
+
const values = input.propertyCompletions.get(attribute);
|
50
|
+
if (!values?.length) {
|
51
|
+
return Lit.nothing;
|
52
|
+
}
|
53
|
+
|
54
|
+
return html`<datalist id=completions>
|
55
|
+
${values.map(value => html`<option>${value}</option>`)}
|
56
|
+
</datalist>`;
|
57
|
+
};
|
58
|
+
|
59
|
+
render(
|
60
|
+
// clang-format off
|
61
|
+
input.attributes.length === 0 ?
|
62
|
+
html`
|
63
|
+
<style>${accessibilityPropertiesStyles}</style>
|
64
|
+
<devtools-widget
|
65
|
+
.widgetConfig=${UI.Widget.widgetConfig(UI.EmptyWidget.EmptyWidget,
|
66
|
+
{text: i18nString(UIStrings.noAriaAttributes)})}
|
67
|
+
class="gray-info-message info-message-overflow"></devtools-widget>` :
|
68
|
+
html`<devtools-tree
|
69
|
+
hide-overflow
|
70
|
+
.template=${html`
|
71
|
+
<ul role="tree">
|
72
|
+
${input.attributes?.map(attribute => html`
|
73
|
+
<li role="treeitem">
|
74
|
+
<style>${accessibilityPropertiesStyles}</style>
|
75
|
+
<span class="ax-name monospace" @mousedown=${onStartEditing.bind(null, attribute)}>
|
76
|
+
${attribute.name}
|
77
|
+
</span>
|
78
|
+
<span class="separator" @mousedown=${onStartEditing.bind(null, attribute)}>${':\xA0'}</span>
|
79
|
+
<devtools-prompt
|
80
|
+
completions=completions
|
81
|
+
class="monospace"
|
82
|
+
@mousedown=${onStartEditing.bind(null, attribute)}
|
83
|
+
.completionTimeout=${0}
|
84
|
+
?editing=${input.attributeBeingEdited === attribute}
|
85
|
+
@commit=${(e: UI.TextPrompt.TextPromptElement.CommitEvent) =>
|
86
|
+
input.onCommitEditing(attribute, e.detail)}
|
87
|
+
@cancel=${() => input.onCancelEditing(attribute)}>
|
88
|
+
${Platform.StringUtilities.trimMiddle(attribute.value, MAX_CONTENT_LENGTH)}
|
89
|
+
${propertyCompletions(attribute)}
|
90
|
+
</devtools-prompt>
|
91
|
+
</li>`)}
|
92
|
+
</ul>
|
93
|
+
`}></devtools-tree>`,
|
94
|
+
// clang-format on
|
95
|
+
target);
|
96
|
+
};
|
97
|
+
|
27
98
|
export class ARIAAttributesPane extends AccessibilitySubPane {
|
28
|
-
|
29
|
-
|
99
|
+
readonly #view: View;
|
100
|
+
#attributeBeingEdited: SDK.DOMModel.Attribute|null = null;
|
30
101
|
|
31
|
-
constructor() {
|
102
|
+
constructor(view = DEFAULT_VIEW) {
|
32
103
|
super({
|
33
104
|
title: i18nString(UIStrings.ariaAttributes),
|
34
105
|
viewId: 'aria-attributes',
|
35
106
|
jslog: `${VisualLogging.section('aria-attributes')}`,
|
36
107
|
});
|
37
108
|
|
38
|
-
this
|
39
|
-
this.treeOutline = this.createTreeOutline();
|
109
|
+
this.#view = view;
|
40
110
|
}
|
41
111
|
|
42
112
|
override setNode(node: SDK.DOMModel.DOMNode|null): void {
|
43
113
|
super.setNode(node);
|
44
|
-
this.
|
45
|
-
|
46
|
-
return;
|
47
|
-
}
|
48
|
-
const target = node.domModel().target();
|
49
|
-
const attributes = node.attributes();
|
50
|
-
for (let i = 0; i < attributes.length; ++i) {
|
51
|
-
const attribute = attributes[i];
|
52
|
-
if (!this.isARIAAttribute(attribute)) {
|
53
|
-
continue;
|
54
|
-
}
|
114
|
+
this.requestUpdate();
|
115
|
+
}
|
55
116
|
|
56
|
-
|
57
|
-
|
117
|
+
override performUpdate(): void {
|
118
|
+
const onStartEditing = (attribute: SDK.DOMModel.Attribute): void => {
|
119
|
+
this.#attributeBeingEdited = attribute;
|
120
|
+
this.requestUpdate();
|
121
|
+
};
|
122
|
+
const onCancelEditing = (attribute: SDK.DOMModel.Attribute): void => {
|
123
|
+
if (attribute === this.#attributeBeingEdited) {
|
124
|
+
this.#attributeBeingEdited = null;
|
125
|
+
}
|
126
|
+
this.requestUpdate();
|
127
|
+
};
|
128
|
+
|
129
|
+
const onCommitEditing = (attribute: SDK.DOMModel.Attribute, result: string): void => {
|
130
|
+
// Make the changes to the attribute
|
131
|
+
const node = this.node();
|
132
|
+
if (node && attribute.value !== result) {
|
133
|
+
node.setAttributeValue(attribute.name, result);
|
134
|
+
}
|
135
|
+
if (attribute === this.#attributeBeingEdited) {
|
136
|
+
this.#attributeBeingEdited = null;
|
137
|
+
}
|
138
|
+
this.requestUpdate();
|
139
|
+
};
|
58
140
|
|
59
|
-
const
|
60
|
-
|
61
|
-
|
62
|
-
}
|
141
|
+
const attributes = this.node()?.attributes()?.filter(attribute => this.isARIAAttribute(attribute)) ?? [];
|
142
|
+
const propertyCompletions =
|
143
|
+
new Map(attributes.map(attribute => [attribute, ariaMetadata().valuesForProperty(attribute.name)]));
|
63
144
|
|
64
|
-
|
65
|
-
|
145
|
+
const input: ViewInput = {
|
146
|
+
attributeBeingEdited: this.#attributeBeingEdited,
|
147
|
+
attributes,
|
148
|
+
onStartEditing,
|
149
|
+
onCommitEditing,
|
150
|
+
onCancelEditing,
|
151
|
+
propertyCompletions,
|
152
|
+
};
|
153
|
+
this.#view(input, {}, this.contentElement);
|
66
154
|
}
|
67
155
|
|
68
156
|
private isARIAAttribute(attribute: SDK.DOMModel.Attribute): boolean {
|
69
157
|
return SDK.DOMModel.ARIA_ATTRIBUTES.has(attribute.name);
|
70
158
|
}
|
71
159
|
}
|
72
|
-
|
73
|
-
export class ARIAAttributesTreeElement extends UI.TreeOutline.TreeElement {
|
74
|
-
private readonly parentPane: ARIAAttributesPane;
|
75
|
-
private readonly attribute: SDK.DOMModel.Attribute;
|
76
|
-
private nameElement?: HTMLSpanElement;
|
77
|
-
private valueElement?: Element;
|
78
|
-
private prompt?: ARIAAttributePrompt;
|
79
|
-
|
80
|
-
constructor(parentPane: ARIAAttributesPane, attribute: SDK.DOMModel.Attribute, _target: SDK.Target.Target) {
|
81
|
-
super('');
|
82
|
-
|
83
|
-
this.parentPane = parentPane;
|
84
|
-
this.attribute = attribute;
|
85
|
-
|
86
|
-
this.selectable = false;
|
87
|
-
}
|
88
|
-
|
89
|
-
static createARIAValueElement(value: string): Element {
|
90
|
-
const valueElement = document.createElement('span');
|
91
|
-
valueElement.classList.add('monospace');
|
92
|
-
// TODO(aboxhall): quotation marks?
|
93
|
-
valueElement.setTextContentTruncatedIfNeeded(value || '');
|
94
|
-
return valueElement;
|
95
|
-
}
|
96
|
-
|
97
|
-
override onattach(): void {
|
98
|
-
this.populateListItem();
|
99
|
-
this.listItemElement.addEventListener('click', this.mouseClick.bind(this));
|
100
|
-
}
|
101
|
-
|
102
|
-
getPromptForTesting(): Readonly<ARIAAttributePrompt>|undefined {
|
103
|
-
return this.prompt;
|
104
|
-
}
|
105
|
-
|
106
|
-
private populateListItem(): void {
|
107
|
-
this.listItemElement.removeChildren();
|
108
|
-
this.appendNameElement(this.attribute.name);
|
109
|
-
this.listItemElement.createChild('span', 'separator').textContent = ':\xA0';
|
110
|
-
this.appendAttributeValueElement(this.attribute.value);
|
111
|
-
}
|
112
|
-
|
113
|
-
appendNameElement(name: string): void {
|
114
|
-
this.nameElement = document.createElement('span');
|
115
|
-
this.nameElement.textContent = name;
|
116
|
-
this.nameElement.classList.add('ax-name');
|
117
|
-
this.nameElement.classList.add('monospace');
|
118
|
-
this.listItemElement.appendChild(this.nameElement);
|
119
|
-
}
|
120
|
-
|
121
|
-
appendAttributeValueElement(value: string): void {
|
122
|
-
this.valueElement = ARIAAttributesTreeElement.createARIAValueElement(value);
|
123
|
-
this.listItemElement.appendChild(this.valueElement);
|
124
|
-
}
|
125
|
-
|
126
|
-
private mouseClick(event: Event): void {
|
127
|
-
if (event.target === this.listItemElement) {
|
128
|
-
return;
|
129
|
-
}
|
130
|
-
|
131
|
-
event.consume(true);
|
132
|
-
|
133
|
-
this.startEditing();
|
134
|
-
}
|
135
|
-
|
136
|
-
private startEditing(): void {
|
137
|
-
const valueElement = this.valueElement;
|
138
|
-
|
139
|
-
if (!valueElement || UI.UIUtils.isBeingEdited(valueElement)) {
|
140
|
-
return;
|
141
|
-
}
|
142
|
-
|
143
|
-
const previousContent = valueElement.textContent || '';
|
144
|
-
|
145
|
-
function blurListener(this: ARIAAttributesTreeElement, previousContent: string, event: Event): void {
|
146
|
-
const target = event.target as HTMLElement;
|
147
|
-
const text = target.textContent || '';
|
148
|
-
this.editingCommitted(text, previousContent);
|
149
|
-
}
|
150
|
-
|
151
|
-
const attributeName = (this.nameElement as HTMLSpanElement).textContent || '';
|
152
|
-
this.prompt = new ARIAAttributePrompt(ariaMetadata().valuesForProperty(attributeName));
|
153
|
-
this.prompt.setAutocompletionTimeout(0);
|
154
|
-
const proxyElement =
|
155
|
-
this.prompt.attachAndStartEditing(valueElement, blurListener.bind(this, previousContent)) as HTMLElement;
|
156
|
-
|
157
|
-
proxyElement.addEventListener('keydown', event => this.editingValueKeyDown(previousContent, event), false);
|
158
|
-
|
159
|
-
const selection = valueElement.getComponentSelection();
|
160
|
-
if (selection) {
|
161
|
-
selection.selectAllChildren(valueElement);
|
162
|
-
}
|
163
|
-
}
|
164
|
-
|
165
|
-
private removePrompt(): void {
|
166
|
-
if (!this.prompt) {
|
167
|
-
return;
|
168
|
-
}
|
169
|
-
this.prompt.detach();
|
170
|
-
delete this.prompt;
|
171
|
-
}
|
172
|
-
|
173
|
-
private editingCommitted(userInput: string, previousContent: string): void {
|
174
|
-
this.removePrompt();
|
175
|
-
|
176
|
-
// Make the changes to the attribute
|
177
|
-
if (userInput !== previousContent) {
|
178
|
-
const node = this.parentPane.node() as SDK.DOMModel.DOMNode;
|
179
|
-
node.setAttributeValue(this.attribute.name, userInput);
|
180
|
-
}
|
181
|
-
}
|
182
|
-
|
183
|
-
private editingCancelled(): void {
|
184
|
-
this.removePrompt();
|
185
|
-
this.populateListItem();
|
186
|
-
}
|
187
|
-
|
188
|
-
private editingValueKeyDown(previousContent: string, event: KeyboardEvent): void {
|
189
|
-
if (event.handled) {
|
190
|
-
return;
|
191
|
-
}
|
192
|
-
|
193
|
-
if (event.key === 'Enter') {
|
194
|
-
const target = event.target as HTMLElement;
|
195
|
-
this.editingCommitted(target.textContent || '', previousContent);
|
196
|
-
event.consume();
|
197
|
-
return;
|
198
|
-
}
|
199
|
-
|
200
|
-
if (Platform.KeyboardUtilities.isEscKey(event)) {
|
201
|
-
this.editingCancelled();
|
202
|
-
event.consume();
|
203
|
-
return;
|
204
|
-
}
|
205
|
-
}
|
206
|
-
}
|
207
|
-
|
208
|
-
export class ARIAAttributePrompt extends UI.TextPrompt.TextPrompt {
|
209
|
-
private readonly ariaCompletions: string[];
|
210
|
-
constructor(ariaCompletions: string[]) {
|
211
|
-
super();
|
212
|
-
this.initialize(this.buildPropertyCompletions.bind(this));
|
213
|
-
|
214
|
-
this.ariaCompletions = ariaCompletions;
|
215
|
-
}
|
216
|
-
|
217
|
-
private async buildPropertyCompletions(expression: string, prefix: string, force?: boolean):
|
218
|
-
Promise<UI.SuggestBox.Suggestions> {
|
219
|
-
prefix = prefix.toLowerCase();
|
220
|
-
if (!prefix && !force && expression) {
|
221
|
-
return [];
|
222
|
-
}
|
223
|
-
return this.ariaCompletions.filter(value => value.startsWith(prefix)).map(c => {
|
224
|
-
return {
|
225
|
-
text: c,
|
226
|
-
title: undefined,
|
227
|
-
subtitle: undefined,
|
228
|
-
priority: undefined,
|
229
|
-
isSecondary: undefined,
|
230
|
-
subtitleRenderer: undefined,
|
231
|
-
selectionRange: undefined,
|
232
|
-
hideGhostText: undefined,
|
233
|
-
iconElement: undefined,
|
234
|
-
};
|
235
|
-
});
|
236
|
-
}
|
237
|
-
}
|
@@ -120,8 +120,8 @@ const str_ = i18n.i18n.registerUIStrings('panels/accessibility/AccessibilityNode
|
|
120
120
|
const i18nString = i18n.i18n.getLocalizedString.bind(undefined, str_);
|
121
121
|
export class AXNodeSubPane extends AccessibilitySubPane {
|
122
122
|
override axNode: SDK.AccessibilityModel.AccessibilityNode|null;
|
123
|
-
private readonly noNodeInfo:
|
124
|
-
private readonly ignoredInfo:
|
123
|
+
private readonly noNodeInfo: UI.Widget.Widget;
|
124
|
+
private readonly ignoredInfo: UI.Widget.Widget;
|
125
125
|
private readonly treeOutline: UI.TreeOutline.TreeOutline;
|
126
126
|
private readonly ignoredReasonsTree: UI.TreeOutline.TreeOutline;
|
127
127
|
constructor() {
|
@@ -137,7 +137,7 @@ export class AXNodeSubPane extends AccessibilitySubPane {
|
|
137
137
|
this.contentElement.classList.add('ax-subpane');
|
138
138
|
|
139
139
|
this.noNodeInfo = this.createInfo(i18nString(UIStrings.noAccessibilityNode));
|
140
|
-
this.ignoredInfo = this.createInfo(i18nString(UIStrings.accessibilityNodeNotExposed), 'ax-ignored-info hidden');
|
140
|
+
this.ignoredInfo = this.createInfo(i18nString(UIStrings.accessibilityNodeNotExposed), 'ax-ignored-info', 'hidden');
|
141
141
|
|
142
142
|
this.treeOutline = this.createTreeOutline();
|
143
143
|
this.ignoredReasonsTree = this.createTreeOutline();
|
@@ -160,21 +160,21 @@ export class AXNodeSubPane extends AccessibilitySubPane {
|
|
160
160
|
|
161
161
|
if (!axNode) {
|
162
162
|
treeOutline.element.classList.add('hidden');
|
163
|
-
this.ignoredInfo.classList.add('hidden');
|
163
|
+
this.ignoredInfo.element.classList.add('hidden');
|
164
164
|
ignoredReasons.element.classList.add('hidden');
|
165
165
|
|
166
|
-
this.noNodeInfo.classList.remove('hidden');
|
166
|
+
this.noNodeInfo.element.classList.remove('hidden');
|
167
167
|
this.element.classList.add('ax-ignored-node-pane');
|
168
168
|
|
169
169
|
return;
|
170
170
|
}
|
171
171
|
|
172
172
|
if (axNode.ignored()) {
|
173
|
-
this.noNodeInfo.classList.add('hidden');
|
173
|
+
this.noNodeInfo.element.classList.add('hidden');
|
174
174
|
treeOutline.element.classList.add('hidden');
|
175
175
|
this.element.classList.add('ax-ignored-node-pane');
|
176
176
|
|
177
|
-
this.ignoredInfo.classList.remove('hidden');
|
177
|
+
this.ignoredInfo.element.classList.remove('hidden');
|
178
178
|
ignoredReasons.element.classList.remove('hidden');
|
179
179
|
function addIgnoredReason(property: Protocol.Accessibility.AXProperty): void {
|
180
180
|
ignoredReasons.appendChild(
|
@@ -191,9 +191,9 @@ export class AXNodeSubPane extends AccessibilitySubPane {
|
|
191
191
|
}
|
192
192
|
this.element.classList.remove('ax-ignored-node-pane');
|
193
193
|
|
194
|
-
this.ignoredInfo.classList.add('hidden');
|
194
|
+
this.ignoredInfo.element.classList.add('hidden');
|
195
195
|
ignoredReasons.element.classList.add('hidden');
|
196
|
-
this.noNodeInfo.classList.add('hidden');
|
196
|
+
this.noNodeInfo.element.classList.add('hidden');
|
197
197
|
|
198
198
|
treeOutline.element.classList.remove('hidden');
|
199
199
|
|
@@ -33,10 +33,12 @@ export class AccessibilitySubPane extends UI.View.SimpleView {
|
|
33
33
|
this.nodeInternal = node;
|
34
34
|
}
|
35
35
|
|
36
|
-
createInfo(textContent: string,
|
37
|
-
const info =
|
38
|
-
|
39
|
-
|
36
|
+
createInfo(textContent: string, ...classNames: string[]): UI.Widget.Widget {
|
37
|
+
const info = new UI.EmptyWidget.EmptyWidget(textContent);
|
38
|
+
if (classNames.length === 0) {
|
39
|
+
classNames.push('gray-info-message');
|
40
|
+
}
|
41
|
+
info.element.classList.add(...classNames, 'info-message-overflow');
|
40
42
|
return info;
|
41
43
|
}
|
42
44
|
|
@@ -12,6 +12,7 @@ import * as Root from '../../core/root/root.js';
|
|
12
12
|
import * as SDK from '../../core/sdk/sdk.js';
|
13
13
|
import * as Protocol from '../../generated/protocol.js';
|
14
14
|
import * as AiAssistanceModel from '../../models/ai_assistance/ai_assistance.js';
|
15
|
+
import * as Badges from '../../models/badges/badges.js';
|
15
16
|
import * as TextUtils from '../../models/text_utils/text_utils.js';
|
16
17
|
import * as Workspace from '../../models/workspace/workspace.js';
|
17
18
|
import * as Buttons from '../../ui/components/buttons/buttons.js';
|
@@ -35,6 +36,8 @@ import {
|
|
35
36
|
type Step
|
36
37
|
} from './components/ChatView.js';
|
37
38
|
import {ExploreWidget} from './components/ExploreWidget.js';
|
39
|
+
import {MarkdownRendererWithCodeBlock} from './components/MarkdownRendererWithCodeBlock.js';
|
40
|
+
import {PerformanceAgentMarkdownRenderer} from './components/PerformanceAgentMarkdownRenderer.js';
|
38
41
|
import {isAiAssistancePatchingEnabled} from './PatchWidget.js';
|
39
42
|
|
40
43
|
const {html} = Lit;
|
@@ -263,6 +266,16 @@ async function getEmptyStateSuggestions(
|
|
263
266
|
}
|
264
267
|
}
|
265
268
|
|
269
|
+
function getMarkdownRenderer(context: AiAssistanceModel.ConversationContext<unknown>|null):
|
270
|
+
MarkdownRendererWithCodeBlock {
|
271
|
+
if (context instanceof AiAssistanceModel.PerformanceTraceContext && !context.external) {
|
272
|
+
const focus = context.getItem();
|
273
|
+
return new PerformanceAgentMarkdownRenderer(focus.lookupEvent.bind(focus));
|
274
|
+
}
|
275
|
+
|
276
|
+
return new MarkdownRendererWithCodeBlock();
|
277
|
+
}
|
278
|
+
|
266
279
|
interface ToolbarViewInput {
|
267
280
|
onNewChatClick: () => void;
|
268
281
|
populateHistoryMenu: (contextMenu: UI.ContextMenu.ContextMenu) => void;
|
@@ -837,6 +850,7 @@ export class AiAssistancePanel extends UI.Panel.Panel {
|
|
837
850
|
|
838
851
|
override async performUpdate(): Promise<void> {
|
839
852
|
const emptyStateSuggestions = await getEmptyStateSuggestions(this.#selectedContext, this.#conversation);
|
853
|
+
const markdownRenderer = getMarkdownRenderer(this.#selectedContext);
|
840
854
|
|
841
855
|
this.view(
|
842
856
|
{
|
@@ -865,6 +879,7 @@ export class AiAssistancePanel extends UI.Panel.Panel {
|
|
865
879
|
changeManager: this.#changeManager,
|
866
880
|
uploadImageInputEnabled: isAiAssistanceMultimodalUploadInputEnabled() &&
|
867
881
|
this.#conversation?.type === AiAssistanceModel.ConversationType.STYLING,
|
882
|
+
markdownRenderer,
|
868
883
|
onNewChatClick: this.#handleNewChatRequest.bind(this),
|
869
884
|
populateHistoryMenu: this.#populateHistoryMenu.bind(this),
|
870
885
|
onDeleteClick: this.#onDeleteClicked.bind(this),
|
@@ -1054,8 +1069,8 @@ export class AiAssistancePanel extends UI.Panel.Panel {
|
|
1054
1069
|
const focus = context.getItem().data;
|
1055
1070
|
if (focus.callTree) {
|
1056
1071
|
const event = focus.callTree.selectedNode?.event ?? focus.callTree.rootNode.event;
|
1057
|
-
const
|
1058
|
-
return Common.Revealer.reveal(
|
1072
|
+
const revealable = new SDK.TraceObject.RevealableEvent(event);
|
1073
|
+
return Common.Revealer.reveal(revealable);
|
1059
1074
|
}
|
1060
1075
|
if (focus.insight) {
|
1061
1076
|
return Common.Revealer.reveal(focus.insight);
|
@@ -1395,7 +1410,9 @@ export class AiAssistancePanel extends UI.Panel.Panel {
|
|
1395
1410
|
// invariants do not hold anymore.
|
1396
1411
|
throw new Error('cross-origin context data should not be included');
|
1397
1412
|
}
|
1398
|
-
|
1413
|
+
if (this.#conversation?.isEmpty) {
|
1414
|
+
Badges.UserBadges.instance().recordAction(Badges.BadgeAction.STARTED_AI_CONVERSATION);
|
1415
|
+
}
|
1399
1416
|
const image = isAiAssistanceMultimodalInputEnabled() ? imageInput : undefined;
|
1400
1417
|
const imageId = image ? crypto.randomUUID() : undefined;
|
1401
1418
|
const multimodalInput = image && imageId && multimodalInputType ? {
|
@@ -18,13 +18,13 @@ import * as PanelUtils from '../../../panels/utils/utils.js';
|
|
18
18
|
import * as Marked from '../../../third_party/marked/marked.js';
|
19
19
|
import * as Buttons from '../../../ui/components/buttons/buttons.js';
|
20
20
|
import type * as MarkdownView from '../../../ui/components/markdown_view/markdown_view.js';
|
21
|
+
import type {MarkdownLitRenderer} from '../../../ui/components/markdown_view/MarkdownView.js';
|
21
22
|
import * as UI from '../../../ui/legacy/legacy.js';
|
22
23
|
import * as Lit from '../../../ui/lit/lit.js';
|
23
24
|
import * as VisualLogging from '../../../ui/visual_logging/visual_logging.js';
|
24
25
|
import {PatchWidget} from '../PatchWidget.js';
|
25
26
|
|
26
27
|
import chatViewStyles from './chatView.css.js';
|
27
|
-
import {MarkdownRendererWithCodeBlock} from './MarkdownRendererWithCodeBlock.js';
|
28
28
|
import {UserActionRow} from './UserActionRow.js';
|
29
29
|
|
30
30
|
const {html, Directives: {ifDefined, ref}} = Lit;
|
@@ -303,11 +303,11 @@ export interface Props {
|
|
303
303
|
disclaimerText: Platform.UIString.LocalizedString;
|
304
304
|
isTextInputEmpty: boolean;
|
305
305
|
uploadImageInputEnabled?: boolean;
|
306
|
+
markdownRenderer: MarkdownLitRenderer;
|
306
307
|
}
|
307
308
|
|
308
309
|
export class ChatView extends HTMLElement {
|
309
310
|
readonly #shadow = this.attachShadow({mode: 'open'});
|
310
|
-
#markdownRenderer = new MarkdownRendererWithCodeBlock();
|
311
311
|
#scrollTop?: number;
|
312
312
|
#props: Props;
|
313
313
|
#messagesContainerElement?: Element;
|
@@ -338,7 +338,6 @@ export class ChatView extends HTMLElement {
|
|
338
338
|
}
|
339
339
|
|
340
340
|
set props(props: Props) {
|
341
|
-
this.#markdownRenderer = new MarkdownRendererWithCodeBlock();
|
342
341
|
this.#props = props;
|
343
342
|
this.#render();
|
344
343
|
}
|
@@ -624,7 +623,7 @@ export class ChatView extends HTMLElement {
|
|
624
623
|
isTextInputDisabled: this.#props.isTextInputDisabled,
|
625
624
|
suggestions: this.#props.emptyStateSuggestions,
|
626
625
|
userInfo: this.#props.userInfo,
|
627
|
-
markdownRenderer: this.#markdownRenderer,
|
626
|
+
markdownRenderer: this.#props.markdownRenderer,
|
628
627
|
conversationType: this.#props.conversationType,
|
629
628
|
changeSummary: this.#props.changeSummary,
|
630
629
|
changeManager: this.#props.changeManager,
|
@@ -672,7 +671,7 @@ export class ChatView extends HTMLElement {
|
|
672
671
|
}
|
673
672
|
}
|
674
673
|
|
675
|
-
function renderTextAsMarkdown(text: string, markdownRenderer:
|
674
|
+
function renderTextAsMarkdown(text: string, markdownRenderer: MarkdownLitRenderer, {animate, ref: refFn}: {
|
676
675
|
animate?: boolean,
|
677
676
|
ref?: (element?: Element) => void,
|
678
677
|
} = {}): Lit.TemplateResult {
|
@@ -753,7 +752,7 @@ function renderStepDetails({
|
|
753
752
|
isLast,
|
754
753
|
}: {
|
755
754
|
step: Step,
|
756
|
-
markdownRenderer:
|
755
|
+
markdownRenderer: MarkdownLitRenderer,
|
757
756
|
isLast: boolean,
|
758
757
|
}): Lit.LitTemplate {
|
759
758
|
const sideEffects = isLast && step.sideEffect ? renderSideEffectConfirmationUi(step) : Lit.nothing;
|
@@ -817,7 +816,7 @@ function renderStepBadge({step, isLoading, isLast}: {
|
|
817
816
|
function renderStep({step, isLoading, markdownRenderer, isLast}: {
|
818
817
|
step: Step,
|
819
818
|
isLoading: boolean,
|
820
|
-
markdownRenderer:
|
819
|
+
markdownRenderer: MarkdownLitRenderer,
|
821
820
|
isLast: boolean,
|
822
821
|
}): Lit.LitTemplate {
|
823
822
|
const stepClasses = Lit.Directives.classMap({
|
@@ -926,7 +925,7 @@ function renderChatMessage({
|
|
926
925
|
canShowFeedbackForm: boolean,
|
927
926
|
isLast: boolean,
|
928
927
|
userInfo: Pick<Host.InspectorFrontendHostAPI.SyncInformation, 'accountImage'|'accountFullName'>,
|
929
|
-
markdownRenderer:
|
928
|
+
markdownRenderer: MarkdownLitRenderer,
|
930
929
|
onSuggestionClick: (suggestion: string) => void,
|
931
930
|
onFeedbackSubmit: (rpcId: Host.AidaClient.RpcGlobalId, rate: Host.AidaClient.Rating, feedback?: string) => void,
|
932
931
|
onCopyResponseClick: (message: ModelChatMessage) => void,
|
@@ -1156,7 +1155,7 @@ function renderMessages({
|
|
1156
1155
|
isReadOnly: boolean,
|
1157
1156
|
canShowFeedbackForm: boolean,
|
1158
1157
|
userInfo: Pick<Host.InspectorFrontendHostAPI.SyncInformation, 'accountImage'|'accountFullName'>,
|
1159
|
-
markdownRenderer:
|
1158
|
+
markdownRenderer: MarkdownLitRenderer,
|
1160
1159
|
onSuggestionClick: (suggestion: string) => void,
|
1161
1160
|
onFeedbackSubmit: (rpcId: Host.AidaClient.RpcGlobalId, rate: Host.AidaClient.Rating, feedback?: string) => void,
|
1162
1161
|
onCopyResponseClick: (message: ModelChatMessage) => void,
|
@@ -1657,7 +1656,7 @@ function renderMainContents({
|
|
1657
1656
|
isTextInputDisabled: boolean,
|
1658
1657
|
suggestions: AiAssistanceModel.ConversationSuggestion[],
|
1659
1658
|
userInfo: Pick<Host.InspectorFrontendHostAPI.SyncInformation, 'accountImage'|'accountFullName'>,
|
1660
|
-
markdownRenderer:
|
1659
|
+
markdownRenderer: MarkdownLitRenderer,
|
1661
1660
|
changeManager: AiAssistanceModel.ChangeManager,
|
1662
1661
|
onSuggestionClick: (suggestion: string) => void,
|
1663
1662
|
onFeedbackSubmit: (rpcId: Host.AidaClient.RpcGlobalId, rate: Host.AidaClient.Rating, feedback?: string) => void,
|
@@ -0,0 +1,44 @@
|
|
1
|
+
// Copyright 2025 The Chromium Authors
|
2
|
+
// Use of this source code is governed by a BSD-style license that can be
|
3
|
+
// found in the LICENSE file.
|
4
|
+
|
5
|
+
import * as Common from '../../../core/common/common.js';
|
6
|
+
import * as SDK from '../../../core/sdk/sdk.js';
|
7
|
+
import * as Trace from '../../../models/trace/trace.js';
|
8
|
+
import type * as Marked from '../../../third_party/marked/marked.js';
|
9
|
+
import * as Lit from '../../../ui/lit/lit.js';
|
10
|
+
|
11
|
+
import {MarkdownRendererWithCodeBlock} from './MarkdownRendererWithCodeBlock.js';
|
12
|
+
|
13
|
+
const {html} = Lit;
|
14
|
+
|
15
|
+
export class PerformanceAgentMarkdownRenderer extends MarkdownRendererWithCodeBlock {
|
16
|
+
constructor(private lookupEvent: (key: Trace.Types.File.SerializableKey) => Trace.Types.Events.Event | null) {
|
17
|
+
super();
|
18
|
+
}
|
19
|
+
|
20
|
+
override templateForToken(token: Marked.Marked.MarkedToken): Lit.TemplateResult|null {
|
21
|
+
if (token.type === 'link' && token.href.startsWith('#')) {
|
22
|
+
const event = this.lookupEvent(token.href.slice(1) as Trace.Types.File.SerializableKey);
|
23
|
+
if (!event) {
|
24
|
+
return html`${token.text}`;
|
25
|
+
}
|
26
|
+
|
27
|
+
let label = token.text;
|
28
|
+
let title = '';
|
29
|
+
if (Trace.Types.Events.isSyntheticNetworkRequest(event)) {
|
30
|
+
title = event.args.data.url;
|
31
|
+
} else {
|
32
|
+
label += ` (${event.name})`;
|
33
|
+
}
|
34
|
+
|
35
|
+
// eslint-disable-next-line rulesdir/no-a-tags-in-lit
|
36
|
+
return html`<a href="#" draggable=false .title=${title} @click=${(e: Event) => {
|
37
|
+
e.stopPropagation();
|
38
|
+
void Common.Revealer.reveal(new SDK.TraceObject.RevealableEvent(event));
|
39
|
+
}}>${label}</a>`;
|
40
|
+
}
|
41
|
+
|
42
|
+
return super.templateForToken(token);
|
43
|
+
}
|
44
|
+
}
|
@@ -146,9 +146,9 @@ export class BounceTrackingMitigationsView extends LegacyWrapper.LegacyWrapper.W
|
|
146
146
|
// clang-format on
|
147
147
|
}
|
148
148
|
|
149
|
-
#renderDeletedSitesOrNoSitesMessage(): Lit.
|
149
|
+
#renderDeletedSitesOrNoSitesMessage(): Lit.LitTemplate {
|
150
150
|
if (!this.#seenButtonClick) {
|
151
|
-
return
|
151
|
+
return Lit.nothing;
|
152
152
|
}
|
153
153
|
|
154
154
|
if (this.#trackingSites.length === 0) {
|