@zag-js/interact-outside 0.2.2 → 0.2.3

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.
@@ -0,0 +1,30 @@
1
+ // src/get-window-frames.ts
2
+ function getWindowFrames(win) {
3
+ const frames = {
4
+ each(cb) {
5
+ for (let i = 0; i < win.frames?.length; i += 1) {
6
+ const frame = win.frames[i];
7
+ if (frame)
8
+ cb(frame);
9
+ }
10
+ },
11
+ addEventListener(event, listener, options) {
12
+ frames.each((frame) => {
13
+ frame.document.addEventListener(event, listener, options);
14
+ });
15
+ return () => {
16
+ frames.removeEventListener(event, listener, options);
17
+ };
18
+ },
19
+ removeEventListener(event, listener, options) {
20
+ frames.each((frame) => {
21
+ frame.document.removeEventListener(event, listener, options);
22
+ });
23
+ }
24
+ };
25
+ return frames;
26
+ }
27
+
28
+ export {
29
+ getWindowFrames
30
+ };
@@ -0,0 +1,7 @@
1
+ declare function getWindowFrames(win: Window): {
2
+ each(cb: (win: Window) => void): void;
3
+ addEventListener(event: string, listener: any, options?: any): () => void;
4
+ removeEventListener(event: string, listener: any, options?: any): void;
5
+ };
6
+
7
+ export { getWindowFrames };
@@ -0,0 +1,54 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/get-window-frames.ts
21
+ var get_window_frames_exports = {};
22
+ __export(get_window_frames_exports, {
23
+ getWindowFrames: () => getWindowFrames
24
+ });
25
+ module.exports = __toCommonJS(get_window_frames_exports);
26
+ function getWindowFrames(win) {
27
+ const frames = {
28
+ each(cb) {
29
+ for (let i = 0; i < win.frames?.length; i += 1) {
30
+ const frame = win.frames[i];
31
+ if (frame)
32
+ cb(frame);
33
+ }
34
+ },
35
+ addEventListener(event, listener, options) {
36
+ frames.each((frame) => {
37
+ frame.document.addEventListener(event, listener, options);
38
+ });
39
+ return () => {
40
+ frames.removeEventListener(event, listener, options);
41
+ };
42
+ },
43
+ removeEventListener(event, listener, options) {
44
+ frames.each((frame) => {
45
+ frame.document.removeEventListener(event, listener, options);
46
+ });
47
+ }
48
+ };
49
+ return frames;
50
+ }
51
+ // Annotate the CommonJS export names for ESM import in node:
52
+ 0 && (module.exports = {
53
+ getWindowFrames
54
+ });
@@ -0,0 +1,6 @@
1
+ import {
2
+ getWindowFrames
3
+ } from "./chunk-XJMPFMOP.mjs";
4
+ export {
5
+ getWindowFrames
6
+ };
package/dist/index.js CHANGED
@@ -23,96 +23,36 @@ __export(src_exports, {
23
23
  trackInteractOutside: () => trackInteractOutside
24
24
  });
25
25
  module.exports = __toCommonJS(src_exports);
26
+ var import_dom_event = require("@zag-js/dom-event");
27
+ var import_dom_query = require("@zag-js/dom-query");
28
+ var import_tabbable = require("@zag-js/tabbable");
29
+ var import_utils = require("@zag-js/utils");
26
30
 
