ng-primitives 0.90.0 → 0.91.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/a11y/index.d.ts +38 -46
- package/accordion/index.d.ts +252 -104
- package/ai/index.d.ts +1 -1
- package/autofill/index.d.ts +49 -9
- package/avatar/index.d.ts +96 -61
- package/breadcrumbs/index.d.ts +156 -16
- package/button/index.d.ts +23 -28
- package/checkbox/index.d.ts +93 -14
- package/combobox/index.d.ts +1 -1
- package/date-picker/index.d.ts +12 -11
- package/fesm2022/ng-primitives-a11y.mjs +36 -52
- package/fesm2022/ng-primitives-a11y.mjs.map +1 -1
- package/fesm2022/ng-primitives-accordion.mjs +210 -189
- package/fesm2022/ng-primitives-accordion.mjs.map +1 -1
- package/fesm2022/ng-primitives-ai.mjs +4 -4
- package/fesm2022/ng-primitives-ai.mjs.map +1 -1
- package/fesm2022/ng-primitives-autofill.mjs +53 -36
- package/fesm2022/ng-primitives-autofill.mjs.map +1 -1
- package/fesm2022/ng-primitives-avatar.mjs +97 -138
- package/fesm2022/ng-primitives-avatar.mjs.map +1 -1
- package/fesm2022/ng-primitives-breadcrumbs.mjs +92 -35
- package/fesm2022/ng-primitives-breadcrumbs.mjs.map +1 -1
- package/fesm2022/ng-primitives-button.mjs +14 -36
- package/fesm2022/ng-primitives-button.mjs.map +1 -1
- package/fesm2022/ng-primitives-checkbox.mjs +87 -65
- package/fesm2022/ng-primitives-checkbox.mjs.map +1 -1
- package/fesm2022/ng-primitives-combobox.mjs +9 -9
- package/fesm2022/ng-primitives-combobox.mjs.map +1 -1
- package/fesm2022/ng-primitives-date-picker.mjs +5 -4
- package/fesm2022/ng-primitives-date-picker.mjs.map +1 -1
- package/fesm2022/ng-primitives-form-field.mjs +48 -16
- package/fesm2022/ng-primitives-form-field.mjs.map +1 -1
- package/fesm2022/ng-primitives-input.mjs +32 -48
- package/fesm2022/ng-primitives-input.mjs.map +1 -1
- package/fesm2022/ng-primitives-interactions.mjs +4 -4
- package/fesm2022/ng-primitives-interactions.mjs.map +1 -1
- package/fesm2022/ng-primitives-listbox.mjs.map +1 -1
- package/fesm2022/ng-primitives-menu.mjs +13 -6
- package/fesm2022/ng-primitives-menu.mjs.map +1 -1
- package/fesm2022/ng-primitives-pagination.mjs +6 -6
- package/fesm2022/ng-primitives-pagination.mjs.map +1 -1
- package/fesm2022/ng-primitives-progress.mjs +2 -2
- package/fesm2022/ng-primitives-progress.mjs.map +1 -1
- package/fesm2022/ng-primitives-radio.mjs +3 -3
- package/fesm2022/ng-primitives-radio.mjs.map +1 -1
- package/fesm2022/ng-primitives-roving-focus.mjs +259 -236
- package/fesm2022/ng-primitives-roving-focus.mjs.map +1 -1
- package/fesm2022/ng-primitives-search.mjs.map +1 -1
- package/fesm2022/ng-primitives-select.mjs +8 -8
- package/fesm2022/ng-primitives-select.mjs.map +1 -1
- package/fesm2022/ng-primitives-slider.mjs +195 -172
- package/fesm2022/ng-primitives-slider.mjs.map +1 -1
- package/fesm2022/ng-primitives-state.mjs +172 -2
- package/fesm2022/ng-primitives-state.mjs.map +1 -1
- package/fesm2022/ng-primitives-switch.mjs +90 -88
- package/fesm2022/ng-primitives-switch.mjs.map +1 -1
- package/fesm2022/ng-primitives-tabs.mjs +4 -1
- package/fesm2022/ng-primitives-tabs.mjs.map +1 -1
- package/fesm2022/ng-primitives-textarea.mjs +27 -35
- package/fesm2022/ng-primitives-textarea.mjs.map +1 -1
- package/fesm2022/ng-primitives-toggle-group.mjs +134 -136
- package/fesm2022/ng-primitives-toggle-group.mjs.map +1 -1
- package/fesm2022/ng-primitives-toggle.mjs +69 -58
- package/fesm2022/ng-primitives-toggle.mjs.map +1 -1
- package/fesm2022/ng-primitives-toolbar.mjs +26 -35
- package/fesm2022/ng-primitives-toolbar.mjs.map +1 -1
- package/fesm2022/ng-primitives-utils.mjs +48 -35
- package/fesm2022/ng-primitives-utils.mjs.map +1 -1
- package/form-field/index.d.ts +7 -3
- package/input/index.d.ts +61 -24
- package/interactions/index.d.ts +5 -5
- package/listbox/index.d.ts +1 -1
- package/menu/index.d.ts +3 -2
- package/package.json +1 -1
- package/pagination/index.d.ts +7 -7
- package/roving-focus/index.d.ts +77 -101
- package/schematics/ng-add/schema.d.ts +0 -1
- package/schematics/ng-generate/templates/checkbox/checkbox.__fileSuffix@dasherize__.ts.template +2 -2
- package/schematics/ng-generate/templates/slider/slider.__fileSuffix@dasherize__.ts.template +6 -3
- package/schematics/ng-generate/templates/switch/switch.__fileSuffix@dasherize__.ts.template +2 -2
- package/schematics/ng-generate/templates/toggle/toggle.__fileSuffix@dasherize__.ts.template +2 -2
- package/schematics/ng-generate/templates/toggle-group/toggle-group.__fileSuffix@dasherize__.ts.template +2 -2
- package/schematics/ng-generate/templates/toolbar/toolbar.__fileSuffix@dasherize__.ts.template +1 -1
- package/search/index.d.ts +1 -1
- package/select/index.d.ts +2 -2
- package/slider/index.d.ts +195 -56
- package/state/index.d.ts +57 -3
- package/switch/index.d.ts +103 -28
- package/textarea/index.d.ts +63 -8
- package/toggle/index.d.ts +65 -24
- package/toggle-group/index.d.ts +79 -54
- package/toolbar/index.d.ts +27 -17
- package/utils/index.d.ts +1 -0
|
@@ -1,193 +1,92 @@
|
|
|
1
|
-
import { Directionality } from '@angular/cdk/bidi';
|
|
2
1
|
import * as i0 from '@angular/core';
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
2
|
+
import { inject, signal, InjectionToken, input, booleanAttribute, Directive, computed } from '@angular/core';
|
|
3
|
+
import { Directionality } from '@angular/cdk/bidi';
|
|
4
|
+
import { createPrimitive, injectInheritedState, controlled, attrBinding, listener, onDestroy } from 'ng-primitives/state';
|
|
5
5
|
import { FocusMonitor } from '@angular/cdk/a11y';
|
|
6
|
+
import { injectElementRef } from 'ng-primitives/internal';
|
|
7
|
+
import { uniqueId } from 'ng-primitives/utils';
|
|
6
8
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
*/
|
|
14
|
-
const provideRovingFocusGroupState = createStateProvider(NgpRovingFocusGroupStateToken);
|
|
15
|
-
/**
|
|
16
|
-
* Injects the RovingFocusGroup state.
|
|
17
|
-
*/
|
|
18
|
-
const injectRovingFocusGroupState = createStateInjector(NgpRovingFocusGroupStateToken);
|
|
19
|
-
/**
|
|
20
|
-
* The RovingFocusGroup state registration function.
|
|
21
|
-
*/
|
|
22
|
-
const rovingFocusGroupState = createState(NgpRovingFocusGroupStateToken);
|
|
23
|
-
|
|
24
|
-
const NgpRovingFocusGroupToken = new InjectionToken('NgpRovingFocusGroupToken');
|
|
25
|
-
/**
|
|
26
|
-
* Inject the RovingFocusGroup directive instance
|
|
27
|
-
* @returns The RovingFocusGroup directive instance
|
|
28
|
-
*/
|
|
29
|
-
function injectRovingFocusGroup() {
|
|
30
|
-
return inject(NgpRovingFocusGroupToken);
|
|
31
|
-
}
|
|
32
|
-
/**
|
|
33
|
-
* Provide the RovingFocusGroup directive instance
|
|
34
|
-
* @param type The RovingFocusGroup directive type
|
|
35
|
-
* @returns The RovingFocusGroup token
|
|
36
|
-
*/
|
|
37
|
-
function provideRovingFocusGroup(type, { inherit = true } = {}) {
|
|
38
|
-
return {
|
|
39
|
-
provide: NgpRovingFocusGroupToken,
|
|
40
|
-
// Roving focus groups may be nested, in this case, the parent group should be used
|
|
41
|
-
useFactory: () => {
|
|
42
|
-
if (!inherit) {
|
|
43
|
-
return inject(type, { self: true });
|
|
44
|
-
}
|
|
45
|
-
// If the parent group is not found, return the current group
|
|
46
|
-
// This is useful for nested groups
|
|
47
|
-
return (inject(NgpRovingFocusGroupToken, { skipSelf: true, optional: true }) ??
|
|
48
|
-
inject(type, { self: true }));
|
|
49
|
-
},
|
|
50
|
-
};
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
/**
|
|
54
|
-
* Apply the `ngpRovingFocusGroup` directive to an element to manage focus for a group of child elements.
|
|
55
|
-
*/
|
|
56
|
-
class NgpRovingFocusGroup {
|
|
57
|
-
constructor() {
|
|
58
|
-
/**
|
|
59
|
-
* Access the directionality service.
|
|
60
|
-
*/
|
|
61
|
-
this.directionality = inject(Directionality);
|
|
62
|
-
/**
|
|
63
|
-
* Determine the orientation of the roving focus group.
|
|
64
|
-
* @default 'vertical'
|
|
65
|
-
*/
|
|
66
|
-
this.orientation = input('vertical', ...(ngDevMode ? [{ debugName: "orientation", alias: 'ngpRovingFocusGroupOrientation' }] : [{
|
|
67
|
-
alias: 'ngpRovingFocusGroupOrientation',
|
|
68
|
-
}]));
|
|
69
|
-
/**
|
|
70
|
-
* Determine if focus should wrap when the end or beginning is reached.
|
|
71
|
-
*/
|
|
72
|
-
this.wrap = input(true, ...(ngDevMode ? [{ debugName: "wrap", alias: 'ngpRovingFocusGroupWrap',
|
|
73
|
-
transform: booleanAttribute }] : [{
|
|
74
|
-
alias: 'ngpRovingFocusGroupWrap',
|
|
75
|
-
transform: booleanAttribute,
|
|
76
|
-
}]));
|
|
77
|
-
/**
|
|
78
|
-
* Determine if the home and end keys should navigate to the first and last items.
|
|
79
|
-
*/
|
|
80
|
-
this.homeEnd = input(true, ...(ngDevMode ? [{ debugName: "homeEnd", alias: 'ngpRovingFocusGroupHomeEnd',
|
|
81
|
-
transform: booleanAttribute }] : [{
|
|
82
|
-
alias: 'ngpRovingFocusGroupHomeEnd',
|
|
83
|
-
transform: booleanAttribute,
|
|
84
|
-
}]));
|
|
85
|
-
/**
|
|
86
|
-
* Determine if the roving focus group is disabled.
|
|
87
|
-
*/
|
|
88
|
-
this.disabled = input(false, ...(ngDevMode ? [{ debugName: "disabled", alias: 'ngpRovingFocusGroupDisabled',
|
|
89
|
-
transform: booleanAttribute }] : [{
|
|
90
|
-
alias: 'ngpRovingFocusGroupDisabled',
|
|
91
|
-
transform: booleanAttribute,
|
|
92
|
-
}]));
|
|
93
|
-
/**
|
|
94
|
-
* Store the items in the roving focus group.
|
|
95
|
-
*/
|
|
96
|
-
this.items = signal([], ...(ngDevMode ? [{ debugName: "items" }] : []));
|
|
97
|
-
/**
|
|
98
|
-
* Store the active item in the roving focus group.
|
|
99
|
-
* @internal
|
|
100
|
-
*/
|
|
101
|
-
this.activeItem = signal(null, ...(ngDevMode ? [{ debugName: "activeItem" }] : []));
|
|
102
|
-
/**
|
|
103
|
-
* The state of the roving focus group.
|
|
104
|
-
*/
|
|
105
|
-
this.state = rovingFocusGroupState(this);
|
|
9
|
+
const [NgpRovingFocusGroupStateToken, ngpRovingFocusGroup, injectRovingFocusGroupState, provideRovingFocusGroupState,] = createPrimitive('NgpRovingFocusGroup', ({ orientation: _orientation = signal('vertical'), wrap = signal(false), homeEnd = signal(true), disabled = signal(false), inherit = true, }) => {
|
|
10
|
+
const parentGroup = inherit
|
|
11
|
+
? injectInheritedState(() => NgpRovingFocusGroupStateToken)?.()
|
|
12
|
+
: null;
|
|
13
|
+
if (parentGroup) {
|
|
14
|
+
return parentGroup;
|
|
106
15
|
}
|
|
16
|
+
const directionality = inject(Directionality);
|
|
17
|
+
const items = signal([], ...(ngDevMode ? [{ debugName: "items" }] : []));
|
|
18
|
+
const orientation = controlled(_orientation);
|
|
107
19
|
/**
|
|
108
20
|
* Get the items in the roving focus group sorted by order.
|
|
109
21
|
*/
|
|
110
|
-
|
|
111
|
-
return
|
|
22
|
+
function getSortedItems() {
|
|
23
|
+
return items().sort((a, b) => {
|
|
112
24
|
// sort the items by their position in the document
|
|
113
|
-
return a.
|
|
25
|
+
return a.element.nativeElement.compareDocumentPosition(b.element.nativeElement) &
|
|
114
26
|
Node.DOCUMENT_POSITION_FOLLOWING
|
|
115
27
|
? -1
|
|
116
28
|
: 1;
|
|
117
29
|
});
|
|
118
30
|
}
|
|
119
31
|
/**
|
|
120
|
-
*
|
|
121
|
-
* @param item The item to register
|
|
122
|
-
* @internal
|
|
32
|
+
* Store the active item in the roving focus group.
|
|
123
33
|
*/
|
|
124
|
-
|
|
125
|
-
this.items.update(items => [...items, item]);
|
|
126
|
-
// if there is no active item, make the first item the tabbable item
|
|
127
|
-
if (!this.activeItem()) {
|
|
128
|
-
this.activeItem.set(item);
|
|
129
|
-
}
|
|
130
|
-
}
|
|
131
|
-
/**
|
|
132
|
-
* Unregister an item with the roving focus group.
|
|
133
|
-
* @param item The item to unregister
|
|
134
|
-
* @internal
|
|
135
|
-
*/
|
|
136
|
-
unregister(item) {
|
|
137
|
-
this.items.update(items => items.filter(i => i !== item));
|
|
138
|
-
// check if the unregistered item is the active item
|
|
139
|
-
if (this.activeItem() === item) {
|
|
140
|
-
// if the active item is unregistered, activate the first item
|
|
141
|
-
this.activeItem.set(this.items()[0] ?? null);
|
|
142
|
-
}
|
|
143
|
-
}
|
|
34
|
+
const activeItem = signal(null, ...(ngDevMode ? [{ debugName: "activeItem" }] : []));
|
|
144
35
|
/**
|
|
145
36
|
* Activate an item in the roving focus group.
|
|
146
37
|
* @param item The item to activate
|
|
147
38
|
* @param origin The origin of the focus change
|
|
148
39
|
*/
|
|
149
|
-
setActiveItem(
|
|
150
|
-
|
|
151
|
-
item
|
|
40
|
+
function setActiveItem(id, origin = 'program') {
|
|
41
|
+
activeItem.set(id);
|
|
42
|
+
const item = items().find(i => i.id() === id) ?? null;
|
|
43
|
+
if (item) {
|
|
44
|
+
item.focus(origin);
|
|
45
|
+
}
|
|
152
46
|
}
|
|
153
47
|
/**
|
|
154
48
|
* Activate the first item in the roving focus group.
|
|
155
49
|
* @param origin The origin of the focus change
|
|
156
50
|
*/
|
|
157
|
-
activateFirstItem(origin) {
|
|
51
|
+
function activateFirstItem(origin) {
|
|
158
52
|
// find the first item that is not disabled
|
|
159
|
-
const item =
|
|
53
|
+
const item = getSortedItems().find(i => !i.disabled()) ?? null;
|
|
160
54
|
// set the first item as the active item
|
|
161
|
-
|
|
55
|
+
if (item) {
|
|
56
|
+
setActiveItem(item.id(), origin);
|
|
57
|
+
}
|
|
162
58
|
}
|
|
163
59
|
/**
|
|
164
60
|
* Activate the last item in the roving focus group.
|
|
165
61
|
* @param origin The origin of the focus change
|
|
166
62
|
*/
|
|
167
|
-
activateLastItem(origin) {
|
|
63
|
+
function activateLastItem(origin) {
|
|
168
64
|
// find the last item that is not disabled
|
|
169
|
-
const item = [...
|
|
65
|
+
const item = [...getSortedItems()].reverse().find(i => !i.disabled()) ?? null;
|
|
170
66
|
// set the last item as the active item
|
|
171
|
-
|
|
67
|
+
if (item) {
|
|
68
|
+
setActiveItem(item.id(), origin);
|
|
69
|
+
}
|
|
172
70
|
}
|
|
173
71
|
/**
|
|
174
72
|
* Activate the next item in the roving focus group.
|
|
175
73
|
* @param origin The origin of the focus change
|
|
176
74
|
*/
|
|
177
|
-
activateNextItem(origin) {
|
|
178
|
-
const
|
|
75
|
+
function activateNextItem(origin) {
|
|
76
|
+
const currentActiveItem = activeItem();
|
|
179
77
|
// if there is no active item, activate the first item
|
|
180
|
-
if (!
|
|
181
|
-
|
|
78
|
+
if (!currentActiveItem) {
|
|
79
|
+
activateFirstItem(origin);
|
|
182
80
|
return;
|
|
183
81
|
}
|
|
184
82
|
// find the index of the active item
|
|
185
|
-
const
|
|
83
|
+
const sortedItems = getSortedItems();
|
|
84
|
+
const index = sortedItems.findIndex(i => i.id() === currentActiveItem);
|
|
186
85
|
// find the next item that is not disabled
|
|
187
|
-
const item =
|
|
86
|
+
const item = sortedItems.slice(index + 1).find(i => !i.disabled()) ?? null;
|
|
188
87
|
// if we are at the end of the list, wrap to the beginning
|
|
189
|
-
if (!item &&
|
|
190
|
-
|
|
88
|
+
if (!item && wrap()) {
|
|
89
|
+
activateFirstItem(origin);
|
|
191
90
|
return;
|
|
192
91
|
}
|
|
193
92
|
// if there is no next item, do nothing
|
|
@@ -195,29 +94,30 @@ class NgpRovingFocusGroup {
|
|
|
195
94
|
return;
|
|
196
95
|
}
|
|
197
96
|
// set the next item as the active item
|
|
198
|
-
|
|
97
|
+
setActiveItem(item.id(), origin);
|
|
199
98
|
}
|
|
200
99
|
/**
|
|
201
100
|
* Activate the previous item in the roving focus group.
|
|
202
101
|
* @param origin The origin of the focus change
|
|
203
102
|
*/
|
|
204
|
-
activatePreviousItem(origin) {
|
|
205
|
-
const
|
|
103
|
+
function activatePreviousItem(origin) {
|
|
104
|
+
const currentActiveItem = activeItem();
|
|
206
105
|
// if there is no active item, activate the last item
|
|
207
|
-
if (!
|
|
208
|
-
|
|
106
|
+
if (!currentActiveItem) {
|
|
107
|
+
activateLastItem(origin);
|
|
209
108
|
return;
|
|
210
109
|
}
|
|
211
110
|
// find the index of the active item
|
|
212
|
-
const
|
|
111
|
+
const sortedItems = getSortedItems();
|
|
112
|
+
const index = sortedItems.findIndex(i => i.id() === currentActiveItem);
|
|
213
113
|
// find the previous item that is not disabled
|
|
214
|
-
const item =
|
|
114
|
+
const item = sortedItems
|
|
215
115
|
.slice(0, index)
|
|
216
116
|
.reverse()
|
|
217
117
|
.find(i => !i.disabled()) ?? null;
|
|
218
118
|
// if we are at the beginning of the list, wrap to the end
|
|
219
|
-
if (!item &&
|
|
220
|
-
|
|
119
|
+
if (!item && wrap()) {
|
|
120
|
+
activateLastItem(origin);
|
|
221
121
|
return;
|
|
222
122
|
}
|
|
223
123
|
// if there is no previous item, do nothing
|
|
@@ -225,169 +125,292 @@ class NgpRovingFocusGroup {
|
|
|
225
125
|
return;
|
|
226
126
|
}
|
|
227
127
|
// set the previous item as the active item
|
|
228
|
-
|
|
128
|
+
setActiveItem(item.id(), origin);
|
|
229
129
|
}
|
|
230
130
|
/**
|
|
231
131
|
* Handle keyboard navigation for the roving focus group.
|
|
232
132
|
* @param event The keyboard event
|
|
233
|
-
* @internal
|
|
234
133
|
*/
|
|
235
|
-
onKeydown(event) {
|
|
236
|
-
if (
|
|
134
|
+
function onKeydown(event) {
|
|
135
|
+
if (disabled()) {
|
|
237
136
|
return;
|
|
238
137
|
}
|
|
239
138
|
switch (event.key) {
|
|
240
139
|
case 'ArrowUp':
|
|
241
|
-
if (
|
|
140
|
+
if (orientation() === 'vertical') {
|
|
242
141
|
event.preventDefault();
|
|
243
|
-
|
|
142
|
+
activatePreviousItem('keyboard');
|
|
244
143
|
}
|
|
245
144
|
break;
|
|
246
145
|
case 'ArrowDown':
|
|
247
|
-
if (
|
|
146
|
+
if (orientation() === 'vertical') {
|
|
248
147
|
event.preventDefault();
|
|
249
|
-
|
|
148
|
+
activateNextItem('keyboard');
|
|
250
149
|
}
|
|
251
150
|
break;
|
|
252
151
|
case 'ArrowLeft':
|
|
253
|
-
if (
|
|
152
|
+
if (orientation() === 'horizontal') {
|
|
254
153
|
event.preventDefault();
|
|
255
|
-
if (
|
|
256
|
-
|
|
154
|
+
if (directionality.value === 'ltr') {
|
|
155
|
+
activatePreviousItem('keyboard');
|
|
257
156
|
}
|
|
258
157
|
else {
|
|
259
|
-
|
|
158
|
+
activateNextItem('keyboard');
|
|
260
159
|
}
|
|
261
160
|
}
|
|
262
161
|
break;
|
|
263
162
|
case 'ArrowRight':
|
|
264
|
-
if (
|
|
163
|
+
if (orientation() === 'horizontal') {
|
|
265
164
|
event.preventDefault();
|
|
266
|
-
if (
|
|
267
|
-
|
|
165
|
+
if (directionality.value === 'ltr') {
|
|
166
|
+
activateNextItem('keyboard');
|
|
268
167
|
}
|
|
269
168
|
else {
|
|
270
|
-
|
|
169
|
+
activatePreviousItem('keyboard');
|
|
271
170
|
}
|
|
272
171
|
}
|
|
273
172
|
break;
|
|
274
173
|
case 'Home':
|
|
275
|
-
if (
|
|
174
|
+
if (homeEnd()) {
|
|
276
175
|
event.preventDefault();
|
|
277
|
-
|
|
176
|
+
activateFirstItem('keyboard');
|
|
278
177
|
}
|
|
279
178
|
break;
|
|
280
179
|
case 'End':
|
|
281
|
-
if (
|
|
180
|
+
if (homeEnd()) {
|
|
282
181
|
event.preventDefault();
|
|
283
|
-
|
|
182
|
+
activateLastItem('keyboard');
|
|
284
183
|
}
|
|
285
184
|
break;
|
|
286
185
|
}
|
|
287
186
|
}
|
|
288
|
-
|
|
289
|
-
|
|
187
|
+
function register(item) {
|
|
188
|
+
items.update(items => [...items, item]);
|
|
189
|
+
// if there is no active item, make the first item the tabbable item
|
|
190
|
+
if (!activeItem()) {
|
|
191
|
+
activeItem.set(item.id());
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
/**
|
|
195
|
+
* Unregister an item with the roving focus group.
|
|
196
|
+
* @param item The item to unregister
|
|
197
|
+
* @internal
|
|
198
|
+
*/
|
|
199
|
+
function unregister(item) {
|
|
200
|
+
items.update(items => items.filter(i => i !== item));
|
|
201
|
+
// check if the unregistered item is the active item
|
|
202
|
+
if (activeItem() === item.id()) {
|
|
203
|
+
// if the active item is unregistered, activate the first item
|
|
204
|
+
activeItem.set(items()[0]?.id() ?? null);
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
/**
|
|
208
|
+
* Set the orientation of the roving focus group.
|
|
209
|
+
* @param value The orientation value
|
|
210
|
+
*/
|
|
211
|
+
function setOrientation(value) {
|
|
212
|
+
orientation.set(value);
|
|
213
|
+
}
|
|
214
|
+
return {
|
|
215
|
+
orientation: orientation.asReadonly(),
|
|
216
|
+
setOrientation,
|
|
217
|
+
wrap,
|
|
218
|
+
homeEnd,
|
|
219
|
+
disabled,
|
|
220
|
+
activeItem,
|
|
221
|
+
setActiveItem,
|
|
222
|
+
onKeydown,
|
|
223
|
+
register,
|
|
224
|
+
unregister,
|
|
225
|
+
};
|
|
226
|
+
});
|
|
227
|
+
|
|
228
|
+
const NgpRovingFocusGroupToken = new InjectionToken('NgpRovingFocusGroupToken');
|
|
229
|
+
/**
|
|
230
|
+
* Inject the RovingFocusGroup directive instance
|
|
231
|
+
* @returns The RovingFocusGroup directive instance
|
|
232
|
+
*/
|
|
233
|
+
function injectRovingFocusGroup() {
|
|
234
|
+
return inject(NgpRovingFocusGroupToken);
|
|
235
|
+
}
|
|
236
|
+
/**
|
|
237
|
+
* Provide the RovingFocusGroup directive instance
|
|
238
|
+
* @param type The RovingFocusGroup directive type
|
|
239
|
+
* @returns The RovingFocusGroup token
|
|
240
|
+
*/
|
|
241
|
+
function provideRovingFocusGroup(type, { inherit = true } = {}) {
|
|
242
|
+
return {
|
|
243
|
+
provide: NgpRovingFocusGroupToken,
|
|
244
|
+
// Roving focus groups may be nested, in this case, the parent group should be used
|
|
245
|
+
useFactory: () => {
|
|
246
|
+
if (!inherit) {
|
|
247
|
+
return inject(type, { self: true });
|
|
248
|
+
}
|
|
249
|
+
// If the parent group is not found, return the current group
|
|
250
|
+
// This is useful for nested groups
|
|
251
|
+
return (inject(NgpRovingFocusGroupToken, { skipSelf: true, optional: true }) ??
|
|
252
|
+
inject(type, { self: true }));
|
|
253
|
+
},
|
|
254
|
+
};
|
|
290
255
|
}
|
|
291
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.9", ngImport: i0, type: NgpRovingFocusGroup, decorators: [{
|
|
292
|
-
type: Directive,
|
|
293
|
-
args: [{
|
|
294
|
-
selector: '[ngpRovingFocusGroup]',
|
|
295
|
-
exportAs: 'ngpRovingFocusGroup',
|
|
296
|
-
providers: [provideRovingFocusGroup(NgpRovingFocusGroup), provideRovingFocusGroupState()],
|
|
297
|
-
}]
|
|
298
|
-
}], propDecorators: { orientation: [{ type: i0.Input, args: [{ isSignal: true, alias: "ngpRovingFocusGroupOrientation", required: false }] }], wrap: [{ type: i0.Input, args: [{ isSignal: true, alias: "ngpRovingFocusGroupWrap", required: false }] }], homeEnd: [{ type: i0.Input, args: [{ isSignal: true, alias: "ngpRovingFocusGroupHomeEnd", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "ngpRovingFocusGroupDisabled", required: false }] }] } });
|
|
299
256
|
|
|
300
257
|
/**
|
|
301
|
-
* Apply the `
|
|
258
|
+
* Apply the `ngpRovingFocusGroup` directive to an element to manage focus for a group of child elements.
|
|
302
259
|
*/
|
|
303
|
-
class
|
|
260
|
+
class NgpRovingFocusGroup {
|
|
304
261
|
constructor() {
|
|
305
262
|
/**
|
|
306
|
-
*
|
|
263
|
+
* Determine the orientation of the roving focus group.
|
|
264
|
+
* @default 'vertical'
|
|
307
265
|
*/
|
|
308
|
-
this.
|
|
266
|
+
this.orientation = input('vertical', ...(ngDevMode ? [{ debugName: "orientation", alias: 'ngpRovingFocusGroupOrientation' }] : [{
|
|
267
|
+
alias: 'ngpRovingFocusGroupOrientation',
|
|
268
|
+
}]));
|
|
309
269
|
/**
|
|
310
|
-
*
|
|
270
|
+
* Determine if focus should wrap when the end or beginning is reached.
|
|
311
271
|
*/
|
|
312
|
-
this.
|
|
272
|
+
this.wrap = input(true, ...(ngDevMode ? [{ debugName: "wrap", alias: 'ngpRovingFocusGroupWrap',
|
|
273
|
+
transform: booleanAttribute }] : [{
|
|
274
|
+
alias: 'ngpRovingFocusGroupWrap',
|
|
275
|
+
transform: booleanAttribute,
|
|
276
|
+
}]));
|
|
313
277
|
/**
|
|
314
|
-
*
|
|
278
|
+
* Determine if the home and end keys should navigate to the first and last items.
|
|
315
279
|
*/
|
|
316
|
-
this.
|
|
280
|
+
this.homeEnd = input(true, ...(ngDevMode ? [{ debugName: "homeEnd", alias: 'ngpRovingFocusGroupHomeEnd',
|
|
281
|
+
transform: booleanAttribute }] : [{
|
|
282
|
+
alias: 'ngpRovingFocusGroupHomeEnd',
|
|
283
|
+
transform: booleanAttribute,
|
|
284
|
+
}]));
|
|
317
285
|
/**
|
|
318
|
-
*
|
|
286
|
+
* Determine if the roving focus group is disabled.
|
|
319
287
|
*/
|
|
320
|
-
this.disabled = input(false, ...(ngDevMode ? [{ debugName: "disabled", alias: '
|
|
288
|
+
this.disabled = input(false, ...(ngDevMode ? [{ debugName: "disabled", alias: 'ngpRovingFocusGroupDisabled',
|
|
321
289
|
transform: booleanAttribute }] : [{
|
|
322
|
-
alias: '
|
|
290
|
+
alias: 'ngpRovingFocusGroupDisabled',
|
|
323
291
|
transform: booleanAttribute,
|
|
324
292
|
}]));
|
|
325
293
|
/**
|
|
326
|
-
*
|
|
294
|
+
* Store the active item in the roving focus group.
|
|
295
|
+
* @internal
|
|
327
296
|
*/
|
|
328
|
-
this.
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
297
|
+
this.activeItem = signal(null, ...(ngDevMode ? [{ debugName: "activeItem" }] : []));
|
|
298
|
+
/**
|
|
299
|
+
* The state of the roving focus group.
|
|
300
|
+
*/
|
|
301
|
+
this.state = ngpRovingFocusGroup({
|
|
302
|
+
orientation: this.orientation,
|
|
303
|
+
wrap: this.wrap,
|
|
304
|
+
homeEnd: this.homeEnd,
|
|
305
|
+
disabled: this.disabled,
|
|
306
|
+
});
|
|
335
307
|
}
|
|
336
308
|
/**
|
|
337
|
-
*
|
|
309
|
+
* Activate an item in the roving focus group.
|
|
310
|
+
* @param item The item to activate
|
|
311
|
+
* @param origin The origin of the focus change
|
|
338
312
|
*/
|
|
339
|
-
|
|
340
|
-
|
|
313
|
+
setActiveItem(item, origin = 'program') {
|
|
314
|
+
if (item) {
|
|
315
|
+
this.state.setActiveItem(item.id(), origin);
|
|
316
|
+
}
|
|
341
317
|
}
|
|
318
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.9", ngImport: i0, type: NgpRovingFocusGroup, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
|
|
319
|
+
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "20.3.9", type: NgpRovingFocusGroup, isStandalone: true, selector: "[ngpRovingFocusGroup]", inputs: { orientation: { classPropertyName: "orientation", publicName: "ngpRovingFocusGroupOrientation", isSignal: true, isRequired: false, transformFunction: null }, wrap: { classPropertyName: "wrap", publicName: "ngpRovingFocusGroupWrap", isSignal: true, isRequired: false, transformFunction: null }, homeEnd: { classPropertyName: "homeEnd", publicName: "ngpRovingFocusGroupHomeEnd", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "ngpRovingFocusGroupDisabled", isSignal: true, isRequired: false, transformFunction: null } }, providers: [
|
|
320
|
+
provideRovingFocusGroup(NgpRovingFocusGroup),
|
|
321
|
+
provideRovingFocusGroupState({ inherit: true }),
|
|
322
|
+
], exportAs: ["ngpRovingFocusGroup"], ngImport: i0 }); }
|
|
323
|
+
}
|
|
324
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.9", ngImport: i0, type: NgpRovingFocusGroup, decorators: [{
|
|
325
|
+
type: Directive,
|
|
326
|
+
args: [{
|
|
327
|
+
selector: '[ngpRovingFocusGroup]',
|
|
328
|
+
exportAs: 'ngpRovingFocusGroup',
|
|
329
|
+
providers: [
|
|
330
|
+
provideRovingFocusGroup(NgpRovingFocusGroup),
|
|
331
|
+
provideRovingFocusGroupState({ inherit: true }),
|
|
332
|
+
],
|
|
333
|
+
}]
|
|
334
|
+
}], propDecorators: { orientation: [{ type: i0.Input, args: [{ isSignal: true, alias: "ngpRovingFocusGroupOrientation", required: false }] }], wrap: [{ type: i0.Input, args: [{ isSignal: true, alias: "ngpRovingFocusGroupWrap", required: false }] }], homeEnd: [{ type: i0.Input, args: [{ isSignal: true, alias: "ngpRovingFocusGroupHomeEnd", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "ngpRovingFocusGroupDisabled", required: false }] }] } });
|
|
335
|
+
|
|
336
|
+
const [NgpRovingFocusItemStateToken, ngpRovingFocusItem, injectRovingFocusItemState, provideRovingFocusItemState,] = createPrimitive('NgpRovingFocusItem', ({ disabled = signal(false) }) => {
|
|
337
|
+
const element = injectElementRef();
|
|
338
|
+
const group = injectRovingFocusGroupState();
|
|
339
|
+
const focusMonitor = inject(FocusMonitor);
|
|
340
|
+
// genertate a unique id for the roving focus item - this is not a DOM id but an internal identifier
|
|
341
|
+
const id = uniqueId('ngp-roving-focus-item');
|
|
342
342
|
/**
|
|
343
|
-
*
|
|
344
|
-
* @param event The keyboard event
|
|
343
|
+
* Derive the tabindex of the roving focus item.
|
|
345
344
|
*/
|
|
346
|
-
|
|
347
|
-
|
|
345
|
+
const tabindex = computed(() => !group()?.disabled() && group()?.activeItem() === id ? 0 : -1, ...(ngDevMode ? [{ debugName: "tabindex" }] : []));
|
|
346
|
+
// Setup host attribute bindings
|
|
347
|
+
attrBinding(element, 'tabindex', () => tabindex().toString());
|
|
348
|
+
// Setup keyboard event listener
|
|
349
|
+
listener(element, 'keydown', (event) => {
|
|
350
|
+
if (disabled()) {
|
|
348
351
|
return;
|
|
349
352
|
}
|
|
350
|
-
|
|
351
|
-
}
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
activate() {
|
|
356
|
-
if (this.disabled()) {
|
|
353
|
+
group()?.onKeydown(event);
|
|
354
|
+
});
|
|
355
|
+
// Setup click event listener
|
|
356
|
+
listener(element, 'click', () => {
|
|
357
|
+
if (disabled()) {
|
|
357
358
|
return;
|
|
358
359
|
}
|
|
359
|
-
|
|
360
|
+
group()?.setActiveItem(id, 'mouse');
|
|
361
|
+
});
|
|
362
|
+
function focus(origin) {
|
|
363
|
+
focusMonitor.focusVia(element, origin);
|
|
360
364
|
}
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
365
|
+
const state = {
|
|
366
|
+
id: signal(id),
|
|
367
|
+
disabled,
|
|
368
|
+
tabindex,
|
|
369
|
+
focus,
|
|
370
|
+
element,
|
|
371
|
+
};
|
|
372
|
+
// Register the item when created
|
|
373
|
+
group()?.register(state);
|
|
374
|
+
// Unregister the item when destroyed
|
|
375
|
+
onDestroy(() => group()?.unregister(state));
|
|
376
|
+
return state;
|
|
377
|
+
});
|
|
378
|
+
|
|
379
|
+
/**
|
|
380
|
+
* Apply the `ngpRovingFocusItem` directive to an element within a roving focus group to automatically manage focus.
|
|
381
|
+
*/
|
|
382
|
+
class NgpRovingFocusItem {
|
|
383
|
+
constructor() {
|
|
384
|
+
/**
|
|
385
|
+
* Define if the item is disabled.
|
|
386
|
+
*/
|
|
387
|
+
this.disabled = input(false, ...(ngDevMode ? [{ debugName: "disabled", alias: 'ngpRovingFocusItemDisabled',
|
|
388
|
+
transform: booleanAttribute }] : [{
|
|
389
|
+
alias: 'ngpRovingFocusItemDisabled',
|
|
390
|
+
transform: booleanAttribute,
|
|
391
|
+
}]));
|
|
392
|
+
this.state = ngpRovingFocusItem({ disabled: this.disabled });
|
|
393
|
+
/**
|
|
394
|
+
* Expose the internal id of the roving focus item.
|
|
395
|
+
* @internal
|
|
396
|
+
*/
|
|
397
|
+
this.id = computed(() => this.state.id(), ...(ngDevMode ? [{ debugName: "id" }] : []));
|
|
367
398
|
}
|
|
368
399
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.9", ngImport: i0, type: NgpRovingFocusItem, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
|
|
369
|
-
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "20.3.9", type: NgpRovingFocusItem, isStandalone: true, selector: "[ngpRovingFocusItem]", inputs: { disabled: { classPropertyName: "disabled", publicName: "ngpRovingFocusItemDisabled", isSignal: true, isRequired: false, transformFunction: null } },
|
|
400
|
+
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "20.3.9", type: NgpRovingFocusItem, isStandalone: true, selector: "[ngpRovingFocusItem]", inputs: { disabled: { classPropertyName: "disabled", publicName: "ngpRovingFocusItemDisabled", isSignal: true, isRequired: false, transformFunction: null } }, providers: [provideRovingFocusItemState()], exportAs: ["ngpRovingFocusItem"], ngImport: i0 }); }
|
|
370
401
|
}
|
|
371
402
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.9", ngImport: i0, type: NgpRovingFocusItem, decorators: [{
|
|
372
403
|
type: Directive,
|
|
373
404
|
args: [{
|
|
374
405
|
selector: '[ngpRovingFocusItem]',
|
|
375
406
|
exportAs: 'ngpRovingFocusItem',
|
|
376
|
-
|
|
377
|
-
'[attr.tabindex]': 'tabindex()',
|
|
378
|
-
},
|
|
407
|
+
providers: [provideRovingFocusItemState()],
|
|
379
408
|
}]
|
|
380
|
-
}], propDecorators: { disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "ngpRovingFocusItemDisabled", required: false }] }]
|
|
381
|
-
type: HostListener,
|
|
382
|
-
args: ['keydown', ['$event']]
|
|
383
|
-
}], activate: [{
|
|
384
|
-
type: HostListener,
|
|
385
|
-
args: ['click']
|
|
386
|
-
}] } });
|
|
409
|
+
}], propDecorators: { disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "ngpRovingFocusItemDisabled", required: false }] }] } });
|
|
387
410
|
|
|
388
411
|
/**
|
|
389
412
|
* Generated bundle index. Do not edit.
|
|
390
413
|
*/
|
|
391
414
|
|
|
392
|
-
export { NgpRovingFocusGroup, NgpRovingFocusGroupToken, NgpRovingFocusItem, injectRovingFocusGroup, injectRovingFocusGroupState, provideRovingFocusGroup, provideRovingFocusGroupState };
|
|
415
|
+
export { NgpRovingFocusGroup, NgpRovingFocusGroupStateToken, NgpRovingFocusGroupToken, NgpRovingFocusItem, NgpRovingFocusItemStateToken, injectRovingFocusGroup, injectRovingFocusGroupState, injectRovingFocusItemState, ngpRovingFocusGroup, ngpRovingFocusItem, provideRovingFocusGroup, provideRovingFocusGroupState, provideRovingFocusItemState };
|
|
393
416
|
//# sourceMappingURL=ng-primitives-roving-focus.mjs.map
|