@destyler/focus-trap 0.2.11 → 0.2.12

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
@@ -194,10 +194,12 @@ type PauseOptions = Pick<FocusTrapOptions, 'onPause' | 'onPostPause'>;
194
194
  type UnpauseOptions = Pick<FocusTrapOptions, 'onUnpause' | 'onPostUnpause'>;
195
195
  //#endregion
196
196
  //#region src/focus-trap.d.ts
197
- declare class FocusTrap {
197
+ declare const activationIdKey: unique symbol;
198
+ export declare class FocusTrap {
198
199
  private trapStack;
199
200
  private config;
200
201
  private doc;
202
+ private [activationIdKey];
201
203
  private state;
202
204
  get active(): boolean;
203
205
  get paused(): boolean;
@@ -230,7 +232,7 @@ declare class FocusTrap {
230
232
  //#endregion
231
233
  //#region index.d.ts
232
234
  type ElementOrGetter = HTMLElement | null | (() => HTMLElement | null);
233
- interface TrapFocusOptions extends Omit<FocusTrapOptions, 'document'> {}
234
- declare function trapFocus(el: ElementOrGetter, options?: TrapFocusOptions): () => void;
235
+ export interface TrapFocusOptions extends Omit<FocusTrapOptions, 'document'> {}
236
+ export declare function trapFocus(el: ElementOrGetter, options?: TrapFocusOptions): () => void;
235
237
  //#endregion
236
- export { FocusTrap, type FocusTrapOptions, TrapFocusOptions, trapFocus };
238
+ export type { FocusTrapOptions };
package/dist/index.mjs CHANGED
@@ -1,5 +1,4 @@
1
1
  import { addDomEvent, getActiveElement, getDocument, getEventTarget, getFocusables, getTabIndex, getTabbables, isDocument, isFocusable, isTabbable, raf } from "@destyler/dom";
2
-
3
2
  //#region src/focus-trap.ts
4
3
  const isTabEvent = (event) => event.key === "Tab";
5
4
  const valueOrHandler = (value, ...params) => typeof value === "function" ? value(...params) : value;
@@ -28,6 +27,7 @@ const activeFocusTraps = {
28
27
  }
29
28
  };
30
29
  const sharedTrapStack = [];
30
+ const activationIdKey = Symbol("activationId");
31
31
  var FocusTrap = class {
32
32
  get active() {
33
33
  return this.state.active;
@@ -36,6 +36,7 @@ var FocusTrap = class {
36
36
  return this.state.paused;
37
37
  }
38
38
  constructor(elements, options) {
39
+ this[activationIdKey] = 0;
39
40
  this.state = {
40
41
  containers: [],
41
42
  containerGroups: [],
@@ -124,7 +125,8 @@ var FocusTrap = class {
124
125
  }
125
126
  };
126
127
  this.setupMutationObserver = () => {
127
- this._mutationObserver = new (this.doc.defaultView || window).MutationObserver((mutations) => {
128
+ const win = this.doc.defaultView || window;
129
+ this._mutationObserver = new win.MutationObserver((mutations) => {
128
130
  if (mutations.some((mutation) => {
129
131
  return Array.from(mutation.removedNodes).includes(this.state.mostRecentlyFocusedNode);
130
132
  })) this.tryFocus(this.getInitialFocusNode());
@@ -142,12 +144,13 @@ var FocusTrap = class {
142
144
  this.getInitialFocusNode = () => {
143
145
  let node = this.getNodeForOption("initialFocus", { hasFallback: true });
144
146
  if (node === false) return false;
145
- if (node === void 0 || node && !isFocusable(node)) if (this.findContainerIndex(this.doc.activeElement) >= 0) node = this.doc.activeElement;
146
- else {
147
- const firstTabbableGroup = this.state.tabbableGroups[0];
148
- node = firstTabbableGroup && firstTabbableGroup.firstTabbableNode || this.getNodeForOption("fallbackFocus");
149
- }
150
- else if (node === null) node = this.getNodeForOption("fallbackFocus");
147
+ if (node === void 0 || node && !isFocusable(node)) {
148
+ if (this.findContainerIndex(this.doc.activeElement) >= 0) node = this.doc.activeElement;
149
+ else {
150
+ const firstTabbableGroup = this.state.tabbableGroups[0];
151
+ node = firstTabbableGroup && firstTabbableGroup.firstTabbableNode || this.getNodeForOption("fallbackFocus");
152
+ }
153
+ } else if (node === null) node = this.getNodeForOption("fallbackFocus");
151
154
  if (!node) throw new Error("Your focus-trap needs to have at least one focusable element");
152
155
  if (!node.isConnected) node = this.getNodeForOption("fallbackFocus");
153
156
  return node;
@@ -165,23 +168,21 @@ var FocusTrap = class {
165
168
  };
166
169
  this.deactivate = (deactivateOptions) => {
167
170
  if (!this.state.active) return this;
168
- const options$1 = {
171
+ const options = {
169
172
  onDeactivate: this.config.onDeactivate,
170
173
  onPostDeactivate: this.config.onPostDeactivate,
171
174
  checkCanReturnFocus: this.config.checkCanReturnFocus,
172
175
  ...deactivateOptions
173
176
  };
174
- clearTimeout(this.state.delayInitialFocusTimer);
175
- this.state.delayInitialFocusTimer = void 0;
176
177
  this.removeListeners();
177
178
  this.state.active = false;
178
179
  this.state.paused = false;
179
180
  this.updateObservedNodes();
180
181
  activeFocusTraps.deactivateTrap(this.trapStack, this);
181
- const onDeactivate = this.getOption(options$1, "onDeactivate");
182
- const onPostDeactivate = this.getOption(options$1, "onPostDeactivate");
183
- const checkCanReturnFocus = this.getOption(options$1, "checkCanReturnFocus");
184
- const returnFocus = this.getOption(options$1, "returnFocus", "returnFocusOnDeactivate");
182
+ const onDeactivate = this.getOption(options, "onDeactivate");
183
+ const onPostDeactivate = this.getOption(options, "onPostDeactivate");
184
+ const checkCanReturnFocus = this.getOption(options, "checkCanReturnFocus");
185
+ const returnFocus = this.getOption(options, "returnFocus", "returnFocusOnDeactivate");
185
186
  onDeactivate?.();
186
187
  const finishDeactivation = () => {
187
188
  delay(() => {
@@ -264,9 +265,10 @@ var FocusTrap = class {
264
265
  if (this.state.tabbableGroups.length > 0) {
265
266
  const containerIndex = this.findContainerIndex(target, event);
266
267
  const containerGroup = containerIndex >= 0 ? this.state.containerGroups[containerIndex] : void 0;
267
- if (containerIndex < 0) if (isBackward) destinationNode = this.state.tabbableGroups[this.state.tabbableGroups.length - 1].lastTabbableNode;
268
- else destinationNode = this.state.tabbableGroups[0].firstTabbableNode;
269
- else if (isBackward) {
268
+ if (containerIndex < 0) {
269
+ if (isBackward) destinationNode = this.state.tabbableGroups[this.state.tabbableGroups.length - 1].lastTabbableNode;
270
+ else destinationNode = this.state.tabbableGroups[0].firstTabbableNode;
271
+ } else if (isBackward) {
270
272
  let startOfGroupIndex = this.state.tabbableGroups.findIndex(({ firstTabbableNode }) => target === firstTabbableNode);
271
273
  if (startOfGroupIndex < 0 && (containerGroup?.container === target || isFocusable(target) && !isTabbable(target) && !containerGroup?.nextTabbableNode(target, false))) startOfGroupIndex = containerIndex;
272
274
  if (startOfGroupIndex >= 0) {
@@ -316,7 +318,7 @@ var FocusTrap = class {
316
318
  const lastTabbableNode = tabbableNodes.length > 0 ? tabbableNodes[tabbableNodes.length - 1] : void 0;
317
319
  const firstDomTabbableNode = focusableNodes.find((node) => isTabbable(node));
318
320
  const lastDomTabbableNode = focusableNodes.slice().reverse().find((node) => isTabbable(node));
319
- const posTabIndexesFound = !!tabbableNodes.find((node) => getTabIndex(node) > 0);
321
+ const posTabIndexesFound = tabbableNodes.some((node) => getTabIndex(node) > 0);
320
322
  function nextTabbableNode(node, forward = true) {
321
323
  const nodeIdx = tabbableNodes.indexOf(node);
322
324
  if (nodeIdx < 0) {
@@ -339,7 +341,7 @@ var FocusTrap = class {
339
341
  });
340
342
  this.state.tabbableGroups = this.state.containerGroups.filter((group) => group.tabbableNodes.length > 0);
341
343
  if (this.state.tabbableGroups.length <= 0 && !this.getNodeForOption("fallbackFocus")) throw new Error("Your focus-trap must have at least one container with at least one tabbable node in it at all times");
342
- if (this.state.containerGroups.find((g) => g.posTabIndexesFound) && this.state.containerGroups.length > 1) throw new Error("At least one node with a positive tabindex was found in one of your focus-trap's multiple containers. Positive tabindexes are only supported in single-container focus-traps.");
344
+ if (this.state.containerGroups.some((g) => g.posTabIndexesFound) && this.state.containerGroups.length > 1) throw new Error("At least one node with a positive tabindex was found in one of your focus-trap's multiple containers. Positive tabindexes are only supported in single-container focus-traps.");
343
345
  }
344
346
  addListeners() {
345
347
  if (!this.state.active) return;
@@ -364,6 +366,8 @@ var FocusTrap = class {
364
366
  }
365
367
  removeListeners() {
366
368
  if (!this.state.active) return;
369
+ clearTimeout(this.state.delayInitialFocusTimer);
370
+ this.state.delayInitialFocusTimer = void 0;
367
371
  this.listenerCleanups.forEach((cleanup) => cleanup());
368
372
  this.listenerCleanups = [];
369
373
  return this;
@@ -373,12 +377,17 @@ var FocusTrap = class {
373
377
  const onActivate = this.getOption(activateOptions, "onActivate");
374
378
  const onPostActivate = this.getOption(activateOptions, "onPostActivate");
375
379
  const checkCanFocusTrap = this.getOption(activateOptions, "checkCanFocusTrap");
380
+ const activationId = ++this[activationIdKey];
381
+ const isCurrentActivation = () => this.state.active && this[activationIdKey] === activationId;
376
382
  if (!checkCanFocusTrap) this.updateTabbableNodes();
383
+ if (this[activationIdKey] !== activationId) return this;
377
384
  this.state.active = true;
378
385
  this.state.paused = false;
379
386
  this.state.nodeFocusedBeforeActivation = this.doc.activeElement || null;
380
387
  onActivate?.();
388
+ if (!isCurrentActivation()) return this;
381
389
  const finishActivation = () => {
390
+ if (!isCurrentActivation()) return;
382
391
  if (checkCanFocusTrap) this.updateTabbableNodes();
383
392
  this.addListeners();
384
393
  this.updateObservedNodes();
@@ -392,7 +401,6 @@ var FocusTrap = class {
392
401
  return this;
393
402
  }
394
403
  };
395
-
396
404
  //#endregion
397
405
  //#region index.ts
398
406
  function trapFocus(el, options = {}) {
@@ -419,6 +427,5 @@ function trapFocus(el, options = {}) {
419
427
  cleanup();
420
428
  };
421
429
  }
422
-
423
430
  //#endregion
424
- export { FocusTrap, trapFocus };
431
+ export { FocusTrap, trapFocus };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@destyler/focus-trap",
3
3
  "type": "module",
4
- "version": "0.2.11",
4
+ "version": "0.2.12",
5
5
  "description": "Focus trap util",
6
6
  "author": "Elone Hoo <elonehoo@gmail.com>",
7
7
  "license": "MIT",
@@ -22,7 +22,7 @@
22
22
  "dist"
23
23
  ],
24
24
  "dependencies": {
25
- "@destyler/dom": "0.2.11"
25
+ "@destyler/dom": "0.2.12"
26
26
  },
27
27
  "publishConfig": {
28
28
  "access": "public"