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