@destyler/interact-outside 0.2.11 → 0.2.13

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.d.mts CHANGED
@@ -1,5 +1,5 @@
1
1
  //#region index.d.ts
2
- interface InteractOutsideHandlers {
2
+ export interface InteractOutsideHandlers {
3
3
  /**
4
4
  * Function called when the pointer is pressed down outside the component
5
5
  */
@@ -13,20 +13,19 @@ interface InteractOutsideHandlers {
13
13
  */
14
14
  onInteractOutside?: ((event: InteractOutsideEvent) => void) | undefined;
15
15
  }
16
- interface InteractOutsideOptions extends InteractOutsideHandlers {
16
+ export interface InteractOutsideOptions extends InteractOutsideHandlers {
17
17
  exclude?: ((target: HTMLElement) => boolean) | undefined;
18
18
  defer?: boolean | undefined;
19
19
  }
20
- interface EventDetails<T> {
20
+ export interface EventDetails<T> {
21
21
  originalEvent: T;
22
22
  contextmenu: boolean;
23
23
  focusable: boolean;
24
24
  }
25
- type PointerDownOutsideEvent = CustomEvent<EventDetails<PointerEvent>>;
26
- type FocusOutsideEvent = CustomEvent<EventDetails<FocusEvent>>;
27
- type InteractOutsideEvent = PointerDownOutsideEvent | FocusOutsideEvent;
28
- type MaybeElement = HTMLElement | null | undefined;
29
- type NodeOrFn = MaybeElement | (() => MaybeElement);
30
- declare function trackInteractOutside(nodeOrFn: NodeOrFn, options: InteractOutsideOptions): () => void;
31
- //#endregion
32
- export { EventDetails, FocusOutsideEvent, InteractOutsideEvent, InteractOutsideHandlers, InteractOutsideOptions, MaybeElement, NodeOrFn, PointerDownOutsideEvent, trackInteractOutside };
25
+ export type PointerDownOutsideEvent = CustomEvent<EventDetails<PointerEvent>>;
26
+ export type FocusOutsideEvent = CustomEvent<EventDetails<FocusEvent>>;
27
+ export type InteractOutsideEvent = PointerDownOutsideEvent | FocusOutsideEvent;
28
+ export type MaybeElement = HTMLElement | null | undefined;
29
+ export type NodeOrFn = MaybeElement | (() => MaybeElement);
30
+ export declare function trackInteractOutside(nodeOrFn: NodeOrFn, options: InteractOutsideOptions): () => void;
31
+ //#endregion
package/dist/index.mjs CHANGED
@@ -1,6 +1,5 @@
1
1
  import { addDomEvent, contains, getDocument, getEventTarget, getNearestOverflowAncestor, getWindow, isContextMenuEvent, isFocusable, isHTMLElement, raf } from "@destyler/dom";
2
2
  import { callAll } from "@destyler/utils";
3
-
4
3
  //#region src/frame-utils.ts
5
4
  function getWindowFrames(win) {
6
5
  const frames = {
@@ -11,15 +10,29 @@ function getWindowFrames(win) {
11
10
  }
12
11
  },
13
12
  addEventListener(event, listener, options) {
13
+ const cleanups = /* @__PURE__ */ new Set();
14
14
  frames.each((frame) => {
15
15
  try {
16
- frame.document.addEventListener(event, listener, options);
16
+ const doc = frame.document;
17
+ doc.addEventListener(event, listener, options);
18
+ cleanups.add(() => doc.removeEventListener(event, listener, options));
17
19
  } catch {}
18
20
  });
21
+ let cleaning = false;
19
22
  return () => {
23
+ if (cleaning) return false;
24
+ cleaning = true;
20
25
  try {
21
- frames.removeEventListener(event, listener, options);
22
- } catch {}
26
+ cleanups.forEach((cleanup) => {
27
+ try {
28
+ cleanup();
29
+ cleanups.delete(cleanup);
30
+ } catch {}
31
+ });
32
+ if (cleanups.size > 0) return false;
33
+ } finally {
34
+ cleaning = false;
35
+ }
23
36
  };
24
37
  },
25
38
  removeEventListener(event, listener, options) {
@@ -42,7 +55,9 @@ function getParentWindow(win) {
42
55
  return () => {
43
56
  try {
44
57
  parent?.removeEventListener(event, listener, options);
45
- } catch {}
58
+ } catch {
59
+ return false;
60
+ }
46
61
  };
47
62
  },
48
63
  removeEventListener: (event, listener, options) => {
@@ -52,7 +67,6 @@ function getParentWindow(win) {
52
67
  }
53
68
  };
54
69
  }
55
-
56
70
  //#endregion
57
71
  //#region index.ts
58
72
  const POINTER_OUTSIDE_EVENT = "pointerdown.outside";
@@ -109,15 +123,31 @@ function trackInteractOutsideImpl(node, options) {
109
123
  return !exclude?.(target);
110
124
  }
111
125
  const pointerdownCleanups = /* @__PURE__ */ new Set();
126
+ const pendingFrames = /* @__PURE__ */ new Set();
127
+ let disposed = false;
128
+ let cleaning = false;
129
+ let cleaned = false;
130
+ function scheduleOutside(callback) {
131
+ if (disposed) return;
132
+ if (!defer) {
133
+ callback();
134
+ return;
135
+ }
136
+ const cancel = raf(() => {
137
+ pendingFrames.delete(cancel);
138
+ if (!disposed) callback();
139
+ });
140
+ pendingFrames.add(cancel);
141
+ }
112
142
  function onPointerDown(event) {
143
+ if (disposed) return;
113
144
  function handler() {
114
- const func = defer ? raf : (v) => v();
115
145
  const composedPath = event.composedPath?.() ?? [event.target];
116
- func(() => {
146
+ scheduleOutside(() => {
117
147
  if (!node || !isEventOutside(event)) return;
118
148
  if (onPointerDownOutside || onInteractOutside) {
119
- const handler$1 = callAll(onPointerDownOutside, onInteractOutside);
120
- node.addEventListener(POINTER_OUTSIDE_EVENT, handler$1, { once: true });
149
+ const handler = callAll(onPointerDownOutside, onInteractOutside);
150
+ node.addEventListener(POINTER_OUTSIDE_EVENT, handler, { once: true });
121
151
  }
122
152
  fireCustomEvent(node, POINTER_OUTSIDE_EVENT, {
123
153
  bubbles: false,
@@ -144,7 +174,7 @@ function trackInteractOutsideImpl(node, options) {
144
174
  cleanups.add(frames.addEventListener("pointerdown", onPointerDown, true));
145
175
  }, 0);
146
176
  function onFocusin(event) {
147
- (defer ? raf : (v) => v())(() => {
177
+ scheduleOutside(() => {
148
178
  if (!node || !isEventOutside(event)) return;
149
179
  if (onFocusOutside || onInteractOutside) {
150
180
  const handler = callAll(onFocusOutside, onInteractOutside);
@@ -165,9 +195,25 @@ function trackInteractOutsideImpl(node, options) {
165
195
  cleanups.add(parentWin.addEventListener("focusin", onFocusin, true));
166
196
  cleanups.add(frames.addEventListener("focusin", onFocusin, true));
167
197
  return () => {
168
- clearTimeout(timer);
169
- pointerdownCleanups.forEach((fn) => fn());
170
- cleanups.forEach((fn) => fn());
198
+ if (cleaning || cleaned) return;
199
+ disposed = true;
200
+ cleaning = true;
201
+ try {
202
+ pendingFrames.forEach((cancel) => {
203
+ cancel();
204
+ pendingFrames.delete(cancel);
205
+ });
206
+ clearTimeout(timer);
207
+ pointerdownCleanups.forEach((cleanup) => {
208
+ if (cleanup() !== false) pointerdownCleanups.delete(cleanup);
209
+ });
210
+ cleanups.forEach((cleanup) => {
211
+ if (cleanup() !== false) cleanups.delete(cleanup);
212
+ });
213
+ cleaned = pointerdownCleanups.size === 0 && cleanups.size === 0;
214
+ } finally {
215
+ cleaning = false;
216
+ }
171
217
  };
172
218
  }
173
219
  function trackInteractOutside(nodeOrFn, options) {
@@ -186,6 +232,5 @@ function fireCustomEvent(el, type, init) {
186
232
  const event = new (el.ownerDocument.defaultView || window).CustomEvent(type, init);
187
233
  return el.dispatchEvent(event);
188
234
  }
189
-
190
235
  //#endregion
191
- export { trackInteractOutside };
236
+ export { trackInteractOutside };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@destyler/interact-outside",
3
3
  "type": "module",
4
- "version": "0.2.11",
4
+ "version": "0.2.13",
5
5
  "description": "",
6
6
  "author": "Elone Hoo <elonehoo@gmail.com>",
7
7
  "license": "MIT",
@@ -22,8 +22,8 @@
22
22
  "dist"
23
23
  ],
24
24
  "dependencies": {
25
- "@destyler/dom": "0.2.11",
26
- "@destyler/utils": "0.2.11"
25
+ "@destyler/dom": "0.2.13",
26
+ "@destyler/utils": "0.2.13"
27
27
  },
28
28
  "publishConfig": {
29
29
  "access": "public"