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.
@@ -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/core.ts
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 currentSelection = createSelection({
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 (!isSelectionVisible) return;
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
- updateSelection(currentSelection, {
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
- isSelectionVisible = true;
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 (isSelectionVisible && currentHoveredElement) {
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 (isSelectionVisible) {
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-grab",
3
- "version": "0.0.9",
3
+ "version": "0.0.11",
4
4
  "description": "",
5
5
  "keywords": [],
6
6
  "homepage": "https://github.com/aidenybai/react-grab#readme",
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 };