ng-primitives 0.0.7 → 0.2.0
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/README.md +14 -4
- package/accordion/accordion-trigger/accordion-trigger.directive.d.ts +2 -1
- package/autofill/README.md +3 -0
- package/autofill/autofill/autofill.directive.d.ts +19 -0
- package/{select/select-button/select-button.token.d.ts → autofill/autofill/autofill.token.d.ts} +4 -4
- package/autofill/index.d.ts +9 -0
- package/avatar/avatar/avatar.directive.d.ts +2 -1
- package/button/README.md +3 -0
- package/button/button/button.directive.d.ts +27 -0
- package/{select/select-option/select-option.token.d.ts → button/button/button.token.d.ts} +4 -4
- package/button/index.d.ts +9 -0
- package/checkbox/checkbox/checkbox.directive.d.ts +11 -61
- package/checkbox/index.d.ts +0 -4
- package/esm2022/a11y/visually-hidden/visually-hidden.directive.mjs +3 -3
- package/esm2022/accordion/accordion/accordion.directive.mjs +5 -4
- package/esm2022/accordion/accordion-content/accordion-content.directive.mjs +5 -6
- package/esm2022/accordion/accordion-item/accordion-item.directive.mjs +5 -5
- package/esm2022/accordion/accordion-trigger/accordion-trigger.directive.mjs +8 -5
- package/esm2022/autofill/autofill/autofill.directive.mjs +71 -0
- package/esm2022/autofill/autofill/autofill.token.mjs +16 -0
- package/esm2022/autofill/index.mjs +10 -0
- package/esm2022/autofill/ng-primitives-autofill.mjs +5 -0
- package/esm2022/avatar/avatar/avatar.directive.mjs +7 -4
- package/esm2022/avatar/avatar-fallback/avatar-fallback.directive.mjs +3 -3
- package/esm2022/avatar/avatar-image/avatar-image.directive.mjs +3 -3
- package/esm2022/button/button/button.directive.mjs +47 -0
- package/esm2022/button/button/button.token.mjs +16 -0
- package/esm2022/button/index.mjs +10 -0
- package/esm2022/button/ng-primitives-button.mjs +5 -0
- package/esm2022/checkbox/checkbox/checkbox.directive.mjs +29 -79
- package/esm2022/checkbox/index.mjs +1 -5
- package/esm2022/file-upload/file-upload/file-upload.directive.mjs +7 -4
- package/esm2022/focus-trap/focus-trap/focus-trap.directive.mjs +262 -0
- package/esm2022/focus-trap/focus-trap/focus-trap.token.mjs +16 -0
- package/esm2022/focus-trap/index.mjs +10 -0
- package/esm2022/focus-trap/ng-primitives-focus-trap.mjs +5 -0
- package/esm2022/form-field/description/description.directive.mjs +14 -14
- package/esm2022/form-field/error/error.directive.mjs +27 -29
- package/esm2022/form-field/form-control/form-control.directive.mjs +22 -16
- package/esm2022/form-field/form-field/form-field.directive.mjs +3 -3
- package/esm2022/form-field/form-field/form-field.token.mjs +3 -7
- package/esm2022/form-field/label/label.directive.mjs +56 -17
- package/esm2022/input/index.mjs +10 -0
- package/esm2022/input/input/input.directive.mjs +55 -0
- package/esm2022/input/input/input.token.mjs +16 -0
- package/esm2022/input/ng-primitives-input.mjs +5 -0
- package/esm2022/interactions/focus/focus.directive.mjs +15 -10
- package/esm2022/interactions/focus-visible/focus-visible.directive.mjs +12 -7
- package/esm2022/interactions/hover/hover.directive.mjs +16 -11
- package/esm2022/interactions/index.mjs +5 -1
- package/esm2022/interactions/move/move.directive.mjs +216 -0
- package/esm2022/interactions/move/move.token.mjs +16 -0
- package/esm2022/interactions/press/press.directive.mjs +118 -0
- package/esm2022/interactions/press/press.token.mjs +16 -0
- package/esm2022/internal/disabled/disabled.mjs +19 -0
- package/esm2022/internal/index.mjs +11 -0
- package/esm2022/internal/ng-primitives-internal.mjs +5 -0
- package/esm2022/internal/orientation/orientation.mjs +19 -0
- package/esm2022/internal/style-injector/style-injector.mjs +81 -0
- package/esm2022/progress/progress/progress.directive.mjs +3 -3
- package/esm2022/progress/progress-indicator/progress-indicator.directive.mjs +3 -3
- package/esm2022/radio/radio-group/radio-group.directive.mjs +14 -54
- package/esm2022/radio/radio-indicator/radio-indicator.directive.mjs +8 -5
- package/esm2022/radio/radio-item/radio-item.directive.mjs +8 -6
- package/esm2022/resize/resize/resize.directive.mjs +3 -3
- package/esm2022/roving-focus/roving-focus-group/roving-focus-group.directive.mjs +14 -9
- package/esm2022/roving-focus/roving-focus-item/roving-focus-item.directive.mjs +3 -3
- package/esm2022/search/index.mjs +10 -0
- package/esm2022/search/ng-primitives-search.mjs +5 -0
- package/esm2022/search/search-field/search-field.directive.mjs +47 -0
- package/esm2022/search/search-field/search-field.token.mjs +16 -0
- package/esm2022/select/index.mjs +1 -7
- package/esm2022/select/select/select.directive.mjs +23 -36
- package/esm2022/select/select/select.token.mjs +1 -1
- package/esm2022/slider/slider/slider.directive.mjs +18 -5
- package/esm2022/slider/slider-range/slider-range.directive.mjs +6 -5
- package/esm2022/slider/slider-thumb/slider-thumb.directive.mjs +7 -4
- package/esm2022/slider/slider-track/slider-track.directive.mjs +8 -4
- package/esm2022/switch/switch/switch.directive.mjs +18 -58
- package/esm2022/switch/switch-thumb/switch-thumb.directive.mjs +9 -6
- package/esm2022/tabs/tab-button/tab-button.directive.mjs +8 -6
- package/esm2022/tabs/tab-list/tab-list.directive.mjs +3 -3
- package/esm2022/tabs/tab-panel/tab-panel.directive.mjs +5 -6
- package/esm2022/tabs/tabset/tabset.directive.mjs +14 -18
- package/esm2022/textarea/index.mjs +10 -0
- package/esm2022/textarea/ng-primitives-textarea.mjs +5 -0
- package/esm2022/textarea/textarea/textarea.directive.mjs +37 -0
- package/esm2022/textarea/textarea/textarea.token.mjs +16 -0
- package/esm2022/toggle/toggle/toggle.directive.mjs +33 -13
- package/esm2022/tooltip/tooltip/tooltip.directive.mjs +3 -3
- package/esm2022/tooltip/tooltip-trigger/tooltip-trigger.directive.mjs +7 -7
- package/esm2022/utils/helpers/focus-manager.mjs +3 -3
- package/esm2022/utils/index.mjs +2 -2
- package/esm2022/utils/signals/async.mjs +11 -17
- package/fesm2022/ng-primitives-a11y.mjs +3 -3
- package/fesm2022/ng-primitives-accordion.mjs +19 -16
- package/fesm2022/ng-primitives-accordion.mjs.map +1 -1
- package/fesm2022/ng-primitives-autofill.mjs +100 -0
- package/fesm2022/ng-primitives-autofill.mjs.map +1 -0
- package/fesm2022/ng-primitives-avatar.mjs +13 -10
- package/fesm2022/ng-primitives-avatar.mjs.map +1 -1
- package/fesm2022/ng-primitives-button.mjs +76 -0
- package/fesm2022/ng-primitives-button.mjs.map +1 -0
- package/fesm2022/ng-primitives-checkbox.mjs +25 -203
- package/fesm2022/ng-primitives-checkbox.mjs.map +1 -1
- package/fesm2022/ng-primitives-file-upload.mjs +6 -3
- package/fesm2022/ng-primitives-file-upload.mjs.map +1 -1
- package/fesm2022/ng-primitives-focus-trap.mjs +291 -0
- package/fesm2022/ng-primitives-focus-trap.mjs.map +1 -0
- package/fesm2022/ng-primitives-form-field.mjs +119 -80
- package/fesm2022/ng-primitives-form-field.mjs.map +1 -1
- package/fesm2022/ng-primitives-input.mjs +84 -0
- package/fesm2022/ng-primitives-input.mjs.map +1 -0
- package/fesm2022/ng-primitives-interactions.mjs +394 -26
- package/fesm2022/ng-primitives-interactions.mjs.map +1 -1
- package/fesm2022/ng-primitives-internal.mjs +132 -0
- package/fesm2022/ng-primitives-internal.mjs.map +1 -0
- package/fesm2022/ng-primitives-progress.mjs +6 -6
- package/fesm2022/ng-primitives-radio.mjs +25 -62
- package/fesm2022/ng-primitives-radio.mjs.map +1 -1
- package/fesm2022/ng-primitives-resize.mjs +3 -3
- package/fesm2022/ng-primitives-roving-focus.mjs +15 -10
- package/fesm2022/ng-primitives-roving-focus.mjs.map +1 -1
- package/fesm2022/ng-primitives-search.mjs +76 -0
- package/fesm2022/ng-primitives-search.mjs.map +1 -0
- package/fesm2022/ng-primitives-select.mjs +23 -395
- package/fesm2022/ng-primitives-select.mjs.map +1 -1
- package/fesm2022/ng-primitives-slider.mjs +35 -14
- package/fesm2022/ng-primitives-slider.mjs.map +1 -1
- package/fesm2022/ng-primitives-switch.mjs +23 -62
- package/fesm2022/ng-primitives-switch.mjs.map +1 -1
- package/fesm2022/ng-primitives-tabs.mjs +27 -30
- package/fesm2022/ng-primitives-tabs.mjs.map +1 -1
- package/fesm2022/ng-primitives-textarea.mjs +66 -0
- package/fesm2022/ng-primitives-textarea.mjs.map +1 -0
- package/fesm2022/ng-primitives-toggle.mjs +32 -12
- package/fesm2022/ng-primitives-toggle.mjs.map +1 -1
- package/fesm2022/ng-primitives-tooltip.mjs +9 -9
- package/fesm2022/ng-primitives-tooltip.mjs.map +1 -1
- package/fesm2022/ng-primitives-utils.mjs +14 -20
- package/fesm2022/ng-primitives-utils.mjs.map +1 -1
- package/file-upload/file-upload/file-upload.directive.d.ts +2 -1
- package/focus-trap/README.md +3 -0
- package/focus-trap/focus-trap/focus-trap.directive.d.ts +64 -0
- package/{select/select-options/select-options.token.d.ts → focus-trap/focus-trap/focus-trap.token.d.ts} +4 -4
- package/focus-trap/index.d.ts +9 -0
- package/form-field/description/description.directive.d.ts +1 -1
- package/form-field/error/error.directive.d.ts +9 -5
- package/form-field/form-control/form-control.directive.d.ts +7 -3
- package/form-field/form-field/form-field.token.d.ts +1 -1
- package/form-field/label/label.directive.d.ts +3 -2
- package/input/README.md +3 -0
- package/input/index.d.ts +9 -0
- package/input/input/input.directive.d.ts +33 -0
- package/input/input/input.token.d.ts +14 -0
- package/interactions/focus/focus.directive.d.ts +6 -2
- package/interactions/focus-visible/focus-visible.directive.d.ts +5 -1
- package/interactions/hover/hover.directive.d.ts +5 -1
- package/interactions/index.d.ts +4 -0
- package/interactions/move/move.directive.d.ts +126 -0
- package/interactions/move/move.token.d.ts +14 -0
- package/interactions/press/press.directive.d.ts +59 -0
- package/interactions/press/press.token.d.ts +14 -0
- package/internal/README.md +3 -0
- package/internal/disabled/disabled.d.ts +21 -0
- package/internal/index.d.ts +10 -0
- package/internal/orientation/orientation.d.ts +22 -0
- package/internal/style-injector/style-injector.d.ts +36 -0
- package/package.json +49 -7
- package/radio/radio-group/radio-group.directive.d.ts +4 -41
- package/radio/radio-indicator/radio-indicator.directive.d.ts +2 -1
- package/radio/radio-item/radio-item.directive.d.ts +2 -1
- package/roving-focus/roving-focus-group/roving-focus-group.directive.d.ts +7 -2
- package/search/README.md +3 -0
- package/search/index.d.ts +9 -0
- package/search/search-field/search-field.directive.d.ts +15 -0
- package/search/search-field/search-field.token.d.ts +14 -0
- package/select/index.d.ts +0 -6
- package/select/select/select.directive.d.ts +7 -22
- package/select/select/select.token.d.ts +2 -2
- package/slider/slider/slider.directive.d.ts +4 -2
- package/slider/slider-thumb/slider-thumb.directive.d.ts +2 -1
- package/slider/slider-track/slider-track.directive.d.ts +1 -1
- package/switch/switch/switch.directive.d.ts +5 -45
- package/switch/switch-thumb/switch-thumb.directive.d.ts +2 -1
- package/tabs/tab-button/tab-button.directive.d.ts +2 -1
- package/tabs/tabset/tabset.directive.d.ts +3 -9
- package/textarea/README.md +3 -0
- package/textarea/index.d.ts +9 -0
- package/textarea/textarea/textarea.directive.d.ts +20 -0
- package/textarea/textarea/textarea.token.d.ts +14 -0
- package/toggle/toggle/toggle.directive.d.ts +16 -4
- package/utils/index.d.ts +1 -1
- package/utils/signals/async.d.ts +10 -12
- package/checkbox/checkbox-indicator/checkbox-indicator.directive.d.ts +0 -19
- package/checkbox/checkbox-indicator/checkbox-indicator.token.d.ts +0 -15
- package/checkbox/checkbox-input/checkbox-input.directive.d.ts +0 -10
- package/checkbox/checkbox-label/checkbox-label.directive.d.ts +0 -9
- package/esm2022/checkbox/checkbox-indicator/checkbox-indicator.directive.mjs +0 -51
- package/esm2022/checkbox/checkbox-indicator/checkbox-indicator.token.mjs +0 -17
- package/esm2022/checkbox/checkbox-input/checkbox-input.directive.mjs +0 -40
- package/esm2022/checkbox/checkbox-label/checkbox-label.directive.mjs +0 -32
- package/esm2022/select/select-button/select-button.directive.mjs +0 -84
- package/esm2022/select/select-button/select-button.token.mjs +0 -16
- package/esm2022/select/select-option/select-option.directive.mjs +0 -90
- package/esm2022/select/select-option/select-option.token.mjs +0 -16
- package/esm2022/select/select-options/select-options.directive.mjs +0 -157
- package/esm2022/select/select-options/select-options.token.mjs +0 -16
- package/select/select-button/select-button.directive.d.ts +0 -51
- package/select/select-option/select-option.directive.d.ts +0 -57
- package/select/select-options/select-options.directive.d.ts +0 -65
|
@@ -0,0 +1,291 @@
|
|
|
1
|
+
import { InteractivityChecker } from '@angular/cdk/a11y';
|
|
2
|
+
import * as i0 from '@angular/core';
|
|
3
|
+
import { InjectionToken, inject, ElementRef, NgZone, input, booleanAttribute, Directive, HostListener } from '@angular/core';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Copyright © 2024 Angular Primitives.
|
|
7
|
+
* https://github.com/ng-primitives/ng-primitives
|
|
8
|
+
*
|
|
9
|
+
* This source code is licensed under the CC BY-ND 4.0 license found in the
|
|
10
|
+
* LICENSE file in the root directory of this source tree.
|
|
11
|
+
*/
|
|
12
|
+
const NgpFocusTrapToken = new InjectionToken('NgpFocusTrapToken');
|
|
13
|
+
/**
|
|
14
|
+
* Inject the FocusTrap directive instance
|
|
15
|
+
*/
|
|
16
|
+
function injectFocusTrap() {
|
|
17
|
+
return inject(NgpFocusTrapToken);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Copyright © 2024 Angular Primitives.
|
|
22
|
+
* https://github.com/ng-primitives/ng-primitives
|
|
23
|
+
*
|
|
24
|
+
* This source code is licensed under the CC BY-ND 4.0 license found in the
|
|
25
|
+
* LICENSE file in the root directory of this source tree.
|
|
26
|
+
*/
|
|
27
|
+
/**
|
|
28
|
+
* This implementation is based on the Radix UI FocusScope:
|
|
29
|
+
* https://github.com/radix-ui/primitives/blob/main/packages/react/focus-scope/src/FocusScope.tsx#L306
|
|
30
|
+
*/
|
|
31
|
+
class FocusTrap {
|
|
32
|
+
constructor() {
|
|
33
|
+
/**
|
|
34
|
+
* Whether the focus trap is active.
|
|
35
|
+
*/
|
|
36
|
+
this.active = false;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Activates the focus trap.
|
|
40
|
+
*/
|
|
41
|
+
activate() {
|
|
42
|
+
this.active = true;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Deactivates the focus trap.
|
|
46
|
+
*/
|
|
47
|
+
deactivate() {
|
|
48
|
+
this.active = false;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
class FocusTrapStack {
|
|
52
|
+
constructor() {
|
|
53
|
+
/**
|
|
54
|
+
* The stack of focus traps.
|
|
55
|
+
*/
|
|
56
|
+
this.stack = [];
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Adds a focus trap to the stack.
|
|
60
|
+
*/
|
|
61
|
+
add(focusTrap) {
|
|
62
|
+
// deactivate the previous focus trap
|
|
63
|
+
this.stack.forEach(t => t.deactivate());
|
|
64
|
+
// add the new focus trap and activate it
|
|
65
|
+
this.stack.push(focusTrap);
|
|
66
|
+
focusTrap.activate();
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Removes a focus trap from the stack.
|
|
70
|
+
*/
|
|
71
|
+
remove(focusTrap) {
|
|
72
|
+
// remove the focus trap
|
|
73
|
+
const index = this.stack.indexOf(focusTrap);
|
|
74
|
+
if (index >= 0) {
|
|
75
|
+
this.stack.splice(index, 1);
|
|
76
|
+
}
|
|
77
|
+
// activate the previous focus trap
|
|
78
|
+
const previous = this.stack[this.stack.length - 1];
|
|
79
|
+
if (previous) {
|
|
80
|
+
previous.activate();
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
// create a global stack of focus traps
|
|
85
|
+
const focusTrapStack = new FocusTrapStack();
|
|
86
|
+
class NgpFocusTrap {
|
|
87
|
+
constructor() {
|
|
88
|
+
/**
|
|
89
|
+
* Create a new focus trap.
|
|
90
|
+
*/
|
|
91
|
+
this.focusTrap = new FocusTrap();
|
|
92
|
+
/**
|
|
93
|
+
* Access the interactivity checker.
|
|
94
|
+
*/
|
|
95
|
+
this.interactivityChecker = inject(InteractivityChecker);
|
|
96
|
+
/**
|
|
97
|
+
* Get the focus trap container element.
|
|
98
|
+
*/
|
|
99
|
+
this.elementRef = inject(ElementRef);
|
|
100
|
+
/**
|
|
101
|
+
* Access NgZone to run the focus trap events outside of Angular's zone.
|
|
102
|
+
*/
|
|
103
|
+
this.ngZone = inject(NgZone);
|
|
104
|
+
/**
|
|
105
|
+
* Store the mutation observer.
|
|
106
|
+
*/
|
|
107
|
+
this.mutationObserver = null;
|
|
108
|
+
/**
|
|
109
|
+
* Store the last focused element.
|
|
110
|
+
*/
|
|
111
|
+
this.lastFocusedElement = null;
|
|
112
|
+
/**
|
|
113
|
+
* Whether the focus trap is disabled.
|
|
114
|
+
*/
|
|
115
|
+
this.disabled = input(false, {
|
|
116
|
+
alias: 'ngpFocusTrapDisabled',
|
|
117
|
+
transform: booleanAttribute,
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
ngOnInit() {
|
|
121
|
+
focusTrapStack.add(this.focusTrap);
|
|
122
|
+
this.mutationObserver = new MutationObserver(this.handleMutations.bind(this));
|
|
123
|
+
// setup event listeners
|
|
124
|
+
this.ngZone.runOutsideAngular(() => {
|
|
125
|
+
this.mutationObserver.observe(this.elementRef.nativeElement, {
|
|
126
|
+
childList: true,
|
|
127
|
+
subtree: true,
|
|
128
|
+
});
|
|
129
|
+
document.addEventListener('focusin', this.handleFocusIn.bind(this));
|
|
130
|
+
document.addEventListener('focusout', this.handleFocusOut.bind(this));
|
|
131
|
+
});
|
|
132
|
+
const previouslyFocusedElement = document.activeElement;
|
|
133
|
+
const hasFocusedCandidate = this.elementRef.nativeElement.contains(previouslyFocusedElement);
|
|
134
|
+
if (!hasFocusedCandidate) {
|
|
135
|
+
this.focusFirst();
|
|
136
|
+
// if the focus didn't change, focus the container
|
|
137
|
+
if (document.activeElement === previouslyFocusedElement) {
|
|
138
|
+
this.focus(this.elementRef.nativeElement);
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
ngOnDestroy() {
|
|
143
|
+
focusTrapStack.remove(this.focusTrap);
|
|
144
|
+
this.mutationObserver?.disconnect();
|
|
145
|
+
}
|
|
146
|
+
handleFocusIn(event) {
|
|
147
|
+
if (!this.focusTrap.active || this.disabled()) {
|
|
148
|
+
return;
|
|
149
|
+
}
|
|
150
|
+
const target = event.target;
|
|
151
|
+
if (this.elementRef.nativeElement.contains(target)) {
|
|
152
|
+
this.lastFocusedElement = target;
|
|
153
|
+
}
|
|
154
|
+
else {
|
|
155
|
+
this.focus(this.lastFocusedElement);
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
/**
|
|
159
|
+
* Handles the `focusout` event.
|
|
160
|
+
*/
|
|
161
|
+
handleFocusOut(event) {
|
|
162
|
+
if (!this.focusTrap.active || this.disabled() || event.relatedTarget === null) {
|
|
163
|
+
return;
|
|
164
|
+
}
|
|
165
|
+
const relatedTarget = event.relatedTarget;
|
|
166
|
+
if (!this.elementRef.nativeElement.contains(relatedTarget)) {
|
|
167
|
+
this.focus(this.lastFocusedElement);
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
/**
|
|
171
|
+
* If the focused element gets removed from the DOM, browsers move focus back to the document.body.
|
|
172
|
+
* We move focus to the container to keep focus trapped correctly.
|
|
173
|
+
*/
|
|
174
|
+
handleMutations(mutations) {
|
|
175
|
+
const focusedElement = document.activeElement;
|
|
176
|
+
if (focusedElement !== document.body) {
|
|
177
|
+
return;
|
|
178
|
+
}
|
|
179
|
+
for (const mutation of mutations) {
|
|
180
|
+
if (mutation.removedNodes.length > 0) {
|
|
181
|
+
this.focus(this.elementRef.nativeElement);
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
/**
|
|
186
|
+
* Handles the `keydown` event.
|
|
187
|
+
*/
|
|
188
|
+
handleKeyDown(event) {
|
|
189
|
+
if (!this.focusTrap.active || this.disabled()) {
|
|
190
|
+
return;
|
|
191
|
+
}
|
|
192
|
+
const isTabKey = event.key === 'Tab' && !event.altKey && !event.ctrlKey && !event.metaKey;
|
|
193
|
+
const focusedElement = document.activeElement;
|
|
194
|
+
if (isTabKey && focusedElement) {
|
|
195
|
+
const container = event.currentTarget;
|
|
196
|
+
const [first, last] = this.getTabbableEdges(container);
|
|
197
|
+
const hasTabbableElementsInside = first && last;
|
|
198
|
+
// we can only wrap focus if we have tabbable edges
|
|
199
|
+
if (!hasTabbableElementsInside) {
|
|
200
|
+
if (focusedElement === container) {
|
|
201
|
+
event.preventDefault();
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
else {
|
|
205
|
+
if (!event.shiftKey && focusedElement === last) {
|
|
206
|
+
event.preventDefault();
|
|
207
|
+
this.focus(first);
|
|
208
|
+
}
|
|
209
|
+
else if (event.shiftKey && focusedElement === first) {
|
|
210
|
+
event.preventDefault();
|
|
211
|
+
this.focus(last);
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
/**
|
|
217
|
+
* Returns the first and last tabbable elements inside a container.
|
|
218
|
+
*/
|
|
219
|
+
getTabbableEdges(container) {
|
|
220
|
+
const candidates = this.getTabbableCandidates(container);
|
|
221
|
+
const first = this.findVisible(candidates);
|
|
222
|
+
const last = this.findVisible(candidates.reverse());
|
|
223
|
+
return [first, last];
|
|
224
|
+
}
|
|
225
|
+
/**
|
|
226
|
+
* Returns a list of potential focusable elements inside a container.
|
|
227
|
+
*/
|
|
228
|
+
getTabbableCandidates(container) {
|
|
229
|
+
const nodes = [];
|
|
230
|
+
const walker = document.createTreeWalker(container, NodeFilter.SHOW_ELEMENT, {
|
|
231
|
+
acceptNode: (node) => this.interactivityChecker.isFocusable(node)
|
|
232
|
+
? NodeFilter.FILTER_ACCEPT
|
|
233
|
+
: NodeFilter.FILTER_SKIP,
|
|
234
|
+
});
|
|
235
|
+
while (walker.nextNode()) {
|
|
236
|
+
nodes.push(walker.currentNode);
|
|
237
|
+
}
|
|
238
|
+
return nodes;
|
|
239
|
+
}
|
|
240
|
+
/**
|
|
241
|
+
* Returns the first visible element in a list..
|
|
242
|
+
*/
|
|
243
|
+
findVisible(elements) {
|
|
244
|
+
return elements.find(element => this.interactivityChecker.isVisible(element)) ?? null;
|
|
245
|
+
}
|
|
246
|
+
focus(element) {
|
|
247
|
+
element?.focus({ preventScroll: true });
|
|
248
|
+
}
|
|
249
|
+
focusFirst() {
|
|
250
|
+
const previouslyFocusedElement = document.activeElement;
|
|
251
|
+
for (const candidate of this.getTabbableCandidates(this.elementRef.nativeElement)) {
|
|
252
|
+
this.focus(candidate);
|
|
253
|
+
if (document.activeElement !== previouslyFocusedElement) {
|
|
254
|
+
return;
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.1.1", ngImport: i0, type: NgpFocusTrap, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
|
|
259
|
+
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "18.1.1", type: NgpFocusTrap, isStandalone: true, selector: "[ngpFocusTrap]", inputs: { disabled: { classPropertyName: "disabled", publicName: "ngpFocusTrapDisabled", isSignal: true, isRequired: false, transformFunction: null } }, host: { listeners: { "keydown": "handleKeyDown($event)" }, properties: { "attr.tabindex": "-1", "attr.data-focus-trap": "!disabled()" } }, providers: [{ provide: NgpFocusTrapToken, useExisting: NgpFocusTrap }], exportAs: ["ngpFocusTrap"], ngImport: i0 }); }
|
|
260
|
+
}
|
|
261
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.1.1", ngImport: i0, type: NgpFocusTrap, decorators: [{
|
|
262
|
+
type: Directive,
|
|
263
|
+
args: [{
|
|
264
|
+
standalone: true,
|
|
265
|
+
selector: '[ngpFocusTrap]',
|
|
266
|
+
exportAs: 'ngpFocusTrap',
|
|
267
|
+
providers: [{ provide: NgpFocusTrapToken, useExisting: NgpFocusTrap }],
|
|
268
|
+
host: {
|
|
269
|
+
'[attr.tabindex]': '-1',
|
|
270
|
+
'[attr.data-focus-trap]': '!disabled()',
|
|
271
|
+
},
|
|
272
|
+
}]
|
|
273
|
+
}], propDecorators: { handleKeyDown: [{
|
|
274
|
+
type: HostListener,
|
|
275
|
+
args: ['keydown', ['$event']]
|
|
276
|
+
}] } });
|
|
277
|
+
|
|
278
|
+
/**
|
|
279
|
+
* Copyright © 2024 Angular Primitives.
|
|
280
|
+
* https://github.com/ng-primitives/ng-primitives
|
|
281
|
+
*
|
|
282
|
+
* This source code is licensed under the CC BY-ND 4.0 license found in the
|
|
283
|
+
* LICENSE file in the root directory of this source tree.
|
|
284
|
+
*/
|
|
285
|
+
|
|
286
|
+
/**
|
|
287
|
+
* Generated bundle index. Do not edit.
|
|
288
|
+
*/
|
|
289
|
+
|
|
290
|
+
export { NgpFocusTrap, NgpFocusTrapToken };
|
|
291
|
+
//# sourceMappingURL=ng-primitives-focus-trap.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ng-primitives-focus-trap.mjs","sources":["../../../../packages/ng-primitives/focus-trap/src/focus-trap/focus-trap.token.ts","../../../../packages/ng-primitives/focus-trap/src/focus-trap/focus-trap.directive.ts","../../../../packages/ng-primitives/focus-trap/src/index.ts","../../../../packages/ng-primitives/focus-trap/src/ng-primitives-focus-trap.ts"],"sourcesContent":["/**\n * Copyright © 2024 Angular Primitives.\n * https://github.com/ng-primitives/ng-primitives\n *\n * This source code is licensed under the CC BY-ND 4.0 license found in the\n * LICENSE file in the root directory of this source tree.\n */\nimport { InjectionToken, inject } from '@angular/core';\nimport type { NgpFocusTrap } from './focus-trap.directive';\n\nexport const NgpFocusTrapToken = new InjectionToken<NgpFocusTrap>('NgpFocusTrapToken');\n\n/**\n * Inject the FocusTrap directive instance\n */\nexport function injectFocusTrap(): NgpFocusTrap {\n return inject(NgpFocusTrapToken);\n}\n","/**\n * Copyright © 2024 Angular Primitives.\n * https://github.com/ng-primitives/ng-primitives\n *\n * This source code is licensed under the CC BY-ND 4.0 license found in the\n * LICENSE file in the root directory of this source tree.\n */\nimport { InteractivityChecker } from '@angular/cdk/a11y';\nimport {\n booleanAttribute,\n Directive,\n ElementRef,\n HostListener,\n inject,\n input,\n NgZone,\n OnDestroy,\n OnInit,\n} from '@angular/core';\nimport { NgpFocusTrapToken } from './focus-trap.token';\n\n/**\n * This implementation is based on the Radix UI FocusScope:\n * https://github.com/radix-ui/primitives/blob/main/packages/react/focus-scope/src/FocusScope.tsx#L306\n */\n\nclass FocusTrap {\n /**\n * Whether the focus trap is active.\n */\n active: boolean = false;\n\n /**\n * Activates the focus trap.\n */\n activate(): void {\n this.active = true;\n }\n\n /**\n * Deactivates the focus trap.\n */\n deactivate(): void {\n this.active = false;\n }\n}\n\nclass FocusTrapStack {\n /**\n * The stack of focus traps.\n */\n private readonly stack: FocusTrap[] = [];\n\n /**\n * Adds a focus trap to the stack.\n */\n add(focusTrap: FocusTrap): void {\n // deactivate the previous focus trap\n this.stack.forEach(t => t.deactivate());\n\n // add the new focus trap and activate it\n this.stack.push(focusTrap);\n focusTrap.activate();\n }\n\n /**\n * Removes a focus trap from the stack.\n */\n remove(focusTrap: FocusTrap): void {\n // remove the focus trap\n const index = this.stack.indexOf(focusTrap);\n\n if (index >= 0) {\n this.stack.splice(index, 1);\n }\n\n // activate the previous focus trap\n const previous = this.stack[this.stack.length - 1];\n\n if (previous) {\n previous.activate();\n }\n }\n}\n\n// create a global stack of focus traps\nconst focusTrapStack = new FocusTrapStack();\n\n@Directive({\n standalone: true,\n selector: '[ngpFocusTrap]',\n exportAs: 'ngpFocusTrap',\n providers: [{ provide: NgpFocusTrapToken, useExisting: NgpFocusTrap }],\n host: {\n '[attr.tabindex]': '-1',\n '[attr.data-focus-trap]': '!disabled()',\n },\n})\nexport class NgpFocusTrap implements OnInit, OnDestroy {\n /**\n * Create a new focus trap.\n */\n private readonly focusTrap = new FocusTrap();\n\n /**\n * Access the interactivity checker.\n */\n private readonly interactivityChecker = inject(InteractivityChecker);\n\n /**\n * Get the focus trap container element.\n */\n private readonly elementRef = inject<ElementRef<HTMLElement>>(ElementRef);\n\n /**\n * Access NgZone to run the focus trap events outside of Angular's zone.\n */\n private readonly ngZone = inject(NgZone);\n\n /**\n * Store the mutation observer.\n */\n private mutationObserver: MutationObserver | null = null;\n\n /**\n * Store the last focused element.\n */\n private lastFocusedElement: HTMLElement | null = null;\n\n /**\n * Whether the focus trap is disabled.\n */\n readonly disabled = input(false, {\n alias: 'ngpFocusTrapDisabled',\n transform: booleanAttribute,\n });\n\n ngOnInit(): void {\n focusTrapStack.add(this.focusTrap);\n\n this.mutationObserver = new MutationObserver(this.handleMutations.bind(this));\n\n // setup event listeners\n this.ngZone.runOutsideAngular(() => {\n this.mutationObserver!.observe(this.elementRef.nativeElement, {\n childList: true,\n subtree: true,\n });\n document.addEventListener('focusin', this.handleFocusIn.bind(this));\n document.addEventListener('focusout', this.handleFocusOut.bind(this));\n });\n\n const previouslyFocusedElement = document.activeElement as HTMLElement | null;\n const hasFocusedCandidate = this.elementRef.nativeElement.contains(previouslyFocusedElement);\n\n if (!hasFocusedCandidate) {\n this.focusFirst();\n\n // if the focus didn't change, focus the container\n if (document.activeElement === previouslyFocusedElement) {\n this.focus(this.elementRef.nativeElement);\n }\n }\n }\n\n ngOnDestroy(): void {\n focusTrapStack.remove(this.focusTrap);\n this.mutationObserver?.disconnect();\n }\n\n private handleFocusIn(event: FocusEvent): void {\n if (!this.focusTrap.active || this.disabled()) {\n return;\n }\n\n const target = event.target as HTMLElement | null;\n\n if (this.elementRef.nativeElement.contains(target)) {\n this.lastFocusedElement = target;\n } else {\n this.focus(this.lastFocusedElement);\n }\n }\n\n /**\n * Handles the `focusout` event.\n */\n private handleFocusOut(event: FocusEvent) {\n if (!this.focusTrap.active || this.disabled() || event.relatedTarget === null) {\n return;\n }\n\n const relatedTarget = event.relatedTarget as HTMLElement;\n\n if (!this.elementRef.nativeElement.contains(relatedTarget)) {\n this.focus(this.lastFocusedElement);\n }\n }\n\n /**\n * If the focused element gets removed from the DOM, browsers move focus back to the document.body.\n * We move focus to the container to keep focus trapped correctly.\n */\n private handleMutations(mutations: MutationRecord[]): void {\n const focusedElement = document.activeElement as HTMLElement | null;\n\n if (focusedElement !== document.body) {\n return;\n }\n\n for (const mutation of mutations) {\n if (mutation.removedNodes.length > 0) {\n this.focus(this.elementRef.nativeElement);\n }\n }\n }\n\n /**\n * Handles the `keydown` event.\n */\n @HostListener('keydown', ['$event'])\n protected handleKeyDown(event: KeyboardEvent): void {\n if (!this.focusTrap.active || this.disabled()) {\n return;\n }\n\n const isTabKey = event.key === 'Tab' && !event.altKey && !event.ctrlKey && !event.metaKey;\n const focusedElement = document.activeElement as HTMLElement | null;\n\n if (isTabKey && focusedElement) {\n const container = event.currentTarget as HTMLElement;\n const [first, last] = this.getTabbableEdges(container);\n const hasTabbableElementsInside = first && last;\n\n // we can only wrap focus if we have tabbable edges\n if (!hasTabbableElementsInside) {\n if (focusedElement === container) {\n event.preventDefault();\n }\n } else {\n if (!event.shiftKey && focusedElement === last) {\n event.preventDefault();\n this.focus(first);\n } else if (event.shiftKey && focusedElement === first) {\n event.preventDefault();\n this.focus(last);\n }\n }\n }\n }\n\n /**\n * Returns the first and last tabbable elements inside a container.\n */\n private getTabbableEdges(container: HTMLElement) {\n const candidates = this.getTabbableCandidates(container);\n const first = this.findVisible(candidates);\n const last = this.findVisible(candidates.reverse());\n return [first, last] as const;\n }\n\n /**\n * Returns a list of potential focusable elements inside a container.\n */\n private getTabbableCandidates(container: HTMLElement) {\n const nodes: HTMLElement[] = [];\n const walker = document.createTreeWalker(container, NodeFilter.SHOW_ELEMENT, {\n acceptNode: (node: HTMLElement) =>\n this.interactivityChecker.isFocusable(node)\n ? NodeFilter.FILTER_ACCEPT\n : NodeFilter.FILTER_SKIP,\n });\n while (walker.nextNode()) {\n nodes.push(walker.currentNode as HTMLElement);\n }\n return nodes;\n }\n\n /**\n * Returns the first visible element in a list..\n */\n private findVisible(elements: HTMLElement[]) {\n return elements.find(element => this.interactivityChecker.isVisible(element)) ?? null;\n }\n\n private focus(element?: HTMLElement | null) {\n element?.focus({ preventScroll: true });\n }\n\n private focusFirst(): void {\n const previouslyFocusedElement = document.activeElement;\n\n for (const candidate of this.getTabbableCandidates(this.elementRef.nativeElement)) {\n this.focus(candidate);\n\n if (document.activeElement !== previouslyFocusedElement) {\n return;\n }\n }\n }\n}\n","/**\n * Copyright © 2024 Angular Primitives.\n * https://github.com/ng-primitives/ng-primitives\n *\n * This source code is licensed under the CC BY-ND 4.0 license found in the\n * LICENSE file in the root directory of this source tree.\n */\n\nexport { NgpFocusTrap } from './focus-trap/focus-trap.directive';\nexport { NgpFocusTrapToken } from './focus-trap/focus-trap.token';\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":"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"}
|