@zag-js/interact-outside 0.2.2 → 0.2.4

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,42 @@
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
+ try {
14
+ frame.document.addEventListener(event, listener, options);
15
+ } catch (err) {
16
+ console.warn(err);
17
+ }
18
+ });
19
+ return () => {
20
+ try {
21
+ frames.removeEventListener(event, listener, options);
22
+ } catch (err) {
23
+ console.warn(err);
24
+ }
25
+ };
26
+ },
27
+ removeEventListener(event, listener, options) {
28
+ frames.each((frame) => {
29
+ try {
30
+ frame.document.removeEventListener(event, listener, options);
31
+ } catch (err) {
32
+ console.warn(err);
33
+ }
34
+ });
35
+ }
36
+ };
37
+ return frames;
38
+ }
39
+
40
+ export {
41
+ getWindowFrames
42
+ };
@@ -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,66 @@
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
+ try {
38
+ frame.document.addEventListener(event, listener, options);
39
+ } catch (err) {
40
+ console.warn(err);
41
+ }
42
+ });
43
+ return () => {
44
+ try {
45
+ frames.removeEventListener(event, listener, options);
46
+ } catch (err) {
47
+ console.warn(err);
48
+ }
49
+ };
50
+ },
51
+ removeEventListener(event, listener, options) {
52
+ frames.each((frame) => {
53
+ try {
54
+ frame.document.removeEventListener(event, listener, options);
55
+ } catch (err) {
56
+ console.warn(err);
57
+ }
58
+ });
59
+ }
60
+ };
61
+ return frames;
62
+ }
63
+ // Annotate the CommonJS export names for ESM import in node:
64
+ 0 && (module.exports = {
65
+ getWindowFrames
66
+ });
@@ -0,0 +1,6 @@
1
+ import {
2
+ getWindowFrames
3
+ } from "./chunk-UQ6OADW7.mjs";
4
+ export {
5
+ getWindowFrames
6
+ };
package/dist/index.js CHANGED
@@ -23,96 +23,48 @@ __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
+ try {
44
+ frame.document.addEventListener(event, listener, options);
45
+ } catch (err) {
46
+ console.warn(err);
47
+ }
48
+ });
49
+ return () => {
50
+ try {
51
+ frames.removeEventListener(event, listener, options);
52
+ } catch (err) {
53
+ console.warn(err);
54
+ }
55
+ };
56
+ },
57
+ removeEventListener(event, listener, options) {
58
+ frames.each((frame) => {
59
+ try {
60
+ frame.document.removeEventListener(event, listener, options);
61
+ } catch (err) {
62
+ console.warn(err);
63
+ }
64
+ });
65
+ }
115
66
  };
67
+ return frames;
116
68
  }
117
69
 
118
70
  // src/index.ts
