react-grab 0.0.24 → 0.0.26
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.cjs +749 -450
- package/dist/index.d.cts +44 -1
- package/dist/index.d.ts +44 -1
- package/dist/index.global.js +17 -30
- package/dist/index.js +751 -452
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { render, createComponent,
|
|
2
|
-
import { createRoot, createSignal, createMemo, createEffect, onCleanup, Show, For } from 'solid-js';
|
|
1
|
+
import { render, createComponent, memo, template, effect, style, insert, setStyleProperty, use } from 'solid-js/web';
|
|
2
|
+
import { createRoot, createSignal, createMemo, createEffect, on, onCleanup, Show, For, onMount } from 'solid-js';
|
|
3
3
|
import { instrument, _fiberRoots, getFiberFromHostInstance } from 'bippy';
|
|
4
4
|
import { getOwnerStack, getSourcesFromStack } from 'bippy/dist/source';
|
|
5
5
|
|
|
@@ -89,93 +89,101 @@ var mountRoot = () => {
|
|
|
89
89
|
return root;
|
|
90
90
|
};
|
|
91
91
|
|
|
92
|
-
// src/
|
|
93
|
-
var isElementVisible = (element, computedStyle = window.getComputedStyle(element)) => {
|
|
94
|
-
return computedStyle.display !== "none" && computedStyle.visibility !== "hidden" && computedStyle.opacity !== "0";
|
|
95
|
-
};
|
|
96
|
-
var _tmpl$ = /* @__PURE__ */ template(`<div>`);
|
|
97
|
-
var _tmpl$2 = /* @__PURE__ */ template(`<span style="display:inline-block;width:8px;height:8px;border:1.5px solid rgb(210, 57, 192);border-top-color:transparent;border-radius:50%;margin-right:4px;vertical-align:middle">`);
|
|
98
|
-
var _tmpl$3 = /* @__PURE__ */ template(`<span style=display:inline-block;margin-right:4px;font-weight:600>\u2713`);
|
|
99
|
-
var _tmpl$4 = /* @__PURE__ */ template(`<span style="font-family:ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, 'Liberation Mono', 'Courier New', monospace;font-variant-numeric:tabular-nums">`);
|
|
100
|
-
var _tmpl$5 = /* @__PURE__ */ template(`<div style="position:fixed;padding:2px 6px;background-color:#fde7f7;color:#b21c8e;border:1px solid #f7c5ec;border-radius:4px;font-size:11px;font-weight:500;font-family:-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;pointer-events:none;transition:opacity 0.2s ease-in-out;display:flex;align-items:center;max-width:calc(100vw - (16px + env(safe-area-inset-left) + env(safe-area-inset-right)));overflow:hidden;text-overflow:ellipsis;white-space:nowrap"><span>`);
|
|
101
|
-
var _tmpl$6 = /* @__PURE__ */ template(`<div style="position:fixed;z-index:2147483647;pointer-events:none;transition:opacity 0.1s ease-in-out"><div style="width:32px;height:2px;background-color:rgba(178, 28, 142, 0.2);border-radius:1px;overflow:hidden;position:relative"><div style="height:100%;background-color:#b21c8e;border-radius:1px;transition:width 0.05s cubic-bezier(0.165, 0.84, 0.44, 1)">`);
|
|
92
|
+
// src/constants.ts
|
|
102
93
|
var VIEWPORT_MARGIN_PX = 8;
|
|
103
|
-
var LABEL_OFFSET_PX = 6;
|
|
104
94
|
var INDICATOR_CLAMP_PADDING_PX = 4;
|
|
105
|
-
var
|
|
95
|
+
var CURSOR_OFFSET_PX = 14;
|
|
106
96
|
var SELECTION_LERP_FACTOR = 0.95;
|
|
107
|
-
|
|
97
|
+
|
|
98
|
+
// src/utils/lerp.ts
|
|
108
99
|
var lerp = (start, end, factor) => {
|
|
109
100
|
return start + (end - start) * factor;
|
|
110
101
|
};
|
|
111
|
-
|
|
102
|
+
|
|
103
|
+
// src/components/selection-box.tsx
|
|
104
|
+
var _tmpl$ = /* @__PURE__ */ template(`<div>`);
|
|
105
|
+
var SelectionBox = (props) => {
|
|
112
106
|
const [currentX, setCurrentX] = createSignal(props.bounds.x);
|
|
113
107
|
const [currentY, setCurrentY] = createSignal(props.bounds.y);
|
|
114
108
|
const [currentWidth, setCurrentWidth] = createSignal(props.bounds.width);
|
|
115
109
|
const [currentHeight, setCurrentHeight] = createSignal(props.bounds.height);
|
|
116
110
|
const [opacity, setOpacity] = createSignal(1);
|
|
117
|
-
let
|
|
111
|
+
let hasBeenRenderedOnce = false;
|
|
118
112
|
let animationFrameId = null;
|
|
113
|
+
let fadeTimerId = null;
|
|
119
114
|
let targetBounds = props.bounds;
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
if (
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
return;
|
|
130
|
-
}
|
|
131
|
-
const EPSILON = 0.5;
|
|
115
|
+
let isAnimating = false;
|
|
116
|
+
const lerpFactor = () => {
|
|
117
|
+
if (props.lerpFactor !== void 0) return props.lerpFactor;
|
|
118
|
+
if (props.variant === "drag") return 0.7;
|
|
119
|
+
return SELECTION_LERP_FACTOR;
|
|
120
|
+
};
|
|
121
|
+
const startAnimation = () => {
|
|
122
|
+
if (isAnimating) return;
|
|
123
|
+
isAnimating = true;
|
|
132
124
|
const animate = () => {
|
|
133
|
-
const
|
|
134
|
-
const
|
|
135
|
-
const
|
|
136
|
-
const
|
|
137
|
-
setCurrentX(
|
|
138
|
-
setCurrentY(
|
|
139
|
-
setCurrentWidth(
|
|
140
|
-
setCurrentHeight(
|
|
141
|
-
const
|
|
142
|
-
if (!
|
|
125
|
+
const interpolatedX = lerp(currentX(), targetBounds.x, lerpFactor());
|
|
126
|
+
const interpolatedY = lerp(currentY(), targetBounds.y, lerpFactor());
|
|
127
|
+
const interpolatedWidth = lerp(currentWidth(), targetBounds.width, lerpFactor());
|
|
128
|
+
const interpolatedHeight = lerp(currentHeight(), targetBounds.height, lerpFactor());
|
|
129
|
+
setCurrentX(interpolatedX);
|
|
130
|
+
setCurrentY(interpolatedY);
|
|
131
|
+
setCurrentWidth(interpolatedWidth);
|
|
132
|
+
setCurrentHeight(interpolatedHeight);
|
|
133
|
+
const hasConvergedToTarget = Math.abs(interpolatedX - targetBounds.x) < 0.5 && Math.abs(interpolatedY - targetBounds.y) < 0.5 && Math.abs(interpolatedWidth - targetBounds.width) < 0.5 && Math.abs(interpolatedHeight - targetBounds.height) < 0.5;
|
|
134
|
+
if (!hasConvergedToTarget) {
|
|
143
135
|
animationFrameId = requestAnimationFrame(animate);
|
|
144
136
|
} else {
|
|
145
137
|
animationFrameId = null;
|
|
138
|
+
isAnimating = false;
|
|
146
139
|
}
|
|
147
140
|
};
|
|
148
|
-
if (animationFrameId !== null) {
|
|
149
|
-
cancelAnimationFrame(animationFrameId);
|
|
150
|
-
}
|
|
151
141
|
animationFrameId = requestAnimationFrame(animate);
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
142
|
+
};
|
|
143
|
+
createEffect(on(() => props.bounds, (newBounds) => {
|
|
144
|
+
targetBounds = newBounds;
|
|
145
|
+
if (!hasBeenRenderedOnce) {
|
|
146
|
+
setCurrentX(targetBounds.x);
|
|
147
|
+
setCurrentY(targetBounds.y);
|
|
148
|
+
setCurrentWidth(targetBounds.width);
|
|
149
|
+
setCurrentHeight(targetBounds.height);
|
|
150
|
+
hasBeenRenderedOnce = true;
|
|
151
|
+
return;
|
|
152
|
+
}
|
|
153
|
+
startAnimation();
|
|
154
|
+
}));
|
|
159
155
|
createEffect(() => {
|
|
160
|
-
if (props.variant === "grabbed") {
|
|
161
|
-
|
|
156
|
+
if (props.variant === "grabbed" && props.createdAt) {
|
|
157
|
+
fadeTimerId = window.setTimeout(() => {
|
|
162
158
|
setOpacity(0);
|
|
163
|
-
});
|
|
159
|
+
}, 1500);
|
|
160
|
+
}
|
|
161
|
+
});
|
|
162
|
+
onCleanup(() => {
|
|
163
|
+
if (animationFrameId !== null) {
|
|
164
|
+
cancelAnimationFrame(animationFrameId);
|
|
165
|
+
animationFrameId = null;
|
|
166
|
+
}
|
|
167
|
+
if (fadeTimerId !== null) {
|
|
168
|
+
window.clearTimeout(fadeTimerId);
|
|
169
|
+
fadeTimerId = null;
|
|
164
170
|
}
|
|
171
|
+
isAnimating = false;
|
|
165
172
|
});
|
|
166
173
|
const baseStyle = {
|
|
167
174
|
position: "fixed",
|
|
168
175
|
"box-sizing": "border-box",
|
|
169
|
-
"pointer-events": props.variant === "
|
|
176
|
+
"pointer-events": props.variant === "drag" ? "none" : "auto",
|
|
170
177
|
"z-index": "2147483646"
|
|
171
178
|
};
|
|
172
179
|
const variantStyle = () => {
|
|
173
|
-
if (props.variant === "
|
|
180
|
+
if (props.variant === "drag") {
|
|
174
181
|
return {
|
|
175
|
-
border: "1px dashed
|
|
176
|
-
"background-color": "rgba(210, 57, 192, 0.
|
|
182
|
+
border: "1px dashed rgba(210, 57, 192, 0.4)",
|
|
183
|
+
"background-color": "rgba(210, 57, 192, 0.05)",
|
|
177
184
|
"will-change": "transform, width, height",
|
|
178
|
-
contain: "layout paint size"
|
|
185
|
+
contain: "layout paint size",
|
|
186
|
+
cursor: "crosshair"
|
|
179
187
|
};
|
|
180
188
|
}
|
|
181
189
|
return {
|
|
@@ -205,11 +213,12 @@ var Overlay = (props) => {
|
|
|
205
213
|
}
|
|
206
214
|
});
|
|
207
215
|
};
|
|
216
|
+
var _tmpl$2 = /* @__PURE__ */ template(`<span style="display:inline-block;width:8px;height:8px;border:1.5px solid rgb(210, 57, 192);border-top-color:transparent;border-radius:50%;margin-right:4px;vertical-align:middle">`);
|
|
208
217
|
var Spinner = (props) => {
|
|
209
|
-
let
|
|
210
|
-
|
|
211
|
-
if (
|
|
212
|
-
|
|
218
|
+
let spinnerRef;
|
|
219
|
+
onMount(() => {
|
|
220
|
+
if (spinnerRef) {
|
|
221
|
+
spinnerRef.animate([{
|
|
213
222
|
transform: "rotate(0deg)"
|
|
214
223
|
}, {
|
|
215
224
|
transform: "rotate(360deg)"
|
|
@@ -221,126 +230,213 @@ var Spinner = (props) => {
|
|
|
221
230
|
}
|
|
222
231
|
});
|
|
223
232
|
return (() => {
|
|
224
|
-
var _el$
|
|
225
|
-
var _ref$ =
|
|
226
|
-
typeof _ref$ === "function" ? use(_ref$, _el$
|
|
227
|
-
effect((_$p) => style(_el
|
|
233
|
+
var _el$ = _tmpl$2();
|
|
234
|
+
var _ref$ = spinnerRef;
|
|
235
|
+
typeof _ref$ === "function" ? use(_ref$, _el$) : spinnerRef = _el$;
|
|
236
|
+
effect((_$p) => style(_el$, {
|
|
228
237
|
...props.style
|
|
229
238
|
}, _$p));
|
|
230
|
-
return _el
|
|
239
|
+
return _el$;
|
|
231
240
|
})();
|
|
232
241
|
};
|
|
242
|
+
|
|
243
|
+
// src/utils/get-clamped-element-position.ts
|
|
244
|
+
var getClampedElementPosition = (positionLeft, positionTop, elementWidth, elementHeight) => {
|
|
245
|
+
const viewportWidth = window.innerWidth;
|
|
246
|
+
const viewportHeight = window.innerHeight;
|
|
247
|
+
const minLeft = VIEWPORT_MARGIN_PX;
|
|
248
|
+
const minTop = VIEWPORT_MARGIN_PX;
|
|
249
|
+
const maxLeft = viewportWidth - elementWidth - VIEWPORT_MARGIN_PX;
|
|
250
|
+
const maxTop = viewportHeight - elementHeight - VIEWPORT_MARGIN_PX;
|
|
251
|
+
const clampedLeft = Math.max(minLeft, Math.min(positionLeft, maxLeft));
|
|
252
|
+
const clampedTop = Math.max(minTop, Math.min(positionTop, maxTop));
|
|
253
|
+
return { left: clampedLeft, top: clampedTop };
|
|
254
|
+
};
|
|
255
|
+
|
|
256
|
+
// src/components/label.tsx
|
|
257
|
+
var _tmpl$3 = /* @__PURE__ */ template(`<span style=display:inline-block;margin-right:4px;font-weight:600>\u2713`);
|
|
258
|
+
var _tmpl$22 = /* @__PURE__ */ template(`<div style=margin-right:4px>Copied`);
|
|
259
|
+
var _tmpl$32 = /* @__PURE__ */ template(`<div style=margin-left:4px>to clipboard`);
|
|
260
|
+
var _tmpl$4 = /* @__PURE__ */ template(`<div style="position:fixed;padding:2px 6px;background-color:#fde7f7;color:#b21c8e;border:1px solid #f7c5ec;border-radius:4px;font-size:11px;font-weight:500;font-family:-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;pointer-events:none;transition:opacity 0.2s ease-in-out;display:flex;align-items:center;max-width:calc(100vw - (16px + env(safe-area-inset-left) + env(safe-area-inset-right)));overflow:hidden;text-overflow:ellipsis;white-space:nowrap">`);
|
|
261
|
+
var _tmpl$5 = /* @__PURE__ */ template(`<span style="font-family:ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, 'Liberation Mono', 'Courier New', monospace;font-variant-numeric:tabular-nums">`);
|
|
233
262
|
var Label = (props) => {
|
|
234
263
|
const [opacity, setOpacity] = createSignal(0);
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
264
|
+
const [positionTick, setPositionTick] = createSignal(0);
|
|
265
|
+
let labelRef;
|
|
266
|
+
let currentX = props.x;
|
|
267
|
+
let currentY = props.y;
|
|
268
|
+
let targetX = props.x;
|
|
269
|
+
let targetY = props.y;
|
|
270
|
+
let animationFrameId = null;
|
|
271
|
+
let hasBeenRenderedOnce = false;
|
|
272
|
+
const animate = () => {
|
|
273
|
+
currentX = lerp(currentX, targetX, 0.3);
|
|
274
|
+
currentY = lerp(currentY, targetY, 0.3);
|
|
275
|
+
setPositionTick((tick) => tick + 1);
|
|
276
|
+
const hasConvergedToTarget = Math.abs(currentX - targetX) < 0.5 && Math.abs(currentY - targetY) < 0.5;
|
|
277
|
+
if (!hasConvergedToTarget) {
|
|
278
|
+
animationFrameId = requestAnimationFrame(animate);
|
|
279
|
+
} else {
|
|
280
|
+
animationFrameId = null;
|
|
281
|
+
}
|
|
282
|
+
};
|
|
283
|
+
const startAnimation = () => {
|
|
284
|
+
if (animationFrameId !== null) return;
|
|
285
|
+
animationFrameId = requestAnimationFrame(animate);
|
|
286
|
+
};
|
|
287
|
+
const updateTarget = () => {
|
|
288
|
+
targetX = props.x;
|
|
289
|
+
targetY = props.y;
|
|
290
|
+
if (!hasBeenRenderedOnce) {
|
|
291
|
+
currentX = targetX;
|
|
292
|
+
currentY = targetY;
|
|
293
|
+
hasBeenRenderedOnce = true;
|
|
294
|
+
setPositionTick((tick) => tick + 1);
|
|
295
|
+
return;
|
|
296
|
+
}
|
|
297
|
+
startAnimation();
|
|
298
|
+
};
|
|
299
|
+
createEffect(on(() => props.visible, (visible) => {
|
|
300
|
+
if (visible !== false) {
|
|
238
301
|
requestAnimationFrame(() => {
|
|
239
302
|
setOpacity(1);
|
|
240
303
|
});
|
|
241
304
|
} else {
|
|
242
305
|
setOpacity(0);
|
|
306
|
+
return;
|
|
243
307
|
}
|
|
244
|
-
});
|
|
245
|
-
createEffect(() => {
|
|
246
308
|
if (props.variant === "success") {
|
|
247
309
|
const fadeOutTimer = setTimeout(() => {
|
|
248
310
|
setOpacity(0);
|
|
249
|
-
},
|
|
311
|
+
}, 1500);
|
|
250
312
|
onCleanup(() => clearTimeout(fadeOutTimer));
|
|
251
313
|
}
|
|
314
|
+
}));
|
|
315
|
+
createEffect(() => {
|
|
316
|
+
updateTarget();
|
|
317
|
+
});
|
|
318
|
+
onCleanup(() => {
|
|
319
|
+
if (animationFrameId !== null) {
|
|
320
|
+
cancelAnimationFrame(animationFrameId);
|
|
321
|
+
animationFrameId = null;
|
|
322
|
+
}
|
|
252
323
|
});
|
|
253
|
-
const
|
|
324
|
+
const labelBoundingRect = () => labelRef?.getBoundingClientRect();
|
|
254
325
|
const computedPosition = () => {
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
326
|
+
positionTick();
|
|
327
|
+
const boundingRect = labelBoundingRect();
|
|
328
|
+
if (!boundingRect) return {
|
|
329
|
+
left: currentX,
|
|
330
|
+
top: currentY
|
|
259
331
|
};
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
indicatorTopPx = Math.max(minTop, Math.min(indicatorTopPx, maxTop));
|
|
273
|
-
if (isClamped) {
|
|
274
|
-
indicatorLeftPx += INDICATOR_CLAMP_PADDING_PX;
|
|
275
|
-
indicatorTopPx += INDICATOR_CLAMP_PADDING_PX;
|
|
332
|
+
if (props.variant === "success") {
|
|
333
|
+
const indicatorLeft = Math.round(currentX);
|
|
334
|
+
const indicatorTop = Math.round(currentY) - boundingRect.height - 6;
|
|
335
|
+
const willClampLeft = indicatorLeft < VIEWPORT_MARGIN_PX;
|
|
336
|
+
const willClampTop = indicatorTop < VIEWPORT_MARGIN_PX;
|
|
337
|
+
const isClamped = willClampLeft || willClampTop;
|
|
338
|
+
const clamped = getClampedElementPosition(indicatorLeft, indicatorTop, boundingRect.width, boundingRect.height);
|
|
339
|
+
if (isClamped) {
|
|
340
|
+
clamped.left += INDICATOR_CLAMP_PADDING_PX;
|
|
341
|
+
clamped.top += INDICATOR_CLAMP_PADDING_PX;
|
|
342
|
+
}
|
|
343
|
+
return clamped;
|
|
276
344
|
}
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
345
|
+
const CROSSHAIR_OFFSET = 12;
|
|
346
|
+
const viewportWidth = window.innerWidth;
|
|
347
|
+
const viewportHeight = window.innerHeight;
|
|
348
|
+
const quadrants = [{
|
|
349
|
+
left: Math.round(currentX) + CROSSHAIR_OFFSET,
|
|
350
|
+
top: Math.round(currentY) + CROSSHAIR_OFFSET
|
|
351
|
+
}, {
|
|
352
|
+
left: Math.round(currentX) - boundingRect.width - CROSSHAIR_OFFSET,
|
|
353
|
+
top: Math.round(currentY) + CROSSHAIR_OFFSET
|
|
354
|
+
}, {
|
|
355
|
+
left: Math.round(currentX) + CROSSHAIR_OFFSET,
|
|
356
|
+
top: Math.round(currentY) - boundingRect.height - CROSSHAIR_OFFSET
|
|
357
|
+
}, {
|
|
358
|
+
left: Math.round(currentX) - boundingRect.width - CROSSHAIR_OFFSET,
|
|
359
|
+
top: Math.round(currentY) - boundingRect.height - CROSSHAIR_OFFSET
|
|
360
|
+
}];
|
|
361
|
+
for (const position of quadrants) {
|
|
362
|
+
const fitsHorizontally = position.left >= VIEWPORT_MARGIN_PX && position.left + boundingRect.width <= viewportWidth - VIEWPORT_MARGIN_PX;
|
|
363
|
+
const fitsVertically = position.top >= VIEWPORT_MARGIN_PX && position.top + boundingRect.height <= viewportHeight - VIEWPORT_MARGIN_PX;
|
|
364
|
+
if (fitsHorizontally && fitsVertically) {
|
|
365
|
+
return position;
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
const fallback = getClampedElementPosition(quadrants[0].left, quadrants[0].top, boundingRect.width, boundingRect.height);
|
|
369
|
+
fallback.left += INDICATOR_CLAMP_PADDING_PX;
|
|
370
|
+
fallback.top += INDICATOR_CLAMP_PADDING_PX;
|
|
371
|
+
return fallback;
|
|
281
372
|
};
|
|
282
373
|
return createComponent(Show, {
|
|
283
374
|
get when() {
|
|
284
375
|
return props.visible !== false;
|
|
285
376
|
},
|
|
286
377
|
get children() {
|
|
287
|
-
var _el$
|
|
288
|
-
var _ref$
|
|
289
|
-
typeof _ref$
|
|
290
|
-
insert(_el
|
|
378
|
+
var _el$ = _tmpl$4();
|
|
379
|
+
var _ref$ = labelRef;
|
|
380
|
+
typeof _ref$ === "function" ? use(_ref$, _el$) : labelRef = _el$;
|
|
381
|
+
insert(_el$, createComponent(Show, {
|
|
291
382
|
get when() {
|
|
292
383
|
return props.variant === "processing";
|
|
293
384
|
},
|
|
294
385
|
get children() {
|
|
295
386
|
return createComponent(Spinner, {});
|
|
296
387
|
}
|
|
297
|
-
}),
|
|
298
|
-
insert(_el
|
|
388
|
+
}), null);
|
|
389
|
+
insert(_el$, createComponent(Show, {
|
|
299
390
|
get when() {
|
|
300
391
|
return props.variant === "success";
|
|
301
392
|
},
|
|
302
393
|
get children() {
|
|
303
394
|
return _tmpl$3();
|
|
304
395
|
}
|
|
305
|
-
}),
|
|
306
|
-
insert(_el
|
|
396
|
+
}), null);
|
|
397
|
+
insert(_el$, createComponent(Show, {
|
|
307
398
|
get when() {
|
|
308
399
|
return props.variant === "success";
|
|
309
400
|
},
|
|
310
|
-
children
|
|
401
|
+
get children() {
|
|
402
|
+
return _tmpl$22();
|
|
403
|
+
}
|
|
311
404
|
}), null);
|
|
312
|
-
insert(_el
|
|
405
|
+
insert(_el$, createComponent(Show, {
|
|
313
406
|
get when() {
|
|
314
407
|
return props.variant === "processing";
|
|
315
408
|
},
|
|
316
409
|
children: "Grabbing\u2026"
|
|
317
410
|
}), null);
|
|
318
|
-
insert(_el
|
|
411
|
+
insert(_el$, createComponent(Show, {
|
|
319
412
|
get when() {
|
|
320
|
-
return props.
|
|
413
|
+
return props.text.startsWith("(");
|
|
414
|
+
},
|
|
415
|
+
get fallback() {
|
|
416
|
+
return (() => {
|
|
417
|
+
var _el$5 = _tmpl$5();
|
|
418
|
+
insert(_el$5, () => props.text);
|
|
419
|
+
return _el$5;
|
|
420
|
+
})();
|
|
321
421
|
},
|
|
322
422
|
get children() {
|
|
323
|
-
|
|
324
|
-
insert(_el$6, () => props.text);
|
|
325
|
-
return _el$6;
|
|
423
|
+
return props.text;
|
|
326
424
|
}
|
|
327
425
|
}), null);
|
|
328
|
-
insert(_el
|
|
426
|
+
insert(_el$, createComponent(Show, {
|
|
329
427
|
get when() {
|
|
330
|
-
return props.variant
|
|
428
|
+
return props.variant === "success";
|
|
331
429
|
},
|
|
332
430
|
get children() {
|
|
333
|
-
|
|
334
|
-
insert(_el$7, () => props.text);
|
|
335
|
-
return _el$7;
|
|
431
|
+
return _tmpl$32();
|
|
336
432
|
}
|
|
337
433
|
}), null);
|
|
338
434
|
effect((_p$) => {
|
|
339
435
|
var _v$ = `${computedPosition().top}px`, _v$2 = `${computedPosition().left}px`, _v$3 = props.zIndex?.toString() ?? "2147483647", _v$4 = opacity();
|
|
340
|
-
_v$ !== _p$.e && setStyleProperty(_el
|
|
341
|
-
_v$2 !== _p$.t && setStyleProperty(_el
|
|
342
|
-
_v$3 !== _p$.a && setStyleProperty(_el
|
|
343
|
-
_v$4 !== _p$.o && setStyleProperty(_el
|
|
436
|
+
_v$ !== _p$.e && setStyleProperty(_el$, "top", _p$.e = _v$);
|
|
437
|
+
_v$2 !== _p$.t && setStyleProperty(_el$, "left", _p$.t = _v$2);
|
|
438
|
+
_v$3 !== _p$.a && setStyleProperty(_el$, "z-index", _p$.a = _v$3);
|
|
439
|
+
_v$4 !== _p$.o && setStyleProperty(_el$, "opacity", _p$.o = _v$4);
|
|
344
440
|
return _p$;
|
|
345
441
|
}, {
|
|
346
442
|
e: void 0,
|
|
@@ -348,58 +444,52 @@ var Label = (props) => {
|
|
|
348
444
|
a: void 0,
|
|
349
445
|
o: void 0
|
|
350
446
|
});
|
|
351
|
-
return _el
|
|
447
|
+
return _el$;
|
|
352
448
|
}
|
|
353
449
|
});
|
|
354
450
|
};
|
|
355
|
-
var
|
|
451
|
+
var _tmpl$6 = /* @__PURE__ */ template(`<div style="position:fixed;z-index:2147483647;pointer-events:none;transition:opacity 0.1s ease-in-out"><div style="width:32px;height:2px;background-color:rgba(178, 28, 142, 0.2);border-radius:1px;overflow:hidden;position:relative"><div style="height:100%;background-color:#b21c8e;border-radius:1px;transition:width 0.05s cubic-bezier(0.165, 0.84, 0.44, 1)">`);
|
|
452
|
+
var useFadeInOut = (visible) => {
|
|
356
453
|
const [opacity, setOpacity] = createSignal(0);
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
if (props.visible !== false) {
|
|
454
|
+
createEffect(on(() => visible, (isVisible) => {
|
|
455
|
+
if (isVisible !== false) {
|
|
360
456
|
requestAnimationFrame(() => {
|
|
361
457
|
setOpacity(1);
|
|
362
458
|
});
|
|
363
459
|
} else {
|
|
364
460
|
setOpacity(0);
|
|
365
461
|
}
|
|
366
|
-
});
|
|
462
|
+
}));
|
|
463
|
+
return opacity;
|
|
464
|
+
};
|
|
465
|
+
var ProgressIndicator = (props) => {
|
|
466
|
+
const opacity = useFadeInOut(props.visible);
|
|
467
|
+
let progressIndicatorRef;
|
|
367
468
|
const computedPosition = () => {
|
|
368
|
-
const
|
|
369
|
-
if (!
|
|
469
|
+
const boundingRect = progressIndicatorRef?.getBoundingClientRect();
|
|
470
|
+
if (!boundingRect) return {
|
|
370
471
|
left: props.mouseX,
|
|
371
472
|
top: props.mouseY
|
|
372
473
|
};
|
|
373
|
-
const viewportWidth = window.innerWidth;
|
|
374
474
|
const viewportHeight = window.innerHeight;
|
|
375
|
-
const
|
|
376
|
-
const
|
|
377
|
-
|
|
378
|
-
let indicatorTop = props.mouseY + CURSOR_OFFSET;
|
|
379
|
-
if (indicatorTop + rect.height + VIEWPORT_MARGIN > viewportHeight) {
|
|
380
|
-
indicatorTop = props.mouseY - rect.height - CURSOR_OFFSET;
|
|
381
|
-
}
|
|
382
|
-
indicatorTop = Math.max(VIEWPORT_MARGIN, Math.min(indicatorTop, viewportHeight - rect.height - VIEWPORT_MARGIN));
|
|
383
|
-
indicatorLeft = Math.max(VIEWPORT_MARGIN, Math.min(indicatorLeft, viewportWidth - rect.width - VIEWPORT_MARGIN));
|
|
384
|
-
return {
|
|
385
|
-
left: indicatorLeft,
|
|
386
|
-
top: indicatorTop
|
|
387
|
-
};
|
|
475
|
+
const indicatorLeft = props.mouseX - boundingRect.width / 2;
|
|
476
|
+
const indicatorTop = props.mouseY + CURSOR_OFFSET_PX + boundingRect.height + VIEWPORT_MARGIN_PX > viewportHeight ? props.mouseY - boundingRect.height - CURSOR_OFFSET_PX : props.mouseY + CURSOR_OFFSET_PX;
|
|
477
|
+
return getClampedElementPosition(indicatorLeft, indicatorTop, boundingRect.width, boundingRect.height);
|
|
388
478
|
};
|
|
389
479
|
return createComponent(Show, {
|
|
390
480
|
get when() {
|
|
391
481
|
return props.visible !== false;
|
|
392
482
|
},
|
|
393
483
|
get children() {
|
|
394
|
-
var _el$
|
|
395
|
-
var _ref$
|
|
396
|
-
typeof _ref$
|
|
484
|
+
var _el$ = _tmpl$6(), _el$2 = _el$.firstChild, _el$3 = _el$2.firstChild;
|
|
485
|
+
var _ref$ = progressIndicatorRef;
|
|
486
|
+
typeof _ref$ === "function" ? use(_ref$, _el$) : progressIndicatorRef = _el$;
|
|
397
487
|
effect((_p$) => {
|
|
398
|
-
var _v$
|
|
399
|
-
_v$
|
|
400
|
-
_v$
|
|
401
|
-
_v$
|
|
402
|
-
_v$
|
|
488
|
+
var _v$ = `${computedPosition().top}px`, _v$2 = `${computedPosition().left}px`, _v$3 = opacity(), _v$4 = `${Math.min(100, Math.max(0, props.progress * 100))}%`;
|
|
489
|
+
_v$ !== _p$.e && setStyleProperty(_el$, "top", _p$.e = _v$);
|
|
490
|
+
_v$2 !== _p$.t && setStyleProperty(_el$, "left", _p$.t = _v$2);
|
|
491
|
+
_v$3 !== _p$.a && setStyleProperty(_el$, "opacity", _p$.a = _v$3);
|
|
492
|
+
_v$4 !== _p$.o && setStyleProperty(_el$3, "width", _p$.o = _v$4);
|
|
403
493
|
return _p$;
|
|
404
494
|
}, {
|
|
405
495
|
e: void 0,
|
|
@@ -407,53 +497,167 @@ var ProgressIndicator = (props) => {
|
|
|
407
497
|
a: void 0,
|
|
408
498
|
o: void 0
|
|
409
499
|
});
|
|
410
|
-
return _el
|
|
500
|
+
return _el$;
|
|
501
|
+
}
|
|
502
|
+
});
|
|
503
|
+
};
|
|
504
|
+
var _tmpl$7 = /* @__PURE__ */ template(`<canvas style=position:fixed;top:0;left:0;pointer-events:none;z-index:2147483645>`);
|
|
505
|
+
var Crosshair = (props) => {
|
|
506
|
+
let canvasRef;
|
|
507
|
+
let context = null;
|
|
508
|
+
let width = 0;
|
|
509
|
+
let height = 0;
|
|
510
|
+
let dpr = 1;
|
|
511
|
+
let currentX = props.mouseX;
|
|
512
|
+
let currentY = props.mouseY;
|
|
513
|
+
let targetX = props.mouseX;
|
|
514
|
+
let targetY = props.mouseY;
|
|
515
|
+
let animationFrameId = null;
|
|
516
|
+
let hasBeenRenderedOnce = false;
|
|
517
|
+
const setupCanvas = () => {
|
|
518
|
+
if (!canvasRef) return;
|
|
519
|
+
dpr = Math.max(window.devicePixelRatio || 1, 2);
|
|
520
|
+
width = window.innerWidth;
|
|
521
|
+
height = window.innerHeight;
|
|
522
|
+
canvasRef.width = width * dpr;
|
|
523
|
+
canvasRef.height = height * dpr;
|
|
524
|
+
canvasRef.style.width = `${width}px`;
|
|
525
|
+
canvasRef.style.height = `${height}px`;
|
|
526
|
+
context = canvasRef.getContext("2d");
|
|
527
|
+
if (context) {
|
|
528
|
+
context.scale(dpr, dpr);
|
|
529
|
+
}
|
|
530
|
+
};
|
|
531
|
+
const render2 = () => {
|
|
532
|
+
if (!context) return;
|
|
533
|
+
context.clearRect(0, 0, width, height);
|
|
534
|
+
context.strokeStyle = "rgba(210, 57, 192)";
|
|
535
|
+
context.lineWidth = 1;
|
|
536
|
+
context.beginPath();
|
|
537
|
+
context.moveTo(currentX, 0);
|
|
538
|
+
context.lineTo(currentX, height);
|
|
539
|
+
context.moveTo(0, currentY);
|
|
540
|
+
context.lineTo(width, currentY);
|
|
541
|
+
context.stroke();
|
|
542
|
+
};
|
|
543
|
+
const animate = () => {
|
|
544
|
+
currentX = lerp(currentX, targetX, 0.3);
|
|
545
|
+
currentY = lerp(currentY, targetY, 0.3);
|
|
546
|
+
render2();
|
|
547
|
+
const hasConvergedToTarget = Math.abs(currentX - targetX) < 0.5 && Math.abs(currentY - targetY) < 0.5;
|
|
548
|
+
if (!hasConvergedToTarget) {
|
|
549
|
+
animationFrameId = requestAnimationFrame(animate);
|
|
550
|
+
} else {
|
|
551
|
+
animationFrameId = null;
|
|
552
|
+
}
|
|
553
|
+
};
|
|
554
|
+
const startAnimation = () => {
|
|
555
|
+
if (animationFrameId !== null) return;
|
|
556
|
+
animationFrameId = requestAnimationFrame(animate);
|
|
557
|
+
};
|
|
558
|
+
const updateTarget = () => {
|
|
559
|
+
targetX = props.mouseX;
|
|
560
|
+
targetY = props.mouseY;
|
|
561
|
+
if (!hasBeenRenderedOnce) {
|
|
562
|
+
currentX = targetX;
|
|
563
|
+
currentY = targetY;
|
|
564
|
+
hasBeenRenderedOnce = true;
|
|
565
|
+
render2();
|
|
566
|
+
return;
|
|
567
|
+
}
|
|
568
|
+
startAnimation();
|
|
569
|
+
};
|
|
570
|
+
createEffect(() => {
|
|
571
|
+
setupCanvas();
|
|
572
|
+
render2();
|
|
573
|
+
const handleResize = () => {
|
|
574
|
+
setupCanvas();
|
|
575
|
+
render2();
|
|
576
|
+
};
|
|
577
|
+
window.addEventListener("resize", handleResize);
|
|
578
|
+
onCleanup(() => {
|
|
579
|
+
window.removeEventListener("resize", handleResize);
|
|
580
|
+
if (animationFrameId !== null) {
|
|
581
|
+
cancelAnimationFrame(animationFrameId);
|
|
582
|
+
animationFrameId = null;
|
|
583
|
+
}
|
|
584
|
+
});
|
|
585
|
+
});
|
|
586
|
+
createEffect(() => {
|
|
587
|
+
updateTarget();
|
|
588
|
+
});
|
|
589
|
+
return createComponent(Show, {
|
|
590
|
+
get when() {
|
|
591
|
+
return props.visible !== false;
|
|
592
|
+
},
|
|
593
|
+
get children() {
|
|
594
|
+
var _el$ = _tmpl$7();
|
|
595
|
+
var _ref$ = canvasRef;
|
|
596
|
+
typeof _ref$ === "function" ? use(_ref$, _el$) : canvasRef = _el$;
|
|
597
|
+
return _el$;
|
|
411
598
|
}
|
|
412
599
|
});
|
|
413
600
|
};
|
|
414
|
-
|
|
601
|
+
|
|
602
|
+
// src/components/renderer.tsx
|
|
603
|
+
var ReactGrabRenderer = (props) => {
|
|
415
604
|
return [createComponent(Show, {
|
|
416
605
|
get when() {
|
|
417
606
|
return memo(() => !!props.selectionVisible)() && props.selectionBounds;
|
|
418
607
|
},
|
|
419
608
|
get children() {
|
|
420
|
-
return createComponent(
|
|
609
|
+
return createComponent(SelectionBox, {
|
|
421
610
|
variant: "selection",
|
|
422
611
|
get bounds() {
|
|
423
612
|
return props.selectionBounds;
|
|
424
613
|
},
|
|
425
614
|
get visible() {
|
|
426
615
|
return props.selectionVisible;
|
|
616
|
+
}
|
|
617
|
+
});
|
|
618
|
+
}
|
|
619
|
+
}), createComponent(Show, {
|
|
620
|
+
get when() {
|
|
621
|
+
return memo(() => !!(props.crosshairVisible === true && props.mouseX !== void 0))() && props.mouseY !== void 0;
|
|
622
|
+
},
|
|
623
|
+
get children() {
|
|
624
|
+
return createComponent(Crosshair, {
|
|
625
|
+
get mouseX() {
|
|
626
|
+
return props.mouseX;
|
|
627
|
+
},
|
|
628
|
+
get mouseY() {
|
|
629
|
+
return props.mouseY;
|
|
427
630
|
},
|
|
428
|
-
|
|
631
|
+
visible: true
|
|
429
632
|
});
|
|
430
633
|
}
|
|
431
634
|
}), createComponent(Show, {
|
|
432
635
|
get when() {
|
|
433
|
-
return memo(() => !!props.
|
|
636
|
+
return memo(() => !!props.dragVisible)() && props.dragBounds;
|
|
434
637
|
},
|
|
435
638
|
get children() {
|
|
436
|
-
return createComponent(
|
|
437
|
-
variant: "
|
|
639
|
+
return createComponent(SelectionBox, {
|
|
640
|
+
variant: "drag",
|
|
438
641
|
get bounds() {
|
|
439
|
-
return props.
|
|
642
|
+
return props.dragBounds;
|
|
440
643
|
},
|
|
441
644
|
get visible() {
|
|
442
|
-
return props.
|
|
443
|
-
}
|
|
444
|
-
lerpFactor: MARQUEE_LERP_FACTOR
|
|
645
|
+
return props.dragVisible;
|
|
646
|
+
}
|
|
445
647
|
});
|
|
446
648
|
}
|
|
447
649
|
}), createComponent(For, {
|
|
448
650
|
get each() {
|
|
449
|
-
return props.
|
|
651
|
+
return props.grabbedBoxes ?? [];
|
|
450
652
|
},
|
|
451
|
-
children: (
|
|
653
|
+
children: (box) => createComponent(SelectionBox, {
|
|
452
654
|
variant: "grabbed",
|
|
453
655
|
get bounds() {
|
|
454
|
-
return
|
|
656
|
+
return box.bounds;
|
|
455
657
|
},
|
|
456
|
-
|
|
658
|
+
get createdAt() {
|
|
659
|
+
return box.createdAt;
|
|
660
|
+
}
|
|
457
661
|
})
|
|
458
662
|
}), createComponent(For, {
|
|
459
663
|
get each() {
|
|
@@ -469,9 +673,7 @@ var ReactGrabOverlay = (props) => {
|
|
|
469
673
|
},
|
|
470
674
|
get y() {
|
|
471
675
|
return label.y;
|
|
472
|
-
}
|
|
473
|
-
visible: true,
|
|
474
|
-
zIndex: 2147483648
|
|
676
|
+
}
|
|
475
677
|
})
|
|
476
678
|
}), createComponent(Show, {
|
|
477
679
|
get when() {
|
|
@@ -526,15 +728,6 @@ instrument({
|
|
|
526
728
|
_fiberRoots.add(fiberRoot);
|
|
527
729
|
}
|
|
528
730
|
});
|
|
529
|
-
var isValidSource = (source) => {
|
|
530
|
-
const fileName = source.fileName;
|
|
531
|
-
if (fileName.includes("node_modules")) return false;
|
|
532
|
-
if (fileName.includes("/dist/")) return false;
|
|
533
|
-
if (fileName.includes("/.next/")) return false;
|
|
534
|
-
if (fileName.includes("/build/")) return false;
|
|
535
|
-
if (fileName.includes("webpack-internal:")) return false;
|
|
536
|
-
return true;
|
|
537
|
-
};
|
|
538
731
|
var getSourceTrace = async (element) => {
|
|
539
732
|
const fiber = getFiberFromHostInstance(element);
|
|
540
733
|
if (!fiber) return null;
|
|
@@ -544,7 +737,7 @@ var getSourceTrace = async (element) => {
|
|
|
544
737
|
Number.MAX_SAFE_INTEGER
|
|
545
738
|
);
|
|
546
739
|
if (!sources) return null;
|
|
547
|
-
return sources
|
|
740
|
+
return sources;
|
|
548
741
|
};
|
|
549
742
|
var getHTMLSnippet = (element) => {
|
|
550
743
|
const semanticTags = /* @__PURE__ */ new Set([
|
|
@@ -819,7 +1012,159 @@ var copyContentFallback = (content) => {
|
|
|
819
1012
|
}
|
|
820
1013
|
};
|
|
821
1014
|
|
|
1015
|
+
// src/utils/is-element-visible.ts
|
|
1016
|
+
var isElementVisible = (element, computedStyle = window.getComputedStyle(element)) => {
|
|
1017
|
+
return computedStyle.display !== "none" && computedStyle.visibility !== "hidden" && computedStyle.opacity !== "0";
|
|
1018
|
+
};
|
|
1019
|
+
|
|
1020
|
+
// src/utils/is-valid-grabbable-element.ts
|
|
1021
|
+
var isValidGrabbableElement = (element) => {
|
|
1022
|
+
if (element.closest(`[${ATTRIBUTE_NAME}]`)) {
|
|
1023
|
+
return false;
|
|
1024
|
+
}
|
|
1025
|
+
const computedStyle = window.getComputedStyle(element);
|
|
1026
|
+
if (!isElementVisible(element, computedStyle)) {
|
|
1027
|
+
return false;
|
|
1028
|
+
}
|
|
1029
|
+
if (computedStyle.pointerEvents === "none") {
|
|
1030
|
+
return false;
|
|
1031
|
+
}
|
|
1032
|
+
return true;
|
|
1033
|
+
};
|
|
1034
|
+
|
|
1035
|
+
// src/utils/get-element-at-position.ts
|
|
1036
|
+
var getElementAtPosition = (clientX, clientY) => {
|
|
1037
|
+
const elementsAtPoint = document.elementsFromPoint(clientX, clientY);
|
|
1038
|
+
for (const candidateElement of elementsAtPoint) {
|
|
1039
|
+
if (isValidGrabbableElement(candidateElement)) {
|
|
1040
|
+
return candidateElement;
|
|
1041
|
+
}
|
|
1042
|
+
}
|
|
1043
|
+
return null;
|
|
1044
|
+
};
|
|
1045
|
+
|
|
1046
|
+
// src/utils/get-elements-in-drag.ts
|
|
1047
|
+
var DRAG_COVERAGE_THRESHOLD = 0.75;
|
|
1048
|
+
var filterElementsInDrag = (dragRect, isValidGrabbableElement2, shouldCheckCoverage) => {
|
|
1049
|
+
const elements = [];
|
|
1050
|
+
const allElements = Array.from(document.querySelectorAll("*"));
|
|
1051
|
+
const dragLeft = dragRect.x;
|
|
1052
|
+
const dragTop = dragRect.y;
|
|
1053
|
+
const dragRight = dragRect.x + dragRect.width;
|
|
1054
|
+
const dragBottom = dragRect.y + dragRect.height;
|
|
1055
|
+
for (const candidateElement of allElements) {
|
|
1056
|
+
if (!shouldCheckCoverage) {
|
|
1057
|
+
const tagName = (candidateElement.tagName || "").toUpperCase();
|
|
1058
|
+
if (tagName === "HTML" || tagName === "BODY") continue;
|
|
1059
|
+
}
|
|
1060
|
+
if (!isValidGrabbableElement2(candidateElement)) {
|
|
1061
|
+
continue;
|
|
1062
|
+
}
|
|
1063
|
+
const elementRect = candidateElement.getBoundingClientRect();
|
|
1064
|
+
const elementLeft = elementRect.left;
|
|
1065
|
+
const elementTop = elementRect.top;
|
|
1066
|
+
const elementRight = elementRect.left + elementRect.width;
|
|
1067
|
+
const elementBottom = elementRect.top + elementRect.height;
|
|
1068
|
+
if (shouldCheckCoverage) {
|
|
1069
|
+
const intersectionLeft = Math.max(dragLeft, elementLeft);
|
|
1070
|
+
const intersectionTop = Math.max(dragTop, elementTop);
|
|
1071
|
+
const intersectionRight = Math.min(dragRight, elementRight);
|
|
1072
|
+
const intersectionBottom = Math.min(dragBottom, elementBottom);
|
|
1073
|
+
const intersectionWidth = Math.max(0, intersectionRight - intersectionLeft);
|
|
1074
|
+
const intersectionHeight = Math.max(0, intersectionBottom - intersectionTop);
|
|
1075
|
+
const intersectionArea = intersectionWidth * intersectionHeight;
|
|
1076
|
+
const elementArea = Math.max(0, elementRect.width * elementRect.height);
|
|
1077
|
+
const hasMajorityCoverage = elementArea > 0 && intersectionArea / elementArea >= DRAG_COVERAGE_THRESHOLD;
|
|
1078
|
+
if (hasMajorityCoverage) {
|
|
1079
|
+
elements.push(candidateElement);
|
|
1080
|
+
}
|
|
1081
|
+
} else {
|
|
1082
|
+
const hasIntersection = elementLeft < dragRight && elementRight > dragLeft && elementTop < dragBottom && elementBottom > dragTop;
|
|
1083
|
+
if (hasIntersection) {
|
|
1084
|
+
elements.push(candidateElement);
|
|
1085
|
+
}
|
|
1086
|
+
}
|
|
1087
|
+
}
|
|
1088
|
+
return elements;
|
|
1089
|
+
};
|
|
1090
|
+
var removeNestedElements = (elements) => {
|
|
1091
|
+
return elements.filter((element) => {
|
|
1092
|
+
return !elements.some(
|
|
1093
|
+
(otherElement) => otherElement !== element && otherElement.contains(element)
|
|
1094
|
+
);
|
|
1095
|
+
});
|
|
1096
|
+
};
|
|
1097
|
+
var findBestParentElement = (elements, dragRect, isValidGrabbableElement2) => {
|
|
1098
|
+
if (elements.length <= 1) return null;
|
|
1099
|
+
const dragLeft = dragRect.x;
|
|
1100
|
+
const dragTop = dragRect.y;
|
|
1101
|
+
const dragRight = dragRect.x + dragRect.width;
|
|
1102
|
+
const dragBottom = dragRect.y + dragRect.height;
|
|
1103
|
+
let currentParent = elements[0];
|
|
1104
|
+
while (currentParent) {
|
|
1105
|
+
const parent = currentParent.parentElement;
|
|
1106
|
+
if (!parent) break;
|
|
1107
|
+
const parentRect = parent.getBoundingClientRect();
|
|
1108
|
+
const intersectionLeft = Math.max(dragLeft, parentRect.left);
|
|
1109
|
+
const intersectionTop = Math.max(dragTop, parentRect.top);
|
|
1110
|
+
const intersectionRight = Math.min(dragRight, parentRect.left + parentRect.width);
|
|
1111
|
+
const intersectionBottom = Math.min(dragBottom, parentRect.top + parentRect.height);
|
|
1112
|
+
const intersectionWidth = Math.max(0, intersectionRight - intersectionLeft);
|
|
1113
|
+
const intersectionHeight = Math.max(0, intersectionBottom - intersectionTop);
|
|
1114
|
+
const intersectionArea = intersectionWidth * intersectionHeight;
|
|
1115
|
+
const parentArea = Math.max(0, parentRect.width * parentRect.height);
|
|
1116
|
+
const hasMajorityCoverage = parentArea > 0 && intersectionArea / parentArea >= DRAG_COVERAGE_THRESHOLD;
|
|
1117
|
+
if (!hasMajorityCoverage) break;
|
|
1118
|
+
if (!isValidGrabbableElement2(parent)) {
|
|
1119
|
+
currentParent = parent;
|
|
1120
|
+
continue;
|
|
1121
|
+
}
|
|
1122
|
+
const allChildrenInParent = elements.every(
|
|
1123
|
+
(element) => parent.contains(element)
|
|
1124
|
+
);
|
|
1125
|
+
if (allChildrenInParent) {
|
|
1126
|
+
return parent;
|
|
1127
|
+
}
|
|
1128
|
+
currentParent = parent;
|
|
1129
|
+
}
|
|
1130
|
+
return null;
|
|
1131
|
+
};
|
|
1132
|
+
var getElementsInDrag = (dragRect, isValidGrabbableElement2) => {
|
|
1133
|
+
const elements = filterElementsInDrag(dragRect, isValidGrabbableElement2, true);
|
|
1134
|
+
const uniqueElements = removeNestedElements(elements);
|
|
1135
|
+
const bestParent = findBestParentElement(uniqueElements, dragRect, isValidGrabbableElement2);
|
|
1136
|
+
if (bestParent) {
|
|
1137
|
+
return [bestParent];
|
|
1138
|
+
}
|
|
1139
|
+
return uniqueElements;
|
|
1140
|
+
};
|
|
1141
|
+
var getElementsInDragLoose = (dragRect, isValidGrabbableElement2) => {
|
|
1142
|
+
const elements = filterElementsInDrag(dragRect, isValidGrabbableElement2, false);
|
|
1143
|
+
const uniqueElements = removeNestedElements(elements);
|
|
1144
|
+
const bestParent = findBestParentElement(uniqueElements, dragRect, isValidGrabbableElement2);
|
|
1145
|
+
if (bestParent) {
|
|
1146
|
+
return [bestParent];
|
|
1147
|
+
}
|
|
1148
|
+
return uniqueElements;
|
|
1149
|
+
};
|
|
1150
|
+
|
|
1151
|
+
// src/utils/create-element-bounds.ts
|
|
1152
|
+
var createElementBounds = (element) => {
|
|
1153
|
+
const boundingRect = element.getBoundingClientRect();
|
|
1154
|
+
const computedStyle = window.getComputedStyle(element);
|
|
1155
|
+
return {
|
|
1156
|
+
borderRadius: computedStyle.borderRadius || "0px",
|
|
1157
|
+
height: boundingRect.height,
|
|
1158
|
+
transform: computedStyle.transform || "none",
|
|
1159
|
+
width: boundingRect.width,
|
|
1160
|
+
x: boundingRect.left,
|
|
1161
|
+
y: boundingRect.top
|
|
1162
|
+
};
|
|
1163
|
+
};
|
|
1164
|
+
|
|
822
1165
|
// src/core.tsx
|
|
1166
|
+
var SUCCESS_LABEL_DURATION_MS = 1700;
|
|
1167
|
+
var PROGRESS_INDICATOR_DELAY_MS = 150;
|
|
823
1168
|
var init = (rawOptions) => {
|
|
824
1169
|
const options = {
|
|
825
1170
|
enabled: true,
|
|
@@ -830,215 +1175,114 @@ var init = (rawOptions) => {
|
|
|
830
1175
|
return;
|
|
831
1176
|
}
|
|
832
1177
|
return createRoot((dispose) => {
|
|
1178
|
+
const OFFSCREEN_POSITION = -1e3;
|
|
833
1179
|
const [isHoldingKeys, setIsHoldingKeys] = createSignal(false);
|
|
834
|
-
const [mouseX, setMouseX] = createSignal(
|
|
835
|
-
const [mouseY, setMouseY] = createSignal(
|
|
1180
|
+
const [mouseX, setMouseX] = createSignal(OFFSCREEN_POSITION);
|
|
1181
|
+
const [mouseY, setMouseY] = createSignal(OFFSCREEN_POSITION);
|
|
836
1182
|
const [isDragging, setIsDragging] = createSignal(false);
|
|
837
|
-
const [dragStartX, setDragStartX] = createSignal(
|
|
838
|
-
const [dragStartY, setDragStartY] = createSignal(
|
|
1183
|
+
const [dragStartX, setDragStartX] = createSignal(OFFSCREEN_POSITION);
|
|
1184
|
+
const [dragStartY, setDragStartY] = createSignal(OFFSCREEN_POSITION);
|
|
839
1185
|
const [isCopying, setIsCopying] = createSignal(false);
|
|
840
1186
|
const [lastGrabbedElement, setLastGrabbedElement] = createSignal(null);
|
|
841
1187
|
const [progressStartTime, setProgressStartTime] = createSignal(null);
|
|
842
1188
|
const [progressTick, setProgressTick] = createSignal(0);
|
|
843
|
-
const [
|
|
1189
|
+
const [grabbedBoxes, setGrabbedBoxes] = createSignal([]);
|
|
844
1190
|
const [successLabels, setSuccessLabels] = createSignal([]);
|
|
845
1191
|
const [isActivated, setIsActivated] = createSignal(false);
|
|
846
1192
|
const [showProgressIndicator, setShowProgressIndicator] = createSignal(false);
|
|
847
1193
|
let holdTimerId = null;
|
|
848
1194
|
let progressAnimationId = null;
|
|
849
1195
|
let progressDelayTimerId = null;
|
|
850
|
-
|
|
1196
|
+
let keydownSpamTimerId = null;
|
|
1197
|
+
const isRendererActive = createMemo(() => isActivated() && !isCopying());
|
|
1198
|
+
const hasValidMousePosition = createMemo(() => mouseX() > OFFSCREEN_POSITION && mouseY() > OFFSCREEN_POSITION);
|
|
851
1199
|
const isTargetKeyCombination = (event) => (event.metaKey || event.ctrlKey) && event.key.toLowerCase() === "c";
|
|
852
|
-
const
|
|
853
|
-
const
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
if (computedStyle.pointerEvents === "none") {
|
|
863
|
-
continue;
|
|
864
|
-
}
|
|
865
|
-
return candidateElement;
|
|
866
|
-
}
|
|
867
|
-
return null;
|
|
868
|
-
};
|
|
869
|
-
const getElementsInMarquee = (marqueeRect) => {
|
|
870
|
-
const elements = [];
|
|
871
|
-
const allElements = Array.from(document.querySelectorAll("*"));
|
|
872
|
-
const marqueeLeft = marqueeRect.x;
|
|
873
|
-
const marqueeTop = marqueeRect.y;
|
|
874
|
-
const marqueeRight = marqueeRect.x + marqueeRect.width;
|
|
875
|
-
const marqueeBottom = marqueeRect.y + marqueeRect.height;
|
|
876
|
-
for (const candidateElement of allElements) {
|
|
877
|
-
if (candidateElement.closest(`[${ATTRIBUTE_NAME}]`)) {
|
|
878
|
-
continue;
|
|
879
|
-
}
|
|
880
|
-
const computedStyle = window.getComputedStyle(candidateElement);
|
|
881
|
-
if (!isElementVisible(candidateElement, computedStyle)) {
|
|
882
|
-
continue;
|
|
883
|
-
}
|
|
884
|
-
if (computedStyle.pointerEvents === "none") {
|
|
885
|
-
continue;
|
|
886
|
-
}
|
|
887
|
-
const rect = candidateElement.getBoundingClientRect();
|
|
888
|
-
const elementLeft = rect.left;
|
|
889
|
-
const elementTop = rect.top;
|
|
890
|
-
const elementRight = rect.left + rect.width;
|
|
891
|
-
const elementBottom = rect.top + rect.height;
|
|
892
|
-
const intersectionLeft = Math.max(marqueeLeft, elementLeft);
|
|
893
|
-
const intersectionTop = Math.max(marqueeTop, elementTop);
|
|
894
|
-
const intersectionRight = Math.min(marqueeRight, elementRight);
|
|
895
|
-
const intersectionBottom = Math.min(marqueeBottom, elementBottom);
|
|
896
|
-
const intersectionWidth = Math.max(0, intersectionRight - intersectionLeft);
|
|
897
|
-
const intersectionHeight = Math.max(0, intersectionBottom - intersectionTop);
|
|
898
|
-
const intersectionArea = intersectionWidth * intersectionHeight;
|
|
899
|
-
const elementArea = Math.max(0, rect.width * rect.height);
|
|
900
|
-
const COVERAGE_THRESHOLD = 0.75;
|
|
901
|
-
const hasMajorityCoverage = elementArea > 0 && intersectionArea / elementArea >= COVERAGE_THRESHOLD;
|
|
902
|
-
if (hasMajorityCoverage) {
|
|
903
|
-
elements.push(candidateElement);
|
|
904
|
-
}
|
|
905
|
-
}
|
|
906
|
-
return elements;
|
|
907
|
-
};
|
|
908
|
-
const getElementsInMarqueeLoose = (marqueeRect) => {
|
|
909
|
-
const elements = [];
|
|
910
|
-
const allElements = Array.from(document.querySelectorAll("*"));
|
|
911
|
-
const marqueeLeft = marqueeRect.x;
|
|
912
|
-
const marqueeTop = marqueeRect.y;
|
|
913
|
-
const marqueeRight = marqueeRect.x + marqueeRect.width;
|
|
914
|
-
const marqueeBottom = marqueeRect.y + marqueeRect.height;
|
|
915
|
-
for (const candidateElement of allElements) {
|
|
916
|
-
if (candidateElement.closest(`[${ATTRIBUTE_NAME}]`)) {
|
|
917
|
-
continue;
|
|
918
|
-
}
|
|
919
|
-
const tag = (candidateElement.tagName || "").toUpperCase();
|
|
920
|
-
if (tag === "HTML" || tag === "BODY") continue;
|
|
921
|
-
const computedStyle = window.getComputedStyle(candidateElement);
|
|
922
|
-
if (!isElementVisible(candidateElement, computedStyle)) {
|
|
923
|
-
continue;
|
|
924
|
-
}
|
|
925
|
-
if (computedStyle.pointerEvents === "none") {
|
|
926
|
-
continue;
|
|
927
|
-
}
|
|
928
|
-
const rect = candidateElement.getBoundingClientRect();
|
|
929
|
-
const elementLeft = rect.left;
|
|
930
|
-
const elementTop = rect.top;
|
|
931
|
-
const elementRight = rect.left + rect.width;
|
|
932
|
-
const elementBottom = rect.top + rect.height;
|
|
933
|
-
const intersects = elementLeft < marqueeRight && elementRight > marqueeLeft && elementTop < marqueeBottom && elementBottom > marqueeTop;
|
|
934
|
-
if (intersects) {
|
|
935
|
-
elements.push(candidateElement);
|
|
936
|
-
}
|
|
937
|
-
}
|
|
938
|
-
return elements;
|
|
939
|
-
};
|
|
940
|
-
const wrapInReferencedElement = (content) => `
|
|
941
|
-
|
|
942
|
-
<referenced_element>
|
|
943
|
-
${content}
|
|
944
|
-
</referenced_element>`;
|
|
945
|
-
const wrapInReferencedElements = (content) => `
|
|
946
|
-
|
|
947
|
-
<referenced_elements>
|
|
948
|
-
${content}
|
|
949
|
-
</referenced_elements>`;
|
|
950
|
-
const addGrabbedOverlay = (bounds) => {
|
|
951
|
-
const id = `grabbed-${Date.now()}-${Math.random()}`;
|
|
952
|
-
setGrabbedOverlays((prev) => [...prev, {
|
|
953
|
-
id,
|
|
954
|
-
bounds
|
|
955
|
-
}]);
|
|
1200
|
+
const addGrabbedBox = (bounds) => {
|
|
1201
|
+
const boxId = `grabbed-${Date.now()}-${Math.random()}`;
|
|
1202
|
+
const createdAt = Date.now();
|
|
1203
|
+
const newBox = {
|
|
1204
|
+
id: boxId,
|
|
1205
|
+
bounds,
|
|
1206
|
+
createdAt
|
|
1207
|
+
};
|
|
1208
|
+
const currentBoxes = grabbedBoxes();
|
|
1209
|
+
setGrabbedBoxes([...currentBoxes, newBox]);
|
|
956
1210
|
setTimeout(() => {
|
|
957
|
-
|
|
958
|
-
},
|
|
1211
|
+
setGrabbedBoxes((previousBoxes) => previousBoxes.filter((box) => box.id !== boxId));
|
|
1212
|
+
}, SUCCESS_LABEL_DURATION_MS);
|
|
959
1213
|
};
|
|
960
|
-
const addSuccessLabel = (text,
|
|
961
|
-
const
|
|
962
|
-
setSuccessLabels((
|
|
963
|
-
id,
|
|
1214
|
+
const addSuccessLabel = (text, positionX, positionY) => {
|
|
1215
|
+
const labelId = `success-${Date.now()}-${Math.random()}`;
|
|
1216
|
+
setSuccessLabels((previousLabels) => [...previousLabels, {
|
|
1217
|
+
id: labelId,
|
|
964
1218
|
text,
|
|
965
|
-
x,
|
|
966
|
-
y
|
|
1219
|
+
x: positionX,
|
|
1220
|
+
y: positionY
|
|
967
1221
|
}]);
|
|
968
1222
|
setTimeout(() => {
|
|
969
|
-
setSuccessLabels((
|
|
970
|
-
},
|
|
1223
|
+
setSuccessLabels((previousLabels) => previousLabels.filter((label) => label.id !== labelId));
|
|
1224
|
+
}, SUCCESS_LABEL_DURATION_MS);
|
|
1225
|
+
};
|
|
1226
|
+
const formatStackTrace = (stackTrace) => {
|
|
1227
|
+
return stackTrace.map((source) => {
|
|
1228
|
+
const functionName = source.functionName ?? "anonymous";
|
|
1229
|
+
const fileName = source.fileName ?? "unknown";
|
|
1230
|
+
const lineNumber = source.lineNumber ?? 0;
|
|
1231
|
+
const columnNumber = source.columnNumber ?? 0;
|
|
1232
|
+
return ` ${functionName} - ${fileName}:${lineNumber}:${columnNumber}`;
|
|
1233
|
+
}).join("\n");
|
|
1234
|
+
};
|
|
1235
|
+
const wrapContextInXmlTags = (context) => {
|
|
1236
|
+
return `<selected_element>${context}</selected_element>`;
|
|
971
1237
|
};
|
|
1238
|
+
const getElementContentWithTrace = async (element) => {
|
|
1239
|
+
const elementHtml = getHTMLSnippet(element);
|
|
1240
|
+
const componentStackTrace = await getSourceTrace(element);
|
|
1241
|
+
if (componentStackTrace?.length) {
|
|
1242
|
+
const formattedStackTrace = formatStackTrace(componentStackTrace);
|
|
1243
|
+
return `${elementHtml}
|
|
1244
|
+
|
|
1245
|
+
Component owner stack:
|
|
1246
|
+
${formattedStackTrace}`;
|
|
1247
|
+
}
|
|
1248
|
+
return elementHtml;
|
|
1249
|
+
};
|
|
1250
|
+
const getElementTagName = (element) => (element.tagName || "").toLowerCase();
|
|
972
1251
|
const handleCopy = async (targetElement2) => {
|
|
973
1252
|
const elementBounds = targetElement2.getBoundingClientRect();
|
|
974
|
-
const tagName = (targetElement2
|
|
975
|
-
|
|
976
|
-
borderRadius: window.getComputedStyle(targetElement2).borderRadius || "0px",
|
|
977
|
-
height: elementBounds.height,
|
|
978
|
-
transform: window.getComputedStyle(targetElement2).transform || "none",
|
|
979
|
-
width: elementBounds.width,
|
|
980
|
-
x: elementBounds.left,
|
|
981
|
-
y: elementBounds.top
|
|
982
|
-
});
|
|
1253
|
+
const tagName = getElementTagName(targetElement2);
|
|
1254
|
+
addGrabbedBox(createElementBounds(targetElement2));
|
|
983
1255
|
try {
|
|
984
|
-
const
|
|
985
|
-
await copyContent(
|
|
986
|
-
const componentStackTrace = await getSourceTrace(targetElement2);
|
|
987
|
-
if (componentStackTrace?.length) {
|
|
988
|
-
const formattedStackTrace = componentStackTrace.map((source) => ` ${source.functionName} - ${source.fileName}:${source.lineNumber}:${source.columnNumber}`).join("\n");
|
|
989
|
-
await copyContent(wrapInReferencedElement(`${elementHtml}
|
|
990
|
-
|
|
991
|
-
Component owner stack:
|
|
992
|
-
${formattedStackTrace}`));
|
|
993
|
-
}
|
|
1256
|
+
const content = await getElementContentWithTrace(targetElement2);
|
|
1257
|
+
await copyContent(wrapContextInXmlTags(content));
|
|
994
1258
|
} catch {
|
|
995
1259
|
}
|
|
996
1260
|
addSuccessLabel(tagName ? `<${tagName}>` : "<element>", elementBounds.left, elementBounds.top);
|
|
997
1261
|
};
|
|
998
1262
|
const handleMultipleCopy = async (targetElements) => {
|
|
999
1263
|
if (targetElements.length === 0) return;
|
|
1000
|
-
let
|
|
1001
|
-
let
|
|
1264
|
+
let minPositionX = Infinity;
|
|
1265
|
+
let minPositionY = Infinity;
|
|
1002
1266
|
for (const element of targetElements) {
|
|
1003
1267
|
const elementBounds = element.getBoundingClientRect();
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
borderRadius: window.getComputedStyle(element).borderRadius || "0px",
|
|
1008
|
-
height: elementBounds.height,
|
|
1009
|
-
transform: window.getComputedStyle(element).transform || "none",
|
|
1010
|
-
width: elementBounds.width,
|
|
1011
|
-
x: elementBounds.left,
|
|
1012
|
-
y: elementBounds.top
|
|
1013
|
-
});
|
|
1268
|
+
minPositionX = Math.min(minPositionX, elementBounds.left);
|
|
1269
|
+
minPositionY = Math.min(minPositionY, elementBounds.top);
|
|
1270
|
+
addGrabbedBox(createElementBounds(element));
|
|
1014
1271
|
}
|
|
1015
1272
|
try {
|
|
1016
|
-
const elementSnippets =
|
|
1017
|
-
for (const element of targetElements) {
|
|
1018
|
-
const elementHtml = getHTMLSnippet(element);
|
|
1019
|
-
const componentStackTrace = await getSourceTrace(element);
|
|
1020
|
-
if (componentStackTrace?.length) {
|
|
1021
|
-
const formattedStackTrace = componentStackTrace.map((source) => ` ${source.functionName} - ${source.fileName}:${source.lineNumber}:${source.columnNumber}`).join("\n");
|
|
1022
|
-
elementSnippets.push(`${elementHtml}
|
|
1023
|
-
|
|
1024
|
-
Component owner stack:
|
|
1025
|
-
${formattedStackTrace}`);
|
|
1026
|
-
} else {
|
|
1027
|
-
elementSnippets.push(elementHtml);
|
|
1028
|
-
}
|
|
1029
|
-
}
|
|
1273
|
+
const elementSnippets = await Promise.all(targetElements.map((element) => getElementContentWithTrace(element)));
|
|
1030
1274
|
const combinedContent = elementSnippets.join("\n\n---\n\n");
|
|
1031
|
-
await copyContent(
|
|
1275
|
+
await copyContent(wrapContextInXmlTags(combinedContent));
|
|
1032
1276
|
} catch {
|
|
1033
1277
|
}
|
|
1034
|
-
addSuccessLabel(`${targetElements.length} elements`,
|
|
1278
|
+
addSuccessLabel(`${targetElements.length} elements`, minPositionX, minPositionY);
|
|
1035
1279
|
};
|
|
1036
1280
|
const targetElement = createMemo(() => {
|
|
1037
|
-
if (!
|
|
1281
|
+
if (!isRendererActive() || isDragging()) return null;
|
|
1038
1282
|
return getElementAtPosition(mouseX(), mouseY());
|
|
1039
1283
|
});
|
|
1040
1284
|
const selectionBounds = createMemo(() => {
|
|
1041
|
-
const element = targetElement()
|
|
1285
|
+
const element = targetElement();
|
|
1042
1286
|
if (!element) return void 0;
|
|
1043
1287
|
const elementBounds = element.getBoundingClientRect();
|
|
1044
1288
|
const computedStyle = window.getComputedStyle(element);
|
|
@@ -1051,54 +1295,68 @@ ${formattedStackTrace}`);
|
|
|
1051
1295
|
y: elementBounds.top
|
|
1052
1296
|
};
|
|
1053
1297
|
});
|
|
1054
|
-
const
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1298
|
+
const DRAG_THRESHOLD_PX = 2;
|
|
1299
|
+
const getDragDistance = (endX, endY) => ({
|
|
1300
|
+
x: Math.abs(endX - dragStartX()),
|
|
1301
|
+
y: Math.abs(endY - dragStartY())
|
|
1302
|
+
});
|
|
1303
|
+
const isDraggingBeyondThreshold = createMemo(() => {
|
|
1304
|
+
if (!isDragging()) return false;
|
|
1305
|
+
const dragDistance = getDragDistance(mouseX(), mouseY());
|
|
1306
|
+
return dragDistance.x > DRAG_THRESHOLD_PX || dragDistance.y > DRAG_THRESHOLD_PX;
|
|
1307
|
+
});
|
|
1308
|
+
const getDragRect = (endX, endY) => {
|
|
1309
|
+
const dragX = Math.min(dragStartX(), endX);
|
|
1310
|
+
const dragY = Math.min(dragStartY(), endY);
|
|
1311
|
+
const dragWidth = Math.abs(endX - dragStartX());
|
|
1312
|
+
const dragHeight = Math.abs(endY - dragStartY());
|
|
1313
|
+
return {
|
|
1314
|
+
x: dragX,
|
|
1315
|
+
y: dragY,
|
|
1316
|
+
width: dragWidth,
|
|
1317
|
+
height: dragHeight
|
|
1318
|
+
};
|
|
1319
|
+
};
|
|
1320
|
+
const dragBounds = createMemo(() => {
|
|
1321
|
+
if (!isDraggingBeyondThreshold()) return void 0;
|
|
1322
|
+
const drag = getDragRect(mouseX(), mouseY());
|
|
1060
1323
|
return {
|
|
1061
1324
|
borderRadius: "0px",
|
|
1062
|
-
height:
|
|
1325
|
+
height: drag.height,
|
|
1063
1326
|
transform: "none",
|
|
1064
|
-
width:
|
|
1065
|
-
x:
|
|
1066
|
-
y:
|
|
1327
|
+
width: drag.width,
|
|
1328
|
+
x: drag.x,
|
|
1329
|
+
y: drag.y
|
|
1067
1330
|
};
|
|
1068
1331
|
});
|
|
1069
1332
|
const labelText = createMemo(() => {
|
|
1070
1333
|
const element = targetElement();
|
|
1071
|
-
if (!element) return "";
|
|
1072
|
-
const tagName = (element
|
|
1334
|
+
if (!element) return "(click or drag to select element(s))";
|
|
1335
|
+
const tagName = getElementTagName(element);
|
|
1073
1336
|
return tagName ? `<${tagName}>` : "<element>";
|
|
1074
1337
|
});
|
|
1075
1338
|
const labelPosition = createMemo(() => {
|
|
1076
|
-
const element = targetElement() ?? lastGrabbedElement();
|
|
1077
|
-
if (element) {
|
|
1078
|
-
const rect = element.getBoundingClientRect();
|
|
1079
|
-
return {
|
|
1080
|
-
x: rect.left,
|
|
1081
|
-
y: rect.top
|
|
1082
|
-
};
|
|
1083
|
-
}
|
|
1084
1339
|
return {
|
|
1085
1340
|
x: mouseX(),
|
|
1086
1341
|
y: mouseY()
|
|
1087
1342
|
};
|
|
1088
1343
|
});
|
|
1089
|
-
|
|
1090
|
-
const
|
|
1091
|
-
const
|
|
1092
|
-
|
|
1344
|
+
const isSameAsLast = createMemo(() => {
|
|
1345
|
+
const currentElement = targetElement();
|
|
1346
|
+
const lastElement = lastGrabbedElement();
|
|
1347
|
+
return !!currentElement && currentElement === lastElement;
|
|
1348
|
+
});
|
|
1349
|
+
createEffect(on(() => [targetElement(), lastGrabbedElement()], ([currentElement, lastElement]) => {
|
|
1350
|
+
if (lastElement && currentElement && lastElement !== currentElement) {
|
|
1093
1351
|
setLastGrabbedElement(null);
|
|
1094
1352
|
}
|
|
1095
|
-
});
|
|
1353
|
+
}));
|
|
1096
1354
|
const progress = createMemo(() => {
|
|
1097
1355
|
const startTime = progressStartTime();
|
|
1098
1356
|
progressTick();
|
|
1099
1357
|
if (startTime === null) return 0;
|
|
1100
|
-
const
|
|
1101
|
-
return Math.min(
|
|
1358
|
+
const elapsedTime = Date.now() - startTime;
|
|
1359
|
+
return Math.min(elapsedTime / options.keyHoldDuration, 1);
|
|
1102
1360
|
});
|
|
1103
1361
|
const startProgressAnimation = () => {
|
|
1104
1362
|
setProgressStartTime(Date.now());
|
|
@@ -1106,10 +1364,10 @@ ${formattedStackTrace}`);
|
|
|
1106
1364
|
progressDelayTimerId = window.setTimeout(() => {
|
|
1107
1365
|
setShowProgressIndicator(true);
|
|
1108
1366
|
progressDelayTimerId = null;
|
|
1109
|
-
},
|
|
1367
|
+
}, PROGRESS_INDICATOR_DELAY_MS);
|
|
1110
1368
|
const animateProgress = () => {
|
|
1111
1369
|
if (progressStartTime() === null) return;
|
|
1112
|
-
setProgressTick((
|
|
1370
|
+
setProgressTick((tick) => tick + 1);
|
|
1113
1371
|
const currentProgress = progress();
|
|
1114
1372
|
if (currentProgress < 1) {
|
|
1115
1373
|
progressAnimationId = requestAnimationFrame(animateProgress);
|
|
@@ -1129,86 +1387,93 @@ ${formattedStackTrace}`);
|
|
|
1129
1387
|
setProgressStartTime(null);
|
|
1130
1388
|
setShowProgressIndicator(false);
|
|
1131
1389
|
};
|
|
1132
|
-
const
|
|
1390
|
+
const activateRenderer = () => {
|
|
1133
1391
|
stopProgressAnimation();
|
|
1134
1392
|
setIsActivated(true);
|
|
1393
|
+
document.body.style.cursor = "crosshair";
|
|
1394
|
+
};
|
|
1395
|
+
const deactivateRenderer = () => {
|
|
1396
|
+
setIsHoldingKeys(false);
|
|
1397
|
+
setIsActivated(false);
|
|
1398
|
+
document.body.style.cursor = "";
|
|
1399
|
+
if (isDragging()) {
|
|
1400
|
+
setIsDragging(false);
|
|
1401
|
+
document.body.style.userSelect = "";
|
|
1402
|
+
}
|
|
1403
|
+
if (holdTimerId) window.clearTimeout(holdTimerId);
|
|
1404
|
+
if (keydownSpamTimerId) window.clearTimeout(keydownSpamTimerId);
|
|
1405
|
+
stopProgressAnimation();
|
|
1135
1406
|
};
|
|
1136
1407
|
const abortController = new AbortController();
|
|
1137
|
-
const
|
|
1408
|
+
const eventListenerSignal = abortController.signal;
|
|
1138
1409
|
window.addEventListener("keydown", (event) => {
|
|
1139
1410
|
if (event.key === "Escape" && isHoldingKeys()) {
|
|
1140
|
-
|
|
1141
|
-
setIsActivated(false);
|
|
1142
|
-
if (holdTimerId) window.clearTimeout(holdTimerId);
|
|
1143
|
-
stopProgressAnimation();
|
|
1411
|
+
deactivateRenderer();
|
|
1144
1412
|
return;
|
|
1145
1413
|
}
|
|
1146
1414
|
if (isKeyboardEventTriggeredByInput(event)) return;
|
|
1147
|
-
if (isTargetKeyCombination(event)
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
|
|
1415
|
+
if (isTargetKeyCombination(event)) {
|
|
1416
|
+
if (!isHoldingKeys()) {
|
|
1417
|
+
setIsHoldingKeys(true);
|
|
1418
|
+
startProgressAnimation();
|
|
1419
|
+
holdTimerId = window.setTimeout(() => {
|
|
1420
|
+
activateRenderer();
|
|
1421
|
+
options.onActivate?.();
|
|
1422
|
+
}, options.keyHoldDuration);
|
|
1423
|
+
}
|
|
1424
|
+
if (isActivated()) {
|
|
1425
|
+
if (keydownSpamTimerId) window.clearTimeout(keydownSpamTimerId);
|
|
1426
|
+
keydownSpamTimerId = window.setTimeout(() => {
|
|
1427
|
+
deactivateRenderer();
|
|
1428
|
+
}, 200);
|
|
1429
|
+
}
|
|
1154
1430
|
}
|
|
1155
1431
|
}, {
|
|
1156
|
-
signal
|
|
1432
|
+
signal: eventListenerSignal
|
|
1157
1433
|
});
|
|
1158
1434
|
window.addEventListener("keyup", (event) => {
|
|
1159
|
-
if (isHoldingKeys() &&
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1435
|
+
if (!isHoldingKeys() && !isActivated()) return;
|
|
1436
|
+
const isReleasingC = event.key.toLowerCase() === "c";
|
|
1437
|
+
const isReleasingModifier = !event.metaKey && !event.ctrlKey;
|
|
1438
|
+
if (isReleasingC || isReleasingModifier) {
|
|
1439
|
+
deactivateRenderer();
|
|
1164
1440
|
}
|
|
1165
1441
|
}, {
|
|
1166
|
-
signal
|
|
1442
|
+
signal: eventListenerSignal,
|
|
1443
|
+
capture: true
|
|
1167
1444
|
});
|
|
1168
1445
|
window.addEventListener("mousemove", (event) => {
|
|
1169
1446
|
setMouseX(event.clientX);
|
|
1170
1447
|
setMouseY(event.clientY);
|
|
1171
1448
|
}, {
|
|
1172
|
-
signal
|
|
1449
|
+
signal: eventListenerSignal
|
|
1173
1450
|
});
|
|
1174
1451
|
window.addEventListener("mousedown", (event) => {
|
|
1175
|
-
if (!
|
|
1452
|
+
if (!isRendererActive() || isCopying()) return;
|
|
1453
|
+
event.preventDefault();
|
|
1176
1454
|
setIsDragging(true);
|
|
1177
1455
|
setDragStartX(event.clientX);
|
|
1178
1456
|
setDragStartY(event.clientY);
|
|
1457
|
+
document.body.style.userSelect = "none";
|
|
1179
1458
|
}, {
|
|
1180
|
-
signal
|
|
1459
|
+
signal: eventListenerSignal
|
|
1181
1460
|
});
|
|
1182
1461
|
window.addEventListener("mouseup", (event) => {
|
|
1183
1462
|
if (!isDragging()) return;
|
|
1184
|
-
const
|
|
1185
|
-
const
|
|
1186
|
-
const DRAG_THRESHOLD = 5;
|
|
1187
|
-
const wasDrag = dragDistanceX > DRAG_THRESHOLD || dragDistanceY > DRAG_THRESHOLD;
|
|
1463
|
+
const dragDistance = getDragDistance(event.clientX, event.clientY);
|
|
1464
|
+
const wasDragGesture = dragDistance.x > DRAG_THRESHOLD_PX || dragDistance.y > DRAG_THRESHOLD_PX;
|
|
1188
1465
|
setIsDragging(false);
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
const
|
|
1192
|
-
const
|
|
1193
|
-
const marqueeHeight = Math.abs(event.clientY - dragStartY());
|
|
1194
|
-
const elements = getElementsInMarquee({
|
|
1195
|
-
x: marqueeX,
|
|
1196
|
-
y: marqueeY,
|
|
1197
|
-
width: marqueeWidth,
|
|
1198
|
-
height: marqueeHeight
|
|
1199
|
-
});
|
|
1466
|
+
document.body.style.userSelect = "";
|
|
1467
|
+
if (wasDragGesture) {
|
|
1468
|
+
const dragRect = getDragRect(event.clientX, event.clientY);
|
|
1469
|
+
const elements = getElementsInDrag(dragRect, isValidGrabbableElement);
|
|
1200
1470
|
if (elements.length > 0) {
|
|
1201
1471
|
setIsCopying(true);
|
|
1202
1472
|
void handleMultipleCopy(elements).finally(() => {
|
|
1203
1473
|
setIsCopying(false);
|
|
1204
1474
|
});
|
|
1205
1475
|
} else {
|
|
1206
|
-
const fallbackElements =
|
|
1207
|
-
x: marqueeX,
|
|
1208
|
-
y: marqueeY,
|
|
1209
|
-
width: marqueeWidth,
|
|
1210
|
-
height: marqueeHeight
|
|
1211
|
-
});
|
|
1476
|
+
const fallbackElements = getElementsInDragLoose(dragRect, isValidGrabbableElement);
|
|
1212
1477
|
if (fallbackElements.length > 0) {
|
|
1213
1478
|
setIsCopying(true);
|
|
1214
1479
|
void handleMultipleCopy(fallbackElements).finally(() => {
|
|
@@ -1226,51 +1491,85 @@ ${formattedStackTrace}`);
|
|
|
1226
1491
|
});
|
|
1227
1492
|
}
|
|
1228
1493
|
}, {
|
|
1229
|
-
signal
|
|
1230
|
-
});
|
|
1231
|
-
window.addEventListener("scroll", () => {
|
|
1232
|
-
}, {
|
|
1233
|
-
signal,
|
|
1234
|
-
capture: true
|
|
1235
|
-
});
|
|
1236
|
-
window.addEventListener("resize", () => {
|
|
1237
|
-
}, {
|
|
1238
|
-
signal
|
|
1494
|
+
signal: eventListenerSignal
|
|
1239
1495
|
});
|
|
1240
1496
|
document.addEventListener("visibilitychange", () => {
|
|
1241
1497
|
if (document.hidden) {
|
|
1242
|
-
|
|
1498
|
+
setGrabbedBoxes([]);
|
|
1243
1499
|
}
|
|
1244
1500
|
}, {
|
|
1245
|
-
signal
|
|
1501
|
+
signal: eventListenerSignal
|
|
1246
1502
|
});
|
|
1247
1503
|
onCleanup(() => {
|
|
1248
1504
|
abortController.abort();
|
|
1249
1505
|
if (holdTimerId) window.clearTimeout(holdTimerId);
|
|
1506
|
+
if (keydownSpamTimerId) window.clearTimeout(keydownSpamTimerId);
|
|
1250
1507
|
stopProgressAnimation();
|
|
1508
|
+
document.body.style.userSelect = "";
|
|
1509
|
+
document.body.style.cursor = "";
|
|
1251
1510
|
});
|
|
1252
|
-
const
|
|
1253
|
-
const
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
|
|
1262
|
-
|
|
1263
|
-
|
|
1264
|
-
|
|
1265
|
-
|
|
1266
|
-
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
|
|
1511
|
+
const rendererRoot = mountRoot();
|
|
1512
|
+
const selectionVisible = createMemo(() => false);
|
|
1513
|
+
const dragVisible = createMemo(() => isRendererActive() && isDraggingBeyondThreshold());
|
|
1514
|
+
const labelVariant = createMemo(() => isCopying() ? "processing" : "hover");
|
|
1515
|
+
const labelVisible = createMemo(() => isRendererActive() && !isDragging() && (!!targetElement() && !isSameAsLast() || !targetElement()) || isCopying());
|
|
1516
|
+
const progressVisible = createMemo(() => isHoldingKeys() && showProgressIndicator() && hasValidMousePosition());
|
|
1517
|
+
const crosshairVisible = createMemo(() => isRendererActive() && !isDragging());
|
|
1518
|
+
render(() => createComponent(ReactGrabRenderer, {
|
|
1519
|
+
get selectionVisible() {
|
|
1520
|
+
return selectionVisible();
|
|
1521
|
+
},
|
|
1522
|
+
get selectionBounds() {
|
|
1523
|
+
return selectionBounds();
|
|
1524
|
+
},
|
|
1525
|
+
get dragVisible() {
|
|
1526
|
+
return dragVisible();
|
|
1527
|
+
},
|
|
1528
|
+
get dragBounds() {
|
|
1529
|
+
return dragBounds();
|
|
1530
|
+
},
|
|
1531
|
+
get grabbedBoxes() {
|
|
1532
|
+
return grabbedBoxes();
|
|
1533
|
+
},
|
|
1534
|
+
get successLabels() {
|
|
1535
|
+
return successLabels();
|
|
1536
|
+
},
|
|
1537
|
+
get labelVariant() {
|
|
1538
|
+
return labelVariant();
|
|
1539
|
+
},
|
|
1540
|
+
get labelText() {
|
|
1541
|
+
return labelText();
|
|
1542
|
+
},
|
|
1543
|
+
get labelX() {
|
|
1544
|
+
return labelPosition().x;
|
|
1545
|
+
},
|
|
1546
|
+
get labelY() {
|
|
1547
|
+
return labelPosition().y;
|
|
1548
|
+
},
|
|
1549
|
+
get labelVisible() {
|
|
1550
|
+
return labelVisible();
|
|
1551
|
+
},
|
|
1552
|
+
get progressVisible() {
|
|
1553
|
+
return progressVisible();
|
|
1554
|
+
},
|
|
1555
|
+
get progress() {
|
|
1556
|
+
return progress();
|
|
1557
|
+
},
|
|
1558
|
+
get mouseX() {
|
|
1559
|
+
return mouseX();
|
|
1560
|
+
},
|
|
1561
|
+
get mouseY() {
|
|
1562
|
+
return mouseY();
|
|
1563
|
+
},
|
|
1564
|
+
get crosshairVisible() {
|
|
1565
|
+
return crosshairVisible();
|
|
1566
|
+
}
|
|
1567
|
+
}), rendererRoot);
|
|
1271
1568
|
return dispose;
|
|
1272
1569
|
});
|
|
1273
1570
|
};
|
|
1274
1571
|
|
|
1275
1572
|
// src/index.ts
|
|
1276
1573
|
init();
|
|
1574
|
+
|
|
1575
|
+
export { init };
|