@zag-js/interact-outside 0.72.0 → 0.73.1

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
@@ -5,6 +5,8 @@ var domQuery = require('@zag-js/dom-query');
5
5
  var utils = require('@zag-js/utils');
6
6
 
7
7
  // src/index.ts
8
+
9
+ // src/frame-utils.ts
8
10
  function getWindowFrames(win) {
9
11
  const frames = {
10
12
  each(cb) {
@@ -13,21 +15,6 @@ function getWindowFrames(win) {
13
15
  if (frame) cb(frame);
14
16
  }
15
17
  },
16
- queueBeforeEvent(event, listener) {
17
- const cleanup = /* @__PURE__ */ new Set();
18
- frames.each((frame) => {
19
- try {
20
- cleanup.add(domEvent.queueBeforeEvent(frame.document, event, listener));
21
- } catch {
22
- }
23
- });
24
- return () => {
25
- try {
26
- cleanup.forEach((fn) => fn());
27
- } catch {
28
- }
29
- };
30
- },
31
18
  addEventListener(event, listener, options) {
32
19
  frames.each((frame) => {
33
20
  try {
@@ -53,6 +40,29 @@ function getWindowFrames(win) {
53
40
  };
54
41
  return frames;
55
42
  }
43
+ function getParentWindow(win) {
44
+ const parent = win.frameElement != null ? win.parent : null;
45
+ return {
46
+ addEventListener: (event, listener, options) => {
47
+ try {
48
+ parent?.addEventListener(event, listener, options);
49
+ } catch {
50
+ }
51
+ return () => {
52
+ try {
53
+ parent?.removeEventListener(event, listener, options);
54
+ } catch {
55
+ }
56
+ };
57
+ },
58
+ removeEventListener: (event, listener, options) => {
59
+ try {
60
+ parent?.removeEventListener(event, listener, options);
61
+ } catch {
62
+ }
63
+ }
64
+ };
65
+ }
56
66
 
57
67
  // src/index.ts
58
68
  var POINTER_OUTSIDE_EVENT = "pointerdown.outside";
@@ -70,8 +80,7 @@ function isEventPointWithin(node, event) {
70
80
  if (rect.width === 0 || rect.height === 0) return false;
71
81
  return rect.top <= event.clientY && event.clientY <= rect.top + rect.height && rect.left <= event.clientX && event.clientX <= rect.left + rect.width;
72
82
  }
73
- function isEventWithinScrollbar(event) {
74
- const target = domQuery.getEventTarget(event);
83
+ function isEventWithinScrollbar(event, target) {
75
84
  if (!target || !isPointerEvent(event)) return false;
76
85
  const isScrollableY = target.scrollHeight > target.clientHeight;
77
86
  const onScrollbarY = isScrollableY && event.clientX > target.clientWidth;
@@ -85,12 +94,15 @@ function trackInteractOutsideImpl(node, options) {
85
94
  const doc = domQuery.getDocument(node);
86
95
  const win = domQuery.getWindow(node);
87
96
  const frames = getWindowFrames(win);
97
+ const parentWin = getParentWindow(win);
88
98
  function isEventOutside(event) {
89
99
  const target = domQuery.getEventTarget(event);
90
100
  if (!domQuery.isHTMLElement(target)) return false;
91
101
  if (domQuery.contains(node, target)) return false;
92
102
  if (isEventPointWithin(node, event)) return false;
93
- if (isEventWithinScrollbar(event)) return false;
103
+ if (isEventWithinScrollbar(event, target)) return false;
104
+ const scrollParent = domQuery.getNearestOverflowAncestor(node);
105
+ if (isEventWithinScrollbar(event, scrollParent)) return false;
94
106
  return !exclude?.(target);
95
107
  }
96
108
  const pointerdownCleanups = /* @__PURE__ */ new Set();
@@ -118,6 +130,7 @@ function trackInteractOutsideImpl(node, options) {
118
130
  if (event.pointerType === "touch") {
119
131
  pointerdownCleanups.forEach((fn) => fn());
120
132
  pointerdownCleanups.add(domEvent.addDomEvent(doc, "click", handler, { once: true }));
133
+ pointerdownCleanups.add(parentWin.addEventListener("click", handler, { once: true }));
121
134
  pointerdownCleanups.add(frames.addEventListener("click", handler, { once: true }));
122
135
  } else {
123
136
  handler();
@@ -125,8 +138,9 @@ function trackInteractOutsideImpl(node, options) {
125
138
  }
126
139
  const cleanups = /* @__PURE__ */ new Set();
127
140
  const timer = setTimeout(() => {
128
- cleanups.add(frames.addEventListener("pointerdown", onPointerDown, true));
129
141
  cleanups.add(domEvent.addDomEvent(doc, "pointerdown", onPointerDown, true));
142
+ cleanups.add(parentWin.addEventListener("pointerdown", onPointerDown, true));
143
+ cleanups.add(frames.addEventListener("pointerdown", onPointerDown, true));
130
144
  }, 0);
131
145
  function onFocusin(event) {
132
146
  const func = defer ? domQuery.raf : (v) => v();
@@ -148,6 +162,7 @@ function trackInteractOutsideImpl(node, options) {
148
162
  });
149
163
  }
150
164
  cleanups.add(domEvent.addDomEvent(doc, "focusin", onFocusin, true));
165
+ cleanups.add(parentWin.addEventListener("focusin", onFocusin, true));
151
166
  cleanups.add(frames.addEventListener("focusin", onFocusin, true));
152
167
  return () => {
153
168
  clearTimeout(timer);
package/dist/index.mjs CHANGED
@@ -1,8 +1,10 @@
1
- import { addDomEvent, fireCustomEvent, isContextMenuEvent, queueBeforeEvent } from '@zag-js/dom-event';
2
- import { getDocument, getWindow, raf, isFocusable, getEventTarget, isHTMLElement, contains } from '@zag-js/dom-query';
1
+ import { addDomEvent, fireCustomEvent, isContextMenuEvent } from '@zag-js/dom-event';
2
+ import { getDocument, getWindow, raf, isFocusable, getEventTarget, isHTMLElement, contains, getNearestOverflowAncestor } from '@zag-js/dom-query';
3
3
  import { callAll } from '@zag-js/utils';
4
4
 
5
5
  // src/index.ts
6
+
7
+ // src/frame-utils.ts
6
8
  function getWindowFrames(win) {
7
9
  const frames = {
8
10
  each(cb) {
@@ -11,21 +13,6 @@ function getWindowFrames(win) {
11
13
  if (frame) cb(frame);
12
14
  }
13
15
  },
14
- queueBeforeEvent(event, listener) {
15
- const cleanup = /* @__PURE__ */ new Set();
16
- frames.each((frame) => {
17
- try {
18
- cleanup.add(queueBeforeEvent(frame.document, event, listener));
19
- } catch {
20
- }
21
- });
22
- return () => {
23
- try {
24
- cleanup.forEach((fn) => fn());
25
- } catch {
26
- }
27
- };
28
- },
29
16
  addEventListener(event, listener, options) {
30
17
  frames.each((frame) => {
31
18
  try {
@@ -51,6 +38,29 @@ function getWindowFrames(win) {
51
38
  };
52
39
  return frames;
53
40
  }
41
+ function getParentWindow(win) {
42
+ const parent = win.frameElement != null ? win.parent : null;
43
+ return {
44
+ addEventListener: (event, listener, options) => {
45
+ try {
46
+ parent?.addEventListener(event, listener, options);
47
+ } catch {
48
+ }
49
+ return () => {
50
+ try {
51
+ parent?.removeEventListener(event, listener, options);
52
+ } catch {
53
+ }
54
+ };
55
+ },
56
+ removeEventListener: (event, listener, options) => {
57
+ try {
58
+ parent?.removeEventListener(event, listener, options);
59
+ } catch {
60
+ }
61
+ }
62
+ };
63
+ }
54
64
 
55
65
  // src/index.ts
56
66
  var POINTER_OUTSIDE_EVENT = "pointerdown.outside";
@@ -68,8 +78,7 @@ function isEventPointWithin(node, event) {
68
78
  if (rect.width === 0 || rect.height === 0) return false;
69
79
  return rect.top <= event.clientY && event.clientY <= rect.top + rect.height && rect.left <= event.clientX && event.clientX <= rect.left + rect.width;
70
80
  }
71
- function isEventWithinScrollbar(event) {
72
- const target = getEventTarget(event);
81
+ function isEventWithinScrollbar(event, target) {
73
82
  if (!target || !isPointerEvent(event)) return false;
74
83
  const isScrollableY = target.scrollHeight > target.clientHeight;
75
84
  const onScrollbarY = isScrollableY && event.clientX > target.clientWidth;
@@ -83,12 +92,15 @@ function trackInteractOutsideImpl(node, options) {
83
92
  const doc = getDocument(node);
84
93
  const win = getWindow(node);
85
94
  const frames = getWindowFrames(win);
95
+ const parentWin = getParentWindow(win);
86
96
  function isEventOutside(event) {
87
97
  const target = getEventTarget(event);
88
98
  if (!isHTMLElement(target)) return false;
89
99
  if (contains(node, target)) return false;
90
100
  if (isEventPointWithin(node, event)) return false;
91
- if (isEventWithinScrollbar(event)) return false;
101
+ if (isEventWithinScrollbar(event, target)) return false;
102
+ const scrollParent = getNearestOverflowAncestor(node);
103
+ if (isEventWithinScrollbar(event, scrollParent)) return false;
92
104
  return !exclude?.(target);
93
105
  }
94
106
  const pointerdownCleanups = /* @__PURE__ */ new Set();
@@ -116,6 +128,7 @@ function trackInteractOutsideImpl(node, options) {
116
128
  if (event.pointerType === "touch") {
117
129
  pointerdownCleanups.forEach((fn) => fn());
118
130
  pointerdownCleanups.add(addDomEvent(doc, "click", handler, { once: true }));
131
+ pointerdownCleanups.add(parentWin.addEventListener("click", handler, { once: true }));
119
132
  pointerdownCleanups.add(frames.addEventListener("click", handler, { once: true }));
120
133
  } else {
121
134
  handler();
@@ -123,8 +136,9 @@ function trackInteractOutsideImpl(node, options) {
123
136
  }
124
137
  const cleanups = /* @__PURE__ */ new Set();
125
138
  const timer = setTimeout(() => {
126
- cleanups.add(frames.addEventListener("pointerdown", onPointerDown, true));
127
139
  cleanups.add(addDomEvent(doc, "pointerdown", onPointerDown, true));
140
+ cleanups.add(parentWin.addEventListener("pointerdown", onPointerDown, true));
141
+ cleanups.add(frames.addEventListener("pointerdown", onPointerDown, true));
128
142
  }, 0);
129
143
  function onFocusin(event) {
130
144
  const func = defer ? raf : (v) => v();
@@ -146,6 +160,7 @@ function trackInteractOutsideImpl(node, options) {
146
160
  });
147
161
  }
148
162
  cleanups.add(addDomEvent(doc, "focusin", onFocusin, true));
163
+ cleanups.add(parentWin.addEventListener("focusin", onFocusin, true));
149
164
  cleanups.add(frames.addEventListener("focusin", onFocusin, true));
150
165
  return () => {
151
166
  clearTimeout(timer);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zag-js/interact-outside",
3
- "version": "0.72.0",
3
+ "version": "0.73.1",
4
4
  "description": "Track interations or focus outside an element",
5
5
  "keywords": [
6
6
  "js",
@@ -16,9 +16,9 @@
16
16
  "dist"
17
17
  ],
18
18
  "dependencies": {
19
- "@zag-js/dom-query": "0.72.0",
20
- "@zag-js/dom-event": "0.72.0",
21
- "@zag-js/utils": "0.72.0"
19
+ "@zag-js/dom-query": "0.73.1",
20
+ "@zag-js/dom-event": "0.73.1",
21
+ "@zag-js/utils": "0.73.1"
22
22
  },
23
23
  "devDependencies": {
24
24
  "clean-package": "2.2.0"