@@ -122,17 +74,15 @@ function trackInteractOutside(node, options) {
122
74
  const { exclude, onFocusOutside, onPointerDownOutside, onInteractOutside } = options;
123
75
  if (!node)
124
76
  return;
125
- const doc = getDocument(node);
126
- const win = getWindow(node);
77
+ const doc = (0, import_dom_query.getDocument)(node);
78
+ const win = (0, import_dom_query.getWindow)(node);
79
+ const frames = getWindowFrames(win);
127
80
  function isEventOutside(event) {
128
- const target = getEventTarget(event);
129
- if (!(target instanceof win.HTMLElement)) {
130
- return false;
131
- }
132
- if (!contains(doc.documentElement, target)) {
81
+ const target = (0, import_dom_query.getEventTarget)(event);
82
+ if (!(0, import_dom_query.isHTMLElement)(target)) {
133
83
  return false;
134
84
  }
135
- if (contains(node, target)) {
85
+ if ((0, import_dom_query.contains)(node, target)) {
136
86
  return false;
137
87
  }
138
88
  return !exclude?.(target);
@@ -143,53 +93,59 @@ function trackInteractOutside(node, options) {
143
93
  if (!node || !isEventOutside(event))
144
94
  return;
145
95
  if (onPointerDownOutside || onInteractOutside) {
146
- const handler2 = callAll(onPointerDownOutside, onInteractOutside);
96
+ const handler2 = (0, import_utils.callAll)(onPointerDownOutside, onInteractOutside);
147
97
  node.addEventListener(POINTER_OUTSIDE_EVENT, handler2, { once: true });
148
98
  }
149
- fireCustomEvent(node, POINTER_OUTSIDE_EVENT, {
99
+ (0, import_dom_event.fireCustomEvent)(node, POINTER_OUTSIDE_EVENT, {
150
100
  bubbles: false,
151
101
  cancelable: true,
152
102
  detail: {
153
103
  originalEvent: event,
154
- contextmenu: isContextMenuEvent(event),
155
- focusable: isFocusable(getEventTarget(event))
104
+ contextmenu: (0, import_dom_event.isContextMenuEvent)(event),
105
+ focusable: (0, import_tabbable.isFocusable)((0, import_dom_query.getEventTarget)(event))
156
106
  }
157
107
  });
158
108
  }
159
109
  if (event.pointerType === "touch") {
110
+ frames.removeEventListener("click", handler);
160
111
  doc.removeEventListener("click", handler);
161
112
  clickHandler = handler;
162
113
  doc.addEventListener("click", handler, { once: true });
114
+ frames.addEventListener("click", handler, { once: true });
163
115
  } else {
164
116
  handler();
165
117
  }
166
118
  }
167
119
  const cleanups = /* @__PURE__ */ new Set();
168
120
  const timer = setTimeout(() => {
169
- cleanups.add(addDomEvent(doc, "pointerdown", onPointerDown, true));
121
+ cleanups.add(frames.addEventListener("pointerdown", onPointerDown, true));
122
+ cleanups.add((0, import_dom_event.addDomEvent)(doc, "pointerdown", onPointerDown, true));
170
123
  }, 0);
171
124
  function onFocusin(event) {
172
125
  if (!node || !isEventOutside(event))
173
126
  return;
174
127
  if (onFocusOutside || onInteractOutside) {
175
- const handler = callAll(onFocusOutside, onInteractOutside);
128
+ const handler = (0, import_utils.callAll)(onFocusOutside, onInteractOutside);
176
129
  node.addEventListener(FOCUS_OUTSIDE_EVENT, handler, { once: true });
177
130
  }
178
- fireCustomEvent(node, FOCUS_OUTSIDE_EVENT, {
131
+ (0, import_dom_event.fireCustomEvent)(node, FOCUS_OUTSIDE_EVENT, {
179
132
  bubbles: false,
180
133
  cancelable: true,
181
134
  detail: {
182
135
  originalEvent: event,
183
136
  contextmenu: false,
184
- focusable: isFocusable(getEventTarget(event))
137
+ focusable: (0, import_tabbable.isFocusable)((0, import_dom_query.getEventTarget)(event))
185
138
  }
186
139
  });
187
140
  }
188
- cleanups.add(addDomEvent(doc, "focusin", onFocusin, true));
141
+ cleanups.add((0, import_dom_event.addDomEvent)(doc, "focusin", onFocusin, true));
142
+ cleanups.add(frames.addEventListener("focusin", onFocusin, true));
189
143
  return () => {
190
144
  clearTimeout(timer);
191
- if (clickHandler)
145
+ if (clickHandler) {
146
+ frames.removeEventListener("click", clickHandler);
192
147
  doc.removeEventListener("click", clickHandler);
148
+ }
193
149
  cleanups.forEach((fn) => fn());
194
150
  };
195
151
  }
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-UQ6OADW7.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.4",
4
4
  "description": "Track interations or focus outside an element",
5
5
  "keywords": [
6
6
  "js",
@@ -15,11 +15,15 @@
15
15
  "files": [
16
16
  "dist/**/*"
17
17
  ],
18
- "devDependencies": {
19
- "clean-package": "2.2.0",
20
- "@zag-js/dom-utils": "0.2.4",
18
+ "dependencies": {
19
+ "@zag-js/dom-query": "0.1.4",
20
+ "@zag-js/dom-event": "0.0.1",
21
+ "@zag-js/tabbable": "0.0.1",
21
22
  "@zag-js/utils": "0.3.3"
22
23
  },
24
+ "devDependencies": {
25
+ "clean-package": "2.2.0"
26
+ },
23
27
  "publishConfig": {
24
28
  "access": "public"
25
29
  },