27
- // ../core/src/functions.ts
28
- var runIfFn = (v, ...a) => {
29
- const res = typeof v === "function" ? v(...a) : v;
30
- return res ?? void 0;
31
- };
32
- var callAll = (...fns) => (...a) => {
33
- fns.forEach(function(fn) {
34
- fn?.(...a);
35
- });
36
- };
37
-
38
- // ../core/src/guard.ts
39
- var hasProp = (obj, prop) => Object.prototype.hasOwnProperty.call(obj, prop);
40
-
41
- // ../dom/src/platform.ts
42
- var isDom = () => typeof window !== "undefined";
43
- function getPlatform() {
44
- const agent = navigator.userAgentData;
45
- return agent?.platform ?? navigator.platform;
46
- }
47
- var pt = (v) => isDom() && v.test(getPlatform());
48
- var isTouchDevice = () => isDom() && !!navigator.maxTouchPoints;
49
- var isMac = () => pt(/^Mac/) && !isTouchDevice;
50
-
51
- // ../dom/src/query.ts
52
- function isDocument(el) {
53
- return el.nodeType === Node.DOCUMENT_NODE;
54
- }
55
- function isWindow(value) {
56
- return value?.toString() === "[object Window]";
57
- }
58
- function getDocument(el) {
59
- if (isWindow(el))
60
- return el.document;
61
- if (isDocument(el))
62
- return el;
63
- return el?.ownerDocument ?? document;
64
- }
65
- function getWindow(el) {
66
- return el?.ownerDocument.defaultView ?? window;
67
- }
68
- function getEventTarget(event) {
69
- return event.composedPath?.()[0] ?? event.target;
70
- }
71
- function contains(parent, child) {
72
- if (!parent)
73
- return false;
74
- return parent === child || isHTMLElement(parent) && isHTMLElement(child) && parent.contains(child);
75
- }
76
- function isHTMLElement(v) {
77
- return typeof v === "object" && v?.nodeType === Node.ELEMENT_NODE && typeof v?.nodeName === "string";
78
- }
79
- function isVisible(el) {
80
- if (!isHTMLElement(el))
81
- return false;
82
- return el.offsetWidth > 0 || el.offsetHeight > 0 || el.getClientRects().length > 0;
83
- }
84
-
85
- // ../dom/src/event.ts
86
- var isContextMenuEvent = (e) => {
87
- return e.button === 2 || isCtrlKey(e) && e.button === 0;
88
- };
89
- var isCtrlKey = (v) => isMac() ? v.metaKey && !v.ctrlKey : v.ctrlKey && !v.metaKey;
90
-
91
- // ../dom/src/fire-event.ts
92
- function fireCustomEvent(el, type, init) {
93
- if (!el)
94
- return;
95
- const win = getWindow(el);
96
- const event = new win.CustomEvent(type, init);
97
- return el.dispatchEvent(event);
98
- }
99
-
100
- // ../dom/src/focusable.ts
101
- var focusableSelector = "input:not([type='hidden']):not([disabled]), select:not([disabled]), textarea:not([disabled]), a[href], button:not([disabled]), [tabindex], iframe, object, embed, area[href], audio[controls], video[controls], [contenteditable]:not([contenteditable='false']), details > summary:first-of-type";
102
- function isFocusable(element) {
103
- if (!element)
104
- return false;
105
- return element.matches(focusableSelector) && isVisible(element);
106
- }
107
-
108
- // ../dom/src/listener.ts
109
- var isRef = (v) => hasProp(v, "current");
110
- function addDomEvent(target, eventName, handler, options) {
111
- const node = isRef(target) ? target.current : runIfFn(target);
112
- node?.addEventListener(eventName, handler, options);
113
- return () => {
114
- node?.removeEventListener(eventName, handler, options);
31
+ // src/get-window-frames.ts
32
+ function getWindowFrames(win) {
33
+ const frames = {
34
+ each(cb) {
35
+ for (let i = 0; i < win.frames?.length; i += 1) {
36
+ const frame = win.frames[i];
37
+ if (frame)
38
+ cb(frame);
39
+ }
40
+ },
41
+ addEventListener(event, listener, options) {
42
+ frames.each((frame) => {
43
+ frame.document.addEventListener(event, listener, options);
44
+ });
45
+ return () => {
46
+ frames.removeEventListener(event, listener, options);
47
+ };
48
+ },
49
+ removeEventListener(event, listener, options) {
50
+ frames.each((frame) => {
51
+ frame.document.removeEventListener(event, listener, options);
52
+ });
53
+ }
115
54
  };
55
+ return frames;
116
56
  }
117
57
 
118
58
  // src/index.ts
@@ -122,17 +62,15 @@ function trackInteractOutside(node, options) {
122
62
  const { exclude, onFocusOutside, onPointerDownOutside, onInteractOutside } = options;
123
63
  if (!node)
124
64
  return;
125
- const doc = getDocument(node);
126
- const win = getWindow(node);
65
+ const doc = (0, import_dom_query.getDocument)(node);
66
+ const win = (0, import_dom_query.getWindow)(node);
67
+ const frames = getWindowFrames(win);
127
68
  function isEventOutside(event) {
128
- const target = getEventTarget(event);
129
- if (!(target instanceof win.HTMLElement)) {
69
+ const target = (0, import_dom_query.getEventTarget)(event);
70
+ if (!(0, import_dom_query.isHTMLElement)(target)) {
130
71
  return false;
131
72
  }
132
- if (!contains(doc.documentElement, target)) {
133
- return false;
134
- }
135
- if (contains(node, target)) {
73
+ if ((0, import_dom_query.contains)(node, target)) {
136
74
  return false;
137
75
  }
138
76
  return !exclude?.(target);
@@ -143,53 +81,59 @@ function trackInteractOutside(node, options) {
143
81
  if (!node || !isEventOutside(event))
144
82
  return;
145
83
  if (onPointerDownOutside || onInteractOutside) {
146
- const handler2 = callAll(onPointerDownOutside, onInteractOutside);
84
+ const handler2 = (0, import_utils.callAll)(onPointerDownOutside, onInteractOutside);
147
85
  node.addEventListener(POINTER_OUTSIDE_EVENT, handler2, { once: true });
148
86
  }
149
- fireCustomEvent(node, POINTER_OUTSIDE_EVENT, {
87
+ (0, import_dom_event.fireCustomEvent)(node, POINTER_OUTSIDE_EVENT, {
150
88
  bubbles: false,
151
89
  cancelable: true,
152
90
  detail: {
153
91
  originalEvent: event,
154
- contextmenu: isContextMenuEvent(event),
155
- focusable: isFocusable(getEventTarget(event))
92
+ contextmenu: (0, import_dom_event.isContextMenuEvent)(event),
93
+ focusable: (0, import_tabbable.isFocusable)((0, import_dom_query.getEventTarget)(event))
156
94
  }
157
95
  });
158
96
  }
159
97
  if (event.pointerType === "touch") {
98
+ frames.removeEventListener("click", handler);
160
99
  doc.removeEventListener("click", handler);
161
100
  clickHandler = handler;
162
101
  doc.addEventListener("click", handler, { once: true });
102
+ frames.addEventListener("click", handler, { once: true });
163
103
  } else {
164
104
  handler();
165
105
  }
166
106
  }
167
107
  const cleanups = /* @__PURE__ */ new Set();
168
108
  const timer = setTimeout(() => {
169
- cleanups.add(addDomEvent(doc, "pointerdown", onPointerDown, true));
109
+ cleanups.add(frames.addEventListener("pointerdown", onPointerDown, true));
110
+ cleanups.add((0, import_dom_event.addDomEvent)(doc, "pointerdown", onPointerDown, true));
170
111
  }, 0);
171
112
  function onFocusin(event) {
172
113
  if (!node || !isEventOutside(event))
173
114
  return;
174
115
  if (onFocusOutside || onInteractOutside) {
175
- const handler = callAll(onFocusOutside, onInteractOutside);
116
+ const handler = (0, import_utils.callAll)(onFocusOutside, onInteractOutside);
176
117
  node.addEventListener(FOCUS_OUTSIDE_EVENT, handler, { once: true });
177
118
  }
178
- fireCustomEvent(node, FOCUS_OUTSIDE_EVENT, {
119
+ (0, import_dom_event.fireCustomEvent)(node, FOCUS_OUTSIDE_EVENT, {
179
120
  bubbles: false,
180
121
  cancelable: true,
181
122
  detail: {
182
123
  originalEvent: event,
183
124
  contextmenu: false,
184
- focusable: isFocusable(getEventTarget(event))
125
+ focusable: (0, import_tabbable.isFocusable)((0, import_dom_query.getEventTarget)(event))
185
126
  }
186
127
  });
187
128
  }
188
- cleanups.add(addDomEvent(doc, "focusin", onFocusin, true));
129
+ cleanups.add((0, import_dom_event.addDomEvent)(doc, "focusin", onFocusin, true));
130
+ cleanups.add(frames.addEventListener("focusin", onFocusin, true));
189
131
  return () => {
190
132
  clearTimeout(timer);
191
- if (clickHandler)
133
+ if (clickHandler) {
134
+ frames.removeEventListener("click", clickHandler);
192
135
  doc.removeEventListener("click", clickHandler);
136
+ }
193
137
  cleanups.forEach((fn) => fn());
194
138
  };
195
139
  }
package/dist/index.mjs CHANGED
@@ -1,95 +1,12 @@
1
- // ../core/src/functions.ts
2
- var runIfFn = (v, ...a) => {
3
- const res = typeof v === "function" ? v(...a) : v;
4
- return res ?? void 0;
5
- };
6
- var callAll = (...fns) => (...a) => {
7
- fns.forEach(function(fn) {
8
- fn?.(...a);
9
- });
10
- };
11
-
12
- // ../core/src/guard.ts
13
- var hasProp = (obj, prop) => Object.prototype.hasOwnProperty.call(obj, prop);
14
-
15
- // ../dom/src/platform.ts
16
- var isDom = () => typeof window !== "undefined";
17
- function getPlatform() {
18
- const agent = navigator.userAgentData;
19
- return agent?.platform ?? navigator.platform;
20
- }
21
- var pt = (v) => isDom() && v.test(getPlatform());
22
- var isTouchDevice = () => isDom() && !!navigator.maxTouchPoints;
23
- var isMac = () => pt(/^Mac/) && !isTouchDevice;
24
-
25
- // ../dom/src/query.ts
26
- function isDocument(el) {
27
- return el.nodeType === Node.DOCUMENT_NODE;
28
- }
29
- function isWindow(value) {
30
- return value?.toString() === "[object Window]";
31
- }
32
- function getDocument(el) {
33
- if (isWindow(el))
34
- return el.document;
35
- if (isDocument(el))
36
- return el;
37
- return el?.ownerDocument ?? document;
38
- }
39
- function getWindow(el) {
40
- return el?.ownerDocument.defaultView ?? window;
41
- }
42
- function getEventTarget(event) {
43
- return event.composedPath?.()[0] ?? event.target;
44
- }
45
- function contains(parent, child) {
46
- if (!parent)
47
- return false;
48
- return parent === child || isHTMLElement(parent) && isHTMLElement(child) && parent.contains(child);
49
- }
50
- function isHTMLElement(v) {
51
- return typeof v === "object" && v?.nodeType === Node.ELEMENT_NODE && typeof v?.nodeName === "string";
52
- }
53
- function isVisible(el) {
54
- if (!isHTMLElement(el))
55
- return false;
56
- return el.offsetWidth > 0 || el.offsetHeight > 0 || el.getClientRects().length > 0;
57
- }
58
-
59
- // ../dom/src/event.ts
60
- var isContextMenuEvent = (e) => {
61
- return e.button === 2 || isCtrlKey(e) && e.button === 0;
62
- };
63
- var isCtrlKey = (v) => isMac() ? v.metaKey && !v.ctrlKey : v.ctrlKey && !v.metaKey;
64
-
65
- // ../dom/src/fire-event.ts
66
- function fireCustomEvent(el, type, init) {
67
- if (!el)
68
- return;
69
- const win = getWindow(el);
70
- const event = new win.CustomEvent(type, init);
71
- return el.dispatchEvent(event);
72
- }
73
-
74
- // ../dom/src/focusable.ts
75
- var focusableSelector = "input:not([type='hidden']):not([disabled]), select:not([disabled]), textarea:not([disabled]), a[href], button:not([disabled]), [tabindex], iframe, object, embed, area[href], audio[controls], video[controls], [contenteditable]:not([contenteditable='false']), details > summary:first-of-type";
76
- function isFocusable(element) {
77
- if (!element)
78
- return false;
79
- return element.matches(focusableSelector) && isVisible(element);
80
- }
81
-
82
- // ../dom/src/listener.ts
83
- var isRef = (v) => hasProp(v, "current");
84
- function addDomEvent(target, eventName, handler, options) {
85
- const node = isRef(target) ? target.current : runIfFn(target);
86
- node?.addEventListener(eventName, handler, options);
87
- return () => {
88
- node?.removeEventListener(eventName, handler, options);
89
- };
90
- }
1
+ import {
2
+ getWindowFrames
3
+ } from "./chunk-XJMPFMOP.mjs";
91
4
 
92
5
  // src/index.ts
6
+ import { addDomEvent, fireCustomEvent, isContextMenuEvent } from "@zag-js/dom-event";
7
+ import { contains, getDocument, getEventTarget, getWindow, isHTMLElement } from "@zag-js/dom-query";
8
+ import { isFocusable } from "@zag-js/tabbable";
9
+ import { callAll } from "@zag-js/utils";
93
10
  var POINTER_OUTSIDE_EVENT = "pointerdown.outside";
94
11
  var FOCUS_OUTSIDE_EVENT = "focus.outside";
95
12
  function trackInteractOutside(node, options) {
@@ -98,12 +15,10 @@ function trackInteractOutside(node, options) {
98
15
  return;
99
16
  const doc = getDocument(node);
100
17
  const win = getWindow(node);
18
+ const frames = getWindowFrames(win);
101
19
  function isEventOutside(event) {
102
20
  const target = getEventTarget(event);
103
- if (!(target instanceof win.HTMLElement)) {
104
- return false;
105
- }
106
- if (!contains(doc.documentElement, target)) {
21
+ if (!isHTMLElement(target)) {
107
22
  return false;
108
23
  }
109
24
  if (contains(node, target)) {
@@ -131,15 +46,18 @@ function trackInteractOutside(node, options) {
131
46
  });
132
47
  }
133
48
  if (event.pointerType === "touch") {
49
+ frames.removeEventListener("click", handler);
134
50
  doc.removeEventListener("click", handler);
135
51
  clickHandler = handler;
136
52
  doc.addEventListener("click", handler, { once: true });
53
+ frames.addEventListener("click", handler, { once: true });
137
54
  } else {
138
55
  handler();
139
56
  }
140
57
  }
141
58
  const cleanups = /* @__PURE__ */ new Set();
142
59
  const timer = setTimeout(() => {
60
+ cleanups.add(frames.addEventListener("pointerdown", onPointerDown, true));
143
61
  cleanups.add(addDomEvent(doc, "pointerdown", onPointerDown, true));
144
62
  }, 0);
145
63
  function onFocusin(event) {
@@ -160,10 +78,13 @@ function trackInteractOutside(node, options) {
160
78
  });
161
79
  }
162
80
  cleanups.add(addDomEvent(doc, "focusin", onFocusin, true));
81
+ cleanups.add(frames.addEventListener("focusin", onFocusin, true));
163
82
  return () => {
164
83
  clearTimeout(timer);
165
- if (clickHandler)
84
+ if (clickHandler) {
85
+ frames.removeEventListener("click", clickHandler);
166
86
  doc.removeEventListener("click", clickHandler);
87
+ }
167
88
  cleanups.forEach((fn) => fn());
168
89
  };
169
90
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zag-js/interact-outside",
3
- "version": "0.2.2",
3
+ "version": "0.2.3",
4
4
  "description": "Track interations or focus outside an element",
5
5
  "keywords": [
6
6
  "js",
@@ -15,10 +15,14 @@
15
15
  "files": [
16
16
  "dist/**/*"
17
17
  ],
18
+ "dependencies": {
19
+ "@zag-js/dom-query": "0.1.3",
20
+ "@zag-js/dom-event": "0.0.1",
21
+ "@zag-js/utils": "0.3.3",
22
+ "@zag-js/tabbable": "0.0.1"
23
+ },
18
24
  "devDependencies": {
19
- "clean-package": "2.2.0",
20
- "@zag-js/dom-utils": "0.2.4",
21
- "@zag-js/utils": "0.3.3"
25
+ "clean-package": "2.2.0"
22
26
  },
23
27
  "publishConfig": {
24
28
  "access": "public"