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 CHANGED
@@ -91,93 +91,101 @@ var mountRoot = () => {
91
91
  return root;
92
92
  };
93
93
 
94
- // src/utils/is-element-visible.ts
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 INDICATOR_SUCCESS_VISIBLE_MS = 1500;
97
+ var CURSOR_OFFSET_PX = 14;
108
98
  var SELECTION_LERP_FACTOR = 0.95;
109
- var MARQUEE_LERP_FACTOR = 0.9;
99
+
100
+ // src/utils/lerp.ts
110
101
  var lerp = (start, end, factor) => {
111
102
  return start + (end - start) * factor;
112
103
  };
113
- var Overlay = (props) => {
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 hasBeenShown = false;
113
+ let hasBeenRenderedOnce = false;
120
114
  let animationFrameId = null;
115
+ let fadeTimerId = null;
121
116
  let targetBounds = props.bounds;
122
- solidJs.createEffect(() => {
123
- targetBounds = props.bounds;
124
- const factor = props.lerpFactor ?? SELECTION_LERP_FACTOR;
125
- if (!hasBeenShown) {
126
- setCurrentX(targetBounds.x);
127
- setCurrentY(targetBounds.y);
128
- setCurrentWidth(targetBounds.width);
129
- setCurrentHeight(targetBounds.height);
130
- hasBeenShown = true;
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 newX = lerp(currentX(), targetBounds.x, factor);
136
- const newY = lerp(currentY(), targetBounds.y, factor);
137
- const newWidth = lerp(currentWidth(), targetBounds.width, factor);
138
- const newHeight = lerp(currentHeight(), targetBounds.height, factor);
139
- setCurrentX(newX);
140
- setCurrentY(newY);
141
- setCurrentWidth(newWidth);
142
- setCurrentHeight(newHeight);
143
- const hasConverged = Math.abs(newX - targetBounds.x) < EPSILON && Math.abs(newY - targetBounds.y) < EPSILON && Math.abs(newWidth - targetBounds.width) < EPSILON && Math.abs(newHeight - targetBounds.height) < EPSILON;
144
- if (!hasConverged) {
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
- solidJs.onCleanup(() => {
155
- if (animationFrameId !== null) {
156
- cancelAnimationFrame(animationFrameId);
157
- animationFrameId = null;
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
- requestAnimationFrame(() => {
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 === "marquee" ? "none" : "auto",
178
+ "pointer-events": props.variant === "drag" ? "none" : "auto",
172
179
  "z-index": "2147483646"
173
180
  };
174
181
  const variantStyle = () => {
175
- if (props.variant === "marquee") {
182
+ if (props.variant === "drag") {
176
183
  return {
177
- border: "1px dashed rgb(210, 57, 192)",
178
- "background-color": "rgba(210, 57, 192, 0.1)",
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 ref;
212
- solidJs.createEffect(() => {
213
- if (ref) {
214
- ref.animate([{
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$2 = _tmpl$2();
227
- var _ref$ = ref;
228
- typeof _ref$ === "function" ? web.use(_ref$, _el$2) : ref = _el$2;
229
- web.effect((_$p) => web.style(_el$2, {
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$2;
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
- let ref;
238
- solidJs.createEffect(() => {
239
- if (props.visible !== false) {
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
- }, INDICATOR_SUCCESS_VISIBLE_MS);
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 indicatorRect = () => ref?.getBoundingClientRect();
326
+ const labelBoundingRect = () => labelRef?.getBoundingClientRect();
256
327
  const computedPosition = () => {
257
- const rect = indicatorRect();
258
- if (!rect) return {
259
- left: props.x,
260
- top: props.y
328
+ positionTick();
329
+ const boundingRect = labelBoundingRect();
330
+ if (!boundingRect) return {
331
+ left: currentX,
332
+ top: currentY
261
333
  };
262
- const viewportWidthPx = window.innerWidth;
263
- const viewportHeightPx = window.innerHeight;
264
- let indicatorLeftPx = Math.round(props.x);
265
- let indicatorTopPx = Math.round(props.y) - rect.height - LABEL_OFFSET_PX;
266
- const minLeft = VIEWPORT_MARGIN_PX;
267
- const minTop = VIEWPORT_MARGIN_PX;
268
- const maxLeft = viewportWidthPx - rect.width - VIEWPORT_MARGIN_PX;
269
- const maxTop = viewportHeightPx - rect.height - VIEWPORT_MARGIN_PX;
270
- const willClampLeft = indicatorLeftPx < minLeft;
271
- const willClampTop = indicatorTopPx < minTop;
272
- const isClamped = willClampLeft || willClampTop;
273
- indicatorLeftPx = Math.max(minLeft, Math.min(indicatorLeftPx, maxLeft));
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
- return {
280
- left: indicatorLeftPx,
281
- top: indicatorTopPx
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$3 = _tmpl$5(), _el$5 = _el$3.firstChild;
290
- var _ref$2 = ref;
291
- typeof _ref$2 === "function" ? web.use(_ref$2, _el$3) : ref = _el$3;
292
- web.insert(_el$3, web.createComponent(solidJs.Show, {
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
- }), _el$5);
300
- web.insert(_el$3, web.createComponent(solidJs.Show, {
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
- }), _el$5);
308
- web.insert(_el$5, web.createComponent(solidJs.Show, {
398
+ }), null);
399
+ web.insert(_el$, web.createComponent(solidJs.Show, {
309
400
  get when() {
310
401
  return props.variant === "success";
311
402
  },
312
- children: "Grabbed "
403
+ get children() {
404
+ return _tmpl$22();
405
+ }
313
406
  }), null);
314
- web.insert(_el$5, web.createComponent(solidJs.Show, {
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$5, web.createComponent(solidJs.Show, {
413
+ web.insert(_el$, web.createComponent(solidJs.Show, {
321
414
  get when() {
322
- return props.variant === "hover";
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
- var _el$6 = _tmpl$4();
326
- web.insert(_el$6, () => props.text);
327
- return _el$6;
425
+ return props.text;
328
426
  }
329
427
  }), null);
330
- web.insert(_el$5, web.createComponent(solidJs.Show, {
428
+ web.insert(_el$, web.createComponent(solidJs.Show, {
331
429
  get when() {
332
- return props.variant !== "hover";
430
+ return props.variant === "success";
333
431
  },
334
432
  get children() {
335
- var _el$7 = _tmpl$4();
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$3, "top", _p$.e = _v$);
343
- _v$2 !== _p$.t && web.setStyleProperty(_el$3, "left", _p$.t = _v$2);
344
- _v$3 !== _p$.a && web.setStyleProperty(_el$3, "z-index", _p$.a = _v$3);
345
- _v$4 !== _p$.o && web.setStyleProperty(_el$3, "opacity", _p$.o = _v$4);
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$3;
449
+ return _el$;
354
450
  }
355
451
  });
356
452
  };
357
- var ProgressIndicator = (props) => {
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
- let ref;
360
- solidJs.createEffect(() => {
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 rect = ref?.getBoundingClientRect();
371
- if (!rect) return {
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 CURSOR_OFFSET = 14;
378
- const VIEWPORT_MARGIN = 8;
379
- let indicatorLeft = props.mouseX - rect.width / 2;
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$8 = _tmpl$6(), _el$9 = _el$8.firstChild, _el$0 = _el$9.firstChild;
397
- var _ref$3 = ref;
398
- typeof _ref$3 === "function" ? web.use(_ref$3, _el$8) : ref = _el$8;
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$5 = `${computedPosition().top}px`, _v$6 = `${computedPosition().left}px`, _v$7 = opacity(), _v$8 = `${Math.min(100, Math.max(0, props.progress * 100))}%`;
401
- _v$5 !== _p$.e && web.setStyleProperty(_el$8, "top", _p$.e = _v$5);
402
- _v$6 !== _p$.t && web.setStyleProperty(_el$8, "left", _p$.t = _v$6);
403
- _v$7 !== _p$.a && web.setStyleProperty(_el$8, "opacity", _p$.a = _v$7);
404
- _v$8 !== _p$.o && web.setStyleProperty(_el$0, "width", _p$.o = _v$8);
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$8;
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
- var ReactGrabOverlay = (props) => {
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(Overlay, {
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
- lerpFactor: SELECTION_LERP_FACTOR
633
+ visible: true
431
634
  });
432
635
  }
433
636
  }), web.createComponent(solidJs.Show, {
434
637
  get when() {
435
- return web.memo(() => !!props.marqueeVisible)() && props.marqueeBounds;
638
+ return web.memo(() => !!props.dragVisible)() && props.dragBounds;
436
639
  },
437
640
  get children() {
438
- return web.createComponent(Overlay, {
439
- variant: "marquee",
641
+ return web.createComponent(SelectionBox, {
642
+ variant: "drag",
440
643
  get bounds() {
441
- return props.marqueeBounds;
644
+ return props.dragBounds;
442
645
  },
443
646
  get visible() {
444
- return props.marqueeVisible;
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.grabbedOverlays ?? [];
653
+ return props.grabbedBoxes ?? [];
452
654
  },
453
- children: (overlay) => web.createComponent(Overlay, {
655
+ children: (box) => web.createComponent(SelectionBox, {
454
656
  variant: "grabbed",
455
657
  get bounds() {
456
- return overlay.bounds;
658
+ return box.bounds;
457
659
  },
458
- visible: true
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.filter(isValidSource);
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(-1e3);
837
- const [mouseY, setMouseY] = solidJs.createSignal(-1e3);
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(-1e3);
840
- const [dragStartY, setDragStartY] = solidJs.createSignal(-1e3);
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 [grabbedOverlays, setGrabbedOverlays] = solidJs.createSignal([]);
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
- const isOverlayActive = solidJs.createMemo(() => isActivated() && !isCopying());
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 getElementAtPosition = (x, y) => {
855
- const elementsAtPoint = document.elementsFromPoint(x, y);
856
- for (const candidateElement of elementsAtPoint) {
857
- if (candidateElement.closest(`[${ATTRIBUTE_NAME}]`)) {
858
- continue;
859
- }
860
- const computedStyle = window.getComputedStyle(candidateElement);
861
- if (!isElementVisible(candidateElement, computedStyle)) {
862
- continue;
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
- setGrabbedOverlays((prev) => prev.filter((overlay) => overlay.id !== id));
960
- }, 300);
1213
+ setGrabbedBoxes((previousBoxes) => previousBoxes.filter((box) => box.id !== boxId));
1214
+ }, SUCCESS_LABEL_DURATION_MS);
961
1215
  };
962
- const addSuccessLabel = (text, x, y) => {
963
- const id = `success-${Date.now()}-${Math.random()}`;
964
- setSuccessLabels((prev) => [...prev, {
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((prev) => prev.filter((label) => label.id !== id));
972
- }, 1700);
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.tagName || "").toLowerCase();
977
- addGrabbedOverlay({
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 elementHtml = getHTMLSnippet(targetElement2);
987
- await copyContent(wrapInReferencedElement(elementHtml));
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 minX = Infinity;
1003
- let minY = Infinity;
1266
+ let minPositionX = Infinity;
1267
+ let minPositionY = Infinity;
1004
1268
  for (const element of targetElements) {
1005
1269
  const elementBounds = element.getBoundingClientRect();
1006
- minX = Math.min(minX, elementBounds.left);
1007
- minY = Math.min(minY, elementBounds.top);
1008
- addGrabbedOverlay({
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(wrapInReferencedElements(combinedContent));
1277
+ await copyContent(wrapContextInXmlTags(combinedContent));
1034
1278
  } catch {
1035
1279
  }
1036
- addSuccessLabel(`${targetElements.length} elements`, minX, minY);
1280
+ addSuccessLabel(`${targetElements.length} elements`, minPositionX, minPositionY);
1037
1281
  };
1038
1282
  const targetElement = solidJs.createMemo(() => {
1039
- if (!isOverlayActive() || isDragging()) return null;
1283
+ if (!isRendererActive() || isDragging()) return null;
1040
1284
  return getElementAtPosition(mouseX(), mouseY());
1041
1285
  });
1042
1286
  const selectionBounds = solidJs.createMemo(() => {
1043
- const element = targetElement() ?? lastGrabbedElement();
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 marqueeBounds = solidJs.createMemo(() => {
1057
- if (!isDragging()) return void 0;
1058
- const marqueeX = Math.min(dragStartX(), mouseX());
1059
- const marqueeY = Math.min(dragStartY(), mouseY());
1060
- const marqueeWidth = Math.abs(mouseX() - dragStartX());
1061
- const marqueeHeight = Math.abs(mouseY() - dragStartY());
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: marqueeHeight,
1327
+ height: drag.height,
1065
1328
  transform: "none",
1066
- width: marqueeWidth,
1067
- x: marqueeX,
1068
- y: marqueeY
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.tagName || "").toLowerCase();
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.createEffect(() => {
1092
- const current = targetElement();
1093
- const last = lastGrabbedElement();
1094
- if (last && current && last !== current) {
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 elapsed = Date.now() - startTime;
1103
- return Math.min(elapsed / options.keyHoldDuration, 1);
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
- }, 150);
1369
+ }, PROGRESS_INDICATOR_DELAY_MS);
1112
1370
  const animateProgress = () => {
1113
1371
  if (progressStartTime() === null) return;
1114
- setProgressTick((t) => t + 1);
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 activateOverlay = () => {
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 signal = abortController.signal;
1410
+ const eventListenerSignal = abortController.signal;
1140
1411
  window.addEventListener("keydown", (event) => {
1141
1412
  if (event.key === "Escape" && isHoldingKeys()) {
1142
- setIsHoldingKeys(false);
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) && !isHoldingKeys()) {
1150
- setIsHoldingKeys(true);
1151
- startProgressAnimation();
1152
- holdTimerId = window.setTimeout(() => {
1153
- activateOverlay();
1154
- options.onActivate?.();
1155
- }, options.keyHoldDuration);
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() && (!isTargetKeyCombination(event) || event.key.toLowerCase() === "c")) {
1162
- setIsHoldingKeys(false);
1163
- setIsActivated(false);
1164
- if (holdTimerId) window.clearTimeout(holdTimerId);
1165
- stopProgressAnimation();
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 (!isOverlayActive() || isCopying()) return;
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 dragDistanceX = Math.abs(event.clientX - dragStartX());
1187
- const dragDistanceY = Math.abs(event.clientY - dragStartY());
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
- if (wasDrag) {
1192
- const marqueeX = Math.min(dragStartX(), event.clientX);
1193
- const marqueeY = Math.min(dragStartY(), event.clientY);
1194
- const marqueeWidth = Math.abs(event.clientX - dragStartX());
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 = getElementsInMarqueeLoose({
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
- setGrabbedOverlays([]);
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 overlayRoot = mountRoot();
1255
- const overlayProps = solidJs.createMemo(() => ({
1256
- selectionVisible: isOverlayActive() && !isDragging() && !!selectionBounds(),
1257
- selectionBounds: selectionBounds(),
1258
- marqueeVisible: isOverlayActive() && isDragging(),
1259
- marqueeBounds: marqueeBounds(),
1260
- grabbedOverlays: grabbedOverlays(),
1261
- successLabels: successLabels(),
1262
- labelVariant: isCopying() ? "processing" : "hover",
1263
- labelText: labelText(),
1264
- labelX: labelPosition().x,
1265
- labelY: labelPosition().y,
1266
- labelVisible: isOverlayActive() && !isDragging() && !!targetElement() || isCopying(),
1267
- progressVisible: isHoldingKeys() && showProgressIndicator(),
1268
- progress: progress(),
1269
- mouseX: mouseX(),
1270
- mouseY: mouseY()
1271
- }));
1272
- web.render(() => web.createComponent(ReactGrabOverlay, web.mergeProps(overlayProps)), overlayRoot);
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;