react-grab 0.1.19 → 0.1.20

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.js CHANGED
@@ -1,4 +1,4 @@
1
- import {i}from'./chunk-F2RYLP4R.js';export{f as DEFAULT_THEME,g as commentPlugin,c as formatElementInfo,e as generateSnippet,b as getStack,i as init,a as isInstrumentationActive,h as openPlugin}from'./chunk-F2RYLP4R.js';/**
1
+ import {i}from'./chunk-5NNTSQ2N.js';export{f as DEFAULT_THEME,g as commentPlugin,c as formatElementInfo,e as generateSnippet,b as getStack,i as init,a as isInstrumentationActive,h as openPlugin}from'./chunk-5NNTSQ2N.js';/**
2
2
  * @license MIT
3
3
  *
4
4
  * Copyright (c) 2025 Aiden Bai
package/dist/react.cjs CHANGED
@@ -2148,11 +2148,11 @@ var init_store = __esm({
2148
2148
  });
2149
2149
 
2150
2150
  // src/constants.ts
2151
- var VERSION, VIEWPORT_MARGIN_PX, OFFSCREEN_POSITION, SELECTION_LERP_FACTOR, FEEDBACK_DURATION_MS, FADE_DURATION_MS, FADE_COMPLETE_BUFFER_MS, DISMISS_ANIMATION_BUFFER_MS, KEYDOWN_SPAM_TIMEOUT_MS, BLUR_DEACTIVATION_THRESHOLD_MS, WINDOW_REFOCUS_GRACE_PERIOD_MS, INPUT_FOCUS_ACTIVATION_DELAY_MS, INPUT_TEXT_SELECTION_ACTIVATION_DELAY_MS, DEFERRED_EXECUTION_DELAY_MS, DEFAULT_KEY_HOLD_DURATION_MS, MIN_HOLD_FOR_ACTIVATION_AFTER_COPY_MS, RECENT_THRESHOLD_MS, FINDER_TIMEOUT_MS, SELECTOR_ATTR_VALUE_MAX_LENGTH_CHARS, ACTION_CYCLE_IDLE_TRIGGER_MS, DRAG_THRESHOLD_PX, ELEMENT_DETECTION_THROTTLE_MS, COMPONENT_NAME_DEBOUNCE_MS, DRAG_PREVIEW_DEBOUNCE_MS, BOUNDS_CACHE_TTL_MS, BOUNDS_RECALC_INTERVAL_MS, AUTO_SCROLL_EDGE_THRESHOLD_PX, AUTO_SCROLL_SPEED_PX, Z_INDEX_HOST, Z_INDEX_LABEL, Z_INDEX_OVERLAY_CANVAS, DRAG_LERP_FACTOR, LERP_CONVERGENCE_THRESHOLD_PX, FADE_OUT_BUFFER_MS, MIN_DEVICE_PIXEL_RATIO, GRAB_PURPLE_RGB, OVERLAY_CROSSHAIR_COLOR, OVERLAY_BORDER_COLOR_DRAG, OVERLAY_FILL_COLOR_DRAG, OVERLAY_BORDER_COLOR_DEFAULT, OVERLAY_FILL_COLOR_DEFAULT, FROZEN_GLOW_COLOR, FROZEN_GLOW_EDGE_PX, ARROW_HEIGHT_PX, ARROW_MIN_SIZE_PX, ARROW_MAX_LABEL_WIDTH_RATIO, ARROW_CENTER_PERCENT, ARROW_LABEL_MARGIN_PX, LABEL_GAP_PX, PREVIEW_TEXT_MAX_LENGTH, PREVIEW_ATTR_VALUE_MAX_LENGTH, PREVIEW_MAX_ATTRS, PREVIEW_PRIORITY_ATTRS, SYMBOLICATION_TIMEOUT_MS, MODIFIER_KEYS, ARROW_KEYS, FROZEN_ELEMENT_ATTRIBUTE, USER_IGNORE_ATTRIBUTE, VIEWPORT_COVERAGE_THRESHOLD, OVERLAY_Z_INDEX_THRESHOLD, DEV_TOOLS_OVERLAY_Z_INDEX_THRESHOLD, TOOLTIP_DELAY_MS, TOOLTIP_GRACE_PERIOD_MS, TOOLBAR_SNAP_MARGIN_PX, TOOLBAR_FADE_IN_DELAY_MS, TOOLBAR_SNAP_ANIMATION_DURATION_MS, TOOLBAR_DRAG_THRESHOLD_PX, TOOLBAR_VELOCITY_MULTIPLIER_MS, TOOLBAR_COLLAPSED_SHORT_PX, TOOLBAR_COLLAPSED_LONG_PX, TOOLBAR_COLLAPSE_ANIMATION_DURATION_MS, TOGGLE_ANIMATION_BUFFER_MS, TOOLBAR_DEFAULT_WIDTH_PX, TOOLBAR_DEFAULT_HEIGHT_PX, TOOLBAR_SHAKE_TOOLTIP_DURATION_MS, DRAG_SELECTION_COVERAGE_THRESHOLD, DRAG_SELECTION_SAMPLE_SPACING_PX, DRAG_SELECTION_MIN_SAMPLES_PER_AXIS, DRAG_SELECTION_MAX_SAMPLES_PER_AXIS, DRAG_SELECTION_MAX_TOTAL_SAMPLE_POINTS, DRAG_SELECTION_EDGE_INSET_PX, MAX_ARROW_NAVIGATION_HISTORY, MAX_MEMORY_SESSIONS, MAX_TRANSFORM_ANCESTOR_DEPTH, TRANSFORM_EARLY_BAIL_DEPTH, ELEMENT_POSITION_CACHE_DISTANCE_THRESHOLD_PX, ELEMENT_POSITION_THROTTLE_MS, VISIBILITY_CACHE_TTL_MS, ZOOM_DETECTION_THRESHOLD, MOUNT_ROOT_RECHECK_DELAY_MS, MAX_HISTORY_ITEMS, MAX_SESSION_STORAGE_SIZE_BYTES, DROPDOWN_ANIMATION_DURATION_MS, DROPDOWN_HOVER_OPEN_DELAY_MS, DROPDOWN_VIEWPORT_PADDING_PX, DROPDOWN_ANCHOR_GAP_PX, SAFE_POLYGON_BUFFER_PX, DROPDOWN_ICON_SIZE_PX, DROPDOWN_MIN_WIDTH_PX, DROPDOWN_MAX_WIDTH_PX, TOOLBAR_MENU_MIN_WIDTH_PX, PANEL_STYLES, DROPDOWN_OFFSCREEN_POSITION, DROPDOWN_EDGE_TRANSFORM_ORIGIN, LOGO_SVG, NEXTJS_REVALIDATION_DELAY_MS, IME_COMPOSING_KEY_CODE, SELECTION_LABEL_OFFSCREEN_PX, RELEVANT_CSS_PROPERTIES;
2151
+ var VERSION, VIEWPORT_MARGIN_PX, OFFSCREEN_POSITION, SELECTION_LERP_FACTOR, FEEDBACK_DURATION_MS, FADE_DURATION_MS, FADE_COMPLETE_BUFFER_MS, DISMISS_ANIMATION_BUFFER_MS, KEYDOWN_SPAM_TIMEOUT_MS, BLUR_DEACTIVATION_THRESHOLD_MS, WINDOW_REFOCUS_GRACE_PERIOD_MS, INPUT_FOCUS_ACTIVATION_DELAY_MS, INPUT_TEXT_SELECTION_ACTIVATION_DELAY_MS, DEFERRED_EXECUTION_DELAY_MS, DEFAULT_KEY_HOLD_DURATION_MS, MIN_HOLD_FOR_ACTIVATION_AFTER_COPY_MS, RECENT_THRESHOLD_MS, FINDER_TIMEOUT_MS, SELECTOR_ATTR_VALUE_MAX_LENGTH_CHARS, ACTION_CYCLE_IDLE_TRIGGER_MS, DRAG_THRESHOLD_PX, ELEMENT_DETECTION_THROTTLE_MS, PENDING_DETECTION_STALENESS_MS, COMPONENT_NAME_DEBOUNCE_MS, DRAG_PREVIEW_DEBOUNCE_MS, BOUNDS_CACHE_TTL_MS, BOUNDS_RECALC_INTERVAL_MS, AUTO_SCROLL_EDGE_THRESHOLD_PX, AUTO_SCROLL_SPEED_PX, Z_INDEX_HOST, Z_INDEX_LABEL, Z_INDEX_OVERLAY_CANVAS, DRAG_LERP_FACTOR, LERP_CONVERGENCE_THRESHOLD_PX, FADE_OUT_BUFFER_MS, MIN_DEVICE_PIXEL_RATIO, GRAB_PURPLE_RGB, OVERLAY_CROSSHAIR_COLOR, OVERLAY_BORDER_COLOR_DRAG, OVERLAY_FILL_COLOR_DRAG, OVERLAY_BORDER_COLOR_DEFAULT, OVERLAY_FILL_COLOR_DEFAULT, FROZEN_GLOW_COLOR, FROZEN_GLOW_EDGE_PX, ARROW_HEIGHT_PX, ARROW_MIN_SIZE_PX, ARROW_MAX_LABEL_WIDTH_RATIO, ARROW_CENTER_PERCENT, ARROW_LABEL_MARGIN_PX, LABEL_GAP_PX, PREVIEW_TEXT_MAX_LENGTH, PREVIEW_ATTR_VALUE_MAX_LENGTH, PREVIEW_MAX_ATTRS, PREVIEW_PRIORITY_ATTRS, SYMBOLICATION_TIMEOUT_MS, MODIFIER_KEYS, ARROW_KEYS, FROZEN_ELEMENT_ATTRIBUTE, USER_IGNORE_ATTRIBUTE, VIEWPORT_COVERAGE_THRESHOLD, OVERLAY_Z_INDEX_THRESHOLD, DEV_TOOLS_OVERLAY_Z_INDEX_THRESHOLD, TOOLTIP_DELAY_MS, TOOLTIP_GRACE_PERIOD_MS, TOOLBAR_SNAP_MARGIN_PX, TOOLBAR_FADE_IN_DELAY_MS, TOOLBAR_SNAP_ANIMATION_DURATION_MS, TOOLBAR_DRAG_THRESHOLD_PX, TOOLBAR_VELOCITY_MULTIPLIER_MS, TOOLBAR_COLLAPSED_SHORT_PX, TOOLBAR_COLLAPSED_LONG_PX, TOOLBAR_COLLAPSE_ANIMATION_DURATION_MS, TOGGLE_ANIMATION_BUFFER_MS, TOOLBAR_DEFAULT_WIDTH_PX, TOOLBAR_DEFAULT_HEIGHT_PX, TOOLBAR_SHAKE_TOOLTIP_DURATION_MS, DRAG_SELECTION_COVERAGE_THRESHOLD, DRAG_SELECTION_SAMPLE_SPACING_PX, DRAG_SELECTION_MIN_SAMPLES_PER_AXIS, DRAG_SELECTION_MAX_SAMPLES_PER_AXIS, DRAG_SELECTION_MAX_TOTAL_SAMPLE_POINTS, DRAG_SELECTION_EDGE_INSET_PX, MAX_ARROW_NAVIGATION_HISTORY, MAX_MEMORY_SESSIONS, MAX_TRANSFORM_ANCESTOR_DEPTH, TRANSFORM_EARLY_BAIL_DEPTH, ELEMENT_POSITION_CACHE_DISTANCE_THRESHOLD_PX, ELEMENT_POSITION_THROTTLE_MS, POINTER_EVENTS_RESUME_DEBOUNCE_MS, VISIBILITY_CACHE_TTL_MS, ZOOM_DETECTION_THRESHOLD, MOUNT_ROOT_RECHECK_DELAY_MS, MAX_HISTORY_ITEMS, MAX_SESSION_STORAGE_SIZE_BYTES, DROPDOWN_ANIMATION_DURATION_MS, DROPDOWN_HOVER_OPEN_DELAY_MS, DROPDOWN_VIEWPORT_PADDING_PX, DROPDOWN_ANCHOR_GAP_PX, SAFE_POLYGON_BUFFER_PX, DROPDOWN_ICON_SIZE_PX, DROPDOWN_MIN_WIDTH_PX, DROPDOWN_MAX_WIDTH_PX, TOOLBAR_MENU_MIN_WIDTH_PX, PANEL_STYLES, DROPDOWN_OFFSCREEN_POSITION, DROPDOWN_EDGE_TRANSFORM_ORIGIN, LOGO_SVG, NEXTJS_REVALIDATION_DELAY_MS, IME_COMPOSING_KEY_CODE, SELECTION_LABEL_OFFSCREEN_PX, RELEVANT_CSS_PROPERTIES;
2152
2152
  var init_constants = __esm({
2153
2153
  "src/constants.ts"() {
2154
2154
  "use strict";
2155
- VERSION = "0.1.19";
2155
+ VERSION = "0.1.20";
2156
2156
  VIEWPORT_MARGIN_PX = 8;
2157
2157
  OFFSCREEN_POSITION = -1e3;
2158
2158
  SELECTION_LERP_FACTOR = 0.95;
@@ -2174,6 +2174,7 @@ var init_constants = __esm({
2174
2174
  ACTION_CYCLE_IDLE_TRIGGER_MS = 600;
2175
2175
  DRAG_THRESHOLD_PX = 2;
2176
2176
  ELEMENT_DETECTION_THROTTLE_MS = 32;
2177
+ PENDING_DETECTION_STALENESS_MS = 200;
2177
2178
  COMPONENT_NAME_DEBOUNCE_MS = 100;
2178
2179
  DRAG_PREVIEW_DEBOUNCE_MS = 32;
2179
2180
  BOUNDS_CACHE_TTL_MS = 16;
@@ -2257,6 +2258,7 @@ var init_constants = __esm({
2257
2258
  TRANSFORM_EARLY_BAIL_DEPTH = 3;
2258
2259
  ELEMENT_POSITION_CACHE_DISTANCE_THRESHOLD_PX = 2;
2259
2260
  ELEMENT_POSITION_THROTTLE_MS = 16;
2261
+ POINTER_EVENTS_RESUME_DEBOUNCE_MS = 100;
2260
2262
  VISIBILITY_CACHE_TTL_MS = 50;
2261
2263
  ZOOM_DETECTION_THRESHOLD = 0.01;
2262
2264
  MOUNT_ROOT_RECHECK_DELAY_MS = 1e3;
@@ -8368,16 +8370,7 @@ var init_selection_label = __esm({
8368
8370
  }
8369
8371
  return false;
8370
8372
  };
8371
- const measureContainer = () => {
8372
- if (containerRef && !isTagCurrentlyHovered) {
8373
- const rect = containerRef.getBoundingClientRect();
8374
- setMeasuredWidth(rect.width);
8375
- setMeasuredHeight(rect.height);
8376
- }
8377
- if (panelRef) {
8378
- setPanelWidth(panelRef.getBoundingClientRect().width);
8379
- }
8380
- };
8373
+ let resizeObserver;
8381
8374
  const handleTagHoverChange = (hovered) => {
8382
8375
  isTagCurrentlyHovered = hovered;
8383
8376
  };
@@ -8401,7 +8394,27 @@ var init_selection_label = __esm({
8401
8394
  }
8402
8395
  };
8403
8396
  onMount(() => {
8404
- measureContainer();
8397
+ resizeObserver = new ResizeObserver((entries) => {
8398
+ for (const entry of entries) {
8399
+ const rect = entry.target.getBoundingClientRect();
8400
+ if (entry.target === containerRef && !isTagCurrentlyHovered) {
8401
+ setMeasuredWidth(rect.width);
8402
+ setMeasuredHeight(rect.height);
8403
+ } else if (entry.target === panelRef) {
8404
+ setPanelWidth(rect.width);
8405
+ }
8406
+ }
8407
+ });
8408
+ if (containerRef) {
8409
+ const rect = containerRef.getBoundingClientRect();
8410
+ setMeasuredWidth(rect.width);
8411
+ setMeasuredHeight(rect.height);
8412
+ resizeObserver.observe(containerRef);
8413
+ }
8414
+ if (panelRef) {
8415
+ setPanelWidth(panelRef.getBoundingClientRect().width);
8416
+ resizeObserver.observe(panelRef);
8417
+ }
8405
8418
  window.addEventListener("scroll", handleViewportChange, true);
8406
8419
  window.addEventListener("resize", handleViewportChange);
8407
8420
  window.addEventListener("keydown", handleGlobalKeyDown, {
@@ -8409,6 +8422,7 @@ var init_selection_label = __esm({
8409
8422
  });
8410
8423
  });
8411
8424
  onCleanup(() => {
8425
+ resizeObserver?.disconnect();
8412
8426
  window.removeEventListener("scroll", handleViewportChange, true);
8413
8427
  window.removeEventListener("resize", handleViewportChange);
8414
8428
  window.removeEventListener("keydown", handleGlobalKeyDown, {
@@ -8422,11 +8436,6 @@ var init_selection_label = __esm({
8422
8436
  lastValidPosition = null;
8423
8437
  }
8424
8438
  });
8425
- const sizeAffectingSignature = createMemo(() => [props.tagName, props.componentName, props.elementsCount, props.statusText, props.inputValue, props.hasAgent, props.isPromptMode, props.isPendingDismiss, props.error, props.isPendingAbort, props.visible, props.status, props.actionCycleState?.items, props.actionCycleState?.activeIndex, props.actionCycleState?.isVisible]);
8426
- createEffect(() => {
8427
- void sizeAffectingSignature();
8428
- queueMicrotask(measureContainer);
8429
- });
8430
8439
  createEffect(() => {
8431
8440
  if (props.isPromptMode && inputRef && props.onSubmit) {
8432
8441
  const focusTimeout = setTimeout(() => {
@@ -8629,9 +8638,6 @@ var init_selection_label = __esm({
8629
8638
  get onFollowUpSubmit() {
8630
8639
  return props.onFollowUpSubmit;
8631
8640
  },
8632
- onCopyStateChange: () => {
8633
- queueMicrotask(measureContainer);
8634
- },
8635
8641
  onFadingChange: setIsInternalFading,
8636
8642
  get onShowContextMenu() {
8637
8643
  return props.onShowContextMenu;
@@ -9818,37 +9824,62 @@ var init_is_valid_grabbable_element = __esm({
9818
9824
  return cached.isVisible;
9819
9825
  }
9820
9826
  const computedStyle = window.getComputedStyle(element);
9821
- if (isDevToolsOverlay(computedStyle)) {
9827
+ const isVisible = isElementVisible(element, computedStyle);
9828
+ if (!isVisible) {
9829
+ visibilityCache.set(element, { isVisible: false, timestamp: now });
9822
9830
  return false;
9823
9831
  }
9824
- if (isFullViewportOverlay(element, computedStyle)) {
9825
- return false;
9832
+ const couldBeOverlay = element.clientWidth / window.innerWidth >= VIEWPORT_COVERAGE_THRESHOLD && element.clientHeight / window.innerHeight >= VIEWPORT_COVERAGE_THRESHOLD;
9833
+ if (couldBeOverlay) {
9834
+ if (isDevToolsOverlay(computedStyle)) {
9835
+ return false;
9836
+ }
9837
+ if (isFullViewportOverlay(element, computedStyle)) {
9838
+ return false;
9839
+ }
9826
9840
  }
9827
- const isVisible = isElementVisible(element, computedStyle);
9828
- visibilityCache.set(element, { isVisible, timestamp: now });
9829
- return isVisible;
9841
+ visibilityCache.set(element, { isVisible: true, timestamp: now });
9842
+ return true;
9830
9843
  };
9831
9844
  }
9832
9845
  });
9833
9846
 
9834
9847
  // src/utils/get-element-at-position.ts
9835
- var cache, isWithinThreshold, getElementsAtPoint, getElementAtPosition, clearElementPositionCache;
9848
+ var cache, resumeTimerId, scheduleResume, cancelScheduledResume, isWithinThreshold, getElementsAtPoint, getElementAtPosition, clearElementPositionCache;
9836
9849
  var init_get_element_at_position = __esm({
9837
9850
  "src/utils/get-element-at-position.ts"() {
9838
9851
  "use strict";
9839
9852
  init_is_valid_grabbable_element();
9840
9853
  init_constants();
9841
9854
  init_freeze_pseudo_states();
9855
+ init_create_element_bounds();
9842
9856
  cache = null;
9857
+ resumeTimerId = null;
9858
+ scheduleResume = () => {
9859
+ if (resumeTimerId !== null) {
9860
+ clearTimeout(resumeTimerId);
9861
+ }
9862
+ resumeTimerId = setTimeout(() => {
9863
+ resumeTimerId = null;
9864
+ resumePointerEventsFreeze();
9865
+ }, POINTER_EVENTS_RESUME_DEBOUNCE_MS);
9866
+ };
9867
+ cancelScheduledResume = () => {
9868
+ if (resumeTimerId !== null) {
9869
+ clearTimeout(resumeTimerId);
9870
+ resumeTimerId = null;
9871
+ }
9872
+ };
9843
9873
  isWithinThreshold = (x1, y1, x22, y22) => {
9844
9874
  const deltaX = Math.abs(x1 - x22);
9845
9875
  const deltaY = Math.abs(y1 - y22);
9846
9876
  return deltaX <= ELEMENT_POSITION_CACHE_DISTANCE_THRESHOLD_PX && deltaY <= ELEMENT_POSITION_CACHE_DISTANCE_THRESHOLD_PX;
9847
9877
  };
9848
9878
  getElementsAtPoint = (clientX, clientY) => {
9879
+ cancelScheduledResume();
9849
9880
  suspendPointerEventsFreeze();
9850
9881
  const elements = document.elementsFromPoint(clientX, clientY);
9851
- resumePointerEventsFreeze();
9882
+ scheduleResume();
9852
9883
  return elements;
9853
9884
  };
9854
9885
  getElementAtPosition = (clientX, clientY) => {
@@ -9865,18 +9896,31 @@ var init_get_element_at_position = __esm({
9865
9896
  return cache.element;
9866
9897
  }
9867
9898
  }
9868
- const elementsAtPoint = getElementsAtPoint(clientX, clientY);
9899
+ cancelScheduledResume();
9900
+ suspendPointerEventsFreeze();
9869
9901
  let result = null;
9870
- for (const candidateElement of elementsAtPoint) {
9871
- if (isValidGrabbableElement(candidateElement)) {
9872
- result = candidateElement;
9873
- break;
9902
+ const topElement = document.elementFromPoint(clientX, clientY);
9903
+ if (topElement && isValidGrabbableElement(topElement)) {
9904
+ result = topElement;
9905
+ } else {
9906
+ const elementsAtPoint = document.elementsFromPoint(clientX, clientY);
9907
+ for (const candidateElement of elementsAtPoint) {
9908
+ if (candidateElement !== topElement && isValidGrabbableElement(candidateElement)) {
9909
+ result = candidateElement;
9910
+ break;
9911
+ }
9874
9912
  }
9875
9913
  }
9914
+ if (result) {
9915
+ createElementBounds(result);
9916
+ }
9917
+ scheduleResume();
9876
9918
  cache = { clientX, clientY, element: result, timestamp: now };
9877
9919
  return result;
9878
9920
  };
9879
9921
  clearElementPositionCache = () => {
9922
+ cancelScheduledResume();
9923
+ resumePointerEventsFreeze();
9880
9924
  cache = null;
9881
9925
  };
9882
9926
  }
@@ -15025,7 +15069,7 @@ var init_log_intro = __esm({
15025
15069
  init_is_extension_context();
15026
15070
  logIntro = () => {
15027
15071
  try {
15028
- const version = "0.1.19";
15072
+ const version = "0.1.20";
15029
15073
  const logoDataUri = `data:image/svg+xml;base64,${btoa(LOGO_SVG)}`;
15030
15074
  console.log(
15031
15075
  `%cReact Grab${version ? ` v${version}` : ""}%c
@@ -15795,6 +15839,9 @@ var init_core = __esm({
15795
15839
  return createElementBounds(element);
15796
15840
  };
15797
15841
  let lastElementDetectionTime = 0;
15842
+ let pendingDetectionScheduledAt = 0;
15843
+ let latestDetectionX = 0;
15844
+ let latestDetectionY = 0;
15798
15845
  let dragPreviewDebounceTimerId = null;
15799
15846
  const [debouncedDragPointer, setDebouncedDragPointer] = createSignal(null);
15800
15847
  const scheduleDragPreviewUpdate = (clientX, clientY) => {
@@ -16714,12 +16761,19 @@ var init_core = __esm({
16714
16761
  x: clientX,
16715
16762
  y: clientY
16716
16763
  });
16764
+ latestDetectionX = clientX;
16765
+ latestDetectionY = clientY;
16717
16766
  const now = performance.now();
16718
- if (now - lastElementDetectionTime >= ELEMENT_DETECTION_THROTTLE_MS) {
16767
+ const isDetectionPending = pendingDetectionScheduledAt > 0 && now - pendingDetectionScheduledAt < PENDING_DETECTION_STALENESS_MS;
16768
+ if (now - lastElementDetectionTime >= ELEMENT_DETECTION_THROTTLE_MS && !isDetectionPending) {
16719
16769
  lastElementDetectionTime = now;
16770
+ pendingDetectionScheduledAt = now;
16720
16771
  onIdle(() => {
16721
- const candidate = getElementAtPosition(clientX, clientY);
16722
- actions.setDetectedElement(candidate);
16772
+ const candidate = getElementAtPosition(latestDetectionX, latestDetectionY);
16773
+ if (candidate !== store.detectedElement) {
16774
+ actions.setDetectedElement(candidate);
16775
+ }
16776
+ pendingDetectionScheduledAt = 0;
16723
16777
  });
16724
16778
  }
16725
16779
  if (isDragging()) {
package/dist/react.js CHANGED
@@ -2136,11 +2136,11 @@ var init_store = __esm({
2136
2136
  });
2137
2137
 
2138
2138
  // src/constants.ts
2139
- var VERSION, VIEWPORT_MARGIN_PX, OFFSCREEN_POSITION, SELECTION_LERP_FACTOR, FEEDBACK_DURATION_MS, FADE_DURATION_MS, FADE_COMPLETE_BUFFER_MS, DISMISS_ANIMATION_BUFFER_MS, KEYDOWN_SPAM_TIMEOUT_MS, BLUR_DEACTIVATION_THRESHOLD_MS, WINDOW_REFOCUS_GRACE_PERIOD_MS, INPUT_FOCUS_ACTIVATION_DELAY_MS, INPUT_TEXT_SELECTION_ACTIVATION_DELAY_MS, DEFERRED_EXECUTION_DELAY_MS, DEFAULT_KEY_HOLD_DURATION_MS, MIN_HOLD_FOR_ACTIVATION_AFTER_COPY_MS, RECENT_THRESHOLD_MS, FINDER_TIMEOUT_MS, SELECTOR_ATTR_VALUE_MAX_LENGTH_CHARS, ACTION_CYCLE_IDLE_TRIGGER_MS, DRAG_THRESHOLD_PX, ELEMENT_DETECTION_THROTTLE_MS, COMPONENT_NAME_DEBOUNCE_MS, DRAG_PREVIEW_DEBOUNCE_MS, BOUNDS_CACHE_TTL_MS, BOUNDS_RECALC_INTERVAL_MS, AUTO_SCROLL_EDGE_THRESHOLD_PX, AUTO_SCROLL_SPEED_PX, Z_INDEX_HOST, Z_INDEX_LABEL, Z_INDEX_OVERLAY_CANVAS, DRAG_LERP_FACTOR, LERP_CONVERGENCE_THRESHOLD_PX, FADE_OUT_BUFFER_MS, MIN_DEVICE_PIXEL_RATIO, GRAB_PURPLE_RGB, OVERLAY_CROSSHAIR_COLOR, OVERLAY_BORDER_COLOR_DRAG, OVERLAY_FILL_COLOR_DRAG, OVERLAY_BORDER_COLOR_DEFAULT, OVERLAY_FILL_COLOR_DEFAULT, FROZEN_GLOW_COLOR, FROZEN_GLOW_EDGE_PX, ARROW_HEIGHT_PX, ARROW_MIN_SIZE_PX, ARROW_MAX_LABEL_WIDTH_RATIO, ARROW_CENTER_PERCENT, ARROW_LABEL_MARGIN_PX, LABEL_GAP_PX, PREVIEW_TEXT_MAX_LENGTH, PREVIEW_ATTR_VALUE_MAX_LENGTH, PREVIEW_MAX_ATTRS, PREVIEW_PRIORITY_ATTRS, SYMBOLICATION_TIMEOUT_MS, MODIFIER_KEYS, ARROW_KEYS, FROZEN_ELEMENT_ATTRIBUTE, USER_IGNORE_ATTRIBUTE, VIEWPORT_COVERAGE_THRESHOLD, OVERLAY_Z_INDEX_THRESHOLD, DEV_TOOLS_OVERLAY_Z_INDEX_THRESHOLD, TOOLTIP_DELAY_MS, TOOLTIP_GRACE_PERIOD_MS, TOOLBAR_SNAP_MARGIN_PX, TOOLBAR_FADE_IN_DELAY_MS, TOOLBAR_SNAP_ANIMATION_DURATION_MS, TOOLBAR_DRAG_THRESHOLD_PX, TOOLBAR_VELOCITY_MULTIPLIER_MS, TOOLBAR_COLLAPSED_SHORT_PX, TOOLBAR_COLLAPSED_LONG_PX, TOOLBAR_COLLAPSE_ANIMATION_DURATION_MS, TOGGLE_ANIMATION_BUFFER_MS, TOOLBAR_DEFAULT_WIDTH_PX, TOOLBAR_DEFAULT_HEIGHT_PX, TOOLBAR_SHAKE_TOOLTIP_DURATION_MS, DRAG_SELECTION_COVERAGE_THRESHOLD, DRAG_SELECTION_SAMPLE_SPACING_PX, DRAG_SELECTION_MIN_SAMPLES_PER_AXIS, DRAG_SELECTION_MAX_SAMPLES_PER_AXIS, DRAG_SELECTION_MAX_TOTAL_SAMPLE_POINTS, DRAG_SELECTION_EDGE_INSET_PX, MAX_ARROW_NAVIGATION_HISTORY, MAX_MEMORY_SESSIONS, MAX_TRANSFORM_ANCESTOR_DEPTH, TRANSFORM_EARLY_BAIL_DEPTH, ELEMENT_POSITION_CACHE_DISTANCE_THRESHOLD_PX, ELEMENT_POSITION_THROTTLE_MS, VISIBILITY_CACHE_TTL_MS, ZOOM_DETECTION_THRESHOLD, MOUNT_ROOT_RECHECK_DELAY_MS, MAX_HISTORY_ITEMS, MAX_SESSION_STORAGE_SIZE_BYTES, DROPDOWN_ANIMATION_DURATION_MS, DROPDOWN_HOVER_OPEN_DELAY_MS, DROPDOWN_VIEWPORT_PADDING_PX, DROPDOWN_ANCHOR_GAP_PX, SAFE_POLYGON_BUFFER_PX, DROPDOWN_ICON_SIZE_PX, DROPDOWN_MIN_WIDTH_PX, DROPDOWN_MAX_WIDTH_PX, TOOLBAR_MENU_MIN_WIDTH_PX, PANEL_STYLES, DROPDOWN_OFFSCREEN_POSITION, DROPDOWN_EDGE_TRANSFORM_ORIGIN, LOGO_SVG, NEXTJS_REVALIDATION_DELAY_MS, IME_COMPOSING_KEY_CODE, SELECTION_LABEL_OFFSCREEN_PX, RELEVANT_CSS_PROPERTIES;
2139
+ var VERSION, VIEWPORT_MARGIN_PX, OFFSCREEN_POSITION, SELECTION_LERP_FACTOR, FEEDBACK_DURATION_MS, FADE_DURATION_MS, FADE_COMPLETE_BUFFER_MS, DISMISS_ANIMATION_BUFFER_MS, KEYDOWN_SPAM_TIMEOUT_MS, BLUR_DEACTIVATION_THRESHOLD_MS, WINDOW_REFOCUS_GRACE_PERIOD_MS, INPUT_FOCUS_ACTIVATION_DELAY_MS, INPUT_TEXT_SELECTION_ACTIVATION_DELAY_MS, DEFERRED_EXECUTION_DELAY_MS, DEFAULT_KEY_HOLD_DURATION_MS, MIN_HOLD_FOR_ACTIVATION_AFTER_COPY_MS, RECENT_THRESHOLD_MS, FINDER_TIMEOUT_MS, SELECTOR_ATTR_VALUE_MAX_LENGTH_CHARS, ACTION_CYCLE_IDLE_TRIGGER_MS, DRAG_THRESHOLD_PX, ELEMENT_DETECTION_THROTTLE_MS, PENDING_DETECTION_STALENESS_MS, COMPONENT_NAME_DEBOUNCE_MS, DRAG_PREVIEW_DEBOUNCE_MS, BOUNDS_CACHE_TTL_MS, BOUNDS_RECALC_INTERVAL_MS, AUTO_SCROLL_EDGE_THRESHOLD_PX, AUTO_SCROLL_SPEED_PX, Z_INDEX_HOST, Z_INDEX_LABEL, Z_INDEX_OVERLAY_CANVAS, DRAG_LERP_FACTOR, LERP_CONVERGENCE_THRESHOLD_PX, FADE_OUT_BUFFER_MS, MIN_DEVICE_PIXEL_RATIO, GRAB_PURPLE_RGB, OVERLAY_CROSSHAIR_COLOR, OVERLAY_BORDER_COLOR_DRAG, OVERLAY_FILL_COLOR_DRAG, OVERLAY_BORDER_COLOR_DEFAULT, OVERLAY_FILL_COLOR_DEFAULT, FROZEN_GLOW_COLOR, FROZEN_GLOW_EDGE_PX, ARROW_HEIGHT_PX, ARROW_MIN_SIZE_PX, ARROW_MAX_LABEL_WIDTH_RATIO, ARROW_CENTER_PERCENT, ARROW_LABEL_MARGIN_PX, LABEL_GAP_PX, PREVIEW_TEXT_MAX_LENGTH, PREVIEW_ATTR_VALUE_MAX_LENGTH, PREVIEW_MAX_ATTRS, PREVIEW_PRIORITY_ATTRS, SYMBOLICATION_TIMEOUT_MS, MODIFIER_KEYS, ARROW_KEYS, FROZEN_ELEMENT_ATTRIBUTE, USER_IGNORE_ATTRIBUTE, VIEWPORT_COVERAGE_THRESHOLD, OVERLAY_Z_INDEX_THRESHOLD, DEV_TOOLS_OVERLAY_Z_INDEX_THRESHOLD, TOOLTIP_DELAY_MS, TOOLTIP_GRACE_PERIOD_MS, TOOLBAR_SNAP_MARGIN_PX, TOOLBAR_FADE_IN_DELAY_MS, TOOLBAR_SNAP_ANIMATION_DURATION_MS, TOOLBAR_DRAG_THRESHOLD_PX, TOOLBAR_VELOCITY_MULTIPLIER_MS, TOOLBAR_COLLAPSED_SHORT_PX, TOOLBAR_COLLAPSED_LONG_PX, TOOLBAR_COLLAPSE_ANIMATION_DURATION_MS, TOGGLE_ANIMATION_BUFFER_MS, TOOLBAR_DEFAULT_WIDTH_PX, TOOLBAR_DEFAULT_HEIGHT_PX, TOOLBAR_SHAKE_TOOLTIP_DURATION_MS, DRAG_SELECTION_COVERAGE_THRESHOLD, DRAG_SELECTION_SAMPLE_SPACING_PX, DRAG_SELECTION_MIN_SAMPLES_PER_AXIS, DRAG_SELECTION_MAX_SAMPLES_PER_AXIS, DRAG_SELECTION_MAX_TOTAL_SAMPLE_POINTS, DRAG_SELECTION_EDGE_INSET_PX, MAX_ARROW_NAVIGATION_HISTORY, MAX_MEMORY_SESSIONS, MAX_TRANSFORM_ANCESTOR_DEPTH, TRANSFORM_EARLY_BAIL_DEPTH, ELEMENT_POSITION_CACHE_DISTANCE_THRESHOLD_PX, ELEMENT_POSITION_THROTTLE_MS, POINTER_EVENTS_RESUME_DEBOUNCE_MS, VISIBILITY_CACHE_TTL_MS, ZOOM_DETECTION_THRESHOLD, MOUNT_ROOT_RECHECK_DELAY_MS, MAX_HISTORY_ITEMS, MAX_SESSION_STORAGE_SIZE_BYTES, DROPDOWN_ANIMATION_DURATION_MS, DROPDOWN_HOVER_OPEN_DELAY_MS, DROPDOWN_VIEWPORT_PADDING_PX, DROPDOWN_ANCHOR_GAP_PX, SAFE_POLYGON_BUFFER_PX, DROPDOWN_ICON_SIZE_PX, DROPDOWN_MIN_WIDTH_PX, DROPDOWN_MAX_WIDTH_PX, TOOLBAR_MENU_MIN_WIDTH_PX, PANEL_STYLES, DROPDOWN_OFFSCREEN_POSITION, DROPDOWN_EDGE_TRANSFORM_ORIGIN, LOGO_SVG, NEXTJS_REVALIDATION_DELAY_MS, IME_COMPOSING_KEY_CODE, SELECTION_LABEL_OFFSCREEN_PX, RELEVANT_CSS_PROPERTIES;
2140
2140
  var init_constants = __esm({
2141
2141
  "src/constants.ts"() {
2142
2142
  "use strict";
2143
- VERSION = "0.1.19";
2143
+ VERSION = "0.1.20";
2144
2144
  VIEWPORT_MARGIN_PX = 8;
2145
2145
  OFFSCREEN_POSITION = -1e3;
2146
2146
  SELECTION_LERP_FACTOR = 0.95;
@@ -2162,6 +2162,7 @@ var init_constants = __esm({
2162
2162
  ACTION_CYCLE_IDLE_TRIGGER_MS = 600;
2163
2163
  DRAG_THRESHOLD_PX = 2;
2164
2164
  ELEMENT_DETECTION_THROTTLE_MS = 32;
2165
+ PENDING_DETECTION_STALENESS_MS = 200;
2165
2166
  COMPONENT_NAME_DEBOUNCE_MS = 100;
2166
2167
  DRAG_PREVIEW_DEBOUNCE_MS = 32;
2167
2168
  BOUNDS_CACHE_TTL_MS = 16;
@@ -2245,6 +2246,7 @@ var init_constants = __esm({
2245
2246
  TRANSFORM_EARLY_BAIL_DEPTH = 3;
2246
2247
  ELEMENT_POSITION_CACHE_DISTANCE_THRESHOLD_PX = 2;
2247
2248
  ELEMENT_POSITION_THROTTLE_MS = 16;
2249
+ POINTER_EVENTS_RESUME_DEBOUNCE_MS = 100;
2248
2250
  VISIBILITY_CACHE_TTL_MS = 50;
2249
2251
  ZOOM_DETECTION_THRESHOLD = 0.01;
2250
2252
  MOUNT_ROOT_RECHECK_DELAY_MS = 1e3;
@@ -8356,16 +8358,7 @@ var init_selection_label = __esm({
8356
8358
  }
8357
8359
  return false;
8358
8360
  };
8359
- const measureContainer = () => {
8360
- if (containerRef && !isTagCurrentlyHovered) {
8361
- const rect = containerRef.getBoundingClientRect();
8362
- setMeasuredWidth(rect.width);
8363
- setMeasuredHeight(rect.height);
8364
- }
8365
- if (panelRef) {
8366
- setPanelWidth(panelRef.getBoundingClientRect().width);
8367
- }
8368
- };
8361
+ let resizeObserver;
8369
8362
  const handleTagHoverChange = (hovered) => {
8370
8363
  isTagCurrentlyHovered = hovered;
8371
8364
  };
@@ -8389,7 +8382,27 @@ var init_selection_label = __esm({
8389
8382
  }
8390
8383
  };
8391
8384
  onMount(() => {
8392
- measureContainer();
8385
+ resizeObserver = new ResizeObserver((entries) => {
8386
+ for (const entry of entries) {
8387
+ const rect = entry.target.getBoundingClientRect();
8388
+ if (entry.target === containerRef && !isTagCurrentlyHovered) {
8389
+ setMeasuredWidth(rect.width);
8390
+ setMeasuredHeight(rect.height);
8391
+ } else if (entry.target === panelRef) {
8392
+ setPanelWidth(rect.width);
8393
+ }
8394
+ }
8395
+ });
8396
+ if (containerRef) {
8397
+ const rect = containerRef.getBoundingClientRect();
8398
+ setMeasuredWidth(rect.width);
8399
+ setMeasuredHeight(rect.height);
8400
+ resizeObserver.observe(containerRef);
8401
+ }
8402
+ if (panelRef) {
8403
+ setPanelWidth(panelRef.getBoundingClientRect().width);
8404
+ resizeObserver.observe(panelRef);
8405
+ }
8393
8406
  window.addEventListener("scroll", handleViewportChange, true);
8394
8407
  window.addEventListener("resize", handleViewportChange);
8395
8408
  window.addEventListener("keydown", handleGlobalKeyDown, {
@@ -8397,6 +8410,7 @@ var init_selection_label = __esm({
8397
8410
  });
8398
8411
  });
8399
8412
  onCleanup(() => {
8413
+ resizeObserver?.disconnect();
8400
8414
  window.removeEventListener("scroll", handleViewportChange, true);
8401
8415
  window.removeEventListener("resize", handleViewportChange);
8402
8416
  window.removeEventListener("keydown", handleGlobalKeyDown, {
@@ -8410,11 +8424,6 @@ var init_selection_label = __esm({
8410
8424
  lastValidPosition = null;
8411
8425
  }
8412
8426
  });
8413
- const sizeAffectingSignature = createMemo(() => [props.tagName, props.componentName, props.elementsCount, props.statusText, props.inputValue, props.hasAgent, props.isPromptMode, props.isPendingDismiss, props.error, props.isPendingAbort, props.visible, props.status, props.actionCycleState?.items, props.actionCycleState?.activeIndex, props.actionCycleState?.isVisible]);
8414
- createEffect(() => {
8415
- void sizeAffectingSignature();
8416
- queueMicrotask(measureContainer);
8417
- });
8418
8427
  createEffect(() => {
8419
8428
  if (props.isPromptMode && inputRef && props.onSubmit) {
8420
8429
  const focusTimeout = setTimeout(() => {
@@ -8617,9 +8626,6 @@ var init_selection_label = __esm({
8617
8626
  get onFollowUpSubmit() {
8618
8627
  return props.onFollowUpSubmit;
8619
8628
  },
8620
- onCopyStateChange: () => {
8621
- queueMicrotask(measureContainer);
8622
- },
8623
8629
  onFadingChange: setIsInternalFading,
8624
8630
  get onShowContextMenu() {
8625
8631
  return props.onShowContextMenu;
@@ -9806,37 +9812,62 @@ var init_is_valid_grabbable_element = __esm({
9806
9812
  return cached.isVisible;
9807
9813
  }
9808
9814
  const computedStyle = window.getComputedStyle(element);
9809
- if (isDevToolsOverlay(computedStyle)) {
9815
+ const isVisible = isElementVisible(element, computedStyle);
9816
+ if (!isVisible) {
9817
+ visibilityCache.set(element, { isVisible: false, timestamp: now });
9810
9818
  return false;
9811
9819
  }
9812
- if (isFullViewportOverlay(element, computedStyle)) {
9813
- return false;
9820
+ const couldBeOverlay = element.clientWidth / window.innerWidth >= VIEWPORT_COVERAGE_THRESHOLD && element.clientHeight / window.innerHeight >= VIEWPORT_COVERAGE_THRESHOLD;
9821
+ if (couldBeOverlay) {
9822
+ if (isDevToolsOverlay(computedStyle)) {
9823
+ return false;
9824
+ }
9825
+ if (isFullViewportOverlay(element, computedStyle)) {
9826
+ return false;
9827
+ }
9814
9828
  }
9815
- const isVisible = isElementVisible(element, computedStyle);
9816
- visibilityCache.set(element, { isVisible, timestamp: now });
9817
- return isVisible;
9829
+ visibilityCache.set(element, { isVisible: true, timestamp: now });
9830
+ return true;
9818
9831
  };
9819
9832
  }
9820
9833
  });
9821
9834
 
9822
9835
  // src/utils/get-element-at-position.ts
9823
- var cache, isWithinThreshold, getElementsAtPoint, getElementAtPosition, clearElementPositionCache;
9836
+ var cache, resumeTimerId, scheduleResume, cancelScheduledResume, isWithinThreshold, getElementsAtPoint, getElementAtPosition, clearElementPositionCache;
9824
9837
  var init_get_element_at_position = __esm({
9825
9838
  "src/utils/get-element-at-position.ts"() {
9826
9839
  "use strict";
9827
9840
  init_is_valid_grabbable_element();
9828
9841
  init_constants();
9829
9842
  init_freeze_pseudo_states();
9843
+ init_create_element_bounds();
9830
9844
  cache = null;
9845
+ resumeTimerId = null;
9846
+ scheduleResume = () => {
9847
+ if (resumeTimerId !== null) {
9848
+ clearTimeout(resumeTimerId);
9849
+ }
9850
+ resumeTimerId = setTimeout(() => {
9851
+ resumeTimerId = null;
9852
+ resumePointerEventsFreeze();
9853
+ }, POINTER_EVENTS_RESUME_DEBOUNCE_MS);
9854
+ };
9855
+ cancelScheduledResume = () => {
9856
+ if (resumeTimerId !== null) {
9857
+ clearTimeout(resumeTimerId);
9858
+ resumeTimerId = null;
9859
+ }
9860
+ };
9831
9861
  isWithinThreshold = (x1, y1, x22, y22) => {
9832
9862
  const deltaX = Math.abs(x1 - x22);
9833
9863
  const deltaY = Math.abs(y1 - y22);
9834
9864
  return deltaX <= ELEMENT_POSITION_CACHE_DISTANCE_THRESHOLD_PX && deltaY <= ELEMENT_POSITION_CACHE_DISTANCE_THRESHOLD_PX;
9835
9865
  };
9836
9866
  getElementsAtPoint = (clientX, clientY) => {
9867
+ cancelScheduledResume();
9837
9868
  suspendPointerEventsFreeze();
9838
9869
  const elements = document.elementsFromPoint(clientX, clientY);
9839
- resumePointerEventsFreeze();
9870
+ scheduleResume();
9840
9871
  return elements;
9841
9872
  };
9842
9873
  getElementAtPosition = (clientX, clientY) => {
@@ -9853,18 +9884,31 @@ var init_get_element_at_position = __esm({
9853
9884
  return cache.element;
9854
9885
  }
9855
9886
  }
9856
- const elementsAtPoint = getElementsAtPoint(clientX, clientY);
9887
+ cancelScheduledResume();
9888
+ suspendPointerEventsFreeze();
9857
9889
  let result = null;
9858
- for (const candidateElement of elementsAtPoint) {
9859
- if (isValidGrabbableElement(candidateElement)) {
9860
- result = candidateElement;
9861
- break;
9890
+ const topElement = document.elementFromPoint(clientX, clientY);
9891
+ if (topElement && isValidGrabbableElement(topElement)) {
9892
+ result = topElement;
9893
+ } else {
9894
+ const elementsAtPoint = document.elementsFromPoint(clientX, clientY);
9895
+ for (const candidateElement of elementsAtPoint) {
9896
+ if (candidateElement !== topElement && isValidGrabbableElement(candidateElement)) {
9897
+ result = candidateElement;
9898
+ break;
9899
+ }
9862
9900
  }
9863
9901
  }
9902
+ if (result) {
9903
+ createElementBounds(result);
9904
+ }
9905
+ scheduleResume();
9864
9906
  cache = { clientX, clientY, element: result, timestamp: now };
9865
9907
  return result;
9866
9908
  };
9867
9909
  clearElementPositionCache = () => {
9910
+ cancelScheduledResume();
9911
+ resumePointerEventsFreeze();
9868
9912
  cache = null;
9869
9913
  };
9870
9914
  }
@@ -15013,7 +15057,7 @@ var init_log_intro = __esm({
15013
15057
  init_is_extension_context();
15014
15058
  logIntro = () => {
15015
15059
  try {
15016
- const version = "0.1.19";
15060
+ const version = "0.1.20";
15017
15061
  const logoDataUri = `data:image/svg+xml;base64,${btoa(LOGO_SVG)}`;
15018
15062
  console.log(
15019
15063
  `%cReact Grab${version ? ` v${version}` : ""}%c
@@ -15783,6 +15827,9 @@ var init_core = __esm({
15783
15827
  return createElementBounds(element);
15784
15828
  };
15785
15829
  let lastElementDetectionTime = 0;
15830
+ let pendingDetectionScheduledAt = 0;
15831
+ let latestDetectionX = 0;
15832
+ let latestDetectionY = 0;
15786
15833
  let dragPreviewDebounceTimerId = null;
15787
15834
  const [debouncedDragPointer, setDebouncedDragPointer] = createSignal(null);
15788
15835
  const scheduleDragPreviewUpdate = (clientX, clientY) => {
@@ -16702,12 +16749,19 @@ var init_core = __esm({
16702
16749
  x: clientX,
16703
16750
  y: clientY
16704
16751
  });
16752
+ latestDetectionX = clientX;
16753
+ latestDetectionY = clientY;
16705
16754
  const now = performance.now();
16706
- if (now - lastElementDetectionTime >= ELEMENT_DETECTION_THROTTLE_MS) {
16755
+ const isDetectionPending = pendingDetectionScheduledAt > 0 && now - pendingDetectionScheduledAt < PENDING_DETECTION_STALENESS_MS;
16756
+ if (now - lastElementDetectionTime >= ELEMENT_DETECTION_THROTTLE_MS && !isDetectionPending) {
16707
16757
  lastElementDetectionTime = now;
16758
+ pendingDetectionScheduledAt = now;
16708
16759
  onIdle(() => {
16709
- const candidate = getElementAtPosition(clientX, clientY);
16710
- actions.setDetectedElement(candidate);
16760
+ const candidate = getElementAtPosition(latestDetectionX, latestDetectionY);
16761
+ if (candidate !== store.detectedElement) {
16762
+ actions.setDetectedElement(candidate);
16763
+ }
16764
+ pendingDetectionScheduledAt = 0;
16711
16765
  });
16712
16766
  }
16713
16767
  if (isDragging()) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-grab",
3
- "version": "0.1.19",
3
+ "version": "0.1.20",
4
4
  "description": "Select context for coding agents directly from your website",
5
5
  "keywords": [
6
6
  "agent",