@primer/behaviors 0.0.0-202218135849 → 0.0.0-202223113012

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.
@@ -1,7 +1,7 @@
1
1
  declare class ModalDialogElement extends HTMLElement {
2
- private abortController;
3
- private overlayBackdrop;
4
- constructor();
2
+ #private;
3
+ get open(): boolean;
4
+ set open(value: boolean);
5
5
  connectedCallback(): void;
6
6
  disconnectedCallback(): void;
7
7
  show(): void;
@@ -1,98 +1,115 @@
1
1
  "use strict";
2
+ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
3
+ if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
4
+ if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
5
+ return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
6
+ };
7
+ var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
8
+ if (kind === "m") throw new TypeError("Private method is not writable");
9
+ if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
10
+ if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
11
+ return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
12
+ };
13
+ var _ModalDialogElement_instances, _ModalDialogElement_focusAbortController, _ModalDialogElement_abortController, _ModalDialogElement_isComposing, _ModalDialogElement_openButton, _ModalDialogElement_overlayBackdrop_get, _ModalDialogElement_keydown;
2
14
  Object.defineProperty(exports, "__esModule", { value: true });
15
+ const iterate_focusable_elements_js_1 = require("../utils/iterate-focusable-elements.js");
3
16
  const focus_trap_js_1 = require("../focus-trap.js");
