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