react-grab 0.0.9 → 0.0.11
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/dist/index.global.js +215 -189
- package/package.json +1 -1
- package/dist/core.cjs +0 -259
- package/dist/core.d.cts +0 -10
- package/dist/core.d.ts +0 -10
- package/dist/core.js +0 -254
package/dist/index.global.js
CHANGED
|
@@ -10,6 +10,204 @@ var ReactGrab = (function (exports) {
|
|
|
10
10
|
* LICENSE file in the root directory of this source tree.
|
|
11
11
|
*/
|
|
12
12
|
|
|
13
|
+
// src/overlay.ts
|
|
14
|
+
var lerp = (start, end, factor) => {
|
|
15
|
+
return start + (end - start) * factor;
|
|
16
|
+
};
|
|
17
|
+
var SELECTION_LERP_FACTOR = 0.99;
|
|
18
|
+
var createSelectionElement = ({
|
|
19
|
+
borderRadius,
|
|
20
|
+
height,
|
|
21
|
+
transform,
|
|
22
|
+
width,
|
|
23
|
+
x,
|
|
24
|
+
y
|
|
25
|
+
}) => {
|
|
26
|
+
const overlay = document.createElement("div");
|
|
27
|
+
overlay.style.position = "fixed";
|
|
28
|
+
overlay.style.top = `${y}px`;
|
|
29
|
+
overlay.style.left = `${x}px`;
|
|
30
|
+
overlay.style.width = `${width}px`;
|
|
31
|
+
overlay.style.height = `${height}px`;
|
|
32
|
+
overlay.style.borderRadius = borderRadius;
|
|
33
|
+
overlay.style.transform = transform;
|
|
34
|
+
overlay.style.pointerEvents = "none";
|
|
35
|
+
overlay.style.border = "2px solid #007AFF";
|
|
36
|
+
overlay.style.backgroundColor = "rgba(0, 122, 255, 0.1)";
|
|
37
|
+
overlay.style.zIndex = "2147483646";
|
|
38
|
+
overlay.style.boxSizing = "border-box";
|
|
39
|
+
overlay.style.display = "none";
|
|
40
|
+
overlay.animate(
|
|
41
|
+
[
|
|
42
|
+
{ backgroundColor: "rgba(0, 122, 255, 0.1)" },
|
|
43
|
+
{ backgroundColor: "rgba(0, 122, 255, 0.15)" },
|
|
44
|
+
{ backgroundColor: "rgba(0, 122, 255, 0.1)" }
|
|
45
|
+
],
|
|
46
|
+
{
|
|
47
|
+
duration: 2e3,
|
|
48
|
+
easing: "ease-in-out",
|
|
49
|
+
iterations: Infinity
|
|
50
|
+
}
|
|
51
|
+
);
|
|
52
|
+
return overlay;
|
|
53
|
+
};
|
|
54
|
+
var updateSelectionElement = (element, { borderRadius, height, transform, width, x, y }) => {
|
|
55
|
+
const currentTop = parseFloat(element.style.top) || 0;
|
|
56
|
+
const currentLeft = parseFloat(element.style.left) || 0;
|
|
57
|
+
const currentWidth = parseFloat(element.style.width) || 0;
|
|
58
|
+
const currentHeight = parseFloat(element.style.height) || 0;
|
|
59
|
+
const topValue = `${lerp(currentTop, y, SELECTION_LERP_FACTOR)}px`;
|
|
60
|
+
const leftValue = `${lerp(currentLeft, x, SELECTION_LERP_FACTOR)}px`;
|
|
61
|
+
const widthValue = `${lerp(currentWidth, width, SELECTION_LERP_FACTOR)}px`;
|
|
62
|
+
const heightValue = `${lerp(currentHeight, height, SELECTION_LERP_FACTOR)}px`;
|
|
63
|
+
if (element.style.top !== topValue) {
|
|
64
|
+
element.style.top = topValue;
|
|
65
|
+
}
|
|
66
|
+
if (element.style.left !== leftValue) {
|
|
67
|
+
element.style.left = leftValue;
|
|
68
|
+
}
|
|
69
|
+
if (element.style.width !== widthValue) {
|
|
70
|
+
element.style.width = widthValue;
|
|
71
|
+
}
|
|
72
|
+
if (element.style.height !== heightValue) {
|
|
73
|
+
element.style.height = heightValue;
|
|
74
|
+
}
|
|
75
|
+
if (element.style.borderRadius !== borderRadius) {
|
|
76
|
+
element.style.borderRadius = borderRadius;
|
|
77
|
+
}
|
|
78
|
+
if (element.style.transform !== transform) {
|
|
79
|
+
element.style.transform = transform;
|
|
80
|
+
}
|
|
81
|
+
};
|
|
82
|
+
var SelectionOverlay = class {
|
|
83
|
+
element;
|
|
84
|
+
visible = false;
|
|
85
|
+
constructor(root) {
|
|
86
|
+
this.element = createSelectionElement({
|
|
87
|
+
borderRadius: "0px",
|
|
88
|
+
height: 0,
|
|
89
|
+
transform: "none",
|
|
90
|
+
width: 0,
|
|
91
|
+
x: -1e3,
|
|
92
|
+
y: -1e3
|
|
93
|
+
});
|
|
94
|
+
root.appendChild(this.element);
|
|
95
|
+
}
|
|
96
|
+
hide() {
|
|
97
|
+
this.visible = false;
|
|
98
|
+
this.element.style.display = "none";
|
|
99
|
+
this.element.style.pointerEvents = "none";
|
|
100
|
+
}
|
|
101
|
+
isVisible() {
|
|
102
|
+
return this.visible;
|
|
103
|
+
}
|
|
104
|
+
show() {
|
|
105
|
+
this.visible = true;
|
|
106
|
+
this.element.style.display = "block";
|
|
107
|
+
this.element.style.pointerEvents = "auto";
|
|
108
|
+
}
|
|
109
|
+
update(selection) {
|
|
110
|
+
updateSelectionElement(this.element, selection);
|
|
111
|
+
}
|
|
112
|
+
};
|
|
113
|
+
var createSpinner = () => {
|
|
114
|
+
const spinner = document.createElement("span");
|
|
115
|
+
spinner.style.display = "inline-block";
|
|
116
|
+
spinner.style.width = "8px";
|
|
117
|
+
spinner.style.height = "8px";
|
|
118
|
+
spinner.style.border = "1.5px solid #1e4ed8";
|
|
119
|
+
spinner.style.borderTopColor = "transparent";
|
|
120
|
+
spinner.style.borderRadius = "50%";
|
|
121
|
+
spinner.style.marginRight = "4px";
|
|
122
|
+
spinner.style.verticalAlign = "middle";
|
|
123
|
+
spinner.animate(
|
|
124
|
+
[
|
|
125
|
+
{ transform: "rotate(0deg)" },
|
|
126
|
+
{ transform: "rotate(360deg)" }
|
|
127
|
+
],
|
|
128
|
+
{
|
|
129
|
+
duration: 600,
|
|
130
|
+
easing: "linear",
|
|
131
|
+
iterations: Infinity
|
|
132
|
+
}
|
|
133
|
+
);
|
|
134
|
+
return spinner;
|
|
135
|
+
};
|
|
136
|
+
var createIndicator = (x, y) => {
|
|
137
|
+
const indicator = document.createElement("div");
|
|
138
|
+
indicator.style.position = "fixed";
|
|
139
|
+
indicator.style.left = `${x}px`;
|
|
140
|
+
indicator.style.top = `${y - 4}px`;
|
|
141
|
+
indicator.style.transform = "translateY(-100%)";
|
|
142
|
+
indicator.style.padding = "0px 4px";
|
|
143
|
+
indicator.style.backgroundColor = "#dbeafe";
|
|
144
|
+
indicator.style.color = "#1e4ed8";
|
|
145
|
+
indicator.style.border = "1px solid #c7dbfb";
|
|
146
|
+
indicator.style.borderRadius = "4px";
|
|
147
|
+
indicator.style.fontSize = "11px";
|
|
148
|
+
indicator.style.fontWeight = "500";
|
|
149
|
+
indicator.style.fontFamily = "-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif";
|
|
150
|
+
indicator.style.zIndex = "2147483647";
|
|
151
|
+
indicator.style.pointerEvents = "none";
|
|
152
|
+
indicator.style.opacity = "0";
|
|
153
|
+
indicator.style.transition = "opacity 0.2s ease-in-out";
|
|
154
|
+
indicator.style.display = "flex";
|
|
155
|
+
indicator.style.alignItems = "center";
|
|
156
|
+
return indicator;
|
|
157
|
+
};
|
|
158
|
+
var showCopyIndicator = (x, y) => {
|
|
159
|
+
const indicator = createIndicator(x, y);
|
|
160
|
+
const spinner = createSpinner();
|
|
161
|
+
const text = document.createElement("span");
|
|
162
|
+
text.textContent = "Copying\u2026";
|
|
163
|
+
indicator.appendChild(spinner);
|
|
164
|
+
indicator.appendChild(text);
|
|
165
|
+
document.body.appendChild(indicator);
|
|
166
|
+
requestAnimationFrame(() => {
|
|
167
|
+
indicator.style.opacity = "1";
|
|
168
|
+
});
|
|
169
|
+
return () => {
|
|
170
|
+
spinner.remove();
|
|
171
|
+
text.textContent = "Copied!";
|
|
172
|
+
setTimeout(() => {
|
|
173
|
+
indicator.style.opacity = "0";
|
|
174
|
+
setTimeout(() => {
|
|
175
|
+
document.body.removeChild(indicator);
|
|
176
|
+
}, 200);
|
|
177
|
+
}, 1500);
|
|
178
|
+
};
|
|
179
|
+
};
|
|
180
|
+
|
|
181
|
+
// src/utils/copy-text.ts
|
|
182
|
+
var copyText = async (text) => {
|
|
183
|
+
if (navigator.clipboard && window.isSecureContext) {
|
|
184
|
+
try {
|
|
185
|
+
await navigator.clipboard.writeText(text);
|
|
186
|
+
return true;
|
|
187
|
+
} catch {
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
const textareaEl = document.createElement("textarea");
|
|
191
|
+
textareaEl.value = text;
|
|
192
|
+
textareaEl.setAttribute("readonly", "");
|
|
193
|
+
textareaEl.style.position = "fixed";
|
|
194
|
+
textareaEl.style.top = "-9999px";
|
|
195
|
+
textareaEl.style.opacity = "0";
|
|
196
|
+
textareaEl.style.pointerEvents = "none";
|
|
197
|
+
document.body.appendChild(textareaEl);
|
|
198
|
+
textareaEl.select();
|
|
199
|
+
textareaEl.setSelectionRange(0, textareaEl.value.length);
|
|
200
|
+
let didCopy = false;
|
|
201
|
+
try {
|
|
202
|
+
didCopy = document.execCommand("copy");
|
|
203
|
+
} catch {
|
|
204
|
+
didCopy = false;
|
|
205
|
+
} finally {
|
|
206
|
+
document.body.removeChild(textareaEl);
|
|
207
|
+
}
|
|
208
|
+
return didCopy;
|
|
209
|
+
};
|
|
210
|
+
|
|
13
211
|
// node_modules/.pnpm/bippy@0.3.31_@types+react@19.2.2_react@19.2.0/node_modules/bippy/dist/src-R2iEnVC1.js
|
|
14
212
|
var version = "0.3.31";
|
|
15
213
|
var BIPPY_INSTRUMENTATION_STRING = `bippy-${version}`;
|
|
@@ -1983,7 +2181,7 @@ ${error.stack}`;
|
|
|
1983
2181
|
return matches;
|
|
1984
2182
|
};
|
|
1985
2183
|
|
|
1986
|
-
// src/
|
|
2184
|
+
// src/utils/data.ts
|
|
1987
2185
|
var getStack = async (element) => {
|
|
1988
2186
|
const fiber = getFiberFromHostInstance(element);
|
|
1989
2187
|
if (!fiber) return null;
|
|
@@ -2225,172 +2423,6 @@ ${error.stack}`;
|
|
|
2225
2423
|
return lines.join("\n");
|
|
2226
2424
|
};
|
|
2227
2425
|
|
|
2228
|
-
// src/overlay.ts
|
|
2229
|
-
var createSelection = ({
|
|
2230
|
-
borderRadius,
|
|
2231
|
-
height,
|
|
2232
|
-
transform,
|
|
2233
|
-
width,
|
|
2234
|
-
x,
|
|
2235
|
-
y
|
|
2236
|
-
}) => {
|
|
2237
|
-
const overlay = document.createElement("div");
|
|
2238
|
-
overlay.style.position = "fixed";
|
|
2239
|
-
overlay.style.top = `${y}px`;
|
|
2240
|
-
overlay.style.left = `${x}px`;
|
|
2241
|
-
overlay.style.width = `${width}px`;
|
|
2242
|
-
overlay.style.height = `${height}px`;
|
|
2243
|
-
overlay.style.borderRadius = borderRadius;
|
|
2244
|
-
overlay.style.transform = transform;
|
|
2245
|
-
overlay.style.pointerEvents = "none";
|
|
2246
|
-
overlay.style.border = "2px solid #007AFF";
|
|
2247
|
-
overlay.style.backgroundColor = "rgba(0, 122, 255, 0.1)";
|
|
2248
|
-
overlay.style.zIndex = "2147483646";
|
|
2249
|
-
overlay.style.boxSizing = "border-box";
|
|
2250
|
-
overlay.animate(
|
|
2251
|
-
[
|
|
2252
|
-
{ backgroundColor: "rgba(0, 122, 255, 0.1)" },
|
|
2253
|
-
{ backgroundColor: "rgba(0, 122, 255, 0.15)" },
|
|
2254
|
-
{ backgroundColor: "rgba(0, 122, 255, 0.1)" }
|
|
2255
|
-
],
|
|
2256
|
-
{
|
|
2257
|
-
duration: 2e3,
|
|
2258
|
-
easing: "ease-in-out",
|
|
2259
|
-
iterations: Infinity
|
|
2260
|
-
}
|
|
2261
|
-
);
|
|
2262
|
-
return overlay;
|
|
2263
|
-
};
|
|
2264
|
-
var lerp = (start, end, factor) => {
|
|
2265
|
-
return start + (end - start) * factor;
|
|
2266
|
-
};
|
|
2267
|
-
var SELECTION_LERP_FACTOR = 1;
|
|
2268
|
-
var updateSelection = (element, { borderRadius, height, transform, width, x, y }) => {
|
|
2269
|
-
const currentTop = parseFloat(element.style.top) || 0;
|
|
2270
|
-
const currentLeft = parseFloat(element.style.left) || 0;
|
|
2271
|
-
const currentWidth = parseFloat(element.style.width) || 0;
|
|
2272
|
-
const currentHeight = parseFloat(element.style.height) || 0;
|
|
2273
|
-
const topValue = `${lerp(currentTop, y, SELECTION_LERP_FACTOR)}px`;
|
|
2274
|
-
const leftValue = `${lerp(currentLeft, x, SELECTION_LERP_FACTOR)}px`;
|
|
2275
|
-
const widthValue = `${lerp(currentWidth, width, SELECTION_LERP_FACTOR)}px`;
|
|
2276
|
-
const heightValue = `${lerp(currentHeight, height, SELECTION_LERP_FACTOR)}px`;
|
|
2277
|
-
if (element.style.top !== topValue) {
|
|
2278
|
-
element.style.top = topValue;
|
|
2279
|
-
}
|
|
2280
|
-
if (element.style.left !== leftValue) {
|
|
2281
|
-
element.style.left = leftValue;
|
|
2282
|
-
}
|
|
2283
|
-
if (element.style.width !== widthValue) {
|
|
2284
|
-
element.style.width = widthValue;
|
|
2285
|
-
}
|
|
2286
|
-
if (element.style.height !== heightValue) {
|
|
2287
|
-
element.style.height = heightValue;
|
|
2288
|
-
}
|
|
2289
|
-
if (element.style.borderRadius !== borderRadius) {
|
|
2290
|
-
element.style.borderRadius = borderRadius;
|
|
2291
|
-
}
|
|
2292
|
-
if (element.style.transform !== transform) {
|
|
2293
|
-
element.style.transform = transform;
|
|
2294
|
-
}
|
|
2295
|
-
};
|
|
2296
|
-
var createSpinner = () => {
|
|
2297
|
-
const spinner = document.createElement("span");
|
|
2298
|
-
spinner.style.display = "inline-block";
|
|
2299
|
-
spinner.style.width = "8px";
|
|
2300
|
-
spinner.style.height = "8px";
|
|
2301
|
-
spinner.style.border = "1.5px solid #1e4ed8";
|
|
2302
|
-
spinner.style.borderTopColor = "transparent";
|
|
2303
|
-
spinner.style.borderRadius = "50%";
|
|
2304
|
-
spinner.style.marginRight = "4px";
|
|
2305
|
-
spinner.style.verticalAlign = "middle";
|
|
2306
|
-
spinner.animate(
|
|
2307
|
-
[
|
|
2308
|
-
{ transform: "rotate(0deg)" },
|
|
2309
|
-
{ transform: "rotate(360deg)" }
|
|
2310
|
-
],
|
|
2311
|
-
{
|
|
2312
|
-
duration: 600,
|
|
2313
|
-
easing: "linear",
|
|
2314
|
-
iterations: Infinity
|
|
2315
|
-
}
|
|
2316
|
-
);
|
|
2317
|
-
return spinner;
|
|
2318
|
-
};
|
|
2319
|
-
var createIndicator = (x, y) => {
|
|
2320
|
-
const indicator = document.createElement("div");
|
|
2321
|
-
indicator.style.position = "fixed";
|
|
2322
|
-
indicator.style.left = `${x}px`;
|
|
2323
|
-
indicator.style.top = `${y - 4}px`;
|
|
2324
|
-
indicator.style.transform = "translateY(-100%)";
|
|
2325
|
-
indicator.style.padding = "0px 4px";
|
|
2326
|
-
indicator.style.backgroundColor = "#dbeafe";
|
|
2327
|
-
indicator.style.color = "#1e4ed8";
|
|
2328
|
-
indicator.style.border = "1px solid #c7dbfb";
|
|
2329
|
-
indicator.style.borderRadius = "4px";
|
|
2330
|
-
indicator.style.fontSize = "11px";
|
|
2331
|
-
indicator.style.fontWeight = "500";
|
|
2332
|
-
indicator.style.fontFamily = "-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif";
|
|
2333
|
-
indicator.style.zIndex = "2147483647";
|
|
2334
|
-
indicator.style.pointerEvents = "none";
|
|
2335
|
-
indicator.style.opacity = "0";
|
|
2336
|
-
indicator.style.transition = "opacity 0.2s ease-in-out";
|
|
2337
|
-
indicator.style.display = "flex";
|
|
2338
|
-
indicator.style.alignItems = "center";
|
|
2339
|
-
return indicator;
|
|
2340
|
-
};
|
|
2341
|
-
var showCopyIndicator = (x, y) => {
|
|
2342
|
-
const indicator = createIndicator(x, y);
|
|
2343
|
-
const spinner = createSpinner();
|
|
2344
|
-
const text = document.createElement("span");
|
|
2345
|
-
text.textContent = "Copying\u2026";
|
|
2346
|
-
indicator.appendChild(spinner);
|
|
2347
|
-
indicator.appendChild(text);
|
|
2348
|
-
document.body.appendChild(indicator);
|
|
2349
|
-
requestAnimationFrame(() => {
|
|
2350
|
-
indicator.style.opacity = "1";
|
|
2351
|
-
});
|
|
2352
|
-
return () => {
|
|
2353
|
-
spinner.remove();
|
|
2354
|
-
text.textContent = "Copied!";
|
|
2355
|
-
setTimeout(() => {
|
|
2356
|
-
indicator.style.opacity = "0";
|
|
2357
|
-
setTimeout(() => {
|
|
2358
|
-
document.body.removeChild(indicator);
|
|
2359
|
-
}, 200);
|
|
2360
|
-
}, 1500);
|
|
2361
|
-
};
|
|
2362
|
-
};
|
|
2363
|
-
|
|
2364
|
-
// src/utils/copy-text.ts
|
|
2365
|
-
var copyText = async (text) => {
|
|
2366
|
-
if (navigator.clipboard && window.isSecureContext) {
|
|
2367
|
-
try {
|
|
2368
|
-
await navigator.clipboard.writeText(text);
|
|
2369
|
-
return true;
|
|
2370
|
-
} catch {
|
|
2371
|
-
}
|
|
2372
|
-
}
|
|
2373
|
-
const textareaEl = document.createElement("textarea");
|
|
2374
|
-
textareaEl.value = text;
|
|
2375
|
-
textareaEl.setAttribute("readonly", "");
|
|
2376
|
-
textareaEl.style.position = "fixed";
|
|
2377
|
-
textareaEl.style.top = "-9999px";
|
|
2378
|
-
textareaEl.style.opacity = "0";
|
|
2379
|
-
textareaEl.style.pointerEvents = "none";
|
|
2380
|
-
document.body.appendChild(textareaEl);
|
|
2381
|
-
textareaEl.select();
|
|
2382
|
-
textareaEl.setSelectionRange(0, textareaEl.value.length);
|
|
2383
|
-
let didCopy = false;
|
|
2384
|
-
try {
|
|
2385
|
-
didCopy = document.execCommand("copy");
|
|
2386
|
-
} catch {
|
|
2387
|
-
didCopy = false;
|
|
2388
|
-
} finally {
|
|
2389
|
-
document.body.removeChild(textareaEl);
|
|
2390
|
-
}
|
|
2391
|
-
return didCopy;
|
|
2392
|
-
};
|
|
2393
|
-
|
|
2394
2426
|
// src/utils/is-element-visible.ts
|
|
2395
2427
|
var isElementVisible = (element, computedStyle = null) => {
|
|
2396
2428
|
if (!computedStyle) {
|
|
@@ -2468,25 +2500,15 @@ ${error.stack}`;
|
|
|
2468
2500
|
const root = mountRoot();
|
|
2469
2501
|
let mouseX = 0;
|
|
2470
2502
|
let mouseY = 0;
|
|
2471
|
-
let isSelectionVisible = false;
|
|
2472
2503
|
let shiftKeyTimeout = null;
|
|
2473
2504
|
let currentHoveredElement = null;
|
|
2474
2505
|
const isFocusedInInput = () => {
|
|
2475
2506
|
const active = document.activeElement;
|
|
2476
2507
|
return active?.tagName === "INPUT" || active?.tagName === "TEXTAREA";
|
|
2477
2508
|
};
|
|
2478
|
-
const
|
|
2479
|
-
borderRadius: "0px",
|
|
2480
|
-
height: 0,
|
|
2481
|
-
transform: "none",
|
|
2482
|
-
width: 0,
|
|
2483
|
-
x: -1e3,
|
|
2484
|
-
y: -1e3
|
|
2485
|
-
});
|
|
2486
|
-
currentSelection.style.display = "none";
|
|
2487
|
-
root.appendChild(currentSelection);
|
|
2509
|
+
const selectionOverlay = new SelectionOverlay(root);
|
|
2488
2510
|
const render = () => {
|
|
2489
|
-
if (!
|
|
2511
|
+
if (!selectionOverlay.isVisible()) return;
|
|
2490
2512
|
const element = document.elementsFromPoint(mouseX, mouseY).filter((element2) => !element2.hasAttribute(ATTRIBUTE_NAME))[0];
|
|
2491
2513
|
if (!element) {
|
|
2492
2514
|
currentHoveredElement = null;
|
|
@@ -2496,7 +2518,7 @@ ${error.stack}`;
|
|
|
2496
2518
|
if (!isElementVisible(element, computedStyle)) return;
|
|
2497
2519
|
const rect = element.getBoundingClientRect();
|
|
2498
2520
|
currentHoveredElement = element;
|
|
2499
|
-
|
|
2521
|
+
selectionOverlay.update({
|
|
2500
2522
|
borderRadius: computedStyle.borderRadius,
|
|
2501
2523
|
height: rect.height,
|
|
2502
2524
|
transform: computedStyle.transform,
|
|
@@ -2536,14 +2558,21 @@ ${error.stack}`;
|
|
|
2536
2558
|
window.clearTimeout(shiftKeyTimeout);
|
|
2537
2559
|
}
|
|
2538
2560
|
shiftKeyTimeout = window.setTimeout(() => {
|
|
2539
|
-
|
|
2540
|
-
currentSelection.style.display = "block";
|
|
2541
|
-
currentSelection.style.pointerEvents = "auto";
|
|
2561
|
+
selectionOverlay.show();
|
|
2542
2562
|
throttledRender();
|
|
2543
2563
|
}, 200);
|
|
2544
2564
|
}
|
|
2565
|
+
if (event.key === "Escape") {
|
|
2566
|
+
if (selectionOverlay.isVisible()) {
|
|
2567
|
+
selectionOverlay.hide();
|
|
2568
|
+
if (shiftKeyTimeout !== null) {
|
|
2569
|
+
window.clearTimeout(shiftKeyTimeout);
|
|
2570
|
+
shiftKeyTimeout = null;
|
|
2571
|
+
}
|
|
2572
|
+
}
|
|
2573
|
+
}
|
|
2545
2574
|
if ((event.key === "c" || event.key === "C") && event.metaKey) {
|
|
2546
|
-
if (
|
|
2575
|
+
if (selectionOverlay.isVisible() && currentHoveredElement) {
|
|
2547
2576
|
event.preventDefault();
|
|
2548
2577
|
event.stopPropagation();
|
|
2549
2578
|
event.stopImmediatePropagation();
|
|
@@ -2572,7 +2601,7 @@ ${htmlSnippet}`;
|
|
|
2572
2601
|
});
|
|
2573
2602
|
window.addEventListener("mousedown", (event) => {
|
|
2574
2603
|
if (event.button !== 0) return;
|
|
2575
|
-
if (
|
|
2604
|
+
if (selectionOverlay.isVisible()) {
|
|
2576
2605
|
event.preventDefault();
|
|
2577
2606
|
event.stopPropagation();
|
|
2578
2607
|
event.stopImmediatePropagation();
|
|
@@ -2609,11 +2638,8 @@ Path: ${window.location.pathname}`;
|
|
|
2609
2638
|
window.clearTimeout(shiftKeyTimeout);
|
|
2610
2639
|
shiftKeyTimeout = null;
|
|
2611
2640
|
}
|
|
2641
|
+
selectionOverlay.hide();
|
|
2612
2642
|
}
|
|
2613
|
-
currentSelection.style.display = "none";
|
|
2614
|
-
currentSelection.style.pointerEvents = "none";
|
|
2615
|
-
isSelectionVisible = false;
|
|
2616
|
-
throttledRender();
|
|
2617
2643
|
});
|
|
2618
2644
|
return () => {
|
|
2619
2645
|
if (timeout) {
|
package/package.json
CHANGED
package/dist/core.cjs
DELETED
|
@@ -1,259 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
var bippy = require('bippy');
|
|
4
|
-
var source = require('bippy/dist/source');
|
|
5
|
-
|
|
6
|
-
/**
|
|
7
|
-
* @license MIT
|
|
8
|
-
*
|
|
9
|
-
* Copyright (c) 2025 Aiden Bai
|
|
10
|
-
*
|
|
11
|
-
* This source code is licensed under the MIT license found in the
|
|
12
|
-
* LICENSE file in the root directory of this source tree.
|
|
13
|
-
*/
|
|
14
|
-
|
|
15
|
-
var getStack = async (element) => {
|
|
16
|
-
const fiber = bippy.getFiberFromHostInstance(element);
|
|
17
|
-
if (!fiber) return null;
|
|
18
|
-
const stackTrace = source.getFiberStackTrace(fiber);
|
|
19
|
-
console.log(stackTrace);
|
|
20
|
-
const rawOwnerStack = await source.getOwnerStack(stackTrace);
|
|
21
|
-
console.log(rawOwnerStack);
|
|
22
|
-
const stack = rawOwnerStack.map((item) => ({
|
|
23
|
-
componentName: item.name,
|
|
24
|
-
fileName: item.source?.fileName
|
|
25
|
-
}));
|
|
26
|
-
return stack;
|
|
27
|
-
};
|
|
28
|
-
var filterStack = (stack) => {
|
|
29
|
-
return stack.filter(
|
|
30
|
-
(item) => item.fileName && !item.fileName.includes("node_modules") && item.componentName.length > 1 && !item.fileName.startsWith("_")
|
|
31
|
-
);
|
|
32
|
-
};
|
|
33
|
-
var findCommonRoot = (paths) => {
|
|
34
|
-
if (paths.length === 0) return "";
|
|
35
|
-
if (paths.length === 1) {
|
|
36
|
-
const lastSlash2 = paths[0].lastIndexOf("/");
|
|
37
|
-
return lastSlash2 > 0 ? paths[0].substring(0, lastSlash2 + 1) : "";
|
|
38
|
-
}
|
|
39
|
-
let commonPrefix = paths[0];
|
|
40
|
-
for (let i = 1; i < paths.length; i++) {
|
|
41
|
-
const path = paths[i];
|
|
42
|
-
let j = 0;
|
|
43
|
-
while (j < commonPrefix.length && j < path.length && commonPrefix[j] === path[j]) {
|
|
44
|
-
j++;
|
|
45
|
-
}
|
|
46
|
-
commonPrefix = commonPrefix.substring(0, j);
|
|
47
|
-
}
|
|
48
|
-
const lastSlash = commonPrefix.lastIndexOf("/");
|
|
49
|
-
return lastSlash > 0 ? commonPrefix.substring(0, lastSlash + 1) : "";
|
|
50
|
-
};
|
|
51
|
-
var serializeStack = (stack) => {
|
|
52
|
-
const filePaths = stack.map((item) => item.fileName).filter((path) => !!path);
|
|
53
|
-
const commonRoot = findCommonRoot(filePaths);
|
|
54
|
-
return stack.map((item) => {
|
|
55
|
-
let fileName = item.fileName;
|
|
56
|
-
if (fileName && commonRoot) {
|
|
57
|
-
fileName = fileName.startsWith(commonRoot) ? fileName.substring(commonRoot.length) : fileName;
|
|
58
|
-
}
|
|
59
|
-
return `${item.componentName}${fileName ? ` (${fileName})` : ""}`;
|
|
60
|
-
}).join("\n");
|
|
61
|
-
};
|
|
62
|
-
var getHTMLSnippet = (element) => {
|
|
63
|
-
const semanticTags = /* @__PURE__ */ new Set([
|
|
64
|
-
"article",
|
|
65
|
-
"aside",
|
|
66
|
-
"footer",
|
|
67
|
-
"form",
|
|
68
|
-
"header",
|
|
69
|
-
"main",
|
|
70
|
-
"nav",
|
|
71
|
-
"section"
|
|
72
|
-
]);
|
|
73
|
-
const hasDistinguishingFeatures = (el) => {
|
|
74
|
-
const tagName = el.tagName.toLowerCase();
|
|
75
|
-
if (semanticTags.has(tagName)) return true;
|
|
76
|
-
if (el.id) return true;
|
|
77
|
-
if (el.className && typeof el.className === "string") {
|
|
78
|
-
const classes = el.className.trim();
|
|
79
|
-
if (classes && classes.length > 0) return true;
|
|
80
|
-
}
|
|
81
|
-
return Array.from(el.attributes).some(
|
|
82
|
-
(attr) => attr.name.startsWith("data-")
|
|
83
|
-
);
|
|
84
|
-
};
|
|
85
|
-
const getAncestorChain = (el, maxDepth = 10) => {
|
|
86
|
-
const ancestors2 = [];
|
|
87
|
-
let current = el.parentElement;
|
|
88
|
-
let depth = 0;
|
|
89
|
-
while (current && depth < maxDepth && current.tagName !== "BODY") {
|
|
90
|
-
if (hasDistinguishingFeatures(current)) {
|
|
91
|
-
ancestors2.push(current);
|
|
92
|
-
if (ancestors2.length >= 3) break;
|
|
93
|
-
}
|
|
94
|
-
current = current.parentElement;
|
|
95
|
-
depth++;
|
|
96
|
-
}
|
|
97
|
-
return ancestors2.reverse();
|
|
98
|
-
};
|
|
99
|
-
const getCSSPath = (el) => {
|
|
100
|
-
const parts = [];
|
|
101
|
-
let current = el;
|
|
102
|
-
let depth = 0;
|
|
103
|
-
const maxDepth = 5;
|
|
104
|
-
while (current && depth < maxDepth && current.tagName !== "BODY") {
|
|
105
|
-
let selector = current.tagName.toLowerCase();
|
|
106
|
-
if (current.id) {
|
|
107
|
-
selector += `#${current.id}`;
|
|
108
|
-
parts.unshift(selector);
|
|
109
|
-
break;
|
|
110
|
-
} else if (current.className && typeof current.className === "string" && current.className.trim()) {
|
|
111
|
-
const classes = current.className.trim().split(/\s+/).slice(0, 2);
|
|
112
|
-
selector += `.${classes.join(".")}`;
|
|
113
|
-
}
|
|
114
|
-
if (!current.id && (!current.className || !current.className.trim()) && current.parentElement) {
|
|
115
|
-
const siblings = Array.from(current.parentElement.children);
|
|
116
|
-
const index = siblings.indexOf(current);
|
|
117
|
-
if (index >= 0 && siblings.length > 1) {
|
|
118
|
-
selector += `:nth-child(${index + 1})`;
|
|
119
|
-
}
|
|
120
|
-
}
|
|
121
|
-
parts.unshift(selector);
|
|
122
|
-
current = current.parentElement;
|
|
123
|
-
depth++;
|
|
124
|
-
}
|
|
125
|
-
return parts.join(" > ");
|
|
126
|
-
};
|
|
127
|
-
const getElementTag = (el, compact = false) => {
|
|
128
|
-
const tagName = el.tagName.toLowerCase();
|
|
129
|
-
const attrs = [];
|
|
130
|
-
if (el.id) {
|
|
131
|
-
attrs.push(`id="${el.id}"`);
|
|
132
|
-
}
|
|
133
|
-
if (el.className && typeof el.className === "string") {
|
|
134
|
-
const classes = el.className.trim().split(/\s+/);
|
|
135
|
-
if (classes.length > 0 && classes[0]) {
|
|
136
|
-
const displayClasses = compact ? classes.slice(0, 3) : classes;
|
|
137
|
-
let classStr = displayClasses.join(" ");
|
|
138
|
-
if (classStr.length > 30) {
|
|
139
|
-
classStr = classStr.substring(0, 30) + "...";
|
|
140
|
-
}
|
|
141
|
-
attrs.push(`class="${classStr}"`);
|
|
142
|
-
}
|
|
143
|
-
}
|
|
144
|
-
const dataAttrs = Array.from(el.attributes).filter(
|
|
145
|
-
(attr) => attr.name.startsWith("data-")
|
|
146
|
-
);
|
|
147
|
-
const displayDataAttrs = compact ? dataAttrs.slice(0, 1) : dataAttrs;
|
|
148
|
-
for (const attr of displayDataAttrs) {
|
|
149
|
-
let value = attr.value;
|
|
150
|
-
if (value.length > 20) {
|
|
151
|
-
value = value.substring(0, 20) + "...";
|
|
152
|
-
}
|
|
153
|
-
attrs.push(`${attr.name}="${value}"`);
|
|
154
|
-
}
|
|
155
|
-
const ariaLabel = el.getAttribute("aria-label");
|
|
156
|
-
if (ariaLabel && !compact) {
|
|
157
|
-
let value = ariaLabel;
|
|
158
|
-
if (value.length > 20) {
|
|
159
|
-
value = value.substring(0, 20) + "...";
|
|
160
|
-
}
|
|
161
|
-
attrs.push(`aria-label="${value}"`);
|
|
162
|
-
}
|
|
163
|
-
return attrs.length > 0 ? `<${tagName} ${attrs.join(" ")}>` : `<${tagName}>`;
|
|
164
|
-
};
|
|
165
|
-
const getClosingTag = (el) => {
|
|
166
|
-
return `</${el.tagName.toLowerCase()}>`;
|
|
167
|
-
};
|
|
168
|
-
const getTextContent = (el) => {
|
|
169
|
-
let text = el.textContent || "";
|
|
170
|
-
text = text.trim().replace(/\s+/g, " ");
|
|
171
|
-
const maxLength = 60;
|
|
172
|
-
if (text.length > maxLength) {
|
|
173
|
-
text = text.substring(0, maxLength) + "...";
|
|
174
|
-
}
|
|
175
|
-
return text;
|
|
176
|
-
};
|
|
177
|
-
const getSiblingIdentifier = (el) => {
|
|
178
|
-
if (el.id) return `#${el.id}`;
|
|
179
|
-
if (el.className && typeof el.className === "string") {
|
|
180
|
-
const classes = el.className.trim().split(/\s+/);
|
|
181
|
-
if (classes.length > 0 && classes[0]) {
|
|
182
|
-
return `.${classes[0]}`;
|
|
183
|
-
}
|
|
184
|
-
}
|
|
185
|
-
return null;
|
|
186
|
-
};
|
|
187
|
-
const lines = [];
|
|
188
|
-
lines.push(`Path: ${getCSSPath(element)}`);
|
|
189
|
-
lines.push("");
|
|
190
|
-
const ancestors = getAncestorChain(element);
|
|
191
|
-
for (let i = 0; i < ancestors.length; i++) {
|
|
192
|
-
const indent2 = " ".repeat(i);
|
|
193
|
-
lines.push(indent2 + getElementTag(ancestors[i], true));
|
|
194
|
-
}
|
|
195
|
-
const parent = element.parentElement;
|
|
196
|
-
let targetIndex = -1;
|
|
197
|
-
if (parent) {
|
|
198
|
-
const siblings = Array.from(parent.children);
|
|
199
|
-
targetIndex = siblings.indexOf(element);
|
|
200
|
-
if (targetIndex > 0) {
|
|
201
|
-
const prevSibling = siblings[targetIndex - 1];
|
|
202
|
-
const prevId = getSiblingIdentifier(prevSibling);
|
|
203
|
-
if (prevId && targetIndex <= 2) {
|
|
204
|
-
const indent2 = " ".repeat(ancestors.length);
|
|
205
|
-
lines.push(`${indent2} ${getElementTag(prevSibling, true)}`);
|
|
206
|
-
lines.push(`${indent2} </${prevSibling.tagName.toLowerCase()}>`);
|
|
207
|
-
} else if (targetIndex > 0) {
|
|
208
|
-
const indent2 = " ".repeat(ancestors.length);
|
|
209
|
-
lines.push(`${indent2} ... (${targetIndex} element${targetIndex === 1 ? "" : "s"})`);
|
|
210
|
-
}
|
|
211
|
-
}
|
|
212
|
-
}
|
|
213
|
-
const indent = " ".repeat(ancestors.length);
|
|
214
|
-
lines.push(indent + " <!-- SELECTED -->");
|
|
215
|
-
const textContent = getTextContent(element);
|
|
216
|
-
const childrenCount = element.children.length;
|
|
217
|
-
if (textContent && childrenCount === 0 && textContent.length < 40) {
|
|
218
|
-
lines.push(
|
|
219
|
-
`${indent} ${getElementTag(element)}${textContent}${getClosingTag(element)}`
|
|
220
|
-
);
|
|
221
|
-
} else {
|
|
222
|
-
lines.push(indent + " " + getElementTag(element));
|
|
223
|
-
if (textContent) {
|
|
224
|
-
lines.push(`${indent} ${textContent}`);
|
|
225
|
-
}
|
|
226
|
-
if (childrenCount > 0) {
|
|
227
|
-
lines.push(
|
|
228
|
-
`${indent} ... (${childrenCount} element${childrenCount === 1 ? "" : "s"})`
|
|
229
|
-
);
|
|
230
|
-
}
|
|
231
|
-
lines.push(indent + " " + getClosingTag(element));
|
|
232
|
-
}
|
|
233
|
-
if (parent && targetIndex >= 0) {
|
|
234
|
-
const siblings = Array.from(parent.children);
|
|
235
|
-
const siblingsAfter = siblings.length - targetIndex - 1;
|
|
236
|
-
if (siblingsAfter > 0) {
|
|
237
|
-
const nextSibling = siblings[targetIndex + 1];
|
|
238
|
-
const nextId = getSiblingIdentifier(nextSibling);
|
|
239
|
-
if (nextId && siblingsAfter <= 2) {
|
|
240
|
-
lines.push(`${indent} ${getElementTag(nextSibling, true)}`);
|
|
241
|
-
lines.push(`${indent} </${nextSibling.tagName.toLowerCase()}>`);
|
|
242
|
-
} else {
|
|
243
|
-
lines.push(
|
|
244
|
-
`${indent} ... (${siblingsAfter} element${siblingsAfter === 1 ? "" : "s"})`
|
|
245
|
-
);
|
|
246
|
-
}
|
|
247
|
-
}
|
|
248
|
-
}
|
|
249
|
-
for (let i = ancestors.length - 1; i >= 0; i--) {
|
|
250
|
-
const indent2 = " ".repeat(i);
|
|
251
|
-
lines.push(indent2 + getClosingTag(ancestors[i]));
|
|
252
|
-
}
|
|
253
|
-
return lines.join("\n");
|
|
254
|
-
};
|
|
255
|
-
|
|
256
|
-
exports.filterStack = filterStack;
|
|
257
|
-
exports.getHTMLSnippet = getHTMLSnippet;
|
|
258
|
-
exports.getStack = getStack;
|
|
259
|
-
exports.serializeStack = serializeStack;
|
package/dist/core.d.cts
DELETED
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
interface StackItem {
|
|
2
|
-
componentName: string;
|
|
3
|
-
fileName: string | undefined;
|
|
4
|
-
}
|
|
5
|
-
declare const getStack: (element: Element) => Promise<StackItem[] | null>;
|
|
6
|
-
declare const filterStack: (stack: StackItem[]) => StackItem[];
|
|
7
|
-
declare const serializeStack: (stack: StackItem[]) => string;
|
|
8
|
-
declare const getHTMLSnippet: (element: Element) => string;
|
|
9
|
-
|
|
10
|
-
export { type StackItem, filterStack, getHTMLSnippet, getStack, serializeStack };
|
package/dist/core.d.ts
DELETED
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
interface StackItem {
|
|
2
|
-
componentName: string;
|
|
3
|
-
fileName: string | undefined;
|
|
4
|
-
}
|
|
5
|
-
declare const getStack: (element: Element) => Promise<StackItem[] | null>;
|
|
6
|
-
declare const filterStack: (stack: StackItem[]) => StackItem[];
|
|
7
|
-
declare const serializeStack: (stack: StackItem[]) => string;
|
|
8
|
-
declare const getHTMLSnippet: (element: Element) => string;
|
|
9
|
-
|
|
10
|
-
export { type StackItem, filterStack, getHTMLSnippet, getStack, serializeStack };
|
package/dist/core.js
DELETED
|
@@ -1,254 +0,0 @@
|
|
|
1
|
-
import { getFiberFromHostInstance } from 'bippy';
|
|
2
|
-
import { getFiberStackTrace, getOwnerStack } from 'bippy/dist/source';
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* @license MIT
|
|
6
|
-
*
|
|
7
|
-
* Copyright (c) 2025 Aiden Bai
|
|
8
|
-
*
|
|
9
|
-
* This source code is licensed under the MIT license found in the
|
|
10
|
-
* LICENSE file in the root directory of this source tree.
|
|
11
|
-
*/
|
|
12
|
-
|
|
13
|
-
var getStack = async (element) => {
|
|
14
|
-
const fiber = getFiberFromHostInstance(element);
|
|
15
|
-
if (!fiber) return null;
|
|
16
|
-
const stackTrace = getFiberStackTrace(fiber);
|
|
17
|
-
console.log(stackTrace);
|
|
18
|
-
const rawOwnerStack = await getOwnerStack(stackTrace);
|
|
19
|
-
console.log(rawOwnerStack);
|
|
20
|
-
const stack = rawOwnerStack.map((item) => ({
|
|
21
|
-
componentName: item.name,
|
|
22
|
-
fileName: item.source?.fileName
|
|
23
|
-
}));
|
|
24
|
-
return stack;
|
|
25
|
-
};
|
|
26
|
-
var filterStack = (stack) => {
|
|
27
|
-
return stack.filter(
|
|
28
|
-
(item) => item.fileName && !item.fileName.includes("node_modules") && item.componentName.length > 1 && !item.fileName.startsWith("_")
|
|
29
|
-
);
|
|
30
|
-
};
|
|
31
|
-
var findCommonRoot = (paths) => {
|
|
32
|
-
if (paths.length === 0) return "";
|
|
33
|
-
if (paths.length === 1) {
|
|
34
|
-
const lastSlash2 = paths[0].lastIndexOf("/");
|
|
35
|
-
return lastSlash2 > 0 ? paths[0].substring(0, lastSlash2 + 1) : "";
|
|
36
|
-
}
|
|
37
|
-
let commonPrefix = paths[0];
|
|
38
|
-
for (let i = 1; i < paths.length; i++) {
|
|
39
|
-
const path = paths[i];
|
|
40
|
-
let j = 0;
|
|
41
|
-
while (j < commonPrefix.length && j < path.length && commonPrefix[j] === path[j]) {
|
|
42
|
-
j++;
|
|
43
|
-
}
|
|
44
|
-
commonPrefix = commonPrefix.substring(0, j);
|
|
45
|
-
}
|
|
46
|
-
const lastSlash = commonPrefix.lastIndexOf("/");
|
|
47
|
-
return lastSlash > 0 ? commonPrefix.substring(0, lastSlash + 1) : "";
|
|
48
|
-
};
|
|
49
|
-
var serializeStack = (stack) => {
|
|
50
|
-
const filePaths = stack.map((item) => item.fileName).filter((path) => !!path);
|
|
51
|
-
const commonRoot = findCommonRoot(filePaths);
|
|
52
|
-
return stack.map((item) => {
|
|
53
|
-
let fileName = item.fileName;
|
|
54
|
-
if (fileName && commonRoot) {
|
|
55
|
-
fileName = fileName.startsWith(commonRoot) ? fileName.substring(commonRoot.length) : fileName;
|
|
56
|
-
}
|
|
57
|
-
return `${item.componentName}${fileName ? ` (${fileName})` : ""}`;
|
|
58
|
-
}).join("\n");
|
|
59
|
-
};
|
|
60
|
-
var getHTMLSnippet = (element) => {
|
|
61
|
-
const semanticTags = /* @__PURE__ */ new Set([
|
|
62
|
-
"article",
|
|
63
|
-
"aside",
|
|
64
|
-
"footer",
|
|
65
|
-
"form",
|
|
66
|
-
"header",
|
|
67
|
-
"main",
|
|
68
|
-
"nav",
|
|
69
|
-
"section"
|
|
70
|
-
]);
|
|
71
|
-
const hasDistinguishingFeatures = (el) => {
|
|
72
|
-
const tagName = el.tagName.toLowerCase();
|
|
73
|
-
if (semanticTags.has(tagName)) return true;
|
|
74
|
-
if (el.id) return true;
|
|
75
|
-
if (el.className && typeof el.className === "string") {
|
|
76
|
-
const classes = el.className.trim();
|
|
77
|
-
if (classes && classes.length > 0) return true;
|
|
78
|
-
}
|
|
79
|
-
return Array.from(el.attributes).some(
|
|
80
|
-
(attr) => attr.name.startsWith("data-")
|
|
81
|
-
);
|
|
82
|
-
};
|
|
83
|
-
const getAncestorChain = (el, maxDepth = 10) => {
|
|
84
|
-
const ancestors2 = [];
|
|
85
|
-
let current = el.parentElement;
|
|
86
|
-
let depth = 0;
|
|
87
|
-
while (current && depth < maxDepth && current.tagName !== "BODY") {
|
|
88
|
-
if (hasDistinguishingFeatures(current)) {
|
|
89
|
-
ancestors2.push(current);
|
|
90
|
-
if (ancestors2.length >= 3) break;
|
|
91
|
-
}
|
|
92
|
-
current = current.parentElement;
|
|
93
|
-
depth++;
|
|
94
|
-
}
|
|
95
|
-
return ancestors2.reverse();
|
|
96
|
-
};
|
|
97
|
-
const getCSSPath = (el) => {
|
|
98
|
-
const parts = [];
|
|
99
|
-
let current = el;
|
|
100
|
-
let depth = 0;
|
|
101
|
-
const maxDepth = 5;
|
|
102
|
-
while (current && depth < maxDepth && current.tagName !== "BODY") {
|
|
103
|
-
let selector = current.tagName.toLowerCase();
|
|
104
|
-
if (current.id) {
|
|
105
|
-
selector += `#${current.id}`;
|
|
106
|
-
parts.unshift(selector);
|
|
107
|
-
break;
|
|
108
|
-
} else if (current.className && typeof current.className === "string" && current.className.trim()) {
|
|
109
|
-
const classes = current.className.trim().split(/\s+/).slice(0, 2);
|
|
110
|
-
selector += `.${classes.join(".")}`;
|
|
111
|
-
}
|
|
112
|
-
if (!current.id && (!current.className || !current.className.trim()) && current.parentElement) {
|
|
113
|
-
const siblings = Array.from(current.parentElement.children);
|
|
114
|
-
const index = siblings.indexOf(current);
|
|
115
|
-
if (index >= 0 && siblings.length > 1) {
|
|
116
|
-
selector += `:nth-child(${index + 1})`;
|
|
117
|
-
}
|
|
118
|
-
}
|
|
119
|
-
parts.unshift(selector);
|
|
120
|
-
current = current.parentElement;
|
|
121
|
-
depth++;
|
|
122
|
-
}
|
|
123
|
-
return parts.join(" > ");
|
|
124
|
-
};
|
|
125
|
-
const getElementTag = (el, compact = false) => {
|
|
126
|
-
const tagName = el.tagName.toLowerCase();
|
|
127
|
-
const attrs = [];
|
|
128
|
-
if (el.id) {
|
|
129
|
-
attrs.push(`id="${el.id}"`);
|
|
130
|
-
}
|
|
131
|
-
if (el.className && typeof el.className === "string") {
|
|
132
|
-
const classes = el.className.trim().split(/\s+/);
|
|
133
|
-
if (classes.length > 0 && classes[0]) {
|
|
134
|
-
const displayClasses = compact ? classes.slice(0, 3) : classes;
|
|
135
|
-
let classStr = displayClasses.join(" ");
|
|
136
|
-
if (classStr.length > 30) {
|
|
137
|
-
classStr = classStr.substring(0, 30) + "...";
|
|
138
|
-
}
|
|
139
|
-
attrs.push(`class="${classStr}"`);
|
|
140
|
-
}
|
|
141
|
-
}
|
|
142
|
-
const dataAttrs = Array.from(el.attributes).filter(
|
|
143
|
-
(attr) => attr.name.startsWith("data-")
|
|
144
|
-
);
|
|
145
|
-
const displayDataAttrs = compact ? dataAttrs.slice(0, 1) : dataAttrs;
|
|
146
|
-
for (const attr of displayDataAttrs) {
|
|
147
|
-
let value = attr.value;
|
|
148
|
-
if (value.length > 20) {
|
|
149
|
-
value = value.substring(0, 20) + "...";
|
|
150
|
-
}
|
|
151
|
-
attrs.push(`${attr.name}="${value}"`);
|
|
152
|
-
}
|
|
153
|
-
const ariaLabel = el.getAttribute("aria-label");
|
|
154
|
-
if (ariaLabel && !compact) {
|
|
155
|
-
let value = ariaLabel;
|
|
156
|
-
if (value.length > 20) {
|
|
157
|
-
value = value.substring(0, 20) + "...";
|
|
158
|
-
}
|
|
159
|
-
attrs.push(`aria-label="${value}"`);
|
|
160
|
-
}
|
|
161
|
-
return attrs.length > 0 ? `<${tagName} ${attrs.join(" ")}>` : `<${tagName}>`;
|
|
162
|
-
};
|
|
163
|
-
const getClosingTag = (el) => {
|
|
164
|
-
return `</${el.tagName.toLowerCase()}>`;
|
|
165
|
-
};
|
|
166
|
-
const getTextContent = (el) => {
|
|
167
|
-
let text = el.textContent || "";
|
|
168
|
-
text = text.trim().replace(/\s+/g, " ");
|
|
169
|
-
const maxLength = 60;
|
|
170
|
-
if (text.length > maxLength) {
|
|
171
|
-
text = text.substring(0, maxLength) + "...";
|
|
172
|
-
}
|
|
173
|
-
return text;
|
|
174
|
-
};
|
|
175
|
-
const getSiblingIdentifier = (el) => {
|
|
176
|
-
if (el.id) return `#${el.id}`;
|
|
177
|
-
if (el.className && typeof el.className === "string") {
|
|
178
|
-
const classes = el.className.trim().split(/\s+/);
|
|
179
|
-
if (classes.length > 0 && classes[0]) {
|
|
180
|
-
return `.${classes[0]}`;
|
|
181
|
-
}
|
|
182
|
-
}
|
|
183
|
-
return null;
|
|
184
|
-
};
|
|
185
|
-
const lines = [];
|
|
186
|
-
lines.push(`Path: ${getCSSPath(element)}`);
|
|
187
|
-
lines.push("");
|
|
188
|
-
const ancestors = getAncestorChain(element);
|
|
189
|
-
for (let i = 0; i < ancestors.length; i++) {
|
|
190
|
-
const indent2 = " ".repeat(i);
|
|
191
|
-
lines.push(indent2 + getElementTag(ancestors[i], true));
|
|
192
|
-
}
|
|
193
|
-
const parent = element.parentElement;
|
|
194
|
-
let targetIndex = -1;
|
|
195
|
-
if (parent) {
|
|
196
|
-
const siblings = Array.from(parent.children);
|
|
197
|
-
targetIndex = siblings.indexOf(element);
|
|
198
|
-
if (targetIndex > 0) {
|
|
199
|
-
const prevSibling = siblings[targetIndex - 1];
|
|
200
|
-
const prevId = getSiblingIdentifier(prevSibling);
|
|
201
|
-
if (prevId && targetIndex <= 2) {
|
|
202
|
-
const indent2 = " ".repeat(ancestors.length);
|
|
203
|
-
lines.push(`${indent2} ${getElementTag(prevSibling, true)}`);
|
|
204
|
-
lines.push(`${indent2} </${prevSibling.tagName.toLowerCase()}>`);
|
|
205
|
-
} else if (targetIndex > 0) {
|
|
206
|
-
const indent2 = " ".repeat(ancestors.length);
|
|
207
|
-
lines.push(`${indent2} ... (${targetIndex} element${targetIndex === 1 ? "" : "s"})`);
|
|
208
|
-
}
|
|
209
|
-
}
|
|
210
|
-
}
|
|
211
|
-
const indent = " ".repeat(ancestors.length);
|
|
212
|
-
lines.push(indent + " <!-- SELECTED -->");
|
|
213
|
-
const textContent = getTextContent(element);
|
|
214
|
-
const childrenCount = element.children.length;
|
|
215
|
-
if (textContent && childrenCount === 0 && textContent.length < 40) {
|
|
216
|
-
lines.push(
|
|
217
|
-
`${indent} ${getElementTag(element)}${textContent}${getClosingTag(element)}`
|
|
218
|
-
);
|
|
219
|
-
} else {
|
|
220
|
-
lines.push(indent + " " + getElementTag(element));
|
|
221
|
-
if (textContent) {
|
|
222
|
-
lines.push(`${indent} ${textContent}`);
|
|
223
|
-
}
|
|
224
|
-
if (childrenCount > 0) {
|
|
225
|
-
lines.push(
|
|
226
|
-
`${indent} ... (${childrenCount} element${childrenCount === 1 ? "" : "s"})`
|
|
227
|
-
);
|
|
228
|
-
}
|
|
229
|
-
lines.push(indent + " " + getClosingTag(element));
|
|
230
|
-
}
|
|
231
|
-
if (parent && targetIndex >= 0) {
|
|
232
|
-
const siblings = Array.from(parent.children);
|
|
233
|
-
const siblingsAfter = siblings.length - targetIndex - 1;
|
|
234
|
-
if (siblingsAfter > 0) {
|
|
235
|
-
const nextSibling = siblings[targetIndex + 1];
|
|
236
|
-
const nextId = getSiblingIdentifier(nextSibling);
|
|
237
|
-
if (nextId && siblingsAfter <= 2) {
|
|
238
|
-
lines.push(`${indent} ${getElementTag(nextSibling, true)}`);
|
|
239
|
-
lines.push(`${indent} </${nextSibling.tagName.toLowerCase()}>`);
|
|
240
|
-
} else {
|
|
241
|
-
lines.push(
|
|
242
|
-
`${indent} ... (${siblingsAfter} element${siblingsAfter === 1 ? "" : "s"})`
|
|
243
|
-
);
|
|
244
|
-
}
|
|
245
|
-
}
|
|
246
|
-
}
|
|
247
|
-
for (let i = ancestors.length - 1; i >= 0; i--) {
|
|
248
|
-
const indent2 = " ".repeat(i);
|
|
249
|
-
lines.push(indent2 + getClosingTag(ancestors[i]));
|
|
250
|
-
}
|
|
251
|
-
return lines.join("\n");
|
|
252
|
-
};
|
|
253
|
-
|
|
254
|
-
export { filterStack, getHTMLSnippet, getStack, serializeStack };
|