@treelocator/runtime 0.5.2 → 0.6.0
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/.eslintignore +1 -0
- package/dist/_generated_styles.d.ts +1 -1
- package/dist/_generated_styles.js +20 -0
- package/dist/_generated_tree_icon.d.ts +1 -1
- package/dist/adapters/HtmlElementTreeNode.d.ts +2 -2
- package/dist/adapters/HtmlElementTreeNode.js +4 -6
- package/dist/adapters/createTreeNode.js +17 -44
- package/dist/adapters/detectFramework.d.ts +8 -0
- package/dist/adapters/detectFramework.js +25 -0
- package/dist/adapters/detectFramework.test.d.ts +1 -0
- package/dist/adapters/detectFramework.test.js +60 -0
- package/dist/adapters/jsx/jsxAdapter.js +54 -89
- package/dist/adapters/jsx/jsxAdapter.test.d.ts +1 -0
- package/dist/adapters/jsx/jsxAdapter.test.js +273 -0
- package/dist/adapters/nextjs/parseNextjsDataAttributes.js +1 -1
- package/dist/adapters/nextjs/parseNextjsDataAttributes.test.d.ts +1 -0
- package/dist/adapters/nextjs/parseNextjsDataAttributes.test.js +158 -0
- package/dist/adapters/react/findFiberByHtmlElement.d.ts +1 -1
- package/dist/adapters/react/findFiberByHtmlElement.js +1 -1
- package/dist/adapters/react/getAllParentsElementsAndRootComponent.js +4 -0
- package/dist/adapters/resolveAdapter.d.ts +1 -1
- package/dist/adapters/resolveAdapter.js +4 -8
- package/dist/adapters/svelte/svelteAdapter.test.d.ts +1 -0
- package/dist/adapters/svelte/svelteAdapter.test.js +280 -0
- package/dist/adapters/vue/vueAdapter.test.d.ts +1 -0
- package/dist/adapters/vue/vueAdapter.test.js +222 -0
- package/dist/browserApi.d.ts +148 -0
- package/dist/browserApi.js +146 -5
- package/dist/browserApi.test.d.ts +1 -0
- package/dist/browserApi.test.js +287 -0
- package/dist/components/RecordingPillButton.d.ts +11 -0
- package/dist/components/RecordingPillButton.js +202 -0
- package/dist/components/RecordingResults.d.ts +2 -0
- package/dist/components/RecordingResults.js +213 -78
- package/dist/components/Runtime.js +161 -554
- package/dist/components/SettingsPanel.d.ts +5 -0
- package/dist/components/SettingsPanel.js +312 -0
- package/dist/consoleCapture.d.ts +9 -0
- package/dist/consoleCapture.js +95 -0
- package/dist/functions/cssRuleInspector.d.ts +83 -0
- package/dist/functions/cssRuleInspector.js +608 -0
- package/dist/functions/cssRuleInspector.test.d.ts +1 -0
- package/dist/functions/cssRuleInspector.test.js +439 -0
- package/dist/functions/deduplicateLabels.test.d.ts +1 -0
- package/dist/functions/deduplicateLabels.test.js +178 -0
- package/dist/functions/enrichAncestrySourceMaps.js +0 -1
- package/dist/functions/extractComputedStyles.d.ts +51 -0
- package/dist/functions/extractComputedStyles.js +447 -0
- package/dist/functions/extractComputedStyles.test.d.ts +1 -0
- package/dist/functions/extractComputedStyles.test.js +549 -0
- package/dist/functions/formatAncestryChain.d.ts +8 -0
- package/dist/functions/formatAncestryChain.js +21 -1
- package/dist/functions/formatAncestryChain.test.js +18 -0
- package/dist/functions/getUsableName.test.d.ts +1 -0
- package/dist/functions/getUsableName.test.js +219 -0
- package/dist/functions/isCombinationModifiersPressed.test.d.ts +1 -0
- package/dist/functions/isCombinationModifiersPressed.test.js +192 -0
- package/dist/functions/mergeRects.test.js +210 -1
- package/dist/functions/namedSnapshots.d.ts +52 -0
- package/dist/functions/namedSnapshots.js +161 -0
- package/dist/functions/namedSnapshots.test.d.ts +1 -0
- package/dist/functions/namedSnapshots.test.js +85 -0
- package/dist/functions/normalizeFilePath.test.d.ts +1 -0
- package/dist/functions/normalizeFilePath.test.js +66 -0
- package/dist/functions/parseDataId.test.d.ts +1 -0
- package/dist/functions/parseDataId.test.js +101 -0
- package/dist/hooks/getStorage.d.ts +3 -0
- package/dist/hooks/getStorage.js +17 -0
- package/dist/hooks/useEventListeners.d.ts +15 -0
- package/dist/hooks/useEventListeners.js +56 -0
- package/dist/hooks/useLocatorStorage.d.ts +18 -0
- package/dist/hooks/useLocatorStorage.js +41 -0
- package/dist/hooks/useLocatorStorage.test.d.ts +1 -0
- package/dist/hooks/useLocatorStorage.test.js +124 -0
- package/dist/hooks/useRecordingState.d.ts +43 -0
- package/dist/hooks/useRecordingState.js +387 -0
- package/dist/hooks/useSettings.d.ts +13 -0
- package/dist/hooks/useSettings.js +66 -0
- package/dist/index.d.ts +5 -2
- package/dist/index.js +4 -2
- package/dist/initRuntime.d.ts +3 -1
- package/dist/initRuntime.js +4 -1
- package/dist/mcpBridge.d.ts +61 -0
- package/dist/mcpBridge.js +534 -0
- package/dist/mcpBridge.test.d.ts +1 -0
- package/dist/mcpBridge.test.js +248 -0
- package/dist/output.css +20 -0
- package/dist/visualDiff/diff.d.ts +9 -0
- package/dist/visualDiff/diff.js +209 -0
- package/dist/visualDiff/diff.test.d.ts +1 -0
- package/dist/visualDiff/diff.test.js +253 -0
- package/dist/visualDiff/settle.d.ts +3 -0
- package/dist/visualDiff/settle.js +50 -0
- package/dist/visualDiff/settle.test.d.ts +1 -0
- package/dist/visualDiff/settle.test.js +65 -0
- package/dist/visualDiff/snapshot.d.ts +4 -0
- package/dist/visualDiff/snapshot.js +84 -0
- package/dist/visualDiff/snapshot.test.d.ts +1 -0
- package/dist/visualDiff/snapshot.test.js +245 -0
- package/dist/visualDiff/types.d.ts +37 -0
- package/dist/visualDiff/types.js +1 -0
- package/package.json +2 -2
- package/scripts/wrapCSS.js +1 -1
- package/scripts/wrapImage.js +1 -1
- package/src/_generated_styles.ts +21 -1
- package/src/_generated_tree_icon.ts +1 -1
- package/src/adapters/HtmlElementTreeNode.ts +10 -7
- package/src/adapters/createTreeNode.ts +12 -51
- package/src/adapters/detectFramework.test.ts +73 -0
- package/src/adapters/detectFramework.ts +28 -0
- package/src/adapters/jsx/jsxAdapter.test.ts +240 -0
- package/src/adapters/jsx/jsxAdapter.ts +53 -106
- package/src/adapters/nextjs/parseNextjsDataAttributes.test.ts +212 -0
- package/src/adapters/nextjs/parseNextjsDataAttributes.ts +1 -1
- package/src/adapters/react/findDebugSource.ts +5 -6
- package/src/adapters/react/findFiberByHtmlElement.ts +3 -3
- package/src/adapters/react/getAllParentsElementsAndRootComponent.ts +3 -0
- package/src/adapters/react/reactAdapter.ts +1 -2
- package/src/adapters/resolveAdapter.ts +4 -14
- package/src/adapters/svelte/svelteAdapter.test.ts +334 -0
- package/src/adapters/vue/vueAdapter.test.ts +259 -0
- package/src/browserApi.test.ts +329 -0
- package/src/browserApi.ts +351 -4
- package/src/components/RecordingPillButton.tsx +301 -0
- package/src/components/RecordingResults.tsx +114 -13
- package/src/components/Runtime.tsx +176 -621
- package/src/components/SettingsPanel.tsx +339 -0
- package/src/consoleCapture.ts +113 -0
- package/src/functions/cssRuleInspector.test.ts +517 -0
- package/src/functions/cssRuleInspector.ts +708 -0
- package/src/functions/deduplicateLabels.test.ts +115 -0
- package/src/functions/enrichAncestrySourceMaps.ts +6 -3
- package/src/functions/extractComputedStyles.test.ts +681 -0
- package/src/functions/extractComputedStyles.ts +768 -0
- package/src/functions/formatAncestryChain.test.ts +23 -1
- package/src/functions/formatAncestryChain.ts +22 -1
- package/src/functions/getUsableName.test.ts +242 -0
- package/src/functions/isCombinationModifiersPressed.test.ts +156 -0
- package/src/functions/mergeRects.test.ts +111 -1
- package/src/functions/namedSnapshots.test.ts +106 -0
- package/src/functions/namedSnapshots.ts +232 -0
- package/src/functions/normalizeFilePath.test.ts +80 -0
- package/src/functions/parseDataId.test.ts +125 -0
- package/src/hooks/getStorage.ts +26 -0
- package/src/hooks/useEventListeners.ts +97 -0
- package/src/hooks/useLocatorStorage.test.ts +127 -0
- package/src/hooks/useLocatorStorage.ts +60 -0
- package/src/hooks/useRecordingState.ts +516 -0
- package/src/hooks/useSettings.ts +83 -0
- package/src/index.ts +10 -5
- package/src/initRuntime.ts +5 -0
- package/src/mcpBridge.test.ts +260 -0
- package/src/mcpBridge.ts +677 -0
- package/src/visualDiff/diff.test.ts +167 -0
- package/src/visualDiff/diff.ts +242 -0
- package/src/visualDiff/settle.test.ts +77 -0
- package/src/visualDiff/settle.ts +62 -0
- package/src/visualDiff/snapshot.test.ts +200 -0
- package/src/visualDiff/snapshot.ts +119 -0
- package/src/visualDiff/types.ts +40 -0
- package/tsconfig.json +3 -1
- package/vitest.config.ts +18 -0
- package/jest.config.ts +0 -195
|
@@ -1,85 +1,35 @@
|
|
|
1
1
|
import { template as _$template } from "solid-js/web";
|
|
2
|
-
import { delegateEvents as _$delegateEvents } from "solid-js/web";
|
|
3
|
-
import { createComponent as _$createComponent } from "solid-js/web";
|
|
4
2
|
import { effect as _$effect } from "solid-js/web";
|
|
5
|
-
import { insert as _$insert } from "solid-js/web";
|
|
6
|
-
import { setAttribute as _$setAttribute } from "solid-js/web";
|
|
7
3
|
import { setStyleProperty as _$setStyleProperty } from "solid-js/web";
|
|
4
|
+
import { createComponent as _$createComponent } from "solid-js/web";
|
|
8
5
|
import { memo as _$memo } from "solid-js/web";
|
|
9
|
-
var _tmpl$ = /*#__PURE__*/_$template(`<div
|
|
10
|
-
|
|
11
|
-
_tmpl$3 = /*#__PURE__*/_$template(`<div style=border-radius:3px>`),
|
|
12
|
-
_tmpl$4 = /*#__PURE__*/_$template(`<div style=border-radius:50%>`);
|
|
13
|
-
import { createEffect, createSignal, onCleanup } from "solid-js";
|
|
6
|
+
var _tmpl$ = /*#__PURE__*/_$template(`<div style="z-index:2147483645;border-radius:50%;pointer-events:none;box-shadow:0 0 12px rgba(59, 130, 246, 0.5)">`);
|
|
7
|
+
import { createEffect, createSignal } from "solid-js";
|
|
14
8
|
import { render } from "solid-js/web";
|
|
15
9
|
import { isCombinationModifiersPressed } from "../functions/isCombinationModifiersPressed";
|
|
16
10
|
import { MaybeOutline } from "./MaybeOutline";
|
|
17
11
|
import { isLocatorsOwnElement } from "../functions/isLocatorsOwnElement";
|
|
18
12
|
import { Toast } from "./Toast";
|
|
19
|
-
import { collectAncestry, formatAncestryChain, truncateAtFirstFile } from "../functions/formatAncestryChain";
|
|
13
|
+
import { collectAncestry, formatAncestryChain, truncateAtFirstFile, getElementLabel } from "../functions/formatAncestryChain";
|
|
20
14
|
import { enrichAncestryWithSourceMaps } from "../functions/enrichAncestrySourceMaps";
|
|
15
|
+
import { extractComputedStyles } from "../functions/extractComputedStyles";
|
|
21
16
|
import { createTreeNode } from "../adapters/createTreeNode";
|
|
22
|
-
import treeIconUrl from "../_generated_tree_icon";
|
|
23
|
-
import { createDejitterRecorder } from "../dejitter/recorder";
|
|
24
17
|
import { RecordingOutline } from "./RecordingOutline";
|
|
25
18
|
import { RecordingResults } from "./RecordingResults";
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
idleTimeout: 0,
|
|
32
|
-
mutations: true
|
|
33
|
-
};
|
|
19
|
+
import { RecordingPillButton } from "./RecordingPillButton";
|
|
20
|
+
import { SettingsPanel } from "./SettingsPanel";
|
|
21
|
+
import { useRecordingState } from "../hooks/useRecordingState";
|
|
22
|
+
import { useEventListeners } from "../hooks/useEventListeners";
|
|
23
|
+
import { settings } from "../hooks/useSettings";
|
|
34
24
|
function Runtime(props) {
|
|
35
25
|
const [holdingModKey, setHoldingModKey] = createSignal(false);
|
|
36
26
|
const [holdingShift, setHoldingShift] = createSignal(false);
|
|
37
27
|
const [currentElement, setCurrentElement] = createSignal(null);
|
|
38
28
|
const [toastMessage, setToastMessage] = createSignal(null);
|
|
39
29
|
const [locatorActive, setLocatorActive] = createSignal(false);
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
// --- localStorage persistence ---
|
|
44
|
-
const STORAGE_KEY = '__treelocator_recording__';
|
|
45
|
-
function loadFromStorage() {
|
|
46
|
-
try {
|
|
47
|
-
const raw = localStorage.getItem(STORAGE_KEY);
|
|
48
|
-
if (raw) return JSON.parse(raw);
|
|
49
|
-
} catch {}
|
|
50
|
-
return {
|
|
51
|
-
last: null,
|
|
52
|
-
previous: null
|
|
53
|
-
};
|
|
54
|
-
}
|
|
55
|
-
function saveToStorage(current) {
|
|
56
|
-
try {
|
|
57
|
-
const stored = loadFromStorage();
|
|
58
|
-
localStorage.setItem(STORAGE_KEY, JSON.stringify({
|
|
59
|
-
last: current,
|
|
60
|
-
previous: stored.last
|
|
61
|
-
}));
|
|
62
|
-
} catch {}
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
// Restore last results on mount
|
|
66
|
-
const restored = loadFromStorage();
|
|
67
|
-
const restoredLast = restored.last;
|
|
68
|
-
const [recordingState, setRecordingState] = createSignal(restoredLast ? 'results' : 'idle');
|
|
69
|
-
const [recordedElement, setRecordedElement] = createSignal(null);
|
|
70
|
-
const [recordingFindings, setRecordingFindings] = createSignal(restoredLast?.findings ?? []);
|
|
71
|
-
const [recordingSummary, setRecordingSummary] = createSignal(restoredLast?.summary ?? null);
|
|
72
|
-
const [interactionLog, setInteractionLog] = createSignal(restoredLast?.interactions ?? []);
|
|
73
|
-
const [recordingData, setRecordingData] = createSignal(restoredLast?.data ?? null);
|
|
74
|
-
const [recordingElementPath, setRecordingElementPath] = createSignal(restoredLast?.elementPath ?? "");
|
|
75
|
-
const [replayBox, setReplayBox] = createSignal(null);
|
|
76
|
-
const [replaying, setReplaying] = createSignal(false);
|
|
77
|
-
const [viewingPrevious, setViewingPrevious] = createSignal(false);
|
|
78
|
-
let dejitterInstance = null;
|
|
79
|
-
let interactionClickHandler = null;
|
|
80
|
-
let recordingStartTime = 0;
|
|
81
|
-
let replayTimerId = null;
|
|
82
|
-
const isActive = () => (holdingModKey() || locatorActive() || recordingState() === 'selecting') && currentElement();
|
|
30
|
+
const [settingsOpen, setSettingsOpen] = createSignal(false);
|
|
31
|
+
const recording = useRecordingState(props.adapterId);
|
|
32
|
+
const isActive = () => (holdingModKey() || locatorActive() || recording.recordingState() === "selecting") && currentElement();
|
|
83
33
|
createEffect(() => {
|
|
84
34
|
if (isActive()) {
|
|
85
35
|
document.body.classList.add("locatorjs-active-pointer");
|
|
@@ -90,372 +40,61 @@ function Runtime(props) {
|
|
|
90
40
|
|
|
91
41
|
// Expose replay functions on the browser API
|
|
92
42
|
if (typeof window !== "undefined" && window.__treelocator__) {
|
|
93
|
-
window.__treelocator__.replay = () => replayRecording();
|
|
94
|
-
window.__treelocator__.replayWithRecord = elementOrSelector => replayWithRecord(elementOrSelector);
|
|
43
|
+
window.__treelocator__.replay = () => recording.replayRecording();
|
|
44
|
+
window.__treelocator__.replayWithRecord = elementOrSelector => recording.replayWithRecord(elementOrSelector);
|
|
95
45
|
}
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
setHoldingShift(e.shiftKey);
|
|
103
|
-
}
|
|
104
|
-
function mouseMoveListener(e) {
|
|
105
|
-
// Update modifier state from mouse events - more reliable than keydown/keyup
|
|
106
|
-
setHoldingModKey(e.altKey);
|
|
107
|
-
setHoldingShift(e.shiftKey);
|
|
46
|
+
|
|
47
|
+
// --- Event handlers ---
|
|
48
|
+
|
|
49
|
+
function eventPathHasAttribute(e, attr) {
|
|
50
|
+
const path = typeof e.composedPath === "function" ? e.composedPath() : e.target ? [e.target] : [];
|
|
51
|
+
return path.some(node => node instanceof Element && node.hasAttribute(attr));
|
|
108
52
|
}
|
|
109
53
|
function findElementAtPoint(e) {
|
|
110
54
|
const elementsAtPoint = document.elementsFromPoint(e.clientX, e.clientY);
|
|
111
55
|
for (const el of elementsAtPoint) {
|
|
112
56
|
if (isLocatorsOwnElement(el)) continue;
|
|
113
57
|
if (el instanceof HTMLElement || el instanceof SVGElement) {
|
|
114
|
-
const withLocator = el.closest(
|
|
58
|
+
const withLocator = el.closest("[data-locatorjs-id], [data-locatorjs]");
|
|
115
59
|
if (withLocator) return withLocator;
|
|
116
60
|
}
|
|
117
61
|
}
|
|
118
|
-
// Fallback to e.target
|
|
119
62
|
const target = e.target;
|
|
120
63
|
if (target && (target instanceof HTMLElement || target instanceof SVGElement)) {
|
|
121
|
-
const el = target instanceof SVGElement ? target.closest(
|
|
64
|
+
const el = target instanceof SVGElement ? target.closest("[data-locatorjs-id], [data-locatorjs]") ?? target.closest("svg") ?? target : target;
|
|
122
65
|
if (el && !isLocatorsOwnElement(el)) return el;
|
|
123
66
|
}
|
|
124
67
|
return null;
|
|
125
68
|
}
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
function handleRecordClick() {
|
|
130
|
-
switch (recordingState()) {
|
|
131
|
-
case 'idle':
|
|
132
|
-
setRecordingState('selecting');
|
|
133
|
-
break;
|
|
134
|
-
case 'selecting':
|
|
135
|
-
setRecordingState('idle');
|
|
136
|
-
break;
|
|
137
|
-
case 'recording':
|
|
138
|
-
stopRecording();
|
|
139
|
-
break;
|
|
140
|
-
case 'results':
|
|
141
|
-
dismissResults();
|
|
142
|
-
break;
|
|
143
|
-
}
|
|
144
|
-
}
|
|
145
|
-
function startRecording(element) {
|
|
146
|
-
element.setAttribute('data-treelocator-recording', 'true');
|
|
147
|
-
setRecordedElement(element);
|
|
148
|
-
dejitterInstance = createDejitterRecorder();
|
|
149
|
-
dejitterInstance.configure(DEJITTER_CONFIG);
|
|
150
|
-
dejitterInstance.start();
|
|
151
|
-
startInteractionTracker();
|
|
152
|
-
setRecordingState('recording');
|
|
153
|
-
}
|
|
154
|
-
function stopRecording() {
|
|
155
|
-
if (!dejitterInstance) return;
|
|
156
|
-
dejitterInstance.stop();
|
|
157
|
-
const findings = dejitterInstance.findings(true);
|
|
158
|
-
const summary = dejitterInstance.summary(true);
|
|
159
|
-
const data = dejitterInstance.getData();
|
|
160
|
-
|
|
161
|
-
// Collect ancestry path from treelocator before clearing
|
|
162
|
-
const el = recordedElement();
|
|
163
|
-
let elementPath = "";
|
|
164
|
-
if (el) {
|
|
165
|
-
const treeNode = createTreeNode(el, props.adapterId);
|
|
166
|
-
if (treeNode) {
|
|
167
|
-
const ancestry = collectAncestry(treeNode);
|
|
168
|
-
elementPath = formatAncestryChain(ancestry);
|
|
169
|
-
}
|
|
170
|
-
}
|
|
171
|
-
setRecordingFindings(findings);
|
|
172
|
-
setRecordingSummary(summary);
|
|
173
|
-
setRecordingData(data);
|
|
174
|
-
setRecordingElementPath(elementPath);
|
|
175
|
-
stopInteractionTracker();
|
|
176
|
-
|
|
177
|
-
// Persist to localStorage (moves previous "last" to "previous")
|
|
178
|
-
saveToStorage({
|
|
179
|
-
findings,
|
|
180
|
-
summary,
|
|
181
|
-
data,
|
|
182
|
-
elementPath,
|
|
183
|
-
interactions: interactionLog()
|
|
184
|
-
});
|
|
185
|
-
el?.removeAttribute('data-treelocator-recording');
|
|
186
|
-
setRecordingState('results');
|
|
187
|
-
dejitterInstance = null;
|
|
188
|
-
}
|
|
189
|
-
function replayRecording() {
|
|
190
|
-
const events = interactionLog();
|
|
191
|
-
if (events.length === 0) return;
|
|
192
|
-
stopReplay();
|
|
193
|
-
setReplaying(true);
|
|
194
|
-
let eventIdx = 0;
|
|
195
|
-
function scheduleNext() {
|
|
196
|
-
if (eventIdx >= events.length) {
|
|
197
|
-
stopReplay();
|
|
198
|
-
return;
|
|
199
|
-
}
|
|
200
|
-
const evt = events[eventIdx];
|
|
201
|
-
const delay = eventIdx === 0 ? 100 : evt.t - events[eventIdx - 1].t;
|
|
202
|
-
replayTimerId = window.setTimeout(() => {
|
|
203
|
-
// Show click indicator
|
|
204
|
-
setReplayBox({
|
|
205
|
-
x: evt.x - 12,
|
|
206
|
-
y: evt.y - 12,
|
|
207
|
-
w: 24,
|
|
208
|
-
h: 24
|
|
209
|
-
});
|
|
210
|
-
|
|
211
|
-
// Dispatch a real click at the recorded position
|
|
212
|
-
const target = document.elementFromPoint(evt.x, evt.y);
|
|
213
|
-
if (target) {
|
|
214
|
-
target.dispatchEvent(new MouseEvent('click', {
|
|
215
|
-
bubbles: true,
|
|
216
|
-
cancelable: true,
|
|
217
|
-
clientX: evt.x,
|
|
218
|
-
clientY: evt.y,
|
|
219
|
-
view: window
|
|
220
|
-
}));
|
|
221
|
-
}
|
|
222
|
-
|
|
223
|
-
// Clear click indicator after a short flash
|
|
224
|
-
window.setTimeout(() => setReplayBox(null), 200);
|
|
225
|
-
eventIdx++;
|
|
226
|
-
scheduleNext();
|
|
227
|
-
}, Math.max(delay, 50));
|
|
228
|
-
}
|
|
229
|
-
scheduleNext();
|
|
230
|
-
}
|
|
231
|
-
function stopReplay() {
|
|
232
|
-
if (replayTimerId) {
|
|
233
|
-
clearTimeout(replayTimerId);
|
|
234
|
-
replayTimerId = null;
|
|
235
|
-
}
|
|
236
|
-
setReplaying(false);
|
|
237
|
-
setReplayBox(null);
|
|
238
|
-
}
|
|
239
|
-
function replayWithRecord(elementOrSelector) {
|
|
240
|
-
// Resolve element
|
|
241
|
-
let element;
|
|
242
|
-
if (typeof elementOrSelector === 'string') {
|
|
243
|
-
const found = document.querySelector(elementOrSelector);
|
|
244
|
-
element = found instanceof HTMLElement ? found : null;
|
|
245
|
-
} else {
|
|
246
|
-
element = elementOrSelector;
|
|
247
|
-
}
|
|
248
|
-
if (!element) return Promise.resolve(null);
|
|
249
|
-
|
|
250
|
-
// Get stored interactions to replay
|
|
251
|
-
const stored = loadFromStorage();
|
|
252
|
-
const events = stored.last?.interactions ?? interactionLog();
|
|
253
|
-
if (events.length === 0) return Promise.resolve(null);
|
|
254
|
-
return new Promise(resolve => {
|
|
255
|
-
// Start recording on the element
|
|
256
|
-
element.setAttribute('data-treelocator-recording', 'true');
|
|
257
|
-
setRecordedElement(element);
|
|
258
|
-
dejitterInstance = createDejitterRecorder();
|
|
259
|
-
dejitterInstance.configure(DEJITTER_CONFIG);
|
|
260
|
-
dejitterInstance.start();
|
|
261
|
-
setRecordingState('recording');
|
|
262
|
-
setReplaying(true);
|
|
263
|
-
let eventIdx = 0;
|
|
264
|
-
function finishRecording() {
|
|
265
|
-
setReplaying(false);
|
|
266
|
-
setReplayBox(null);
|
|
267
|
-
if (!dejitterInstance) {
|
|
268
|
-
resolve(null);
|
|
269
|
-
return;
|
|
270
|
-
}
|
|
271
|
-
dejitterInstance.stop();
|
|
272
|
-
const findings = dejitterInstance.findings(true);
|
|
273
|
-
const summary = dejitterInstance.summary(true);
|
|
274
|
-
const data = dejitterInstance.getData();
|
|
275
|
-
const el = recordedElement();
|
|
276
|
-
let elementPath = "";
|
|
277
|
-
if (el) {
|
|
278
|
-
const treeNode = createTreeNode(el, props.adapterId);
|
|
279
|
-
if (treeNode) {
|
|
280
|
-
const ancestry = collectAncestry(treeNode);
|
|
281
|
-
elementPath = formatAncestryChain(ancestry);
|
|
282
|
-
}
|
|
283
|
-
}
|
|
284
|
-
setRecordingFindings(findings);
|
|
285
|
-
setRecordingSummary(summary);
|
|
286
|
-
setRecordingData(data);
|
|
287
|
-
setRecordingElementPath(elementPath);
|
|
288
|
-
setInteractionLog(events);
|
|
289
|
-
saveToStorage({
|
|
290
|
-
findings,
|
|
291
|
-
summary,
|
|
292
|
-
data,
|
|
293
|
-
elementPath,
|
|
294
|
-
interactions: events
|
|
295
|
-
});
|
|
296
|
-
el?.removeAttribute('data-treelocator-recording');
|
|
297
|
-
setRecordingState('results');
|
|
298
|
-
dejitterInstance = null;
|
|
299
|
-
resolve({
|
|
300
|
-
path: elementPath,
|
|
301
|
-
findings,
|
|
302
|
-
summary,
|
|
303
|
-
data,
|
|
304
|
-
interactions: events
|
|
305
|
-
});
|
|
306
|
-
}
|
|
307
|
-
function scheduleNext() {
|
|
308
|
-
if (eventIdx >= events.length) {
|
|
309
|
-
// Wait for CSS transitions to settle before stopping recording
|
|
310
|
-
replayTimerId = window.setTimeout(finishRecording, 500);
|
|
311
|
-
return;
|
|
312
|
-
}
|
|
313
|
-
const evt = events[eventIdx];
|
|
314
|
-
const delay = eventIdx === 0 ? 100 : evt.t - events[eventIdx - 1].t;
|
|
315
|
-
replayTimerId = window.setTimeout(() => {
|
|
316
|
-
setReplayBox({
|
|
317
|
-
x: evt.x - 12,
|
|
318
|
-
y: evt.y - 12,
|
|
319
|
-
w: 24,
|
|
320
|
-
h: 24
|
|
321
|
-
});
|
|
322
|
-
const target = document.elementFromPoint(evt.x, evt.y);
|
|
323
|
-
if (target) {
|
|
324
|
-
target.dispatchEvent(new MouseEvent('click', {
|
|
325
|
-
bubbles: true,
|
|
326
|
-
cancelable: true,
|
|
327
|
-
clientX: evt.x,
|
|
328
|
-
clientY: evt.y,
|
|
329
|
-
view: window
|
|
330
|
-
}));
|
|
331
|
-
}
|
|
332
|
-
window.setTimeout(() => setReplayBox(null), 200);
|
|
333
|
-
eventIdx++;
|
|
334
|
-
scheduleNext();
|
|
335
|
-
}, Math.max(delay, 50));
|
|
336
|
-
}
|
|
337
|
-
scheduleNext();
|
|
338
|
-
});
|
|
339
|
-
}
|
|
340
|
-
function dismissResults() {
|
|
341
|
-
stopReplay();
|
|
342
|
-
setRecordingFindings([]);
|
|
343
|
-
setRecordingSummary(null);
|
|
344
|
-
setRecordingData(null);
|
|
345
|
-
setRecordingElementPath("");
|
|
346
|
-
setInteractionLog([]);
|
|
347
|
-
setRecordedElement(null);
|
|
348
|
-
setViewingPrevious(false);
|
|
349
|
-
setRecordingState('idle');
|
|
350
|
-
try {
|
|
351
|
-
localStorage.removeItem(STORAGE_KEY);
|
|
352
|
-
} catch {}
|
|
353
|
-
}
|
|
354
|
-
function hasPreviousRecording() {
|
|
355
|
-
return loadFromStorage().previous !== null;
|
|
356
|
-
}
|
|
357
|
-
function loadPreviousRecording() {
|
|
358
|
-
const stored = loadFromStorage();
|
|
359
|
-
if (!stored.previous) return;
|
|
360
|
-
const prev = stored.previous;
|
|
361
|
-
setRecordingFindings(prev.findings);
|
|
362
|
-
setRecordingSummary(prev.summary);
|
|
363
|
-
setRecordingData(prev.data);
|
|
364
|
-
setRecordingElementPath(prev.elementPath);
|
|
365
|
-
setInteractionLog(prev.interactions);
|
|
366
|
-
setViewingPrevious(true);
|
|
367
|
-
setRecordingState('results');
|
|
368
|
-
}
|
|
369
|
-
function loadLatestRecording() {
|
|
370
|
-
const stored = loadFromStorage();
|
|
371
|
-
if (!stored.last) return;
|
|
372
|
-
const last = stored.last;
|
|
373
|
-
setRecordingFindings(last.findings);
|
|
374
|
-
setRecordingSummary(last.summary);
|
|
375
|
-
setRecordingData(last.data);
|
|
376
|
-
setRecordingElementPath(last.elementPath);
|
|
377
|
-
setInteractionLog(last.interactions);
|
|
378
|
-
setViewingPrevious(false);
|
|
379
|
-
setRecordingState('results');
|
|
380
|
-
}
|
|
381
|
-
function startInteractionTracker() {
|
|
382
|
-
recordingStartTime = performance.now();
|
|
383
|
-
setInteractionLog([]);
|
|
384
|
-
interactionClickHandler = e => {
|
|
385
|
-
if (isLocatorsOwnElement(e.target)) return;
|
|
386
|
-
const el = e.target;
|
|
387
|
-
const tag = el.tagName?.toLowerCase() || 'unknown';
|
|
388
|
-
const id = el.id ? '#' + el.id : '';
|
|
389
|
-
const cls = el.className && typeof el.className === 'string' ? '.' + el.className.split(' ')[0] : '';
|
|
390
|
-
setInteractionLog(prev => [...prev, {
|
|
391
|
-
t: Math.round(performance.now() - recordingStartTime),
|
|
392
|
-
type: 'click',
|
|
393
|
-
target: `${tag}${id}${cls}`,
|
|
394
|
-
x: e.clientX,
|
|
395
|
-
y: e.clientY
|
|
396
|
-
}]);
|
|
397
|
-
};
|
|
398
|
-
document.addEventListener('click', interactionClickHandler, {
|
|
399
|
-
capture: true
|
|
400
|
-
});
|
|
401
|
-
}
|
|
402
|
-
function stopInteractionTracker() {
|
|
403
|
-
if (interactionClickHandler) {
|
|
404
|
-
document.removeEventListener('click', interactionClickHandler, {
|
|
405
|
-
capture: true
|
|
406
|
-
});
|
|
407
|
-
interactionClickHandler = null;
|
|
69
|
+
function clickListener(e) {
|
|
70
|
+
if (settingsOpen() && !eventPathHasAttribute(e, "data-treelocator-settings-panel") && !eventPathHasAttribute(e, "data-treelocator-settings-toggle")) {
|
|
71
|
+
setSettingsOpen(false);
|
|
408
72
|
}
|
|
409
|
-
}
|
|
410
|
-
function mouseOverListener(e) {
|
|
411
|
-
setHoldingModKey(e.altKey);
|
|
412
|
-
setHoldingShift(e.shiftKey);
|
|
413
73
|
|
|
414
|
-
// Don't update hovered element while recording -- highlight is sticky
|
|
415
|
-
if (recordingState() === 'recording') return;
|
|
416
|
-
const element = findElementAtPoint(e);
|
|
417
|
-
if (element) {
|
|
418
|
-
setCurrentElement(element);
|
|
419
|
-
}
|
|
420
|
-
}
|
|
421
|
-
function mouseDownUpListener(e) {
|
|
422
|
-
setHoldingModKey(e.altKey);
|
|
423
|
-
if (e.altKey || locatorActive() || recordingState() === 'selecting') {
|
|
424
|
-
e.preventDefault();
|
|
425
|
-
e.stopPropagation();
|
|
426
|
-
}
|
|
427
|
-
}
|
|
428
|
-
function clickListener(e) {
|
|
429
74
|
// Handle recording element selection
|
|
430
|
-
if (recordingState() ===
|
|
75
|
+
if (recording.recordingState() === "selecting") {
|
|
431
76
|
e.preventDefault();
|
|
432
77
|
e.stopPropagation();
|
|
433
78
|
const element = findElementAtPoint(e);
|
|
434
79
|
if (element && !isLocatorsOwnElement(element)) {
|
|
435
|
-
startRecording(element);
|
|
80
|
+
recording.startRecording(element);
|
|
436
81
|
}
|
|
437
82
|
return;
|
|
438
83
|
}
|
|
439
84
|
|
|
440
85
|
// During recording, let clicks pass through (tracked by interaction logger)
|
|
441
|
-
if (recordingState() ===
|
|
86
|
+
if (recording.recordingState() === "recording") return;
|
|
442
87
|
if (!e.altKey && !isCombinationModifiersPressed(e) && !locatorActive()) {
|
|
443
88
|
return;
|
|
444
89
|
}
|
|
445
90
|
const element = findElementAtPoint(e);
|
|
446
|
-
if (!element)
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
if (element instanceof HTMLElement && element.shadowRoot) {
|
|
450
|
-
return;
|
|
451
|
-
}
|
|
452
|
-
if (isLocatorsOwnElement(element)) {
|
|
453
|
-
return;
|
|
454
|
-
}
|
|
91
|
+
if (!element) return;
|
|
92
|
+
if (element instanceof HTMLElement && element.shadowRoot) return;
|
|
93
|
+
if (isLocatorsOwnElement(element)) return;
|
|
455
94
|
e.preventDefault();
|
|
456
95
|
e.stopPropagation();
|
|
457
96
|
|
|
458
|
-
// Copy ancestry to clipboard on alt+click
|
|
97
|
+
// Copy ancestry + computed styles to clipboard on alt+click
|
|
459
98
|
const treeNode = createTreeNode(element, props.adapterId);
|
|
460
99
|
if (treeNode) {
|
|
461
100
|
let ancestry = collectAncestry(treeNode);
|
|
@@ -465,17 +104,37 @@ function Runtime(props) {
|
|
|
465
104
|
ancestry = truncateAtFirstFile(ancestry);
|
|
466
105
|
}
|
|
467
106
|
|
|
107
|
+
// Extract computed styles for the clicked element (if enabled)
|
|
108
|
+
const stylesEnabled = settings().computedStyles;
|
|
109
|
+
const elementLabel = getElementLabel(ancestry);
|
|
110
|
+
const stylesResult = stylesEnabled ? extractComputedStyles(element, elementLabel, {
|
|
111
|
+
includeDefaults: settings().computedStylesIncludeDefaults
|
|
112
|
+
}) : null;
|
|
113
|
+
|
|
468
114
|
// Write immediately with component names (preserves user gesture for clipboard API)
|
|
469
115
|
const formatted = formatAncestryChain(ancestry);
|
|
470
|
-
|
|
116
|
+
const fullOutput = stylesResult ? formatted + "\n\n" + stylesResult.formatted : formatted;
|
|
117
|
+
navigator.clipboard.writeText(fullOutput).then(() => {
|
|
471
118
|
setToastMessage("Copied to clipboard");
|
|
472
119
|
});
|
|
473
120
|
|
|
474
|
-
// For React 19+: try to enrich with source map file paths and re-copy
|
|
121
|
+
// For React 19+: try to enrich with source map file paths and re-copy.
|
|
122
|
+
// If the enriched label differs, re-extract with forceFull:true so the
|
|
123
|
+
// diff-mode fast path doesn't collapse the second extraction (for the
|
|
124
|
+
// same element within the diff window) into "No changes detected".
|
|
475
125
|
enrichAncestryWithSourceMaps(ancestry, element).then(enriched => {
|
|
476
126
|
const enrichedFormatted = formatAncestryChain(enriched);
|
|
477
127
|
if (enrichedFormatted !== formatted) {
|
|
478
|
-
|
|
128
|
+
let enrichedFull = enrichedFormatted;
|
|
129
|
+
if (stylesResult) {
|
|
130
|
+
const enrichedLabel = getElementLabel(enriched);
|
|
131
|
+
const enrichedStyles = enrichedLabel !== elementLabel ? extractComputedStyles(element, enrichedLabel, {
|
|
132
|
+
forceFull: true,
|
|
133
|
+
includeDefaults: settings().computedStylesIncludeDefaults
|
|
134
|
+
}).formatted : stylesResult.formatted;
|
|
135
|
+
enrichedFull = enrichedFormatted + "\n\n" + enrichedStyles;
|
|
136
|
+
}
|
|
137
|
+
navigator.clipboard.writeText(enrichedFull).then(() => {
|
|
479
138
|
setToastMessage("Copied to clipboard");
|
|
480
139
|
});
|
|
481
140
|
}
|
|
@@ -487,58 +146,54 @@ function Runtime(props) {
|
|
|
487
146
|
setLocatorActive(false);
|
|
488
147
|
}
|
|
489
148
|
}
|
|
490
|
-
function
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
if (
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
roots.push(node.shadowRoot);
|
|
149
|
+
function mouseOverListener(e) {
|
|
150
|
+
setHoldingModKey(e.altKey);
|
|
151
|
+
setHoldingShift(e.shiftKey);
|
|
152
|
+
|
|
153
|
+
// Don't update hovered element while recording — highlight is sticky
|
|
154
|
+
if (recording.recordingState() === "recording") return;
|
|
155
|
+
const element = findElementAtPoint(e);
|
|
156
|
+
if (element) {
|
|
157
|
+
setCurrentElement(element);
|
|
500
158
|
}
|
|
501
|
-
});
|
|
502
|
-
for (const root of roots) {
|
|
503
|
-
root.addEventListener("mouseover", mouseOverListener, {
|
|
504
|
-
capture: true
|
|
505
|
-
});
|
|
506
|
-
root.addEventListener("mousemove", mouseMoveListener, {
|
|
507
|
-
capture: true
|
|
508
|
-
});
|
|
509
|
-
root.addEventListener("keydown", keyDownListener);
|
|
510
|
-
root.addEventListener("keyup", keyUpListener);
|
|
511
|
-
root.addEventListener("click", clickListener, {
|
|
512
|
-
capture: true
|
|
513
|
-
});
|
|
514
|
-
root.addEventListener("mousedown", mouseDownUpListener, {
|
|
515
|
-
capture: true
|
|
516
|
-
});
|
|
517
|
-
root.addEventListener("mouseup", mouseDownUpListener, {
|
|
518
|
-
capture: true
|
|
519
|
-
});
|
|
520
|
-
root.addEventListener("scroll", scrollListener);
|
|
521
159
|
}
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
160
|
+
useEventListeners({
|
|
161
|
+
mouseOverListener,
|
|
162
|
+
mouseMoveListener(e) {
|
|
163
|
+
setHoldingModKey(e.altKey);
|
|
164
|
+
setHoldingShift(e.shiftKey);
|
|
165
|
+
},
|
|
166
|
+
keyDownListener(e) {
|
|
167
|
+
setHoldingModKey(isCombinationModifiersPressed(e, true));
|
|
168
|
+
setHoldingShift(e.shiftKey);
|
|
169
|
+
if (e.key === "Escape") {
|
|
170
|
+
const wasSelecting = recording.recordingState() === "selecting";
|
|
171
|
+
const wasLocatorActive = locatorActive();
|
|
172
|
+
if (wasSelecting || wasLocatorActive) {
|
|
173
|
+
e.preventDefault();
|
|
174
|
+
e.stopPropagation();
|
|
175
|
+
if (wasLocatorActive) setLocatorActive(false);
|
|
176
|
+
if (wasSelecting) recording.handleRecordClick();
|
|
177
|
+
setCurrentElement(null);
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
},
|
|
181
|
+
keyUpListener(e) {
|
|
182
|
+
setHoldingModKey(isCombinationModifiersPressed(e));
|
|
183
|
+
setHoldingShift(e.shiftKey);
|
|
184
|
+
},
|
|
185
|
+
clickListener,
|
|
186
|
+
mouseDownUpListener(e) {
|
|
187
|
+
setHoldingModKey(e.altKey);
|
|
188
|
+
if (e.altKey || locatorActive() || recording.recordingState() === "selecting") {
|
|
189
|
+
e.preventDefault();
|
|
190
|
+
e.stopPropagation();
|
|
191
|
+
}
|
|
192
|
+
},
|
|
193
|
+
scrollListener() {
|
|
194
|
+
setCurrentElement(null);
|
|
195
|
+
},
|
|
196
|
+
onCleanup: recording.cleanup
|
|
542
197
|
});
|
|
543
198
|
return [_$memo(() => _$memo(() => !!isActive())() ? _$createComponent(MaybeOutline, {
|
|
544
199
|
get currentElement() {
|
|
@@ -553,24 +208,24 @@ function Runtime(props) {
|
|
|
553
208
|
get dashed() {
|
|
554
209
|
return holdingShift();
|
|
555
210
|
}
|
|
556
|
-
}) : null), _$memo(() => _$memo(() => !!(recordingState() ===
|
|
211
|
+
}) : null), _$memo(() => _$memo(() => !!(recording.recordingState() === "recording" && recording.recordedElement()))() ? _$createComponent(RecordingOutline, {
|
|
557
212
|
get element() {
|
|
558
|
-
return recordedElement();
|
|
213
|
+
return recording.recordedElement();
|
|
559
214
|
}
|
|
560
|
-
}) : null), _$memo(() => _$memo(() => !!replayBox())() ? (() => {
|
|
561
|
-
var _el$
|
|
562
|
-
_$setStyleProperty(_el
|
|
563
|
-
_$setStyleProperty(_el
|
|
564
|
-
_$setStyleProperty(_el
|
|
215
|
+
}) : null), _$memo(() => _$memo(() => !!recording.replayBox())() ? (() => {
|
|
216
|
+
var _el$ = _tmpl$();
|
|
217
|
+
_$setStyleProperty(_el$, "position", "fixed");
|
|
218
|
+
_$setStyleProperty(_el$, "background", "rgba(59, 130, 246, 0.4)");
|
|
219
|
+
_$setStyleProperty(_el$, "border", "2px solid #3b82f6");
|
|
565
220
|
_$effect(_p$ => {
|
|
566
|
-
var _v$
|
|
567
|
-
_v$
|
|
568
|
-
_v$
|
|
569
|
-
_v$
|
|
570
|
-
_v$
|
|
571
|
-
_v$
|
|
572
|
-
_v$
|
|
573
|
-
_v$
|
|
221
|
+
var _v$ = recording.replayBox().x + "px",
|
|
222
|
+
_v$2 = recording.replayBox().y + "px",
|
|
223
|
+
_v$3 = recording.replayBox().w + "px",
|
|
224
|
+
_v$4 = recording.replayBox().h + "px";
|
|
225
|
+
_v$ !== _p$.e && _$setStyleProperty(_el$, "left", _p$.e = _v$);
|
|
226
|
+
_v$2 !== _p$.t && _$setStyleProperty(_el$, "top", _p$.t = _v$2);
|
|
227
|
+
_v$3 !== _p$.a && _$setStyleProperty(_el$, "width", _p$.a = _v$3);
|
|
228
|
+
_v$4 !== _p$.o && _$setStyleProperty(_el$, "height", _p$.o = _v$4);
|
|
574
229
|
return _p$;
|
|
575
230
|
}, {
|
|
576
231
|
e: undefined,
|
|
@@ -578,118 +233,71 @@ function Runtime(props) {
|
|
|
578
233
|
a: undefined,
|
|
579
234
|
o: undefined
|
|
580
235
|
});
|
|
581
|
-
return _el
|
|
582
|
-
})() : null), _$memo(() => _$memo(() => recordingState() ===
|
|
236
|
+
return _el$;
|
|
237
|
+
})() : null), _$memo(() => _$memo(() => recording.recordingState() === "results")() ? _$createComponent(RecordingResults, {
|
|
583
238
|
get findings() {
|
|
584
|
-
return recordingFindings();
|
|
239
|
+
return recording.recordingFindings();
|
|
585
240
|
},
|
|
586
241
|
get summary() {
|
|
587
|
-
return recordingSummary();
|
|
242
|
+
return recording.recordingSummary();
|
|
588
243
|
},
|
|
589
244
|
get data() {
|
|
590
|
-
return recordingData();
|
|
245
|
+
return recording.recordingData();
|
|
591
246
|
},
|
|
592
247
|
get elementPath() {
|
|
593
|
-
return recordingElementPath();
|
|
248
|
+
return recording.recordingElementPath();
|
|
594
249
|
},
|
|
595
250
|
get interactions() {
|
|
596
|
-
return interactionLog();
|
|
251
|
+
return recording.interactionLog();
|
|
252
|
+
},
|
|
253
|
+
get visualDiff() {
|
|
254
|
+
return recording.visualDiff();
|
|
255
|
+
},
|
|
256
|
+
get onDismiss() {
|
|
257
|
+
return recording.dismissResults;
|
|
258
|
+
},
|
|
259
|
+
get onReplay() {
|
|
260
|
+
return recording.replayRecording;
|
|
597
261
|
},
|
|
598
|
-
onDismiss: dismissResults,
|
|
599
|
-
onReplay: replayRecording,
|
|
600
262
|
get replaying() {
|
|
601
|
-
return replaying();
|
|
263
|
+
return recording.replaying();
|
|
602
264
|
},
|
|
603
265
|
onToast: setToastMessage,
|
|
604
266
|
get hasPrevious() {
|
|
605
|
-
return _$memo(() => !!!viewingPrevious())() && hasPreviousRecording();
|
|
267
|
+
return _$memo(() => !!!recording.viewingPrevious())() && recording.hasPreviousRecording();
|
|
268
|
+
},
|
|
269
|
+
get onLoadPrevious() {
|
|
270
|
+
return recording.loadPreviousRecording;
|
|
606
271
|
},
|
|
607
|
-
onLoadPrevious: loadPreviousRecording,
|
|
608
272
|
get hasNext() {
|
|
609
|
-
return viewingPrevious();
|
|
273
|
+
return recording.viewingPrevious();
|
|
610
274
|
},
|
|
611
|
-
onLoadNext
|
|
275
|
+
get onLoadNext() {
|
|
276
|
+
return recording.loadLatestRecording;
|
|
277
|
+
}
|
|
278
|
+
}) : null), _$memo(() => _$memo(() => !!settingsOpen())() ? _$createComponent(SettingsPanel, {
|
|
279
|
+
onDismiss: () => setSettingsOpen(false)
|
|
612
280
|
}) : null), _$memo(() => _$memo(() => !!toastMessage())() && _$createComponent(Toast, {
|
|
613
281
|
get message() {
|
|
614
282
|
return toastMessage();
|
|
615
283
|
},
|
|
616
284
|
onClose: () => setToastMessage(null)
|
|
617
|
-
})), (
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
_$setStyleProperty(_el$4, "width", "54px");
|
|
634
|
-
_$setStyleProperty(_el$4, "height", "54px");
|
|
635
|
-
_$setStyleProperty(_el$4, "background", "#ffffff");
|
|
636
|
-
_$setStyleProperty(_el$4, "display", "flex");
|
|
637
|
-
_$setStyleProperty(_el$4, "cursor", "pointer");
|
|
638
|
-
_$setStyleProperty(_el$4, "overflow", "hidden");
|
|
639
|
-
_$setStyleProperty(_el$4, "transition", "background 0.15s ease-in-out");
|
|
640
|
-
_$setAttribute(_el$5, "src", treeIconUrl);
|
|
641
|
-
_el$6.$$click = handleRecordClick;
|
|
642
|
-
_el$6.addEventListener("mouseleave", e => {
|
|
643
|
-
if (recordingState() !== 'recording') e.currentTarget.style.background = "#ffffff";
|
|
644
|
-
});
|
|
645
|
-
_el$6.addEventListener("mouseenter", e => {
|
|
646
|
-
if (recordingState() !== 'recording') e.currentTarget.style.background = "#f0f0f0";
|
|
647
|
-
});
|
|
648
|
-
_$setStyleProperty(_el$6, "width", "54px");
|
|
649
|
-
_$setStyleProperty(_el$6, "height", "54px");
|
|
650
|
-
_$setStyleProperty(_el$6, "display", "flex");
|
|
651
|
-
_$setStyleProperty(_el$6, "cursor", "pointer");
|
|
652
|
-
_$setStyleProperty(_el$6, "transition", "background 0.15s ease-in-out");
|
|
653
|
-
_$insert(_el$6, (() => {
|
|
654
|
-
var _c$ = _$memo(() => recordingState() === 'recording');
|
|
655
|
-
return () => _c$() ? (() => {
|
|
656
|
-
var _el$9 = _tmpl$3();
|
|
657
|
-
_$setStyleProperty(_el$9, "width", "18px");
|
|
658
|
-
_$setStyleProperty(_el$9, "height", "18px");
|
|
659
|
-
_$setStyleProperty(_el$9, "background", "#fff");
|
|
660
|
-
return _el$9;
|
|
661
|
-
})() : (() => {
|
|
662
|
-
var _el$0 = _tmpl$4();
|
|
663
|
-
_$setStyleProperty(_el$0, "width", "18px");
|
|
664
|
-
_$setStyleProperty(_el$0, "height", "18px");
|
|
665
|
-
_$setStyleProperty(_el$0, "background", "#ef4444");
|
|
666
|
-
_$effect(_$p => _$setStyleProperty(_el$0, "animation", recordingState() === 'selecting' ? "treelocator-rec-pulse 1s ease-in-out infinite" : "none"));
|
|
667
|
-
return _el$0;
|
|
668
|
-
})();
|
|
669
|
-
})());
|
|
670
|
-
_$setStyleProperty(_el$7, "position", "absolute");
|
|
671
|
-
_$setStyleProperty(_el$7, "width", "1px");
|
|
672
|
-
_$setStyleProperty(_el$7, "height", "1px");
|
|
673
|
-
_$setStyleProperty(_el$7, "padding", "0");
|
|
674
|
-
_$setStyleProperty(_el$7, "margin", "-1px");
|
|
675
|
-
_$setStyleProperty(_el$7, "overflow", "hidden");
|
|
676
|
-
_$setStyleProperty(_el$7, "clip", "rect(0,0,0,0)");
|
|
677
|
-
_$setStyleProperty(_el$7, "border", "0");
|
|
678
|
-
_$effect(_p$ => {
|
|
679
|
-
var _v$ = locatorActive() ? "0 0 0 3px #3b82f6, 0 4px 14px rgba(0, 0, 0, 0.25)" : recordingState() === 'selecting' ? "0 0 0 3px #3b82f6, 0 4px 14px rgba(0, 0, 0, 0.25)" : recordingState() === 'recording' ? "0 0 0 3px #ef4444, 0 4px 14px rgba(0, 0, 0, 0.25)" : "0 4px 14px rgba(0, 0, 0, 0.25)",
|
|
680
|
-
_v$2 = recordingState() === 'recording' ? "#ef4444" : "#ffffff",
|
|
681
|
-
_v$3 = recordingState() === 'idle' ? "Record element changes. API: window.__treelocator__.replayWithRecord(selector)" : recordingState() === 'selecting' ? "Cancel recording selection" : recordingState() === 'recording' ? "Stop recording" : "Dismiss results";
|
|
682
|
-
_v$ !== _p$.e && _$setStyleProperty(_el$3, "box-shadow", _p$.e = _v$);
|
|
683
|
-
_v$2 !== _p$.t && _$setStyleProperty(_el$6, "background", _p$.t = _v$2);
|
|
684
|
-
_v$3 !== _p$.a && _$setAttribute(_el$6, "aria-label", _p$.a = _v$3);
|
|
685
|
-
return _p$;
|
|
686
|
-
}, {
|
|
687
|
-
e: undefined,
|
|
688
|
-
t: undefined,
|
|
689
|
-
a: undefined
|
|
690
|
-
});
|
|
691
|
-
return _el$;
|
|
692
|
-
})()];
|
|
285
|
+
})), _$createComponent(RecordingPillButton, {
|
|
286
|
+
get locatorActive() {
|
|
287
|
+
return locatorActive();
|
|
288
|
+
},
|
|
289
|
+
get recordingState() {
|
|
290
|
+
return recording.recordingState();
|
|
291
|
+
},
|
|
292
|
+
get settingsOpen() {
|
|
293
|
+
return settingsOpen();
|
|
294
|
+
},
|
|
295
|
+
onLocatorToggle: () => setLocatorActive(!locatorActive()),
|
|
296
|
+
get onRecordClick() {
|
|
297
|
+
return recording.handleRecordClick;
|
|
298
|
+
},
|
|
299
|
+
onSettingsClick: () => setSettingsOpen(!settingsOpen())
|
|
300
|
+
})];
|
|
693
301
|
}
|
|
694
302
|
export function initRender(solidLayer, adapter, targets) {
|
|
695
303
|
render(() => _$createComponent(Runtime, {
|
|
@@ -703,5 +311,4 @@ export function initRender(solidLayer, adapter, targets) {
|
|
|
703
311
|
},
|
|
704
312
|
adapterId: adapter
|
|
705
313
|
}), solidLayer);
|
|
706
|
-
}
|
|
707
|
-
_$delegateEvents(["click"]);
|
|
314
|
+
}
|