4
17
  class ModalDialogElement extends HTMLElement {
5
18
  constructor() {
6
- var _a, _b, _c;
7
- super();
8
- (_a = this.querySelector('.Overlay-closeButton')) === null || _a === void 0 ? void 0 : _a.addEventListener('click', () => this.close());
9
- (_b = document.body.querySelector(`.js-dialog-show-${this.id}`)) === null || _b === void 0 ? void 0 : _b.addEventListener('click', event => {
10
- event.stopPropagation();
11
- this.show();
12
- });
13
- if ((_c = this.parentElement) === null || _c === void 0 ? void 0 : _c.classList.contains('Overlay-backdrop')) {
14
- this.overlayBackdrop = this.parentElement;
15
- this.overlayBackdrop.classList.add('Overlay-hidden');
19
+ super(...arguments);
20
+ _ModalDialogElement_instances.add(this);
21
+ _ModalDialogElement_focusAbortController.set(this, new AbortController());
22
+ _ModalDialogElement_abortController.set(this, new AbortController());
23
+ _ModalDialogElement_isComposing.set(this, false);
24
+ _ModalDialogElement_openButton.set(this, void 0);
25
+ }
26
+ get open() {
27
+ return this.hasAttribute('open');
28
+ }
29
+ set open(value) {
30
+ var _a, _b;
31
+ if (value) {
32
+ if (this.open)
33
+ return;
34
+ this.setAttribute('open', '');
35
+ (_a = __classPrivateFieldGet(this, _ModalDialogElement_instances, "a", _ModalDialogElement_overlayBackdrop_get)) === null || _a === void 0 ? void 0 : _a.classList.remove('Overlay-hidden');
36
+ document.body.style.overflow = 'hidden';
37
+ if (__classPrivateFieldGet(this, _ModalDialogElement_focusAbortController, "f").signal.aborted) {
38
+ __classPrivateFieldSet(this, _ModalDialogElement_focusAbortController, new AbortController(), "f");
39
+ }
40
+ (0, focus_trap_js_1.focusTrap)(this, __classPrivateFieldGet(this, _ModalDialogElement_focusAbortController, "f").signal);
41
+ }
42
+ else {
43
+ if (!this.open)
44
+ return;
45
+ this.removeAttribute('open');
46
+ (_b = __classPrivateFieldGet(this, _ModalDialogElement_instances, "a", _ModalDialogElement_overlayBackdrop_get)) === null || _b === void 0 ? void 0 : _b.classList.add('Overlay-hidden');
47
+ document.body.style.overflow = 'initial';
48
+ __classPrivateFieldGet(this, _ModalDialogElement_focusAbortController, "f").abort();
49
+ (0, iterate_focusable_elements_js_1.focusIfNeeded)(__classPrivateFieldGet(this, _ModalDialogElement_openButton, "f"));
50
+ __classPrivateFieldSet(this, _ModalDialogElement_openButton, undefined, "f");
16
51
  }
17
52
  }
18
53
  connectedCallback() {
19
54
  if (!this.hasAttribute('role'))
20
55
  this.setAttribute('role', 'dialog');
21
- const subscriptions = [
22
- fromEvent(this, 'compositionstart', e => trackComposition(this, e)),
23
- fromEvent(this, 'compositionend', e => trackComposition(this, e)),
24
- fromEvent(this, 'keydown', e => keydown(this, e)),
25
- fromEvent(window, 'click', e => clickToDismiss(this, e))
26
- ];
27
- states.set(this, { subscriptions, loaded: false, isComposing: false });
56
+ const signal = __classPrivateFieldGet(this, _ModalDialogElement_abortController, "f").signal;
57
+ this.ownerDocument.addEventListener('click', event => {
58
+ const target = event.target;
59
+ const clickOutsideDialog = target.closest(this.tagName) !== this;
60
+ const button = target === null || target === void 0 ? void 0 : target.closest('button');
61
+ if (!button) {
62
+ if (clickOutsideDialog) {
63
+ this.close();
64
+ }
65
+ return;
66
+ }
67
+ let dialogId = button.getAttribute('data-close-dialog-id');
68
+ if (dialogId === this.id) {
69
+ this.close();
70
+ }
71
+ dialogId = button.getAttribute('data-show-dialog-id');
72
+ if (dialogId === this.id) {
73
+ event.stopPropagation();
74
+ __classPrivateFieldSet(this, _ModalDialogElement_openButton, button, "f");
75
+ this.show();
76
+ }
77
+ }, { signal });
78
+ this.addEventListener('compositionstart', () => (__classPrivateFieldSet(this, _ModalDialogElement_isComposing, true, "f")));
79
+ this.addEventListener('compositionend', () => (__classPrivateFieldSet(this, _ModalDialogElement_isComposing, false, "f")));
80
+ this.addEventListener('keydown', e => __classPrivateFieldGet(this, _ModalDialogElement_instances, "m", _ModalDialogElement_keydown).call(this, e));
28
81
  }
29
82
  disconnectedCallback() {
30
- const state = states.get(this);
31
- if (!state)
32
- return;
33
- states.delete(this);
34
- for (const sub of state.subscriptions) {
35
- sub.unsubscribe();
36
- }
83
+ __classPrivateFieldGet(this, _ModalDialogElement_abortController, "f").abort();
37
84
  }
38
85
  show() {
39
- var _a;
40
- const isOpen = this.hasAttribute('open');
41
- if (isOpen)
42
- return;
43
- this.setAttribute('open', '');
44
- (_a = this.overlayBackdrop) === null || _a === void 0 ? void 0 : _a.classList.remove('Overlay-hidden');
45
- document.body.style.overflow = 'hidden';
46
- this.abortController = (0, focus_trap_js_1.focusTrap)(this);
86
+ this.open = true;
47
87
  }
48
88
  close() {
49
- var _a, _b;
50
- const isOpen = this.hasAttribute('open');
51
- if (!isOpen)
52
- return;
53
- this.removeAttribute('open');
54
- (_a = this.overlayBackdrop) === null || _a === void 0 ? void 0 : _a.classList.add('Overlay-hidden');
55
- document.body.style.overflow = 'initial';
56
- (_b = this.abortController) === null || _b === void 0 ? void 0 : _b.abort();
89
+ this.open = false;
57
90
  }
58
91
  }
59
- const states = new WeakMap();
60
- function fromEvent(target, eventName, onNext, options = false) {
61
- target.addEventListener(eventName, onNext, options);
62
- return {
63
- unsubscribe: () => {
64
- target.removeEventListener(eventName, onNext, options);
65
- }
66
- };
67
- }
68
- function keydown(dialog, event) {
92
+ _ModalDialogElement_focusAbortController = new WeakMap(), _ModalDialogElement_abortController = new WeakMap(), _ModalDialogElement_isComposing = new WeakMap(), _ModalDialogElement_openButton = new WeakMap(), _ModalDialogElement_instances = new WeakSet(), _ModalDialogElement_overlayBackdrop_get = function _ModalDialogElement_overlayBackdrop_get() {
93
+ var _a;
94
+ if ((_a = this.parentElement) === null || _a === void 0 ? void 0 : _a.classList.contains('Overlay-backdrop')) {
95
+ return this.parentElement;
96
+ }
97
+ return null;
98
+ }, _ModalDialogElement_keydown = function _ModalDialogElement_keydown(event) {
69
99
  if (!(event instanceof KeyboardEvent))
70
100
  return;
71
- const state = states.get(dialog);
72
- if (!state || state.isComposing)
101
+ if (__classPrivateFieldGet(this, _ModalDialogElement_isComposing, "f"))
73
102
  return;
74
103
  switch (event.key) {
75
104
  case 'Escape':
76
- if (dialog.hasAttribute('open')) {
77
- dialog.close();
105
+ if (this.open) {
106
+ this.close();
78
107
  event.preventDefault();
79
108
  event.stopPropagation();
80
109
  }
81
110
  break;
82
111
  }
83
- }
84
- function trackComposition(dialog, event) {
85
- const state = states.get(dialog);
86
- if (!state)
87
- return;
88
- state.isComposing = event.type === 'compositionstart';
89
- }
90
- function clickToDismiss(dialog, event) {
91
- const target = event.target;
92
- if (dialog.hasAttribute('open') && target && !target.matches(`#${dialog.id}, #${dialog.id} *`)) {
93
- dialog.close();
94
- }
95
- }
112
+ };
96
113
  exports.default = ModalDialogElement;
97
114
  if (!window.customElements.get('modal-dialog')) {
98
115
  window.ModalDialogElement = ModalDialogElement;
@@ -1 +1 @@
1
- export declare function focusTrap(container: HTMLElement, initialFocus?: HTMLElement, abortSignal?: AbortSignal): AbortController | undefined;
1
+ export declare function focusTrap(container: HTMLElement, abortSignal: AbortSignal, initialFocus?: HTMLElement): void;
@@ -9,7 +9,7 @@ let activeTrap = undefined;
9
9
  function tryReactivate() {
10
10
  const trapToReactivate = suspendedTrapStack.pop();
11
11
  if (trapToReactivate) {
12
- focusTrap(trapToReactivate.container, trapToReactivate.initialFocus, trapToReactivate.originalSignal);
12
+ focusTrap(trapToReactivate.container, trapToReactivate.originalSignal, trapToReactivate.initialFocus);
13
13
  }
14
14
  }
15
15
  function followSignal(signal) {
@@ -19,9 +19,7 @@ function followSignal(signal) {
19
19
  });
20
20
  return controller;
21
21
  }
22
- function focusTrap(container, initialFocus, abortSignal) {
23
- const controller = new AbortController();
24
- const signal = abortSignal !== null && abortSignal !== void 0 ? abortSignal : controller.signal;
22
+ function focusTrap(container, abortSignal, initialFocus) {
25
23
  container.setAttribute('data-focus-trap', 'active');
26
24
  const sentinelStart = document.createElement('span');
27
25
  sentinelStart.setAttribute('class', 'sentinel');
@@ -50,22 +48,22 @@ function focusTrap(container, initialFocus, abortSignal) {
50
48
  }
51
49
  else {
52
50
  if (lastFocusedChild && (0, iterate_focusable_elements_js_1.isTabbable)(lastFocusedChild) && container.contains(lastFocusedChild)) {
53
- lastFocusedChild.focus();
51
+ (0, iterate_focusable_elements_js_1.focusIfNeeded)(lastFocusedChild);
54
52
  return;
55
53
  }
56
54
  else if (initialFocus && container.contains(initialFocus)) {
57
- initialFocus.focus();
55
+ (0, iterate_focusable_elements_js_1.focusIfNeeded)(initialFocus);
58
56
  return;
59
57
  }
60
58
  else {
61
59
  const firstFocusableChild = (0, iterate_focusable_elements_js_1.getFocusableChild)(container);
62
- firstFocusableChild === null || firstFocusableChild === void 0 ? void 0 : firstFocusableChild.focus();
60
+ (0, iterate_focusable_elements_js_1.focusIfNeeded)(firstFocusableChild);
63
61
  return;
64
62
  }
65
63
  }
66
64
  }
67
65
  }
68
- const wrappingController = followSignal(signal);
66
+ const wrappingController = followSignal(abortSignal);
69
67
  if (activeTrap) {
70
68
  const suspendedTrap = activeTrap;
71
69
  activeTrap.container.setAttribute('data-focus-trap', 'suspended');
@@ -75,7 +73,7 @@ function focusTrap(container, initialFocus, abortSignal) {
75
73
  wrappingController.signal.addEventListener('abort', () => {
76
74
  activeTrap = undefined;
77
75
  });
78
- signal.addEventListener('abort', () => {
76
+ abortSignal.addEventListener('abort', () => {
79
77
  container.removeAttribute('data-focus-trap');
80
78
  const sentinels = container.getElementsByClassName('sentinel');
81
79
  while (sentinels.length > 0)
@@ -94,14 +92,11 @@ function focusTrap(container, initialFocus, abortSignal) {
94
92
  container,
95
93
  controller: wrappingController,
96
94
  initialFocus,
97
- originalSignal: signal
95
+ originalSignal: abortSignal
98
96
  };
99
97
  const suspendedTrapIndex = suspendedTrapStack.findIndex(t => t.container === container);
100
98
  if (suspendedTrapIndex >= 0) {
101
99
  suspendedTrapStack.splice(suspendedTrapIndex, 1);
102
100
  }
103
- if (!abortSignal) {
104
- return controller;
105
- }
106
101
  }
107
102
  exports.focusTrap = focusTrap;
@@ -4,6 +4,7 @@ export interface IterateFocusableElements {
4
4
  onlyTabbable?: boolean;
5
5
  }
6
6
  export declare function iterateFocusableElements(container: HTMLElement, options?: IterateFocusableElements): Generator<HTMLElement, undefined, undefined>;
7
+ export declare function focusIfNeeded(elem?: HTMLElement): void;
7
8
  export declare function getFocusableChild(container: HTMLElement, lastChild?: boolean): HTMLElement | undefined;
8
9
  export declare function isFocusable(elem: HTMLElement, strict?: boolean): boolean;
9
10
  export declare function isTabbable(elem: HTMLElement, strict?: boolean): boolean;
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.isTabbable = exports.isFocusable = exports.getFocusableChild = exports.iterateFocusableElements = void 0;
3
+ exports.isTabbable = exports.isFocusable = exports.getFocusableChild = exports.focusIfNeeded = exports.iterateFocusableElements = void 0;
4
4
  function* iterateFocusableElements(container, options = {}) {
5
5
  var _a, _b;
6
6
  const strict = (_a = options.strict) !== null && _a !== void 0 ? _a : false;
@@ -32,6 +32,12 @@ function* iterateFocusableElements(container, options = {}) {
32
32
  return undefined;
33
33
  }
34
34
  exports.iterateFocusableElements = iterateFocusableElements;
35
+ function focusIfNeeded(elem) {
36
+ if (document.activeElement !== elem) {
37
+ elem === null || elem === void 0 ? void 0 : elem.focus();
38
+ }
39
+ }
40
+ exports.focusIfNeeded = focusIfNeeded;
35
41
  function getFocusableChild(container, lastChild = false) {
36
42
  return iterateFocusableElements(container, { reverse: lastChild, strict: true, onlyTabbable: true }).next().value;
37
43
  }
@@ -1,7 +1,7 @@
1
1
  declare class ModalDialogElement extends HTMLElement {
2
- private abortController;
3
- private overlayBackdrop;
4
- constructor();
2
+ #private;
3
+ get open(): boolean;
4
+ set open(value: boolean);
5
5
  connectedCallback(): void;
6
6
  disconnectedCallback(): void;
7
7
  show(): void;
@@ -1,96 +1,113 @@
1
+ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
2
+ if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
3
+ if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
4
+ return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
5
+ };
6
+ var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
7
+ if (kind === "m") throw new TypeError("Private method is not writable");
8
+ if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
9
+ if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
10
+ return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
11
+ };
12
+ var _ModalDialogElement_instances, _ModalDialogElement_focusAbortController, _ModalDialogElement_abortController, _ModalDialogElement_isComposing, _ModalDialogElement_openButton, _ModalDialogElement_overlayBackdrop_get, _ModalDialogElement_keydown;
13
+ import { focusIfNeeded } from '../utils/iterate-focusable-elements.js';
1
14
  import { focusTrap } from '../focus-trap.js';
2
15
  class ModalDialogElement extends HTMLElement {
3
16
  constructor() {
4
- var _a, _b, _c;
5
- super();
6
- (_a = this.querySelector('.Overlay-closeButton')) === null || _a === void 0 ? void 0 : _a.addEventListener('click', () => this.close());
7
- (_b = document.body.querySelector(`.js-dialog-show-${this.id}`)) === null || _b === void 0 ? void 0 : _b.addEventListener('click', event => {
8
- event.stopPropagation();
9
- this.show();
10
- });
11
- if ((_c = this.parentElement) === null || _c === void 0 ? void 0 : _c.classList.contains('Overlay-backdrop')) {
12
- this.overlayBackdrop = this.parentElement;
13
- this.overlayBackdrop.classList.add('Overlay-hidden');
17
+ super(...arguments);
18
+ _ModalDialogElement_instances.add(this);
19
+ _ModalDialogElement_focusAbortController.set(this, new AbortController());
20
+ _ModalDialogElement_abortController.set(this, new AbortController());
21
+ _ModalDialogElement_isComposing.set(this, false);
22
+ _ModalDialogElement_openButton.set(this, void 0);
23
+ }
24
+ get open() {
25
+ return this.hasAttribute('open');
26
+ }
27
+ set open(value) {
28
+ var _a, _b;
29
+ if (value) {
30
+ if (this.open)
31
+ return;
32
+ this.setAttribute('open', '');
33
+ (_a = __classPrivateFieldGet(this, _ModalDialogElement_instances, "a", _ModalDialogElement_overlayBackdrop_get)) === null || _a === void 0 ? void 0 : _a.classList.remove('Overlay-hidden');
34
+ document.body.style.overflow = 'hidden';
35
+ if (__classPrivateFieldGet(this, _ModalDialogElement_focusAbortController, "f").signal.aborted) {
36
+ __classPrivateFieldSet(this, _ModalDialogElement_focusAbortController, new AbortController(), "f");
37
+ }
38
+ focusTrap(this, __classPrivateFieldGet(this, _ModalDialogElement_focusAbortController, "f").signal);
39
+ }
40
+ else {
41
+ if (!this.open)
42
+ return;
43
+ this.removeAttribute('open');
44
+ (_b = __classPrivateFieldGet(this, _ModalDialogElement_instances, "a", _ModalDialogElement_overlayBackdrop_get)) === null || _b === void 0 ? void 0 : _b.classList.add('Overlay-hidden');
45
+ document.body.style.overflow = 'initial';
46
+ __classPrivateFieldGet(this, _ModalDialogElement_focusAbortController, "f").abort();
47
+ focusIfNeeded(__classPrivateFieldGet(this, _ModalDialogElement_openButton, "f"));
48
+ __classPrivateFieldSet(this, _ModalDialogElement_openButton, undefined, "f");
14
49
  }
15
50
  }
16
51
  connectedCallback() {
17
52
  if (!this.hasAttribute('role'))
18
53
  this.setAttribute('role', 'dialog');
19
- const subscriptions = [
20
- fromEvent(this, 'compositionstart', e => trackComposition(this, e)),
21
- fromEvent(this, 'compositionend', e => trackComposition(this, e)),
22
- fromEvent(this, 'keydown', e => keydown(this, e)),
23
- fromEvent(window, 'click', e => clickToDismiss(this, e))
24
- ];
25
- states.set(this, { subscriptions, loaded: false, isComposing: false });
54
+ const signal = __classPrivateFieldGet(this, _ModalDialogElement_abortController, "f").signal;
55
+ this.ownerDocument.addEventListener('click', event => {
56
+ const target = event.target;
57
+ const clickOutsideDialog = target.closest(this.tagName) !== this;
58
+ const button = target === null || target === void 0 ? void 0 : target.closest('button');
59
+ if (!button) {
60
+ if (clickOutsideDialog) {
61
+ this.close();
62
+ }
63
+ return;
64
+ }
65
+ let dialogId = button.getAttribute('data-close-dialog-id');
66
+ if (dialogId === this.id) {
67
+ this.close();
68
+ }
69
+ dialogId = button.getAttribute('data-show-dialog-id');
70
+ if (dialogId === this.id) {
71
+ event.stopPropagation();
72
+ __classPrivateFieldSet(this, _ModalDialogElement_openButton, button, "f");
73
+ this.show();
74
+ }
75
+ }, { signal });
76
+ this.addEventListener('compositionstart', () => (__classPrivateFieldSet(this, _ModalDialogElement_isComposing, true, "f")));
77
+ this.addEventListener('compositionend', () => (__classPrivateFieldSet(this, _ModalDialogElement_isComposing, false, "f")));
78
+ this.addEventListener('keydown', e => __classPrivateFieldGet(this, _ModalDialogElement_instances, "m", _ModalDialogElement_keydown).call(this, e));
26
79
  }
27
80
  disconnectedCallback() {
28
- const state = states.get(this);
29
- if (!state)
30
- return;
31
- states.delete(this);
32
- for (const sub of state.subscriptions) {
33
- sub.unsubscribe();
34
- }
81
+ __classPrivateFieldGet(this, _ModalDialogElement_abortController, "f").abort();
35
82
  }
36
83
  show() {
37
- var _a;
38
- const isOpen = this.hasAttribute('open');
39
- if (isOpen)
40
- return;
41
- this.setAttribute('open', '');
42
- (_a = this.overlayBackdrop) === null || _a === void 0 ? void 0 : _a.classList.remove('Overlay-hidden');
43
- document.body.style.overflow = 'hidden';
44
- this.abortController = focusTrap(this);
84
+ this.open = true;
45
85
  }
46
86
  close() {
47
- var _a, _b;
48
- const isOpen = this.hasAttribute('open');
49
- if (!isOpen)
50
- return;
51
- this.removeAttribute('open');
52
- (_a = this.overlayBackdrop) === null || _a === void 0 ? void 0 : _a.classList.add('Overlay-hidden');
53
- document.body.style.overflow = 'initial';
54
- (_b = this.abortController) === null || _b === void 0 ? void 0 : _b.abort();
87
+ this.open = false;
55
88
  }
56
89
  }
57
- const states = new WeakMap();
58
- function fromEvent(target, eventName, onNext, options = false) {
59
- target.addEventListener(eventName, onNext, options);
60
- return {
61
- unsubscribe: () => {
62
- target.removeEventListener(eventName, onNext, options);
63
- }
64
- };
65
- }
66
- function keydown(dialog, event) {
90
+ _ModalDialogElement_focusAbortController = new WeakMap(), _ModalDialogElement_abortController = new WeakMap(), _ModalDialogElement_isComposing = new WeakMap(), _ModalDialogElement_openButton = new WeakMap(), _ModalDialogElement_instances = new WeakSet(), _ModalDialogElement_overlayBackdrop_get = function _ModalDialogElement_overlayBackdrop_get() {
91
+ var _a;
92
+ if ((_a = this.parentElement) === null || _a === void 0 ? void 0 : _a.classList.contains('Overlay-backdrop')) {
93
+ return this.parentElement;
94
+ }
95
+ return null;
96
+ }, _ModalDialogElement_keydown = function _ModalDialogElement_keydown(event) {
67
97
  if (!(event instanceof KeyboardEvent))
68
98
  return;
69
- const state = states.get(dialog);
70
- if (!state || state.isComposing)
99
+ if (__classPrivateFieldGet(this, _ModalDialogElement_isComposing, "f"))
71
100
  return;
72
101
  switch (event.key) {
73
102
  case 'Escape':
74
- if (dialog.hasAttribute('open')) {
75
- dialog.close();
103
+ if (this.open) {
104
+ this.close();
76
105
  event.preventDefault();
77
106
  event.stopPropagation();
78
107
  }
79
108
  break;
80
109
  }
81
- }
82
- function trackComposition(dialog, event) {
83
- const state = states.get(dialog);
84
- if (!state)
85
- return;
86
- state.isComposing = event.type === 'compositionstart';
87
- }
88
- function clickToDismiss(dialog, event) {
89
- const target = event.target;
90
- if (dialog.hasAttribute('open') && target && !target.matches(`#${dialog.id}, #${dialog.id} *`)) {
91
- dialog.close();
92
- }
93
- }
110
+ };
94
111
  export default ModalDialogElement;
95
112
  if (!window.customElements.get('modal-dialog')) {
96
113
  window.ModalDialogElement = ModalDialogElement;
@@ -1 +1 @@
1
- export declare function focusTrap(container: HTMLElement, initialFocus?: HTMLElement, abortSignal?: AbortSignal): AbortController | undefined;
1
+ export declare function focusTrap(container: HTMLElement, abortSignal: AbortSignal, initialFocus?: HTMLElement): void;
@@ -1,4 +1,4 @@
1
- import { getFocusableChild, isTabbable } from './utils/iterate-focusable-elements.js';
1
+ import { focusIfNeeded, getFocusableChild, isTabbable } from './utils/iterate-focusable-elements.js';
2
2
  import { polyfill as eventListenerSignalPolyfill } from './polyfills/event-listener-signal.js';
3
3
  eventListenerSignalPolyfill();
4
4
  const suspendedTrapStack = [];
@@ -6,7 +6,7 @@ let activeTrap = undefined;
6
6
  function tryReactivate() {
7
7
  const trapToReactivate = suspendedTrapStack.pop();
8
8
  if (trapToReactivate) {
9
- focusTrap(trapToReactivate.container, trapToReactivate.initialFocus, trapToReactivate.originalSignal);
9
+ focusTrap(trapToReactivate.container, trapToReactivate.originalSignal, trapToReactivate.initialFocus);
10
10
  }
11
11
  }
12
12
  function followSignal(signal) {
@@ -16,9 +16,7 @@ function followSignal(signal) {
16
16
  });
17
17
  return controller;
18
18
  }
19
- export function focusTrap(container, initialFocus, abortSignal) {
20
- const controller = new AbortController();
21
- const signal = abortSignal !== null && abortSignal !== void 0 ? abortSignal : controller.signal;
19
+ export function focusTrap(container, abortSignal, initialFocus) {
22
20
  container.setAttribute('data-focus-trap', 'active');
23
21
  const sentinelStart = document.createElement('span');
24
22
  sentinelStart.setAttribute('class', 'sentinel');
@@ -47,22 +45,22 @@ export function focusTrap(container, initialFocus, abortSignal) {
47
45
  }
48
46
  else {
49
47
  if (lastFocusedChild && isTabbable(lastFocusedChild) && container.contains(lastFocusedChild)) {
50
- lastFocusedChild.focus();
48
+ focusIfNeeded(lastFocusedChild);
51
49
  return;
52
50
  }
53
51
  else if (initialFocus && container.contains(initialFocus)) {
54
- initialFocus.focus();
52
+ focusIfNeeded(initialFocus);
55
53
  return;
56
54
  }
57
55
  else {
58
56
  const firstFocusableChild = getFocusableChild(container);
59
- firstFocusableChild === null || firstFocusableChild === void 0 ? void 0 : firstFocusableChild.focus();
57
+ focusIfNeeded(firstFocusableChild);
60
58
  return;
61
59
  }
62
60
  }
63
61
  }
64
62
  }
65
- const wrappingController = followSignal(signal);
63
+ const wrappingController = followSignal(abortSignal);
66
64
  if (activeTrap) {
67
65
  const suspendedTrap = activeTrap;
68
66
  activeTrap.container.setAttribute('data-focus-trap', 'suspended');
@@ -72,7 +70,7 @@ export function focusTrap(container, initialFocus, abortSignal) {
72
70
  wrappingController.signal.addEventListener('abort', () => {
73
71
  activeTrap = undefined;
74
72
  });
75
- signal.addEventListener('abort', () => {
73
+ abortSignal.addEventListener('abort', () => {
76
74
  container.removeAttribute('data-focus-trap');
77
75
  const sentinels = container.getElementsByClassName('sentinel');
78
76
  while (sentinels.length > 0)
@@ -91,13 +89,10 @@ export function focusTrap(container, initialFocus, abortSignal) {
91
89
  container,
92
90
  controller: wrappingController,
93
91
  initialFocus,
94
- originalSignal: signal
92
+ originalSignal: abortSignal
95
93
  };
96
94
  const suspendedTrapIndex = suspendedTrapStack.findIndex(t => t.container === container);
97
95
  if (suspendedTrapIndex >= 0) {
98
96
  suspendedTrapStack.splice(suspendedTrapIndex, 1);
99
97
  }
100
- if (!abortSignal) {
101
- return controller;
102
- }
103
98
  }
@@ -4,6 +4,7 @@ export interface IterateFocusableElements {
4
4
  onlyTabbable?: boolean;
5
5
  }
6
6
  export declare function iterateFocusableElements(container: HTMLElement, options?: IterateFocusableElements): Generator<HTMLElement, undefined, undefined>;
7
+ export declare function focusIfNeeded(elem?: HTMLElement): void;
7
8
  export declare function getFocusableChild(container: HTMLElement, lastChild?: boolean): HTMLElement | undefined;
8
9
  export declare function isFocusable(elem: HTMLElement, strict?: boolean): boolean;
9
10
  export declare function isTabbable(elem: HTMLElement, strict?: boolean): boolean;
@@ -28,6 +28,11 @@ export function* iterateFocusableElements(container, options = {}) {
28
28
  }
29
29
  return undefined;
30
30
  }
31
+ export function focusIfNeeded(elem) {
32
+ if (document.activeElement !== elem) {
33
+ elem === null || elem === void 0 ? void 0 : elem.focus();
34
+ }
35
+ }
31
36
  export function getFocusableChild(container, lastChild = false) {
32
37
  return iterateFocusableElements(container, { reverse: lastChild, strict: true, onlyTabbable: true }).next().value;
33
38
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@primer/behaviors",
3
- "version": "0.0.0-202218135849",
3
+ "version": "0.0.0-202223113012",
4
4
  "description": "Shared behaviors for JavaScript components",
5
5
  "main": "dist/cjs/index.js",
6
6
  "module": "dist/esm/index.js",