@agorapulse/ui-components 18.0.9 → 18.0.10
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/agorapulse-ui-components-18.0.10.tgz +0 -0
- package/datepicker/datepicker.component.d.ts +1 -1
- package/esm2022/datepicker/datepicker.component.mjs +2 -2
- package/esm2022/index.mjs +2 -1
- package/esm2022/input-search/input-search.component.mjs +5 -4
- package/esm2022/nav-selector/agorapulse-ui-components-nav-selector.mjs +5 -0
- package/esm2022/nav-selector/directives/tree-node-accessibility.directive.mjs +30 -0
- package/esm2022/nav-selector/nav-selector-category/nav-selector-category.component.mjs +81 -0
- package/esm2022/nav-selector/nav-selector-category/nav-selector-category.presenter.mjs +29 -0
- package/esm2022/nav-selector/nav-selector-group/nav-selector-group.component.mjs +142 -0
- package/esm2022/nav-selector/nav-selector-group/nav-selector-group.presenter.mjs +31 -0
- package/esm2022/nav-selector/nav-selector-leaf/nav-selector-leaf.component.mjs +240 -0
- package/esm2022/nav-selector/nav-selector-leaf/nav-selector-leaf.presenter.mjs +35 -0
- package/esm2022/nav-selector/nav-selector-leaf-detail/nav-selector-leaf-detail.component.mjs +39 -0
- package/esm2022/nav-selector/nav-selector-leaf-detail/nav-selector-leaf-detail.presenter.mjs +18 -0
- package/esm2022/nav-selector/nav-selector-leaf-details/nav-selector-leaf-details.component.mjs +92 -0
- package/esm2022/nav-selector/nav-selector-leaf-details/nav-selector-leaf-details.presenter.mjs +31 -0
- package/esm2022/nav-selector/nav-selector.component.mjs +123 -0
- package/esm2022/nav-selector/nav-selector.mjs +9 -0
- package/esm2022/nav-selector/nav-selector.state.mjs +173 -0
- package/esm2022/nav-selector/public_api.mjs +2 -0
- package/esm2022/nav-selector/utils/leaf.utils.mjs +10 -0
- package/esm2022/nav-selector/utils/nav-selector.accessibility.mjs +171 -0
- package/esm2022/nav-selector/utils/nav-selector.builder.mjs +263 -0
- package/esm2022/nav-selector/utils/nav-selector.filter.mjs +102 -0
- package/esm2022/nav-selector/utils/nav-selector.folding.mjs +219 -0
- package/esm2022/nav-selector/utils/nav-selector.minifying.mjs +50 -0
- package/esm2022/nav-selector/utils/nav-selector.multi-select.mjs +208 -0
- package/esm2022/nav-selector/utils/nav-selector.single-select.mjs +91 -0
- package/esm2022/nav-selector/utils/nav-selector.view-more.mjs +98 -0
- package/fesm2022/agorapulse-ui-components-datepicker.mjs +1 -1
- package/fesm2022/agorapulse-ui-components-datepicker.mjs.map +1 -1
- package/fesm2022/agorapulse-ui-components-input-search.mjs +4 -3
- package/fesm2022/agorapulse-ui-components-input-search.mjs.map +1 -1
- package/fesm2022/agorapulse-ui-components-nav-selector.mjs +2198 -0
- package/fesm2022/agorapulse-ui-components-nav-selector.mjs.map +1 -0
- package/fesm2022/agorapulse-ui-components.mjs +1 -0
- package/fesm2022/agorapulse-ui-components.mjs.map +1 -1
- package/index.d.ts +1 -0
- package/input-search/input-search.component.d.ts +1 -1
- package/nav-selector/directives/tree-node-accessibility.directive.d.ts +9 -0
- package/nav-selector/index.d.ts +5 -0
- package/nav-selector/nav-selector-category/nav-selector-category.component.d.ts +16 -0
- package/nav-selector/nav-selector-category/nav-selector-category.presenter.d.ts +14 -0
- package/nav-selector/nav-selector-group/nav-selector-group.component.d.ts +29 -0
- package/nav-selector/nav-selector-group/nav-selector-group.presenter.d.ts +17 -0
- package/nav-selector/nav-selector-leaf/nav-selector-leaf.component.d.ts +51 -0
- package/nav-selector/nav-selector-leaf/nav-selector-leaf.presenter.d.ts +19 -0
- package/nav-selector/nav-selector-leaf-detail/nav-selector-leaf-detail.component.d.ts +13 -0
- package/nav-selector/nav-selector-leaf-detail/nav-selector-leaf-detail.presenter.d.ts +10 -0
- package/nav-selector/nav-selector-leaf-details/nav-selector-leaf-details.component.d.ts +24 -0
- package/nav-selector/nav-selector-leaf-details/nav-selector-leaf-details.presenter.d.ts +14 -0
- package/nav-selector/nav-selector.component.d.ts +29 -0
- package/nav-selector/nav-selector.d.ts +220 -0
- package/nav-selector/nav-selector.state.d.ts +47 -0
- package/nav-selector/public_api.d.ts +2 -0
- package/nav-selector/utils/leaf.utils.d.ts +5 -0
- package/nav-selector/utils/nav-selector.accessibility.d.ts +52 -0
- package/nav-selector/utils/nav-selector.builder.d.ts +32 -0
- package/nav-selector/utils/nav-selector.filter.d.ts +30 -0
- package/nav-selector/utils/nav-selector.folding.d.ts +47 -0
- package/nav-selector/utils/nav-selector.minifying.d.ts +27 -0
- package/nav-selector/utils/nav-selector.multi-select.d.ts +54 -0
- package/nav-selector/utils/nav-selector.single-select.d.ts +15 -0
- package/nav-selector/utils/nav-selector.view-more.d.ts +30 -0
- package/package.json +13 -7
- package/agorapulse-ui-components-18.0.9.tgz +0 -0
|
@@ -0,0 +1,2198 @@
|
|
|
1
|
+
import { IconButtonComponent } from '@agorapulse/ui-components/icon-button';
|
|
2
|
+
import { InputSearchComponent } from '@agorapulse/ui-components/input-search';
|
|
3
|
+
import { SymbolComponent, withSymbols, apErrorFill, apFeatureLock, apChevronDown, apChevronUp, apFolder, apArrowExpand, apArrowReduce, apSearch } from '@agorapulse/ui-symbol';
|
|
4
|
+
import { trigger, state, transition, style, animate, keyframes } from '@angular/animations';
|
|
5
|
+
import { NgTemplateOutlet } from '@angular/common';
|
|
6
|
+
import * as i0 from '@angular/core';
|
|
7
|
+
import { input, afterRender, Directive, signal, computed, effect, Injectable, ChangeDetectionStrategy, Component, viewChild, afterNextRender, model, contentChild, contentChildren, TemplateRef } from '@angular/core';
|
|
8
|
+
import * as i2 from '@angular/forms';
|
|
9
|
+
import { FormsModule } from '@angular/forms';
|
|
10
|
+
import { EventPluginsModule } from '@tinkoff/ng-event-plugins';
|
|
11
|
+
import { AvatarComponent } from '@agorapulse/ui-components/avatar';
|
|
12
|
+
import { CheckboxComponent } from '@agorapulse/ui-components/checkbox';
|
|
13
|
+
import { CounterComponent } from '@agorapulse/ui-components/counter';
|
|
14
|
+
import { TooltipDirective } from '@agorapulse/ui-components/tooltip';
|
|
15
|
+
import { apMore } from '@agorapulse/ui-symbol/icons';
|
|
16
|
+
import { MatMenu, MatMenuTrigger, MatMenuItem } from '@angular/material/menu';
|
|
17
|
+
|
|
18
|
+
class TreeNodeAccessibilityDirective {
|
|
19
|
+
apTreeNodeAccessibility = input.required();
|
|
20
|
+
constructor(el, renderer) {
|
|
21
|
+
afterRender(() => {
|
|
22
|
+
const nativeEl = el.nativeElement;
|
|
23
|
+
const entry = this.apTreeNodeAccessibility();
|
|
24
|
+
renderer.setAttribute(nativeEl, 'aria-level', `${entry.accessibility.ariaLevel}`);
|
|
25
|
+
renderer.setAttribute(nativeEl, 'aria-setsize', `${entry.accessibility.ariaSetsize}`);
|
|
26
|
+
renderer.setAttribute(nativeEl, 'aria-posinset', `${entry.accessibility.ariaPosinset}`);
|
|
27
|
+
renderer.setAttribute(nativeEl, 'tabindex', `${entry.accessibility.tabIndex}`);
|
|
28
|
+
renderer.setAttribute(nativeEl, 'aria-label', `${entry.alias}`);
|
|
29
|
+
if ('folded' in entry) {
|
|
30
|
+
renderer.setAttribute(nativeEl, 'aria-expanded', `${entry.folded}`);
|
|
31
|
+
}
|
|
32
|
+
renderer.setAttribute(nativeEl, 'role', 'treeitem');
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.9", ngImport: i0, type: TreeNodeAccessibilityDirective, deps: [{ token: i0.ElementRef }, { token: i0.Renderer2 }], target: i0.ɵɵFactoryTarget.Directive });
|
|
36
|
+
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "18.2.9", type: TreeNodeAccessibilityDirective, isStandalone: true, selector: "[apTreeNodeAccessibility]", inputs: { apTreeNodeAccessibility: { classPropertyName: "apTreeNodeAccessibility", publicName: "apTreeNodeAccessibility", isSignal: true, isRequired: true, transformFunction: null } }, ngImport: i0 });
|
|
37
|
+
}
|
|
38
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.9", ngImport: i0, type: TreeNodeAccessibilityDirective, decorators: [{
|
|
39
|
+
type: Directive,
|
|
40
|
+
args: [{
|
|
41
|
+
selector: '[apTreeNodeAccessibility]',
|
|
42
|
+
standalone: true,
|
|
43
|
+
}]
|
|
44
|
+
}], ctorParameters: () => [{ type: i0.ElementRef }, { type: i0.Renderer2 }] });
|
|
45
|
+
|
|
46
|
+
const isNavSelectorEntryALeaf = (entry) => entry.type === 'LEAF';
|
|
47
|
+
const isNavSelectorEntryAGroup = (entry) => entry.type === 'GROUP';
|
|
48
|
+
const isNavSelectorEntryACategory = (entry) => entry.type === 'CATEGORY';
|
|
49
|
+
const isInternalNavSelectorEntryALeaf = (entry) => entry.type === 'LEAF';
|
|
50
|
+
const isInternalNavSelectorEntryANode = (entry) => `children` in entry;
|
|
51
|
+
const isInternalNavSelectorEntryACategory = (entry) => entry.type === 'CATEGORY';
|
|
52
|
+
const isInternalNavSelectorEntryAGroup = (entry) => entry.type === 'GROUP';
|
|
53
|
+
const isInternalNavSelectorEntryALeafDetails = (entry) => entry.type === 'LEAF_DETAILS';
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* NavSelectorAccessibility is a utility class that provides methods to manage the accessibility and the focusability of nav selector entries.
|
|
57
|
+
*/
|
|
58
|
+
class NavSelectorAccessibility {
|
|
59
|
+
/**
|
|
60
|
+
* Set tabIndex to 0 for the first focusable entry and -1 for all other entries
|
|
61
|
+
* @param entries nav selector entries
|
|
62
|
+
*/
|
|
63
|
+
static resetFocus(entries) {
|
|
64
|
+
return entries.reduce((acc, entry) => {
|
|
65
|
+
if (!acc.length) {
|
|
66
|
+
return [{ ...entry, accessibility: { ...entry.accessibility, tabIndex: entry.focusable ? 0 : -1 } }];
|
|
67
|
+
}
|
|
68
|
+
if (acc.every(({ focusable }) => !focusable)) {
|
|
69
|
+
return [...acc, { ...entry, accessibility: { ...entry.accessibility, tabIndex: entry.focusable ? 0 : -1 } }];
|
|
70
|
+
}
|
|
71
|
+
return [...acc, entry];
|
|
72
|
+
}, []);
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Focus the given entry and set tabIndex to 0 for the given uid and -1 for all other entries
|
|
76
|
+
* @param entries nav selector entries
|
|
77
|
+
* @param uid the uid of the entry to focus
|
|
78
|
+
*/
|
|
79
|
+
static focus(entries, uid) {
|
|
80
|
+
return entries.map(entry => {
|
|
81
|
+
if (isInternalNavSelectorEntryAGroup(entry) || isInternalNavSelectorEntryACategory(entry)) {
|
|
82
|
+
return {
|
|
83
|
+
...this.focusAnEntry(entry, uid),
|
|
84
|
+
children: NavSelectorAccessibility.focus(entry.children, uid),
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
if (isInternalNavSelectorEntryALeaf(entry)) {
|
|
88
|
+
return {
|
|
89
|
+
...this.focusAnEntry(entry, uid),
|
|
90
|
+
details: entry.details.map(detail => this.focusAnEntry(detail, uid)),
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
return this.focusAnEntry(entry, uid);
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Unfocus the given entry and set tabIndex to -1 for the given uid and 0 for all other entries
|
|
98
|
+
* @param entries nav selector entries
|
|
99
|
+
* @param uid the uid of the entry to unfocus
|
|
100
|
+
*/
|
|
101
|
+
static unfocus(entries, uid) {
|
|
102
|
+
return entries.map(entry => {
|
|
103
|
+
if (isInternalNavSelectorEntryAGroup(entry) || isInternalNavSelectorEntryACategory(entry)) {
|
|
104
|
+
return {
|
|
105
|
+
...this.unfocusAnEntry(entry, uid),
|
|
106
|
+
children: NavSelectorAccessibility.unfocus(entry.children, uid),
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
if (isInternalNavSelectorEntryALeaf(entry)) {
|
|
110
|
+
return {
|
|
111
|
+
...this.unfocusAnEntry(entry, uid),
|
|
112
|
+
details: entry.details.map(detail => this.unfocusAnEntry(detail, uid)),
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
return this.unfocusAnEntry(entry, uid);
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* Focus the previous entry focusable and set tabIndex to 0 for the previous focusable entry and -1 for all other entries
|
|
120
|
+
*
|
|
121
|
+
* If not previous entries are focusable, entries will not be modified
|
|
122
|
+
*
|
|
123
|
+
* @param entries nav selector entries
|
|
124
|
+
*/
|
|
125
|
+
static focusPrevious(entries) {
|
|
126
|
+
const flattenEntries = this.flatten(entries);
|
|
127
|
+
const idxFocusedId = flattenEntries.findIndex(({ accessibility }) => accessibility.tabIndex === 0);
|
|
128
|
+
if (idxFocusedId === 0 || this.previousEntryIsFirstAndNotFocusable(flattenEntries, idxFocusedId)) {
|
|
129
|
+
return entries;
|
|
130
|
+
}
|
|
131
|
+
const focusedEntry = flattenEntries[idxFocusedId];
|
|
132
|
+
focusedEntry.accessibility.tabIndex = -1;
|
|
133
|
+
for (let i = idxFocusedId - 1; i >= 0; i--) {
|
|
134
|
+
const entry = flattenEntries[i];
|
|
135
|
+
if (entry.focusable) {
|
|
136
|
+
entry.accessibility.tabIndex = 0;
|
|
137
|
+
break;
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
return this.unflatten(flattenEntries);
|
|
141
|
+
}
|
|
142
|
+
/**
|
|
143
|
+
* Focus the next entry focusable and set tabIndex to 0 for the next focusable entry and -1 for all other entries
|
|
144
|
+
*
|
|
145
|
+
* If not next entries are focusable, entries will not be modified
|
|
146
|
+
*
|
|
147
|
+
* @param entries nav selector entries
|
|
148
|
+
*/
|
|
149
|
+
static focusNext(entries) {
|
|
150
|
+
const flattenEntries = this.flatten(entries);
|
|
151
|
+
const focusableFlattenEntries = flattenEntries.filter(entry => entry.focusable);
|
|
152
|
+
const idxFocusedId = focusableFlattenEntries.findIndex(({ accessibility }) => accessibility.tabIndex === 0);
|
|
153
|
+
if (focusableFlattenEntries.length - 1 <= idxFocusedId) {
|
|
154
|
+
return entries;
|
|
155
|
+
}
|
|
156
|
+
focusableFlattenEntries[idxFocusedId].accessibility.tabIndex = -1;
|
|
157
|
+
focusableFlattenEntries[idxFocusedId + 1].accessibility.tabIndex = 0;
|
|
158
|
+
return this.unflatten(flattenEntries);
|
|
159
|
+
}
|
|
160
|
+
static previousEntryIsFirstAndNotFocusable(flattenEntries, idxFocusedId) {
|
|
161
|
+
if (idxFocusedId - 1 === 0) {
|
|
162
|
+
const previous = flattenEntries[0];
|
|
163
|
+
return !previous.focusable;
|
|
164
|
+
}
|
|
165
|
+
return false;
|
|
166
|
+
}
|
|
167
|
+
static focusAnEntry(entry, uid) {
|
|
168
|
+
return { ...entry, accessibility: { ...entry.accessibility, tabIndex: entry.uid === uid ? 0 : -1 } };
|
|
169
|
+
}
|
|
170
|
+
static unfocusAnEntry(entry, uid) {
|
|
171
|
+
return { ...entry, accessibility: { ...entry.accessibility, tabIndex: entry.uid === uid ? -1 : entry.accessibility.tabIndex } };
|
|
172
|
+
}
|
|
173
|
+
/**
|
|
174
|
+
* Flatten the nav selector entries. It is easier to work with flat entries for the focus management as we need to know which is the previous or the next entry
|
|
175
|
+
* @param entries nav selector entries
|
|
176
|
+
*/
|
|
177
|
+
static flatten(entries) {
|
|
178
|
+
return entries.flatMap(entry => {
|
|
179
|
+
if (isInternalNavSelectorEntryAGroup(entry) || isInternalNavSelectorEntryACategory(entry)) {
|
|
180
|
+
return [{ ...entry, children: [] }, ...this.flatten(entry.children)];
|
|
181
|
+
}
|
|
182
|
+
if (isInternalNavSelectorEntryALeaf(entry)) {
|
|
183
|
+
return [{ ...entry, details: [] }, ...entry.details.map(detail => ({ ...detail }))];
|
|
184
|
+
}
|
|
185
|
+
return [{ ...entry }];
|
|
186
|
+
});
|
|
187
|
+
}
|
|
188
|
+
/**
|
|
189
|
+
* Unflatten the nav selector entries
|
|
190
|
+
* @param entries nav selector entries
|
|
191
|
+
*/
|
|
192
|
+
static unflatten(entries) {
|
|
193
|
+
return entries.reduceRight((acc, entry) => {
|
|
194
|
+
if (!acc.length) {
|
|
195
|
+
return [entry];
|
|
196
|
+
}
|
|
197
|
+
if (entry.accessibility.ariaLevel < acc[0].accessibility.ariaLevel) {
|
|
198
|
+
if (isInternalNavSelectorEntryALeaf(entry)) {
|
|
199
|
+
return [
|
|
200
|
+
{
|
|
201
|
+
...entry,
|
|
202
|
+
details: acc
|
|
203
|
+
.filter(it => isInternalNavSelectorEntryALeafDetails(it))
|
|
204
|
+
// Force destroying the reference to the original object else Angular will not detect the change
|
|
205
|
+
.map(it => ({ ...it })),
|
|
206
|
+
},
|
|
207
|
+
...acc.filter(it => !isInternalNavSelectorEntryALeafDetails(it)),
|
|
208
|
+
];
|
|
209
|
+
}
|
|
210
|
+
else if (isInternalNavSelectorEntryAGroup(entry) || isInternalNavSelectorEntryACategory(entry)) {
|
|
211
|
+
return [
|
|
212
|
+
{
|
|
213
|
+
...entry,
|
|
214
|
+
children: acc.filter(({ accessibility }) => accessibility.ariaLevel > entry.accessibility.ariaLevel),
|
|
215
|
+
},
|
|
216
|
+
...acc.filter(({ accessibility }) => accessibility.ariaLevel <= entry.accessibility.ariaLevel),
|
|
217
|
+
];
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
return [entry, ...acc];
|
|
221
|
+
}, []);
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
/**
|
|
226
|
+
* NavSelectorMultiSelect is a utility class that provides methods to select an entry in multiple mode.
|
|
227
|
+
*/
|
|
228
|
+
class NavSelectorMultiSelect {
|
|
229
|
+
/**
|
|
230
|
+
* Select an entry in multiple mode.
|
|
231
|
+
*
|
|
232
|
+
* Categories are not selectable.
|
|
233
|
+
*
|
|
234
|
+
* Groups and leaves are selectable.
|
|
235
|
+
*
|
|
236
|
+
* Groups may be in undetermined state if some of their children are selected and some are not.
|
|
237
|
+
* @param entries nav selector entries
|
|
238
|
+
* @param entryUid the entry uid to select
|
|
239
|
+
*/
|
|
240
|
+
static selectInMultipleMode(entries, entryUid) {
|
|
241
|
+
return entries.map(entry => {
|
|
242
|
+
if (isInternalNavSelectorEntryALeaf(entry)) {
|
|
243
|
+
return this.selectALeafInMultipleMode(entry, entryUid);
|
|
244
|
+
}
|
|
245
|
+
else if (isInternalNavSelectorEntryAGroup(entry)) {
|
|
246
|
+
return this.selectAGroupInMultipleMode(entry, entryUid);
|
|
247
|
+
}
|
|
248
|
+
else if (isInternalNavSelectorEntryACategory(entry)) {
|
|
249
|
+
return this.selectACategoryInMultipleMode(entry, entryUid);
|
|
250
|
+
}
|
|
251
|
+
return entry;
|
|
252
|
+
});
|
|
253
|
+
}
|
|
254
|
+
/**
|
|
255
|
+
* Select only a leaf in multiple mode.
|
|
256
|
+
*
|
|
257
|
+
* Categories are not selectable.
|
|
258
|
+
*
|
|
259
|
+
* Groups may be in undetermined state if some of their children are selected and some are not.
|
|
260
|
+
* @param entries nav selector entries
|
|
261
|
+
* @param entryUid the entry uid to select
|
|
262
|
+
*/
|
|
263
|
+
static selectOnlyALeafInMultipleMode(entries, entryUid) {
|
|
264
|
+
return entries.map(entry => {
|
|
265
|
+
if (isInternalNavSelectorEntryALeaf(entry)) {
|
|
266
|
+
return {
|
|
267
|
+
...entry,
|
|
268
|
+
selected: entry.uid === entryUid,
|
|
269
|
+
};
|
|
270
|
+
}
|
|
271
|
+
else if (isInternalNavSelectorEntryACategory(entry)) {
|
|
272
|
+
return {
|
|
273
|
+
...entry,
|
|
274
|
+
children: this.selectOnlyALeafInMultipleMode(entry.children, entryUid),
|
|
275
|
+
};
|
|
276
|
+
}
|
|
277
|
+
else if (isInternalNavSelectorEntryAGroup(entry)) {
|
|
278
|
+
const children = entry.children.flatMap(child => this.selectOnlyALeafInMultipleMode([child], entryUid));
|
|
279
|
+
const selected = children.every(child => child.selected || (isInternalNavSelectorEntryALeaf(child) && !child.selectable));
|
|
280
|
+
return {
|
|
281
|
+
...entry,
|
|
282
|
+
children,
|
|
283
|
+
selected,
|
|
284
|
+
undeterminedSelection: !selected && children.some(child => child.selected),
|
|
285
|
+
};
|
|
286
|
+
}
|
|
287
|
+
return entry;
|
|
288
|
+
});
|
|
289
|
+
}
|
|
290
|
+
/**
|
|
291
|
+
* Select all entries in multiple mode.
|
|
292
|
+
*
|
|
293
|
+
* Categories are not selectable.
|
|
294
|
+
*
|
|
295
|
+
* Groups and leaves are selectable.
|
|
296
|
+
* @param entries nav selector entries
|
|
297
|
+
*/
|
|
298
|
+
static selectAll(entries) {
|
|
299
|
+
return this.selectChildren(entries);
|
|
300
|
+
}
|
|
301
|
+
/**
|
|
302
|
+
* Unselect all entries in multiple mode.
|
|
303
|
+
*
|
|
304
|
+
* Categories are not selectable.
|
|
305
|
+
*
|
|
306
|
+
* Groups and leaves are selectable.
|
|
307
|
+
* @param entries nav selector entries
|
|
308
|
+
*/
|
|
309
|
+
static unselectAll(entries) {
|
|
310
|
+
return this.unselectChildren(entries);
|
|
311
|
+
}
|
|
312
|
+
static selectALeafInMultipleMode(leaf, entryUid) {
|
|
313
|
+
let selected = false;
|
|
314
|
+
if (leaf.selectable) {
|
|
315
|
+
selected = leaf.uid === entryUid ? !leaf.selected : leaf.selected;
|
|
316
|
+
}
|
|
317
|
+
return {
|
|
318
|
+
...leaf,
|
|
319
|
+
selected,
|
|
320
|
+
};
|
|
321
|
+
}
|
|
322
|
+
static selectACategoryInMultipleMode(entry, entryUid) {
|
|
323
|
+
return {
|
|
324
|
+
...entry,
|
|
325
|
+
children: entry.children.map(child => {
|
|
326
|
+
if (isInternalNavSelectorEntryALeaf(child)) {
|
|
327
|
+
return this.selectALeafInMultipleMode(child, entryUid);
|
|
328
|
+
}
|
|
329
|
+
return this.selectAGroupInMultipleMode(child, entryUid);
|
|
330
|
+
}),
|
|
331
|
+
};
|
|
332
|
+
}
|
|
333
|
+
static selectAGroupInMultipleMode(entry, entryUid) {
|
|
334
|
+
if (!entry.selectable) {
|
|
335
|
+
return entry;
|
|
336
|
+
}
|
|
337
|
+
let selected;
|
|
338
|
+
let children;
|
|
339
|
+
let undeterminedSelection = false;
|
|
340
|
+
if (entry.uid === entryUid) {
|
|
341
|
+
selected = !entry.selected;
|
|
342
|
+
if (selected) {
|
|
343
|
+
children = this.selectLeafs(entry.children);
|
|
344
|
+
}
|
|
345
|
+
else {
|
|
346
|
+
children = this.unselectLeafs(entry.children);
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
else {
|
|
350
|
+
children = entry.children.map(child => this.toggleSelectLeaf(child, entryUid));
|
|
351
|
+
selected = children.every(child => child.selected || (isInternalNavSelectorEntryALeaf(child) && !child.selectable));
|
|
352
|
+
undeterminedSelection = !selected && children.some(child => child.selected);
|
|
353
|
+
}
|
|
354
|
+
return {
|
|
355
|
+
...entry,
|
|
356
|
+
children,
|
|
357
|
+
selected,
|
|
358
|
+
undeterminedSelection,
|
|
359
|
+
};
|
|
360
|
+
}
|
|
361
|
+
static toggleSelectLeaf(leaf, uid) {
|
|
362
|
+
if (leaf.uid === uid) {
|
|
363
|
+
return {
|
|
364
|
+
...leaf,
|
|
365
|
+
selected: !leaf.selected,
|
|
366
|
+
};
|
|
367
|
+
}
|
|
368
|
+
return leaf;
|
|
369
|
+
}
|
|
370
|
+
static selectLeafs(leafs) {
|
|
371
|
+
return leafs.map(leaf => ({
|
|
372
|
+
...leaf,
|
|
373
|
+
selected: true,
|
|
374
|
+
}));
|
|
375
|
+
}
|
|
376
|
+
static unselectLeafs(leafs) {
|
|
377
|
+
return leafs.map(leaf => ({
|
|
378
|
+
...leaf,
|
|
379
|
+
selected: false,
|
|
380
|
+
}));
|
|
381
|
+
}
|
|
382
|
+
static unselectChildren(entry) {
|
|
383
|
+
return entry.map(child => {
|
|
384
|
+
if (isInternalNavSelectorEntryALeaf(child)) {
|
|
385
|
+
return {
|
|
386
|
+
...child,
|
|
387
|
+
selected: false,
|
|
388
|
+
};
|
|
389
|
+
}
|
|
390
|
+
else if (isInternalNavSelectorEntryACategory(child)) {
|
|
391
|
+
return {
|
|
392
|
+
...child,
|
|
393
|
+
children: this.unselectChildren(child.children),
|
|
394
|
+
};
|
|
395
|
+
}
|
|
396
|
+
else if (isInternalNavSelectorEntryANode(child)) {
|
|
397
|
+
return {
|
|
398
|
+
...child,
|
|
399
|
+
children: this.unselectChildren(child.children),
|
|
400
|
+
selected: false,
|
|
401
|
+
};
|
|
402
|
+
}
|
|
403
|
+
return child;
|
|
404
|
+
});
|
|
405
|
+
}
|
|
406
|
+
static selectChildren(entry) {
|
|
407
|
+
return entry.map(child => {
|
|
408
|
+
if (isInternalNavSelectorEntryALeaf(child)) {
|
|
409
|
+
return {
|
|
410
|
+
...child,
|
|
411
|
+
selected: child.selectable,
|
|
412
|
+
};
|
|
413
|
+
}
|
|
414
|
+
else if (isInternalNavSelectorEntryACategory(child)) {
|
|
415
|
+
return {
|
|
416
|
+
...child,
|
|
417
|
+
children: this.selectChildren(child.children),
|
|
418
|
+
};
|
|
419
|
+
}
|
|
420
|
+
else if (isInternalNavSelectorEntryAGroup(child)) {
|
|
421
|
+
return {
|
|
422
|
+
...child,
|
|
423
|
+
children: this.selectChildren(child.children),
|
|
424
|
+
selected: true,
|
|
425
|
+
};
|
|
426
|
+
}
|
|
427
|
+
return child;
|
|
428
|
+
});
|
|
429
|
+
}
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
/**
|
|
433
|
+
* NavSelectorSingleSelect is a utility class that provides methods to select a single entry in a nav selector.
|
|
434
|
+
*/
|
|
435
|
+
class NavSelectorSingleSelect {
|
|
436
|
+
/**
|
|
437
|
+
* Selects a single entry in the nav selector.
|
|
438
|
+
* @param entries nav selector entries
|
|
439
|
+
* @param entryUid the entry uid to select
|
|
440
|
+
*/
|
|
441
|
+
static select(entries, entryUid) {
|
|
442
|
+
return entries.map(entry => {
|
|
443
|
+
if (isInternalNavSelectorEntryALeaf(entry)) {
|
|
444
|
+
return this.selectALeaf(entry, entryUid);
|
|
445
|
+
}
|
|
446
|
+
else if (isInternalNavSelectorEntryANode(entry)) {
|
|
447
|
+
return {
|
|
448
|
+
...entry,
|
|
449
|
+
children: entry.children.flatMap(child => this.select([child], entryUid)),
|
|
450
|
+
};
|
|
451
|
+
}
|
|
452
|
+
return entry;
|
|
453
|
+
});
|
|
454
|
+
}
|
|
455
|
+
static selectALeaf(leaf, entryUid) {
|
|
456
|
+
if (!!leaf.details.length) {
|
|
457
|
+
return this.selectALeafWithDetails(leaf, entryUid);
|
|
458
|
+
}
|
|
459
|
+
return this.selectALeafWithoutDetails(leaf, entryUid);
|
|
460
|
+
}
|
|
461
|
+
static selectALeafWithDetails(leaf, entryUid) {
|
|
462
|
+
if (leaf.uid === entryUid) {
|
|
463
|
+
const leafSelected = !leaf.detailsDisplayable && leaf.selectable;
|
|
464
|
+
return {
|
|
465
|
+
...leaf,
|
|
466
|
+
selected: leafSelected,
|
|
467
|
+
accessibility: {
|
|
468
|
+
...leaf.accessibility,
|
|
469
|
+
tabIndex: leafSelected ? 0 : -1,
|
|
470
|
+
},
|
|
471
|
+
folded: !leaf.detailsDisplayable,
|
|
472
|
+
details: leaf.details.reduce((details, detail, idx) => {
|
|
473
|
+
const detailSelected = leaf.detailsDisplayable && !detail.displayError && (idx === 0 || !details[idx - 1].selected);
|
|
474
|
+
details.push({
|
|
475
|
+
...detail,
|
|
476
|
+
selected: detailSelected,
|
|
477
|
+
accessibility: {
|
|
478
|
+
...detail.accessibility,
|
|
479
|
+
tabIndex: detailSelected ? 0 : -1,
|
|
480
|
+
},
|
|
481
|
+
});
|
|
482
|
+
return details;
|
|
483
|
+
}, []),
|
|
484
|
+
};
|
|
485
|
+
}
|
|
486
|
+
const details = leaf.details.map(detail => {
|
|
487
|
+
const detailSelected = detail.uid === entryUid && !detail.displayError;
|
|
488
|
+
return {
|
|
489
|
+
...detail,
|
|
490
|
+
selected: detailSelected,
|
|
491
|
+
accessibility: {
|
|
492
|
+
...detail.accessibility,
|
|
493
|
+
tabIndex: detailSelected ? 0 : -1,
|
|
494
|
+
},
|
|
495
|
+
};
|
|
496
|
+
});
|
|
497
|
+
return {
|
|
498
|
+
...leaf,
|
|
499
|
+
accessibility: {
|
|
500
|
+
...leaf.accessibility,
|
|
501
|
+
tabIndex: -1,
|
|
502
|
+
},
|
|
503
|
+
selected: false,
|
|
504
|
+
folded: !leaf.folded ? false : details.every(detail => !detail.selected),
|
|
505
|
+
details,
|
|
506
|
+
};
|
|
507
|
+
}
|
|
508
|
+
static selectALeafWithoutDetails(leaf, entryUid) {
|
|
509
|
+
const selected = leaf.selectable && leaf.uid === entryUid;
|
|
510
|
+
return {
|
|
511
|
+
...leaf,
|
|
512
|
+
selected,
|
|
513
|
+
accessibility: {
|
|
514
|
+
...leaf.accessibility,
|
|
515
|
+
tabIndex: selected ? 0 : -1,
|
|
516
|
+
},
|
|
517
|
+
folded: true,
|
|
518
|
+
};
|
|
519
|
+
}
|
|
520
|
+
}
|
|
521
|
+
|
|
522
|
+
const LeafLogics = {
|
|
523
|
+
DISABLED: 'DISABLED',
|
|
524
|
+
FEATURE_LOCKED: 'FEATURE_LOCKED',
|
|
525
|
+
TOKEN_INVALID: 'TOKEN_INVALID',
|
|
526
|
+
COUNTER: 'COUNTER',
|
|
527
|
+
};
|
|
528
|
+
/**
|
|
529
|
+
* NavSelectorBuilder is a utility class that builds the NavSelector entries for single and multiple select modes.
|
|
530
|
+
* It also checks the structure of the entries to ensure they are valid.
|
|
531
|
+
*/
|
|
532
|
+
class NavSelectorBuilder {
|
|
533
|
+
// /!\/!\ Order of logics is important /!\/!\
|
|
534
|
+
static LEAF_LOGICS_PRIORITY = {
|
|
535
|
+
[LeafLogics.DISABLED]: (leaf) => leaf.disableReason !== null,
|
|
536
|
+
[LeafLogics.FEATURE_LOCKED]: (leaf) => leaf.featureLocked,
|
|
537
|
+
[LeafLogics.TOKEN_INVALID]: (leaf) => leaf.tokenInvalid,
|
|
538
|
+
[LeafLogics.COUNTER]: (leaf) => leaf.counter !== null,
|
|
539
|
+
};
|
|
540
|
+
/**
|
|
541
|
+
* Builds the NavSelector entries for single select mode.
|
|
542
|
+
* @param entries nav selector entries
|
|
543
|
+
* @param selectedEntryUid selected entry uid
|
|
544
|
+
* @param detailsDisplayedLimit number of details displayed limit
|
|
545
|
+
*/
|
|
546
|
+
static build(entries, selectedEntryUid, detailsDisplayedLimit) {
|
|
547
|
+
this.structureChecker(entries);
|
|
548
|
+
const builtEntries = this.buildEntries(entries, false, 1, detailsDisplayedLimit);
|
|
549
|
+
if (selectedEntryUid) {
|
|
550
|
+
return NavSelectorSingleSelect.select(builtEntries, selectedEntryUid);
|
|
551
|
+
}
|
|
552
|
+
return builtEntries;
|
|
553
|
+
}
|
|
554
|
+
/**
|
|
555
|
+
* Builds the NavSelector entries for multiple select mode.
|
|
556
|
+
* @param entries nav selector entries
|
|
557
|
+
* @param selectedEntryUids selected entry uids
|
|
558
|
+
* @param detailsDisplayedLimit number of details displayed limit
|
|
559
|
+
*/
|
|
560
|
+
static buildInMultipleMode(entries, selectedEntryUids, detailsDisplayedLimit) {
|
|
561
|
+
this.structureChecker(entries, true);
|
|
562
|
+
let builtEntries = this.buildEntries(entries, true, 1, detailsDisplayedLimit);
|
|
563
|
+
if (selectedEntryUids) {
|
|
564
|
+
for (const selectedEntryUid of selectedEntryUids) {
|
|
565
|
+
builtEntries = NavSelectorMultiSelect.selectInMultipleMode(builtEntries, selectedEntryUid);
|
|
566
|
+
}
|
|
567
|
+
}
|
|
568
|
+
return builtEntries;
|
|
569
|
+
}
|
|
570
|
+
static structureChecker(entries, multipleModeEnabled = false) {
|
|
571
|
+
entries.forEach(entry => {
|
|
572
|
+
if (isNavSelectorEntryAGroup(entry) || isNavSelectorEntryACategory(entry)) {
|
|
573
|
+
this.structureChecker(entry.children, multipleModeEnabled);
|
|
574
|
+
}
|
|
575
|
+
else if (isNavSelectorEntryALeaf(entry)) {
|
|
576
|
+
if (entry.details.length && multipleModeEnabled) {
|
|
577
|
+
console.error(`NavSelectorBuilder: Leaf ${entry.uid} with details is not allowed in multiple mode`);
|
|
578
|
+
}
|
|
579
|
+
}
|
|
580
|
+
});
|
|
581
|
+
}
|
|
582
|
+
static buildEntries(entries, multipleModeEnabled, level = 1, detailsDisplayedLimit) {
|
|
583
|
+
const newEntries = entries
|
|
584
|
+
.map((entry, idx) => this.buildEntry(entry, { multipleModeEnabled, level, idx, totalNumberOfEntry: entries.length, detailsDisplayedLimit }))
|
|
585
|
+
.filter(it => it !== null);
|
|
586
|
+
return NavSelectorAccessibility.resetFocus(newEntries);
|
|
587
|
+
}
|
|
588
|
+
static buildEntry(entry, { multipleModeEnabled, level, idx, totalNumberOfEntry, detailsDisplayedLimit, }) {
|
|
589
|
+
if (isNavSelectorEntryALeaf(entry)) {
|
|
590
|
+
return this.buildLeaf(entry, {
|
|
591
|
+
multipleModeEnabled,
|
|
592
|
+
level,
|
|
593
|
+
idx,
|
|
594
|
+
totalNumberOfLeaf: totalNumberOfEntry,
|
|
595
|
+
focusable: true,
|
|
596
|
+
detailsDisplayedLimit,
|
|
597
|
+
});
|
|
598
|
+
}
|
|
599
|
+
else if (isNavSelectorEntryACategory(entry)) {
|
|
600
|
+
return this.buildCategory(entry, {
|
|
601
|
+
multipleModeEnabled,
|
|
602
|
+
level,
|
|
603
|
+
idx,
|
|
604
|
+
totalNumberOfCategory: totalNumberOfEntry,
|
|
605
|
+
detailsDisplayedLimit,
|
|
606
|
+
});
|
|
607
|
+
}
|
|
608
|
+
else {
|
|
609
|
+
return this.buildGroup(entry, {
|
|
610
|
+
multipleModeEnabled,
|
|
611
|
+
level,
|
|
612
|
+
idx,
|
|
613
|
+
totalNumberOfGroups: totalNumberOfEntry,
|
|
614
|
+
focusable: true,
|
|
615
|
+
detailsDisplayedLimit,
|
|
616
|
+
});
|
|
617
|
+
}
|
|
618
|
+
}
|
|
619
|
+
static buildCategoryChildren(entry, { focusable, multipleModeEnabled, categoryLevel, detailsDisplayedLimit, }) {
|
|
620
|
+
return entry.children
|
|
621
|
+
.map((child, idx) => {
|
|
622
|
+
if (isNavSelectorEntryALeaf(child)) {
|
|
623
|
+
return this.buildLeaf(child, {
|
|
624
|
+
focusable,
|
|
625
|
+
multipleModeEnabled,
|
|
626
|
+
level: categoryLevel + 1,
|
|
627
|
+
idx,
|
|
628
|
+
totalNumberOfLeaf: entry.children.length,
|
|
629
|
+
detailsDisplayedLimit,
|
|
630
|
+
});
|
|
631
|
+
}
|
|
632
|
+
else {
|
|
633
|
+
return this.buildGroup(child, {
|
|
634
|
+
focusable,
|
|
635
|
+
multipleModeEnabled,
|
|
636
|
+
level: categoryLevel + 1,
|
|
637
|
+
idx,
|
|
638
|
+
totalNumberOfGroups: entry.children.length,
|
|
639
|
+
detailsDisplayedLimit,
|
|
640
|
+
});
|
|
641
|
+
}
|
|
642
|
+
})
|
|
643
|
+
.filter(it => it !== null);
|
|
644
|
+
}
|
|
645
|
+
static buildCategory(node, { multipleModeEnabled, level, idx, totalNumberOfCategory, detailsDisplayedLimit, }) {
|
|
646
|
+
const children = this.buildCategoryChildren(node, {
|
|
647
|
+
focusable: !node.folded,
|
|
648
|
+
multipleModeEnabled,
|
|
649
|
+
categoryLevel: level,
|
|
650
|
+
detailsDisplayedLimit,
|
|
651
|
+
});
|
|
652
|
+
return {
|
|
653
|
+
uid: node.uid,
|
|
654
|
+
alias: node.alias,
|
|
655
|
+
children,
|
|
656
|
+
hidden: false,
|
|
657
|
+
focusable: true,
|
|
658
|
+
accessibility: {
|
|
659
|
+
tabIndex: -1,
|
|
660
|
+
ariaLevel: level,
|
|
661
|
+
ariaPosinset: idx + 1,
|
|
662
|
+
ariaSetsize: totalNumberOfCategory,
|
|
663
|
+
},
|
|
664
|
+
folded: node.folded,
|
|
665
|
+
type: node.type,
|
|
666
|
+
};
|
|
667
|
+
}
|
|
668
|
+
static buildGroupChildren(entry, { multipleModeEnabled, groupLevel, focusable, detailsDisplayedLimit, }) {
|
|
669
|
+
return entry.children
|
|
670
|
+
.map((child, idx) => this.buildLeaf(child, {
|
|
671
|
+
multipleModeEnabled,
|
|
672
|
+
level: groupLevel + 1,
|
|
673
|
+
idx,
|
|
674
|
+
totalNumberOfLeaf: entry.children.length,
|
|
675
|
+
focusable: focusable && !entry.folded,
|
|
676
|
+
detailsDisplayedLimit,
|
|
677
|
+
}))
|
|
678
|
+
.filter(it => it !== null);
|
|
679
|
+
}
|
|
680
|
+
static buildGroup(node, { focusable, multipleModeEnabled, level, idx, totalNumberOfGroups, detailsDisplayedLimit, }) {
|
|
681
|
+
const children = this.buildGroupChildren(node, { multipleModeEnabled, groupLevel: level, focusable, detailsDisplayedLimit });
|
|
682
|
+
const displayTokenInvalid = children.some(({ displayTokenInvalid }) => displayTokenInvalid);
|
|
683
|
+
const selectedChildrenCount = children.filter(({ selected }) => selected).length;
|
|
684
|
+
return {
|
|
685
|
+
uid: node.uid,
|
|
686
|
+
alias: node.alias,
|
|
687
|
+
children,
|
|
688
|
+
childrenPictureUrlSample: children
|
|
689
|
+
.map((child, idx) => isInternalNavSelectorEntryALeaf(child) && idx < 4 ? { url: child.pictureUrl, initial: child.alias[0] } : null)
|
|
690
|
+
.filter(it => it !== null),
|
|
691
|
+
hidden: false,
|
|
692
|
+
accessibility: {
|
|
693
|
+
tabIndex: -1,
|
|
694
|
+
ariaPosinset: idx + 1,
|
|
695
|
+
ariaLevel: level,
|
|
696
|
+
ariaSetsize: totalNumberOfGroups,
|
|
697
|
+
},
|
|
698
|
+
focusable,
|
|
699
|
+
displayCounter: node.folded && children.some(child => isInternalNavSelectorEntryALeaf(child) && child.counter !== 0),
|
|
700
|
+
counter: children.reduce((acc, { counter }) => acc + counter, 0),
|
|
701
|
+
displayTokenInvalid,
|
|
702
|
+
selected: false,
|
|
703
|
+
selectable: multipleModeEnabled && children.some(({ selectable }) => selectable),
|
|
704
|
+
undeterminedSelection: selectedChildrenCount !== children.length && selectedChildrenCount > 0,
|
|
705
|
+
folded: node.folded,
|
|
706
|
+
type: node.type,
|
|
707
|
+
};
|
|
708
|
+
}
|
|
709
|
+
static buildLeaf(leaf, { focusable, multipleModeEnabled, level, idx, totalNumberOfLeaf, detailsDisplayedLimit, }) {
|
|
710
|
+
if (leaf.missingPermission) {
|
|
711
|
+
return null;
|
|
712
|
+
}
|
|
713
|
+
const detailsDisplayable = this.isLeafLogicValid(leaf, LeafLogics.COUNTER) && !!leaf.details.length;
|
|
714
|
+
const foldable = !!leaf.details.length && detailsDisplayable;
|
|
715
|
+
const folded = true;
|
|
716
|
+
const counter = (leaf.details.reduce((acc, detail) => acc + (detail.counter ?? 0), 0) || leaf.counter) ?? 0;
|
|
717
|
+
const counterDisplayable = counter !== 0 && this.isLeafLogicValid(leaf, LeafLogics.COUNTER);
|
|
718
|
+
const disabled = leaf.disableReason !== null;
|
|
719
|
+
const viewMoreDisplayable = leaf.details.length > detailsDisplayedLimit;
|
|
720
|
+
return {
|
|
721
|
+
uid: leaf.uid,
|
|
722
|
+
alias: leaf.alias,
|
|
723
|
+
pictureUrl: leaf.pictureUrl,
|
|
724
|
+
disabled,
|
|
725
|
+
disableReason: leaf.disableReason,
|
|
726
|
+
hidden: false,
|
|
727
|
+
focusable: focusable && !disabled,
|
|
728
|
+
accessibility: {
|
|
729
|
+
tabIndex: -1,
|
|
730
|
+
ariaPosinset: idx + 1,
|
|
731
|
+
ariaLevel: level,
|
|
732
|
+
ariaSetsize: totalNumberOfLeaf,
|
|
733
|
+
},
|
|
734
|
+
foldable,
|
|
735
|
+
folded,
|
|
736
|
+
displayCounter: folded && counterDisplayable,
|
|
737
|
+
counterDisplayable,
|
|
738
|
+
counter,
|
|
739
|
+
network: leaf.network,
|
|
740
|
+
displayTokenInvalid: leaf.tokenInvalid && this.isLeafLogicValid(leaf, LeafLogics.TOKEN_INVALID, LeafLogics.COUNTER),
|
|
741
|
+
displayFeatureLocked: leaf.featureLocked && this.isLeafLogicValid(leaf, LeafLogics.FEATURE_LOCKED, LeafLogics.TOKEN_INVALID, LeafLogics.COUNTER),
|
|
742
|
+
selected: false,
|
|
743
|
+
selectable: multipleModeEnabled
|
|
744
|
+
? this.isLeafLogicValid(leaf, LeafLogics.COUNTER)
|
|
745
|
+
: this.isLeafLogicValid(leaf, LeafLogics.FEATURE_LOCKED, LeafLogics.TOKEN_INVALID, LeafLogics.COUNTER),
|
|
746
|
+
detailsDisplayable,
|
|
747
|
+
details: leaf.details.map(detail => this.buildLeafDetail(detail, level + 1, focusable && !folded)),
|
|
748
|
+
type: 'LEAF',
|
|
749
|
+
viewMoreDisplayable,
|
|
750
|
+
viewMoreDisplayed: viewMoreDisplayable,
|
|
751
|
+
viewMoreDetailsDisplayedLimit: detailsDisplayedLimit,
|
|
752
|
+
};
|
|
753
|
+
}
|
|
754
|
+
static buildLeafDetail(detail, level, focusable) {
|
|
755
|
+
return {
|
|
756
|
+
uid: detail.uid,
|
|
757
|
+
counter: detail.counter ?? 0,
|
|
758
|
+
displayCounter: detail.counter !== null,
|
|
759
|
+
alias: detail.name,
|
|
760
|
+
hidden: false,
|
|
761
|
+
accessibility: {
|
|
762
|
+
tabIndex: -1,
|
|
763
|
+
ariaPosinset: 1,
|
|
764
|
+
ariaLevel: level,
|
|
765
|
+
ariaSetsize: 1,
|
|
766
|
+
},
|
|
767
|
+
focusable,
|
|
768
|
+
selected: false,
|
|
769
|
+
errorReason: detail.errorReason,
|
|
770
|
+
displayError: detail.errorReason !== null,
|
|
771
|
+
type: 'LEAF_DETAILS',
|
|
772
|
+
};
|
|
773
|
+
}
|
|
774
|
+
static isLeafLogicValid(leaf, ...excludes) {
|
|
775
|
+
return Object.entries(this.LEAF_LOGICS_PRIORITY)
|
|
776
|
+
.filter(([key]) => !excludes.includes(key))
|
|
777
|
+
.every(([, logic]) => !logic(leaf));
|
|
778
|
+
}
|
|
779
|
+
}
|
|
780
|
+
|
|
781
|
+
const isInternalNavSelectorEntryALeafFocusable = (leaf, { parentFolded, minified }) => {
|
|
782
|
+
if (parentFolded) {
|
|
783
|
+
return false;
|
|
784
|
+
}
|
|
785
|
+
if (minified) {
|
|
786
|
+
return !leaf.disabled && !leaf.displayTokenInvalid && !leaf.displayFeatureLocked;
|
|
787
|
+
}
|
|
788
|
+
return !leaf.disabled;
|
|
789
|
+
};
|
|
790
|
+
|
|
791
|
+
/**
|
|
792
|
+
* NavSelectorFilter is a utility class that provides methods to filter entries
|
|
793
|
+
*/
|
|
794
|
+
class NavSelectorFilter {
|
|
795
|
+
/**
|
|
796
|
+
* Filters the entries based on the search string
|
|
797
|
+
*
|
|
798
|
+
* The search string is normalized and lowercase and trimmed.
|
|
799
|
+
*
|
|
800
|
+
* If a category matches the search string, all its children are unfolded, marked as focusable, and not hidden.
|
|
801
|
+
*
|
|
802
|
+
* If a group matches the search string, the group is unfolded and all its children are unfolded, marked as focusable, and not hidden.
|
|
803
|
+
*
|
|
804
|
+
* If a leaf matches the search string, it is marked as not hidden and focusable.
|
|
805
|
+
*
|
|
806
|
+
* Else the entry marked as hidden and not focusable.
|
|
807
|
+
*
|
|
808
|
+
* It also determines whenever counter and token invalid should be displayed on groups and leaves.
|
|
809
|
+
*
|
|
810
|
+
* @param entries The entries to filter.
|
|
811
|
+
* @param search The search string.
|
|
812
|
+
* @returns The filtered entries.
|
|
813
|
+
*/
|
|
814
|
+
static filter(entries, search) {
|
|
815
|
+
const formattedSearch = this.cleanValue(search);
|
|
816
|
+
if (!formattedSearch) {
|
|
817
|
+
return entries;
|
|
818
|
+
}
|
|
819
|
+
return this.filterEntries(entries, formattedSearch);
|
|
820
|
+
}
|
|
821
|
+
static filterEntries(entries, formattedSearch) {
|
|
822
|
+
const newEntries = entries.map(entry => {
|
|
823
|
+
if (this.matches(entry.alias, formattedSearch)) {
|
|
824
|
+
return this.recursivelyUnfoldEntry(entry);
|
|
825
|
+
}
|
|
826
|
+
if (isInternalNavSelectorEntryANode(entry)) {
|
|
827
|
+
const children = this.filterEntries(entry.children, formattedSearch);
|
|
828
|
+
if (children.every(({ hidden }) => hidden)) {
|
|
829
|
+
return {
|
|
830
|
+
...entry,
|
|
831
|
+
children,
|
|
832
|
+
hidden: true,
|
|
833
|
+
};
|
|
834
|
+
}
|
|
835
|
+
return {
|
|
836
|
+
...entry,
|
|
837
|
+
hidden: false,
|
|
838
|
+
displayCounter: false,
|
|
839
|
+
displayTokenInvalid: false,
|
|
840
|
+
folded: false,
|
|
841
|
+
children,
|
|
842
|
+
};
|
|
843
|
+
}
|
|
844
|
+
return {
|
|
845
|
+
...entry,
|
|
846
|
+
focusable: false,
|
|
847
|
+
hidden: true,
|
|
848
|
+
};
|
|
849
|
+
});
|
|
850
|
+
return NavSelectorAccessibility.resetFocus(newEntries);
|
|
851
|
+
}
|
|
852
|
+
static recursivelyUnfoldEntry(entry) {
|
|
853
|
+
if (isInternalNavSelectorEntryAGroup(entry)) {
|
|
854
|
+
const children = entry.children.map(child => this.recursivelyUnfoldEntry(child));
|
|
855
|
+
return {
|
|
856
|
+
...entry,
|
|
857
|
+
folded: false,
|
|
858
|
+
children,
|
|
859
|
+
displayCounter: false,
|
|
860
|
+
displayTokenInvalid: false,
|
|
861
|
+
};
|
|
862
|
+
}
|
|
863
|
+
else if (isInternalNavSelectorEntryALeaf(entry)) {
|
|
864
|
+
return {
|
|
865
|
+
...entry,
|
|
866
|
+
hidden: false,
|
|
867
|
+
focusable: isInternalNavSelectorEntryALeafFocusable(entry, { parentFolded: false, minified: false }),
|
|
868
|
+
displayCounter: entry.counterDisplayable,
|
|
869
|
+
};
|
|
870
|
+
}
|
|
871
|
+
else if (isInternalNavSelectorEntryACategory(entry)) {
|
|
872
|
+
const children = entry.children.map(child => this.recursivelyUnfoldEntry(child));
|
|
873
|
+
return {
|
|
874
|
+
...entry,
|
|
875
|
+
folded: false,
|
|
876
|
+
hidden: false,
|
|
877
|
+
children,
|
|
878
|
+
};
|
|
879
|
+
}
|
|
880
|
+
return entry;
|
|
881
|
+
}
|
|
882
|
+
static matches(alias, formattedSearch) {
|
|
883
|
+
return this.cleanValue(alias).includes(formattedSearch);
|
|
884
|
+
}
|
|
885
|
+
static cleanValue(value) {
|
|
886
|
+
return value.trim().normalize('NFKC').toLowerCase();
|
|
887
|
+
}
|
|
888
|
+
}
|
|
889
|
+
|
|
890
|
+
/**
|
|
891
|
+
* Class to handle the folding and unfolding of nav selector entries.
|
|
892
|
+
*/
|
|
893
|
+
class NavSelectorFolding {
|
|
894
|
+
/**
|
|
895
|
+
* Toggle the folding state of an entry.
|
|
896
|
+
*
|
|
897
|
+
* @see {@link NavSelectorFolding.fold} and {@link NavSelectorFolding.unfold} for more information on folding and unfolding.
|
|
898
|
+
*
|
|
899
|
+
* @param entries nav selector entries
|
|
900
|
+
* @param entryUid the entry uid to toggle
|
|
901
|
+
* @param minified true if the nav selector is minified. Needed for leaf as they are not foldable in minified mode
|
|
902
|
+
*/
|
|
903
|
+
static toggleFolding(entries, entryUid, minified) {
|
|
904
|
+
return this.toggleEntryFolding(entries, entryUid, minified);
|
|
905
|
+
}
|
|
906
|
+
/**
|
|
907
|
+
* Fold an entry.
|
|
908
|
+
*
|
|
909
|
+
* Set unfocusable on all children of the folded entry.
|
|
910
|
+
* Compute whenever the counter and token invalid should be displayed on groups and leaves.
|
|
911
|
+
*
|
|
912
|
+
* @param entries nav selector entries
|
|
913
|
+
* @param entryUid the entry uid to fold
|
|
914
|
+
* @param minified true if the nav selector is minified. Needed for leaf as they are not foldable in minified mode
|
|
915
|
+
*/
|
|
916
|
+
static fold(entries, entryUid, minified) {
|
|
917
|
+
return this.foldEntry(entries, entryUid, minified);
|
|
918
|
+
}
|
|
919
|
+
/**
|
|
920
|
+
* Unfold an entry.
|
|
921
|
+
*
|
|
922
|
+
* Set focusable on all children of the folded entry.
|
|
923
|
+
* Compute whenever the counter and token invalid should be displayed on groups and leaves.
|
|
924
|
+
*
|
|
925
|
+
* @param entries nav selector entries
|
|
926
|
+
* @param entryUid the entry uid to unfold
|
|
927
|
+
* @param minified true if the nav selector is minified. Needed for leaf as they are not foldable in minified mode
|
|
928
|
+
*/
|
|
929
|
+
static unfold(entries, entryUid, minified) {
|
|
930
|
+
return this.unfoldEntry(entries, entryUid, minified);
|
|
931
|
+
}
|
|
932
|
+
static toggleEntryFolding(entries, entryUid, minified, parentFolded = false) {
|
|
933
|
+
return entries.map(entry => {
|
|
934
|
+
if (isInternalNavSelectorEntryACategory(entry)) {
|
|
935
|
+
if (entry.uid === entryUid) {
|
|
936
|
+
const folded = !entry.folded;
|
|
937
|
+
if (folded) {
|
|
938
|
+
return this.foldCategory(entry, minified);
|
|
939
|
+
}
|
|
940
|
+
else {
|
|
941
|
+
return this.unfoldCategory(entry, minified);
|
|
942
|
+
}
|
|
943
|
+
}
|
|
944
|
+
return {
|
|
945
|
+
...entry,
|
|
946
|
+
children: this.toggleEntryFolding(entry.children, entryUid, minified, entry.folded),
|
|
947
|
+
};
|
|
948
|
+
}
|
|
949
|
+
if (isInternalNavSelectorEntryAGroup(entry)) {
|
|
950
|
+
if (entry.uid === entryUid) {
|
|
951
|
+
const folded = !entry.folded;
|
|
952
|
+
if (folded) {
|
|
953
|
+
return this.foldGroup(entry, minified);
|
|
954
|
+
}
|
|
955
|
+
else {
|
|
956
|
+
return this.unfoldGroup(entry, minified);
|
|
957
|
+
}
|
|
958
|
+
}
|
|
959
|
+
return {
|
|
960
|
+
...entry,
|
|
961
|
+
children: this.toggleEntryFolding(entry.children, entryUid, minified, parentFolded || entry.folded),
|
|
962
|
+
};
|
|
963
|
+
}
|
|
964
|
+
if (isInternalNavSelectorEntryALeaf(entry)) {
|
|
965
|
+
if (entry.uid === entryUid) {
|
|
966
|
+
const folded = !entry.folded;
|
|
967
|
+
if (folded) {
|
|
968
|
+
return this.foldLeaf(entry, minified);
|
|
969
|
+
}
|
|
970
|
+
else {
|
|
971
|
+
return this.unfoldLeaf(entry, minified);
|
|
972
|
+
}
|
|
973
|
+
}
|
|
974
|
+
return {
|
|
975
|
+
...entry,
|
|
976
|
+
focusable: isInternalNavSelectorEntryALeafFocusable(entry, { minified, parentFolded }),
|
|
977
|
+
};
|
|
978
|
+
}
|
|
979
|
+
return { ...entry, focusable: !parentFolded };
|
|
980
|
+
});
|
|
981
|
+
}
|
|
982
|
+
static foldEntry(entries, entryUid, minified, parentFolded = false) {
|
|
983
|
+
return entries.map(entry => {
|
|
984
|
+
if (isInternalNavSelectorEntryACategory(entry)) {
|
|
985
|
+
if (entry.uid === entryUid) {
|
|
986
|
+
return this.foldCategory(entry, minified);
|
|
987
|
+
}
|
|
988
|
+
return {
|
|
989
|
+
...entry,
|
|
990
|
+
children: this.foldEntry(entry.children, entryUid, minified, entry.folded),
|
|
991
|
+
};
|
|
992
|
+
}
|
|
993
|
+
if (isInternalNavSelectorEntryAGroup(entry)) {
|
|
994
|
+
if (entry.uid === entryUid) {
|
|
995
|
+
return this.foldGroup(entry, minified);
|
|
996
|
+
}
|
|
997
|
+
return {
|
|
998
|
+
...entry,
|
|
999
|
+
focusable: !parentFolded,
|
|
1000
|
+
children: this.foldEntry(entry.children, entryUid, minified, parentFolded || entry.folded),
|
|
1001
|
+
};
|
|
1002
|
+
}
|
|
1003
|
+
if (isInternalNavSelectorEntryALeaf(entry)) {
|
|
1004
|
+
if (entry.uid === entryUid) {
|
|
1005
|
+
return this.foldLeaf(entry, minified);
|
|
1006
|
+
}
|
|
1007
|
+
return {
|
|
1008
|
+
...entry,
|
|
1009
|
+
focusable: isInternalNavSelectorEntryALeafFocusable(entry, { minified, parentFolded }),
|
|
1010
|
+
};
|
|
1011
|
+
}
|
|
1012
|
+
return { ...entry, focusable: !parentFolded };
|
|
1013
|
+
});
|
|
1014
|
+
}
|
|
1015
|
+
static unfoldEntry(entries, entryUid, minified, parentFolded = false) {
|
|
1016
|
+
return entries.map(entry => {
|
|
1017
|
+
if (isInternalNavSelectorEntryACategory(entry)) {
|
|
1018
|
+
if (entry.uid === entryUid) {
|
|
1019
|
+
return this.unfoldCategory(entry, minified);
|
|
1020
|
+
}
|
|
1021
|
+
return {
|
|
1022
|
+
...entry,
|
|
1023
|
+
children: this.unfoldEntry(entry.children, entryUid, minified, entry.folded),
|
|
1024
|
+
};
|
|
1025
|
+
}
|
|
1026
|
+
if (isInternalNavSelectorEntryAGroup(entry)) {
|
|
1027
|
+
if (entry.uid === entryUid) {
|
|
1028
|
+
return this.unfoldGroup(entry, minified);
|
|
1029
|
+
}
|
|
1030
|
+
return {
|
|
1031
|
+
...entry,
|
|
1032
|
+
children: this.unfoldEntry(entry.children, entryUid, minified, parentFolded || entry.folded),
|
|
1033
|
+
focusable: !parentFolded,
|
|
1034
|
+
};
|
|
1035
|
+
}
|
|
1036
|
+
if (isInternalNavSelectorEntryALeaf(entry)) {
|
|
1037
|
+
if (entry.uid === entryUid) {
|
|
1038
|
+
return this.unfoldLeaf(entry, minified);
|
|
1039
|
+
}
|
|
1040
|
+
return {
|
|
1041
|
+
...entry,
|
|
1042
|
+
focusable: isInternalNavSelectorEntryALeafFocusable(entry, { minified, parentFolded }),
|
|
1043
|
+
};
|
|
1044
|
+
}
|
|
1045
|
+
return { ...entry, focusable: !parentFolded };
|
|
1046
|
+
});
|
|
1047
|
+
}
|
|
1048
|
+
static foldCategory(category, minified) {
|
|
1049
|
+
return {
|
|
1050
|
+
...category,
|
|
1051
|
+
folded: true,
|
|
1052
|
+
children: this.foldEntry(category.children, category.uid, minified, true),
|
|
1053
|
+
};
|
|
1054
|
+
}
|
|
1055
|
+
static unfoldCategory(category, minified) {
|
|
1056
|
+
return {
|
|
1057
|
+
...category,
|
|
1058
|
+
folded: false,
|
|
1059
|
+
children: this.unfoldEntry(category.children, category.uid, minified, false),
|
|
1060
|
+
};
|
|
1061
|
+
}
|
|
1062
|
+
static foldGroup(group, minified) {
|
|
1063
|
+
return {
|
|
1064
|
+
...group,
|
|
1065
|
+
folded: true,
|
|
1066
|
+
children: this.foldEntry(group.children, group.uid, minified, true),
|
|
1067
|
+
displayCounter: !!group.counter,
|
|
1068
|
+
displayTokenInvalid: group.children.some(({ displayTokenInvalid }) => displayTokenInvalid),
|
|
1069
|
+
};
|
|
1070
|
+
}
|
|
1071
|
+
static unfoldGroup(group, minified) {
|
|
1072
|
+
return {
|
|
1073
|
+
...group,
|
|
1074
|
+
folded: false,
|
|
1075
|
+
children: this.unfoldEntry(group.children, group.uid, minified, false),
|
|
1076
|
+
displayCounter: false,
|
|
1077
|
+
displayTokenInvalid: false,
|
|
1078
|
+
};
|
|
1079
|
+
}
|
|
1080
|
+
static foldLeaf(leaf, minified) {
|
|
1081
|
+
if (!leaf.foldable || minified) {
|
|
1082
|
+
return leaf;
|
|
1083
|
+
}
|
|
1084
|
+
return {
|
|
1085
|
+
...leaf,
|
|
1086
|
+
displayCounter: true,
|
|
1087
|
+
folded: true,
|
|
1088
|
+
details: leaf.details.map(detail => ({ ...detail, focusable: false })),
|
|
1089
|
+
};
|
|
1090
|
+
}
|
|
1091
|
+
static unfoldLeaf(leaf, minified) {
|
|
1092
|
+
if (!leaf.foldable || minified) {
|
|
1093
|
+
return leaf;
|
|
1094
|
+
}
|
|
1095
|
+
return {
|
|
1096
|
+
...leaf,
|
|
1097
|
+
displayCounter: false,
|
|
1098
|
+
folded: false,
|
|
1099
|
+
details: leaf.details.map((detail, idx) => ({
|
|
1100
|
+
...detail,
|
|
1101
|
+
focusable: idx < leaf.viewMoreDetailsDisplayedLimit,
|
|
1102
|
+
})),
|
|
1103
|
+
};
|
|
1104
|
+
}
|
|
1105
|
+
}
|
|
1106
|
+
|
|
1107
|
+
/**
|
|
1108
|
+
* NavSelectorMinifying is a utility class that provides methods to apply rules on entries when minifying or expanded nav selector.
|
|
1109
|
+
*/
|
|
1110
|
+
class NavSelectorMinifying {
|
|
1111
|
+
/**
|
|
1112
|
+
* When minifying the nav selector, compute the focusable state of the entries.
|
|
1113
|
+
*
|
|
1114
|
+
* Leaf are not focusable in any error state when minified.
|
|
1115
|
+
* Detail are not focusable when minified.
|
|
1116
|
+
*
|
|
1117
|
+
* @param entries The entries to minify.
|
|
1118
|
+
* @returns The modified entries.
|
|
1119
|
+
*/
|
|
1120
|
+
static minify(entries) {
|
|
1121
|
+
return this.compute(entries, true);
|
|
1122
|
+
}
|
|
1123
|
+
/**
|
|
1124
|
+
* When expanding the nav selector, compute the focusable state of the entries.
|
|
1125
|
+
*
|
|
1126
|
+
* Leaf are not focusable in disabled state when expanded.
|
|
1127
|
+
* Detail are focusable when expanded.
|
|
1128
|
+
*
|
|
1129
|
+
* @param entries The entries to minify.
|
|
1130
|
+
* @returns The modified entries.
|
|
1131
|
+
*/
|
|
1132
|
+
static expand(entries) {
|
|
1133
|
+
return this.compute(entries, false);
|
|
1134
|
+
}
|
|
1135
|
+
static compute(entries, minified, parent = null) {
|
|
1136
|
+
return entries.map(entry => {
|
|
1137
|
+
if (isInternalNavSelectorEntryALeafDetails(entry)) {
|
|
1138
|
+
return { ...entry, focusable: !minified };
|
|
1139
|
+
}
|
|
1140
|
+
if (isInternalNavSelectorEntryANode(entry)) {
|
|
1141
|
+
return {
|
|
1142
|
+
...entry,
|
|
1143
|
+
children: this.compute(entry.children, minified, entry),
|
|
1144
|
+
};
|
|
1145
|
+
}
|
|
1146
|
+
return {
|
|
1147
|
+
...entry,
|
|
1148
|
+
focusable: isInternalNavSelectorEntryALeafFocusable(entry, { parentFolded: parent?.folded === true, minified: minified }),
|
|
1149
|
+
details: this.compute(entry.details, minified),
|
|
1150
|
+
};
|
|
1151
|
+
});
|
|
1152
|
+
}
|
|
1153
|
+
}
|
|
1154
|
+
|
|
1155
|
+
/**
|
|
1156
|
+
* Utility class to handle the view more functionality on leaves
|
|
1157
|
+
*/
|
|
1158
|
+
class NavSelectorViewMore {
|
|
1159
|
+
/**
|
|
1160
|
+
* Change the view more details displayed limit on leaves
|
|
1161
|
+
* @param entries nav selector entries
|
|
1162
|
+
* @param limit the number of details we want to display by default
|
|
1163
|
+
*/
|
|
1164
|
+
static changeViewMoreDetailsDisplayedLimit(entries, limit) {
|
|
1165
|
+
return entries.map(entry => {
|
|
1166
|
+
if (isInternalNavSelectorEntryANode(entry)) {
|
|
1167
|
+
return {
|
|
1168
|
+
...entry,
|
|
1169
|
+
children: this.changeViewMoreDetailsDisplayedLimit(entry.children, limit),
|
|
1170
|
+
};
|
|
1171
|
+
}
|
|
1172
|
+
if (isInternalNavSelectorEntryALeaf(entry)) {
|
|
1173
|
+
const viewMoreDisplayable = entry.details.length > limit;
|
|
1174
|
+
return {
|
|
1175
|
+
...entry,
|
|
1176
|
+
viewMoreDisplayed: viewMoreDisplayable,
|
|
1177
|
+
viewMoreDisplayable,
|
|
1178
|
+
viewMoreDetailsDisplayedLimit: limit,
|
|
1179
|
+
details: entry.details.map((detail, idx) => ({
|
|
1180
|
+
...detail,
|
|
1181
|
+
focusable: entry.focusable && !entry.folded && idx < limit,
|
|
1182
|
+
})),
|
|
1183
|
+
};
|
|
1184
|
+
}
|
|
1185
|
+
return entry;
|
|
1186
|
+
});
|
|
1187
|
+
}
|
|
1188
|
+
/**
|
|
1189
|
+
* We want to display all details of the leaf
|
|
1190
|
+
*
|
|
1191
|
+
* set viewMoreDisplayed to false and set all details as focusable
|
|
1192
|
+
*
|
|
1193
|
+
* @param entries nav selector entries
|
|
1194
|
+
* @param leafUid the uid of the leaf we want to view all details
|
|
1195
|
+
*/
|
|
1196
|
+
static viewMore(entries, leafUid) {
|
|
1197
|
+
return entries.map(entry => {
|
|
1198
|
+
if (isInternalNavSelectorEntryANode(entry)) {
|
|
1199
|
+
return {
|
|
1200
|
+
...entry,
|
|
1201
|
+
children: this.viewMore(entry.children, leafUid),
|
|
1202
|
+
};
|
|
1203
|
+
}
|
|
1204
|
+
if (isInternalNavSelectorEntryALeaf(entry)) {
|
|
1205
|
+
if (entry.uid === leafUid) {
|
|
1206
|
+
return {
|
|
1207
|
+
...entry,
|
|
1208
|
+
viewMoreDisplayed: false,
|
|
1209
|
+
details: entry.details.map(detail => ({
|
|
1210
|
+
...detail,
|
|
1211
|
+
focusable: true,
|
|
1212
|
+
})),
|
|
1213
|
+
};
|
|
1214
|
+
}
|
|
1215
|
+
}
|
|
1216
|
+
return entry;
|
|
1217
|
+
});
|
|
1218
|
+
}
|
|
1219
|
+
/**
|
|
1220
|
+
* We want to display only the number of details of the leaf corresponding to the viewMoreDetailsDisplayedLimit
|
|
1221
|
+
*
|
|
1222
|
+
* set viewMoreDisplayed to true and set only the details with an index lower than the limit as focusable
|
|
1223
|
+
*
|
|
1224
|
+
* @param entries nav selector entries
|
|
1225
|
+
* @param uid the uid of the leaf we want to view all details
|
|
1226
|
+
*/
|
|
1227
|
+
static viewLess(entries, uid) {
|
|
1228
|
+
return entries.map(entry => {
|
|
1229
|
+
if (isInternalNavSelectorEntryANode(entry)) {
|
|
1230
|
+
return {
|
|
1231
|
+
...entry,
|
|
1232
|
+
children: this.viewLess(entry.children, uid),
|
|
1233
|
+
};
|
|
1234
|
+
}
|
|
1235
|
+
if (isInternalNavSelectorEntryALeaf(entry)) {
|
|
1236
|
+
if (entry.uid === uid) {
|
|
1237
|
+
return {
|
|
1238
|
+
...entry,
|
|
1239
|
+
viewMoreDisplayed: true,
|
|
1240
|
+
details: entry.details.map((detail, idx) => ({
|
|
1241
|
+
...detail,
|
|
1242
|
+
focusable: idx < entry.viewMoreDetailsDisplayedLimit,
|
|
1243
|
+
})),
|
|
1244
|
+
};
|
|
1245
|
+
}
|
|
1246
|
+
}
|
|
1247
|
+
return entry;
|
|
1248
|
+
});
|
|
1249
|
+
}
|
|
1250
|
+
}
|
|
1251
|
+
|
|
1252
|
+
/**
|
|
1253
|
+
* NavSelectorState is a service that manages the state of the nav selector.
|
|
1254
|
+
*
|
|
1255
|
+
* It should be provided by the component to ensure that if many nav selectors are used in the same page, they don't share the same state.
|
|
1256
|
+
*/
|
|
1257
|
+
class NavSelectorState {
|
|
1258
|
+
entries = signal([]);
|
|
1259
|
+
multipleModeEnabled = signal(false);
|
|
1260
|
+
_texts = signal({
|
|
1261
|
+
title: '',
|
|
1262
|
+
only: '',
|
|
1263
|
+
tokenInvalid: '',
|
|
1264
|
+
featureLocked: '',
|
|
1265
|
+
searchPlaceholder: '',
|
|
1266
|
+
noResults: '',
|
|
1267
|
+
viewMore: '',
|
|
1268
|
+
viewLess: '',
|
|
1269
|
+
});
|
|
1270
|
+
lastSelectedUids = signal([]);
|
|
1271
|
+
isMultipleModeEnabled = this.multipleModeEnabled;
|
|
1272
|
+
search = signal('');
|
|
1273
|
+
filteredEntries = computed(() => NavSelectorFilter.filter(this.entries(), this.search()));
|
|
1274
|
+
noResults = computed(() => this.filteredEntries().every(({ hidden }) => hidden));
|
|
1275
|
+
texts = this._texts.asReadonly();
|
|
1276
|
+
leafActionProjection = signal(undefined);
|
|
1277
|
+
expanded = signal(true);
|
|
1278
|
+
expandedAfterDelay = signal(true);
|
|
1279
|
+
selectedUidsChangeCallback = null;
|
|
1280
|
+
constructor() {
|
|
1281
|
+
effect(() => {
|
|
1282
|
+
const newSelectedUids = this.collectSelectedUids(this.entries());
|
|
1283
|
+
if (this.selectedUidsChangeCallback) {
|
|
1284
|
+
this.selectedUidsChangeCallback(newSelectedUids);
|
|
1285
|
+
}
|
|
1286
|
+
}, { allowSignalWrites: true });
|
|
1287
|
+
}
|
|
1288
|
+
updateMultiModeEnabled(enabled) {
|
|
1289
|
+
this.multipleModeEnabled.set(enabled);
|
|
1290
|
+
}
|
|
1291
|
+
updateEntries(entries, initialSelectedEntryUids, detailsDisplayedLimit) {
|
|
1292
|
+
if (this.multipleModeEnabled()) {
|
|
1293
|
+
this.entries.set(NavSelectorBuilder.buildInMultipleMode(entries, initialSelectedEntryUids, detailsDisplayedLimit));
|
|
1294
|
+
}
|
|
1295
|
+
else {
|
|
1296
|
+
this.entries.set(NavSelectorBuilder.build(entries, initialSelectedEntryUids?.[0] ?? null, detailsDisplayedLimit));
|
|
1297
|
+
}
|
|
1298
|
+
}
|
|
1299
|
+
onGroupToggleFolding(group) {
|
|
1300
|
+
this.entries.update(entries => NavSelectorFolding.toggleFolding(entries, group.uid, !this.expanded()));
|
|
1301
|
+
}
|
|
1302
|
+
onNodeSelect(node) {
|
|
1303
|
+
this.entries.update(entries => NavSelectorMultiSelect.selectInMultipleMode(entries, node.uid));
|
|
1304
|
+
}
|
|
1305
|
+
onLeafClicked(leaf) {
|
|
1306
|
+
if (!leaf.selectable) {
|
|
1307
|
+
return;
|
|
1308
|
+
}
|
|
1309
|
+
if (this.multipleModeEnabled()) {
|
|
1310
|
+
this.entries.update(entries => NavSelectorMultiSelect.selectInMultipleMode(entries, leaf.uid));
|
|
1311
|
+
}
|
|
1312
|
+
else {
|
|
1313
|
+
this.entries.update(entries => NavSelectorSingleSelect.select(entries, leaf.uid));
|
|
1314
|
+
}
|
|
1315
|
+
}
|
|
1316
|
+
onLeafToggleFolding(leaf) {
|
|
1317
|
+
this.entries.update(entries => NavSelectorFolding.toggleFolding(entries, leaf.uid, !this.expanded()));
|
|
1318
|
+
}
|
|
1319
|
+
onLeafDetailClicked(leafDetail) {
|
|
1320
|
+
this.entries.update(entries => NavSelectorSingleSelect.select(entries, leafDetail.uid));
|
|
1321
|
+
}
|
|
1322
|
+
updateTexts(texts) {
|
|
1323
|
+
this._texts.set(texts);
|
|
1324
|
+
}
|
|
1325
|
+
selectOnlyLeaf(leaf) {
|
|
1326
|
+
this.entries.update(entries => NavSelectorMultiSelect.selectOnlyALeafInMultipleMode(entries, leaf.uid));
|
|
1327
|
+
}
|
|
1328
|
+
toggleExpanded() {
|
|
1329
|
+
this.expanded.update(expanded => !expanded);
|
|
1330
|
+
this.entries.update(entries => {
|
|
1331
|
+
if (this.expanded()) {
|
|
1332
|
+
return NavSelectorMinifying.expand(entries);
|
|
1333
|
+
}
|
|
1334
|
+
return NavSelectorMinifying.minify(entries);
|
|
1335
|
+
});
|
|
1336
|
+
if (!this.expanded()) {
|
|
1337
|
+
setTimeout(() => this.expandedAfterDelay.set(this.expanded()), 150);
|
|
1338
|
+
}
|
|
1339
|
+
else {
|
|
1340
|
+
this.expandedAfterDelay.set(this.expanded());
|
|
1341
|
+
}
|
|
1342
|
+
}
|
|
1343
|
+
onSelectionChange(uids) {
|
|
1344
|
+
// Avoid infinite loop if you put unexisting uids as select will generate the same entries but with different reference
|
|
1345
|
+
if (JSON.stringify(uids) === JSON.stringify(this.lastSelectedUids())) {
|
|
1346
|
+
return;
|
|
1347
|
+
}
|
|
1348
|
+
this.lastSelectedUids.set(uids);
|
|
1349
|
+
const selectedUids = this.collectSelectedUids(this.entries());
|
|
1350
|
+
const uidToSelect = uids.filter(uid => selectedUids.every(selectedUid => selectedUid !== uid));
|
|
1351
|
+
const uidToUnselect = selectedUids.filter(uid => uids.every(selectedUid => selectedUid !== uid));
|
|
1352
|
+
if (!uidToSelect.length && !uidToUnselect.length) {
|
|
1353
|
+
return;
|
|
1354
|
+
}
|
|
1355
|
+
let entries = this.entries();
|
|
1356
|
+
if (this.multipleModeEnabled()) {
|
|
1357
|
+
for (const uid of [...uidToSelect, ...uidToUnselect]) {
|
|
1358
|
+
entries = NavSelectorMultiSelect.selectInMultipleMode(entries, uid);
|
|
1359
|
+
}
|
|
1360
|
+
}
|
|
1361
|
+
else {
|
|
1362
|
+
entries = NavSelectorSingleSelect.select(entries, uids[0]);
|
|
1363
|
+
}
|
|
1364
|
+
this.entries.set(entries);
|
|
1365
|
+
}
|
|
1366
|
+
registerOnSelectedUidsChange(callback) {
|
|
1367
|
+
this.selectedUidsChangeCallback = callback;
|
|
1368
|
+
}
|
|
1369
|
+
onArrowDown() {
|
|
1370
|
+
this.entries.update(entries => NavSelectorAccessibility.focusNext(entries));
|
|
1371
|
+
}
|
|
1372
|
+
onArrowUp() {
|
|
1373
|
+
this.entries.update(entries => NavSelectorAccessibility.focusPrevious(entries));
|
|
1374
|
+
}
|
|
1375
|
+
collectSelectedUids(entries) {
|
|
1376
|
+
return entries.flatMap(entry => {
|
|
1377
|
+
if (isInternalNavSelectorEntryALeaf(entry)) {
|
|
1378
|
+
if (entry.details.length) {
|
|
1379
|
+
return entry.details.flatMap(detail => (detail.selected ? [detail.uid] : []));
|
|
1380
|
+
}
|
|
1381
|
+
return entry.selected ? [entry.uid] : [];
|
|
1382
|
+
}
|
|
1383
|
+
else if (isInternalNavSelectorEntryANode(entry)) {
|
|
1384
|
+
return this.collectSelectedUids(entry.children);
|
|
1385
|
+
}
|
|
1386
|
+
return [];
|
|
1387
|
+
});
|
|
1388
|
+
}
|
|
1389
|
+
updateLeafAction(leafActionProjection) {
|
|
1390
|
+
this.leafActionProjection.set(leafActionProjection);
|
|
1391
|
+
}
|
|
1392
|
+
fold(entry) {
|
|
1393
|
+
this.entries.update(entries => NavSelectorFolding.fold(entries, entry.uid, !this.expanded()));
|
|
1394
|
+
}
|
|
1395
|
+
unfold(entry) {
|
|
1396
|
+
this.entries.update(entries => NavSelectorFolding.unfold(entries, entry.uid, !this.expanded()));
|
|
1397
|
+
}
|
|
1398
|
+
updateDetailsDisplayedLimit(detailsDisplayedLimit) {
|
|
1399
|
+
this.entries.update(entries => NavSelectorViewMore.changeViewMoreDetailsDisplayedLimit(entries, detailsDisplayedLimit));
|
|
1400
|
+
}
|
|
1401
|
+
viewMore(leaf) {
|
|
1402
|
+
this.entries.update(entries => NavSelectorViewMore.viewMore(entries, leaf.uid));
|
|
1403
|
+
}
|
|
1404
|
+
viewLess(leaf) {
|
|
1405
|
+
this.entries.update(entries => NavSelectorViewMore.viewLess(entries, leaf.uid));
|
|
1406
|
+
}
|
|
1407
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.9", ngImport: i0, type: NavSelectorState, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
1408
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.9", ngImport: i0, type: NavSelectorState });
|
|
1409
|
+
}
|
|
1410
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.9", ngImport: i0, type: NavSelectorState, decorators: [{
|
|
1411
|
+
type: Injectable
|
|
1412
|
+
}], ctorParameters: () => [] });
|
|
1413
|
+
|
|
1414
|
+
class NavSelectorLeafDetailPresenter {
|
|
1415
|
+
navSelectorState;
|
|
1416
|
+
constructor(navSelectorState) {
|
|
1417
|
+
this.navSelectorState = navSelectorState;
|
|
1418
|
+
}
|
|
1419
|
+
onLeafDetailClicked(detail) {
|
|
1420
|
+
this.navSelectorState.onLeafDetailClicked(detail);
|
|
1421
|
+
}
|
|
1422
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.9", ngImport: i0, type: NavSelectorLeafDetailPresenter, deps: [{ token: NavSelectorState }], target: i0.ɵɵFactoryTarget.Injectable });
|
|
1423
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.9", ngImport: i0, type: NavSelectorLeafDetailPresenter });
|
|
1424
|
+
}
|
|
1425
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.9", ngImport: i0, type: NavSelectorLeafDetailPresenter, decorators: [{
|
|
1426
|
+
type: Injectable
|
|
1427
|
+
}], ctorParameters: () => [{ type: NavSelectorState }] });
|
|
1428
|
+
|
|
1429
|
+
class NavSelectorLeafDetailComponent {
|
|
1430
|
+
navSelectorLeafDetailPresenter;
|
|
1431
|
+
detail = input.required();
|
|
1432
|
+
embedded = input(false);
|
|
1433
|
+
constructor(navSelectorLeafDetailPresenter) {
|
|
1434
|
+
this.navSelectorLeafDetailPresenter = navSelectorLeafDetailPresenter;
|
|
1435
|
+
}
|
|
1436
|
+
onClick($event) {
|
|
1437
|
+
$event.stopImmediatePropagation();
|
|
1438
|
+
this.navSelectorLeafDetailPresenter.onLeafDetailClicked(this.detail());
|
|
1439
|
+
}
|
|
1440
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.9", ngImport: i0, type: NavSelectorLeafDetailComponent, deps: [{ token: NavSelectorLeafDetailPresenter }], target: i0.ɵɵFactoryTarget.Component });
|
|
1441
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.9", type: NavSelectorLeafDetailComponent, isStandalone: true, selector: "ap-nav-selector-leaf-detail", inputs: { detail: { classPropertyName: "detail", publicName: "detail", isSignal: true, isRequired: true, transformFunction: null }, embedded: { classPropertyName: "embedded", publicName: "embedded", isSignal: true, isRequired: false, transformFunction: null } }, host: { listeners: { "click": "onClick($event)", "keydown.enter": "onClick($event)", "keydown.space": "onClick($event)" }, properties: { "class.selected": "detail().selected && !embedded()", "class.embedded": "embedded()" } }, providers: [withSymbols(apErrorFill), NavSelectorLeafDetailPresenter], hostDirectives: [{ directive: TreeNodeAccessibilityDirective, inputs: ["apTreeNodeAccessibility", "detail"] }], ngImport: i0, template: "<span class=\"caption\">\n {{ detail().alias }}\n</span>\n\n@if (detail().displayCounter) {\n <ap-counter\n color=\"orange\"\n size=\"normal\"\n [background]=\"false\">\n {{ detail().counter }}\n </ap-counter>\n}\n@if (detail().displayError) {\n <ap-symbol\n size=\"sm\"\n symbolId=\"error_fill\" />\n}\n", styles: [":host{display:flex;height:32px;padding:0 var(--ref-spacing-xxs);align-items:center;gap:var(--ref-spacing-xxs);align-self:stretch;flex-grow:1}:host.embedded{padding:0}:host ap-symbol[symbol-id=error_fill]{color:var(--ref-color-red-100)}:host:not(.disabled):not(.embedded){cursor:pointer}:host:not(.disabled):not(.embedded):hover{border-radius:var(--ref-border-radius-sm);background:var(--ref-color-electric-blue-10)}:host:not(.disabled):not(.embedded):active{border-radius:var(--ref-border-radius-sm);background:var(--ref-color-electric-blue-20)}:host:not(.disabled):not(.embedded):focus{outline:none;border-radius:var(--ref-border-radius-sm);background:var(--ref-color-electric-blue-10);box-shadow:0 0 0 1px var(--ref-color-white),0 0 0 3px var(--ref-color-electric-blue-100)}:host:not(.disabled):not(.embedded).selected{border-radius:var(--ref-border-radius-sm);background:var(--ref-color-electric-blue-20)}:host:not(.disabled):not(.embedded).selected:focus{box-shadow:0 0 0 1px var(--ref-color-white),0 0 0 3px var(--ref-color-electric-blue-100)}:host .caption{flex-grow:1;overflow:hidden;color:var(--ref-color-grey-100);text-overflow:ellipsis;white-space:nowrap;font-family:Averta;font-size:var(--ref-font-size-xs);font-style:normal;font-weight:var(--ref-font-weight-regular);line-height:var(--ref-font-line-height-xs)}\n"], dependencies: [{ kind: "component", type: CounterComponent, selector: "ap-counter", inputs: ["color", "size", "background", "notif"] }, { kind: "component", type: SymbolComponent, selector: "ap-symbol", inputs: ["symbolId", "color", "size"], outputs: ["sizeChange"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
1442
|
+
}
|
|
1443
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.9", ngImport: i0, type: NavSelectorLeafDetailComponent, decorators: [{
|
|
1444
|
+
type: Component,
|
|
1445
|
+
args: [{ selector: 'ap-nav-selector-leaf-detail', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, imports: [CounterComponent, SymbolComponent], providers: [withSymbols(apErrorFill), NavSelectorLeafDetailPresenter], host: {
|
|
1446
|
+
'(click)': 'onClick($event)',
|
|
1447
|
+
'[class.selected]': 'detail().selected && !embedded()',
|
|
1448
|
+
'[class.embedded]': 'embedded()',
|
|
1449
|
+
'(keydown.enter)': 'onClick($event)',
|
|
1450
|
+
'(keydown.space)': 'onClick($event)',
|
|
1451
|
+
}, hostDirectives: [
|
|
1452
|
+
{
|
|
1453
|
+
directive: TreeNodeAccessibilityDirective,
|
|
1454
|
+
// Alias the input of the directive to detail the input detail will be used in the directive and in the component as well
|
|
1455
|
+
inputs: ['apTreeNodeAccessibility: detail'],
|
|
1456
|
+
},
|
|
1457
|
+
], template: "<span class=\"caption\">\n {{ detail().alias }}\n</span>\n\n@if (detail().displayCounter) {\n <ap-counter\n color=\"orange\"\n size=\"normal\"\n [background]=\"false\">\n {{ detail().counter }}\n </ap-counter>\n}\n@if (detail().displayError) {\n <ap-symbol\n size=\"sm\"\n symbolId=\"error_fill\" />\n}\n", styles: [":host{display:flex;height:32px;padding:0 var(--ref-spacing-xxs);align-items:center;gap:var(--ref-spacing-xxs);align-self:stretch;flex-grow:1}:host.embedded{padding:0}:host ap-symbol[symbol-id=error_fill]{color:var(--ref-color-red-100)}:host:not(.disabled):not(.embedded){cursor:pointer}:host:not(.disabled):not(.embedded):hover{border-radius:var(--ref-border-radius-sm);background:var(--ref-color-electric-blue-10)}:host:not(.disabled):not(.embedded):active{border-radius:var(--ref-border-radius-sm);background:var(--ref-color-electric-blue-20)}:host:not(.disabled):not(.embedded):focus{outline:none;border-radius:var(--ref-border-radius-sm);background:var(--ref-color-electric-blue-10);box-shadow:0 0 0 1px var(--ref-color-white),0 0 0 3px var(--ref-color-electric-blue-100)}:host:not(.disabled):not(.embedded).selected{border-radius:var(--ref-border-radius-sm);background:var(--ref-color-electric-blue-20)}:host:not(.disabled):not(.embedded).selected:focus{box-shadow:0 0 0 1px var(--ref-color-white),0 0 0 3px var(--ref-color-electric-blue-100)}:host .caption{flex-grow:1;overflow:hidden;color:var(--ref-color-grey-100);text-overflow:ellipsis;white-space:nowrap;font-family:Averta;font-size:var(--ref-font-size-xs);font-style:normal;font-weight:var(--ref-font-weight-regular);line-height:var(--ref-font-line-height-xs)}\n"] }]
|
|
1458
|
+
}], ctorParameters: () => [{ type: NavSelectorLeafDetailPresenter }] });
|
|
1459
|
+
|
|
1460
|
+
class NavSelectorLeafDetailsPresenter {
|
|
1461
|
+
navSelectorState;
|
|
1462
|
+
viewMoreText = computed(() => this.navSelectorState.texts().viewMore);
|
|
1463
|
+
viewLessText = computed(() => this.navSelectorState.texts().viewLess);
|
|
1464
|
+
constructor(navSelectorState) {
|
|
1465
|
+
this.navSelectorState = navSelectorState;
|
|
1466
|
+
}
|
|
1467
|
+
toggleViewMore(leaf) {
|
|
1468
|
+
if (leaf.viewMoreDisplayed) {
|
|
1469
|
+
this.viewMore(leaf);
|
|
1470
|
+
}
|
|
1471
|
+
else {
|
|
1472
|
+
this.viewLess(leaf);
|
|
1473
|
+
}
|
|
1474
|
+
}
|
|
1475
|
+
viewMore(leaf) {
|
|
1476
|
+
this.navSelectorState.viewMore(leaf);
|
|
1477
|
+
}
|
|
1478
|
+
viewLess(leaf) {
|
|
1479
|
+
this.navSelectorState.viewLess(leaf);
|
|
1480
|
+
}
|
|
1481
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.9", ngImport: i0, type: NavSelectorLeafDetailsPresenter, deps: [{ token: NavSelectorState }], target: i0.ɵɵFactoryTarget.Injectable });
|
|
1482
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.9", ngImport: i0, type: NavSelectorLeafDetailsPresenter });
|
|
1483
|
+
}
|
|
1484
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.9", ngImport: i0, type: NavSelectorLeafDetailsPresenter, decorators: [{
|
|
1485
|
+
type: Injectable
|
|
1486
|
+
}], ctorParameters: () => [{ type: NavSelectorState }] });
|
|
1487
|
+
|
|
1488
|
+
class NavSelectorLeafDetailsComponent {
|
|
1489
|
+
el;
|
|
1490
|
+
navSelectorLeafDetailsPresenter;
|
|
1491
|
+
leaf = input.required();
|
|
1492
|
+
details = input.required();
|
|
1493
|
+
firstDetails = computed(() => this.details().slice(0, this.leaf().viewMoreDetailsDisplayedLimit));
|
|
1494
|
+
lastDetails = computed(() => this.details().slice(this.leaf().viewMoreDetailsDisplayedLimit));
|
|
1495
|
+
viewMoreDelay = signal(false);
|
|
1496
|
+
animationState = computed(() => (this.leaf().viewMoreDisplayable && this.leaf().viewMoreDisplayed ? 'collapsed' : 'expanded'));
|
|
1497
|
+
/**
|
|
1498
|
+
* The height when details are all displayed
|
|
1499
|
+
*/
|
|
1500
|
+
maxHeight = signal('0px');
|
|
1501
|
+
constructor(el, navSelectorLeafDetailsPresenter) {
|
|
1502
|
+
this.el = el;
|
|
1503
|
+
this.navSelectorLeafDetailsPresenter = navSelectorLeafDetailsPresenter;
|
|
1504
|
+
effect(() => {
|
|
1505
|
+
if (this.leaf().viewMoreDisplayed) {
|
|
1506
|
+
setTimeout(() => this.viewMoreDelay.set(false), 150);
|
|
1507
|
+
}
|
|
1508
|
+
else {
|
|
1509
|
+
this.viewMoreDelay.set(true);
|
|
1510
|
+
}
|
|
1511
|
+
}, { allowSignalWrites: true });
|
|
1512
|
+
}
|
|
1513
|
+
ngAfterViewInit() {
|
|
1514
|
+
// scrollHeight = leaf + first details displayed when there is a limit
|
|
1515
|
+
const height = this.el.nativeElement.scrollHeight;
|
|
1516
|
+
// cross multiplication to determine height of remaining details
|
|
1517
|
+
this.maxHeight.set(`${(height * this.lastDetails().length) / this.firstDetails().length}px`);
|
|
1518
|
+
}
|
|
1519
|
+
toggleViewMore() {
|
|
1520
|
+
this.navSelectorLeafDetailsPresenter.toggleViewMore(this.leaf());
|
|
1521
|
+
}
|
|
1522
|
+
onSpaceOrEnter(event) {
|
|
1523
|
+
event.stopImmediatePropagation();
|
|
1524
|
+
this.toggleViewMore();
|
|
1525
|
+
}
|
|
1526
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.9", ngImport: i0, type: NavSelectorLeafDetailsComponent, deps: [{ token: i0.ElementRef }, { token: NavSelectorLeafDetailsPresenter }], target: i0.ɵɵFactoryTarget.Component });
|
|
1527
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.9", type: NavSelectorLeafDetailsComponent, isStandalone: true, selector: "ap-nav-selector-leaf-details", inputs: { leaf: { classPropertyName: "leaf", publicName: "leaf", isSignal: true, isRequired: true, transformFunction: null }, details: { classPropertyName: "details", publicName: "details", isSignal: true, isRequired: true, transformFunction: null } }, host: { properties: { "attr.aria-expanded": "!leaf().viewMoreDisplayable || leaf().viewMoreDisplayed" } }, providers: [NavSelectorLeafDetailsPresenter], ngImport: i0, template: "@for (detail of firstDetails(); track detail.uid) {\n <div class=\"detail\">\n <div class=\"separator\">\n <div class=\"rectangle\"></div>\n </div>\n <ap-nav-selector-leaf-detail [detail]=\"detail\" />\n </div>\n}\n\n@if (leaf().viewMoreDisplayable) {\n <div\n class=\"details-container\"\n [@accordion]=\"{\n value: animationState(),\n params: {\n maxHeight: maxHeight()\n }\n }\">\n @if (viewMoreDelay()) {\n @for (detail of lastDetails(); track detail.uid) {\n <div class=\"detail\">\n <div class=\"separator\">\n <div class=\"rectangle\"></div>\n </div>\n <ap-nav-selector-leaf-detail [detail]=\"detail\" />\n </div>\n }\n }\n </div>\n\n <div class=\"detail\">\n <div class=\"separator\">\n <div class=\"rectangle\"></div>\n </div>\n <a\n tabindex=\"0\"\n role=\"button\"\n class=\"standalone view-more\"\n (keydown.space)=\"onSpaceOrEnter($event)\"\n (keydown.enter)=\"onSpaceOrEnter($event)\"\n (click)=\"toggleViewMore()\">\n @if (leaf().viewMoreDisplayed) {\n {{ navSelectorLeafDetailsPresenter.viewMoreText() }}\n } @else {\n {{ navSelectorLeafDetailsPresenter.viewLessText() }}\n }\n </a>\n </div>\n}\n", styles: [":host{display:flex;flex-direction:column;align-items:flex-start;flex:1 0 0}:host .detail{display:flex;align-self:stretch}:host .separator{display:flex;padding:0 11px 0 20px;align-items:center;align-self:stretch}:host .rectangle{width:1px;align-self:stretch;background:var(--ref-color-grey-10)}:host .view-more{display:flex;padding:8px;align-items:center;align-self:stretch}:host .details-container{display:flex;flex-direction:column;align-self:stretch}\n"], dependencies: [{ kind: "component", type: NavSelectorLeafDetailComponent, selector: "ap-nav-selector-leaf-detail", inputs: ["detail", "embedded"] }], animations: [
|
|
1528
|
+
/**
|
|
1529
|
+
* Overflow hidden is put only during the animation and on the collapsed state because if it is put on the expanded state then children’s border will be cut (hover / focus)
|
|
1530
|
+
*/
|
|
1531
|
+
trigger('accordion', [
|
|
1532
|
+
state('collapsed', style({
|
|
1533
|
+
maxHeight: '0',
|
|
1534
|
+
overflow: 'hidden',
|
|
1535
|
+
})),
|
|
1536
|
+
state('expanded', style({
|
|
1537
|
+
maxHeight: 'initial',
|
|
1538
|
+
})),
|
|
1539
|
+
transition('collapsed => expanded', [
|
|
1540
|
+
animate('250ms cubic-bezier(.4, 0, .3, 1)', style({ overflow: 'hidden', maxHeight: '{{maxHeight}}' })),
|
|
1541
|
+
]),
|
|
1542
|
+
transition('expanded => collapsed', [
|
|
1543
|
+
animate('250ms cubic-bezier(.4, 0, .3, 1)', keyframes([style({ overflow: 'hidden', maxHeight: '{{maxHeight}}' }), style({ maxHeight: 0 })])),
|
|
1544
|
+
]),
|
|
1545
|
+
]),
|
|
1546
|
+
], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
1547
|
+
}
|
|
1548
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.9", ngImport: i0, type: NavSelectorLeafDetailsComponent, decorators: [{
|
|
1549
|
+
type: Component,
|
|
1550
|
+
args: [{ selector: 'ap-nav-selector-leaf-details', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, imports: [NavSelectorLeafDetailComponent], providers: [NavSelectorLeafDetailsPresenter], host: {
|
|
1551
|
+
'[attr.aria-expanded]': '!leaf().viewMoreDisplayable || leaf().viewMoreDisplayed',
|
|
1552
|
+
}, animations: [
|
|
1553
|
+
/**
|
|
1554
|
+
* Overflow hidden is put only during the animation and on the collapsed state because if it is put on the expanded state then children’s border will be cut (hover / focus)
|
|
1555
|
+
*/
|
|
1556
|
+
trigger('accordion', [
|
|
1557
|
+
state('collapsed', style({
|
|
1558
|
+
maxHeight: '0',
|
|
1559
|
+
overflow: 'hidden',
|
|
1560
|
+
})),
|
|
1561
|
+
state('expanded', style({
|
|
1562
|
+
maxHeight: 'initial',
|
|
1563
|
+
})),
|
|
1564
|
+
transition('collapsed => expanded', [
|
|
1565
|
+
animate('250ms cubic-bezier(.4, 0, .3, 1)', style({ overflow: 'hidden', maxHeight: '{{maxHeight}}' })),
|
|
1566
|
+
]),
|
|
1567
|
+
transition('expanded => collapsed', [
|
|
1568
|
+
animate('250ms cubic-bezier(.4, 0, .3, 1)', keyframes([style({ overflow: 'hidden', maxHeight: '{{maxHeight}}' }), style({ maxHeight: 0 })])),
|
|
1569
|
+
]),
|
|
1570
|
+
]),
|
|
1571
|
+
], template: "@for (detail of firstDetails(); track detail.uid) {\n <div class=\"detail\">\n <div class=\"separator\">\n <div class=\"rectangle\"></div>\n </div>\n <ap-nav-selector-leaf-detail [detail]=\"detail\" />\n </div>\n}\n\n@if (leaf().viewMoreDisplayable) {\n <div\n class=\"details-container\"\n [@accordion]=\"{\n value: animationState(),\n params: {\n maxHeight: maxHeight()\n }\n }\">\n @if (viewMoreDelay()) {\n @for (detail of lastDetails(); track detail.uid) {\n <div class=\"detail\">\n <div class=\"separator\">\n <div class=\"rectangle\"></div>\n </div>\n <ap-nav-selector-leaf-detail [detail]=\"detail\" />\n </div>\n }\n }\n </div>\n\n <div class=\"detail\">\n <div class=\"separator\">\n <div class=\"rectangle\"></div>\n </div>\n <a\n tabindex=\"0\"\n role=\"button\"\n class=\"standalone view-more\"\n (keydown.space)=\"onSpaceOrEnter($event)\"\n (keydown.enter)=\"onSpaceOrEnter($event)\"\n (click)=\"toggleViewMore()\">\n @if (leaf().viewMoreDisplayed) {\n {{ navSelectorLeafDetailsPresenter.viewMoreText() }}\n } @else {\n {{ navSelectorLeafDetailsPresenter.viewLessText() }}\n }\n </a>\n </div>\n}\n", styles: [":host{display:flex;flex-direction:column;align-items:flex-start;flex:1 0 0}:host .detail{display:flex;align-self:stretch}:host .separator{display:flex;padding:0 11px 0 20px;align-items:center;align-self:stretch}:host .rectangle{width:1px;align-self:stretch;background:var(--ref-color-grey-10)}:host .view-more{display:flex;padding:8px;align-items:center;align-self:stretch}:host .details-container{display:flex;flex-direction:column;align-self:stretch}\n"] }]
|
|
1572
|
+
}], ctorParameters: () => [{ type: i0.ElementRef }, { type: NavSelectorLeafDetailsPresenter }] });
|
|
1573
|
+
|
|
1574
|
+
class NavSelectorLeafPresenter {
|
|
1575
|
+
navSelectorState;
|
|
1576
|
+
expanded = computed(() => this.navSelectorState.expanded());
|
|
1577
|
+
texts = computed(() => this.navSelectorState.texts());
|
|
1578
|
+
isMultipleModeEnabled = computed(() => this.navSelectorState.isMultipleModeEnabled());
|
|
1579
|
+
leafActionProjection = computed(() => this.navSelectorState.leafActionProjection());
|
|
1580
|
+
expandedAfterDelay = computed(() => this.navSelectorState.expandedAfterDelay());
|
|
1581
|
+
constructor(navSelectorState) {
|
|
1582
|
+
this.navSelectorState = navSelectorState;
|
|
1583
|
+
}
|
|
1584
|
+
onLeafClicked(leaf) {
|
|
1585
|
+
this.navSelectorState.onLeafClicked(leaf);
|
|
1586
|
+
}
|
|
1587
|
+
onLeafToggleFolding(leaf) {
|
|
1588
|
+
this.navSelectorState.onLeafToggleFolding(leaf);
|
|
1589
|
+
}
|
|
1590
|
+
selectOnlyLeaf(leaf) {
|
|
1591
|
+
this.navSelectorState.selectOnlyLeaf(leaf);
|
|
1592
|
+
}
|
|
1593
|
+
fold(leaf) {
|
|
1594
|
+
this.navSelectorState.fold(leaf);
|
|
1595
|
+
}
|
|
1596
|
+
unfold(leaf) {
|
|
1597
|
+
this.navSelectorState.unfold(leaf);
|
|
1598
|
+
}
|
|
1599
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.9", ngImport: i0, type: NavSelectorLeafPresenter, deps: [{ token: NavSelectorState }], target: i0.ɵɵFactoryTarget.Injectable });
|
|
1600
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.9", ngImport: i0, type: NavSelectorLeafPresenter });
|
|
1601
|
+
}
|
|
1602
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.9", ngImport: i0, type: NavSelectorLeafPresenter, decorators: [{
|
|
1603
|
+
type: Injectable
|
|
1604
|
+
}], ctorParameters: () => [{ type: NavSelectorState }] });
|
|
1605
|
+
|
|
1606
|
+
class NavSelectorLeafComponent {
|
|
1607
|
+
el;
|
|
1608
|
+
navSelectorLeafPresenter;
|
|
1609
|
+
leaf = input.required();
|
|
1610
|
+
initial = computed(() => this.leaf().alias[0].toUpperCase());
|
|
1611
|
+
foldSymbol = computed(() => (this.leaf().folded ? 'chevron-down' : 'chevron-up'));
|
|
1612
|
+
hovering = signal(false);
|
|
1613
|
+
hoveringMenu = signal(false);
|
|
1614
|
+
onlyButtonDisplayed = computed(() => this.navSelectorLeafPresenter.isMultipleModeEnabled() &&
|
|
1615
|
+
(this.hovering() || this.leaf().accessibility.tabIndex === 0) &&
|
|
1616
|
+
this.leaf().selectable);
|
|
1617
|
+
aliasEl = viewChild('alias');
|
|
1618
|
+
aliasBoundedClientRect = signal({
|
|
1619
|
+
offsetWidth: 0,
|
|
1620
|
+
offsetHeight: 0,
|
|
1621
|
+
scrollWidth: 0,
|
|
1622
|
+
scrollHeight: 0,
|
|
1623
|
+
});
|
|
1624
|
+
tooltipContent = computed(() => {
|
|
1625
|
+
const content = [];
|
|
1626
|
+
const el = this.aliasBoundedClientRect();
|
|
1627
|
+
if (!this.navSelectorLeafPresenter.expanded() || el.offsetWidth < el.scrollWidth || el.offsetHeight < el.scrollHeight) {
|
|
1628
|
+
content.push(this.leaf().alias);
|
|
1629
|
+
}
|
|
1630
|
+
const disableReason = this.leaf().disableReason;
|
|
1631
|
+
if (disableReason) {
|
|
1632
|
+
content.push(disableReason);
|
|
1633
|
+
}
|
|
1634
|
+
if (this.leaf().displayFeatureLocked) {
|
|
1635
|
+
content.push(this.navSelectorLeafPresenter.texts().featureLocked);
|
|
1636
|
+
}
|
|
1637
|
+
if (this.leaf().displayTokenInvalid) {
|
|
1638
|
+
content.push(this.navSelectorLeafPresenter.texts().tokenInvalid);
|
|
1639
|
+
}
|
|
1640
|
+
return content.join('<br>');
|
|
1641
|
+
});
|
|
1642
|
+
tooltipDisabled = computed(() => !this.tooltipContent().length || this.leaf().detailsDisplayable);
|
|
1643
|
+
minifiedEl = viewChild('minified');
|
|
1644
|
+
menuEl = viewChild('menuContainer');
|
|
1645
|
+
menuTriggerEl = viewChild('menuTrigger');
|
|
1646
|
+
actionMenuTriggerEl = viewChild('actionMenuTrigger');
|
|
1647
|
+
foldedWithDelay = signal(false);
|
|
1648
|
+
network = computed(() => (this.leaf().network ? this.leaf().network : undefined));
|
|
1649
|
+
constructor(el, navSelectorLeafPresenter) {
|
|
1650
|
+
this.el = el;
|
|
1651
|
+
this.navSelectorLeafPresenter = navSelectorLeafPresenter;
|
|
1652
|
+
afterNextRender(() => {
|
|
1653
|
+
this.maxHeight.set(`${this.el.nativeElement.scrollHeight}px`);
|
|
1654
|
+
const el = this.aliasEl()?.nativeElement;
|
|
1655
|
+
if (el) {
|
|
1656
|
+
this.aliasBoundedClientRect.set({
|
|
1657
|
+
offsetWidth: el.offsetWidth,
|
|
1658
|
+
offsetHeight: el.offsetHeight,
|
|
1659
|
+
scrollWidth: el.scrollWidth,
|
|
1660
|
+
scrollHeight: el.scrollHeight,
|
|
1661
|
+
});
|
|
1662
|
+
}
|
|
1663
|
+
});
|
|
1664
|
+
effect(() => {
|
|
1665
|
+
if (this.leaf().folded) {
|
|
1666
|
+
setTimeout(() => this.foldedWithDelay.set(true), 150);
|
|
1667
|
+
}
|
|
1668
|
+
else {
|
|
1669
|
+
this.foldedWithDelay.set(false);
|
|
1670
|
+
}
|
|
1671
|
+
}, { allowSignalWrites: true });
|
|
1672
|
+
}
|
|
1673
|
+
animationState = computed(() => (this.leaf().folded ? 'collapsed' : 'expanded'));
|
|
1674
|
+
maxHeight = signal('0px');
|
|
1675
|
+
onClick($event) {
|
|
1676
|
+
$event.stopImmediatePropagation();
|
|
1677
|
+
this.navSelectorLeafPresenter.onLeafClicked(this.leaf());
|
|
1678
|
+
}
|
|
1679
|
+
toggleFolding(event) {
|
|
1680
|
+
event.stopImmediatePropagation();
|
|
1681
|
+
this.navSelectorLeafPresenter.onLeafToggleFolding(this.leaf());
|
|
1682
|
+
}
|
|
1683
|
+
mouseEntered() {
|
|
1684
|
+
this.hovering.set(true);
|
|
1685
|
+
const menuTrigger = this.menuTriggerEl();
|
|
1686
|
+
if (menuTrigger && this.leaf().detailsDisplayable) {
|
|
1687
|
+
menuTrigger.openMenu();
|
|
1688
|
+
}
|
|
1689
|
+
}
|
|
1690
|
+
mouseLeft($event) {
|
|
1691
|
+
this.hovering.set(false);
|
|
1692
|
+
const menuTrigger = this.menuTriggerEl();
|
|
1693
|
+
if (menuTrigger) {
|
|
1694
|
+
setTimeout(() => {
|
|
1695
|
+
this.tryCloseMenu(menuTrigger, $event);
|
|
1696
|
+
}, 100);
|
|
1697
|
+
}
|
|
1698
|
+
}
|
|
1699
|
+
mouseEnteredMenu() {
|
|
1700
|
+
this.hoveringMenu.set(true);
|
|
1701
|
+
}
|
|
1702
|
+
mouseLeftMenu(menuTrigger, $event) {
|
|
1703
|
+
this.hoveringMenu.set(false);
|
|
1704
|
+
this.tryCloseMenu(menuTrigger, $event);
|
|
1705
|
+
}
|
|
1706
|
+
menuOpened() {
|
|
1707
|
+
if (!this.leaf().detailsDisplayable) {
|
|
1708
|
+
this.menuTriggerEl()?.closeMenu();
|
|
1709
|
+
}
|
|
1710
|
+
}
|
|
1711
|
+
onActionButtonClick($event) {
|
|
1712
|
+
$event.stopImmediatePropagation();
|
|
1713
|
+
}
|
|
1714
|
+
onActionButtonKeyDownSpaceOrEnter($event) {
|
|
1715
|
+
$event.stopImmediatePropagation();
|
|
1716
|
+
this.actionMenuTriggerEl()?.openMenu();
|
|
1717
|
+
}
|
|
1718
|
+
selectOnly(event) {
|
|
1719
|
+
event.stopImmediatePropagation();
|
|
1720
|
+
this.navSelectorLeafPresenter.selectOnlyLeaf(this.leaf());
|
|
1721
|
+
}
|
|
1722
|
+
onCheckboxToggle() {
|
|
1723
|
+
this.navSelectorLeafPresenter.onLeafClicked(this.leaf());
|
|
1724
|
+
}
|
|
1725
|
+
onSpaceOrEnterPressed($event) {
|
|
1726
|
+
$event.stopImmediatePropagation();
|
|
1727
|
+
if (document.activeElement === this.el.nativeElement.querySelector('.nav-selector-leaf')) {
|
|
1728
|
+
if (this.leaf().foldable) {
|
|
1729
|
+
this.toggleFolding($event);
|
|
1730
|
+
}
|
|
1731
|
+
else {
|
|
1732
|
+
this.navSelectorLeafPresenter.onLeafClicked(this.leaf());
|
|
1733
|
+
}
|
|
1734
|
+
}
|
|
1735
|
+
}
|
|
1736
|
+
fold(event) {
|
|
1737
|
+
event.stopImmediatePropagation();
|
|
1738
|
+
this.navSelectorLeafPresenter.fold(this.leaf());
|
|
1739
|
+
}
|
|
1740
|
+
unfold(event) {
|
|
1741
|
+
event.stopImmediatePropagation();
|
|
1742
|
+
this.navSelectorLeafPresenter.unfold(this.leaf());
|
|
1743
|
+
}
|
|
1744
|
+
tryCloseMenu(menuTrigger, $event) {
|
|
1745
|
+
if (!this.hoveringMenu()) {
|
|
1746
|
+
const minifiedEl = this.minifiedEl();
|
|
1747
|
+
const minifiedBoundedClientRect = minifiedEl.nativeElement.getBoundingClientRect();
|
|
1748
|
+
const mouseHoveringLeaf = this.mouseIsHovering($event, minifiedBoundedClientRect);
|
|
1749
|
+
const menuEl = this.menuEl();
|
|
1750
|
+
const menuBoundedClientRect = menuEl.nativeElement.getBoundingClientRect();
|
|
1751
|
+
const mouseHoveringMenu = this.mouseIsHovering($event, menuBoundedClientRect);
|
|
1752
|
+
if (!mouseHoveringLeaf && !mouseHoveringMenu) {
|
|
1753
|
+
menuTrigger.closeMenu();
|
|
1754
|
+
}
|
|
1755
|
+
}
|
|
1756
|
+
}
|
|
1757
|
+
mouseIsHovering($event, boundingClientRect) {
|
|
1758
|
+
return (boundingClientRect.left <= $event.clientX &&
|
|
1759
|
+
$event.clientX <= boundingClientRect.right &&
|
|
1760
|
+
boundingClientRect.top <= $event.clientY &&
|
|
1761
|
+
$event.clientY <= boundingClientRect.bottom);
|
|
1762
|
+
}
|
|
1763
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.9", ngImport: i0, type: NavSelectorLeafComponent, deps: [{ token: i0.ElementRef }, { token: NavSelectorLeafPresenter }], target: i0.ɵɵFactoryTarget.Component });
|
|
1764
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.9", type: NavSelectorLeafComponent, isStandalone: true, selector: "ap-nav-selector-leaf", inputs: { leaf: { classPropertyName: "leaf", publicName: "leaf", isSignal: true, isRequired: true, transformFunction: null } }, host: { attributes: { "role": "treeitem" }, listeners: { "mouseenter": "mouseEntered()", "mouseleave": "mouseLeft($event)", "keydown.arrowLeft": "fold($event)", "keydown.arrowRight": "unfold($event)" }, properties: { "class.minified": "!navSelectorLeafPresenter.expanded()" } }, providers: [withSymbols(apErrorFill, apFeatureLock, apChevronDown, apChevronUp, apMore), NavSelectorLeafPresenter], viewQueries: [{ propertyName: "aliasEl", first: true, predicate: ["alias"], descendants: true, isSignal: true }, { propertyName: "minifiedEl", first: true, predicate: ["minified"], descendants: true, isSignal: true }, { propertyName: "menuEl", first: true, predicate: ["menuContainer"], descendants: true, isSignal: true }, { propertyName: "menuTriggerEl", first: true, predicate: ["menuTrigger"], descendants: true, isSignal: true }, { propertyName: "actionMenuTriggerEl", first: true, predicate: ["actionMenuTrigger"], descendants: true, isSignal: true }], ngImport: i0, template: "@if (navSelectorLeafPresenter.expandedAfterDelay()) {\n <div\n class=\"nav-selector-leaf\"\n apTooltipPosition=\"right\"\n role=\"treeitem\"\n [apTooltip]=\"tooltipContent()\"\n [apTooltipDisabled]=\"tooltipDisabled()\"\n [class.feature-locked]=\"leaf().displayFeatureLocked\"\n [class.selected]=\"leaf().selected\"\n [class.token-error]=\"leaf().displayTokenInvalid\"\n [class.disabled]=\"leaf().disabled\"\n [apTreeNodeAccessibility]=\"leaf()\"\n (keydown.space)=\"onSpaceOrEnterPressed($event)\"\n (keydown.enter)=\"onSpaceOrEnterPressed($event)\"\n (click)=\"onClick($event)\">\n @if (navSelectorLeafPresenter.isMultipleModeEnabled()) {\n <ap-checkbox\n [name]=\"leaf().uid\"\n [checked]=\"leaf().selected\"\n [disabled]=\"!leaf().selectable\"\n (change)=\"onCheckboxToggle()\" />\n }\n <ap-avatar\n size=\"24\"\n [profilePicture]=\"leaf().pictureUrl ?? undefined\"\n [network]=\"$any(leaf().network)\"\n [showInitials]=\"initial()\" />\n\n <span\n #alias\n class=\"caption\">\n {{ leaf().alias }}\n </span>\n\n @if (onlyButtonDisplayed()) {\n <a\n class=\"standalone\"\n role=\"button\"\n [attr.aria-label]=\"'Select only ' + leaf().alias\"\n [attr.tabindex]=\"leaf().accessibility.tabIndex\"\n (keydown.space)=\"selectOnly($event)\"\n (keydown.enter)=\"selectOnly($event)\"\n (click)=\"selectOnly($event)\">\n {{ navSelectorLeafPresenter.texts().only }}\n </a>\n } @else {\n @if (leaf().displayCounter) {\n <ap-counter\n color=\"orange\"\n size=\"normal\"\n [background]=\"false\">\n {{ leaf().counter }}\n </ap-counter>\n }\n @if (leaf().displayTokenInvalid) {\n <ap-symbol\n size=\"sm\"\n symbolId=\"error_fill\" />\n }\n @if (leaf().displayFeatureLocked) {\n <ap-symbol\n size=\"sm\"\n symbolId=\"feature-lock\" />\n }\n\n @let actionProjection = navSelectorLeafPresenter.leafActionProjection();\n @if (actionProjection?.length) {\n <ap-symbol\n #actionMenuTrigger=\"matMenuTrigger\"\n class=\"actions-menu\"\n size=\"sm\"\n symbolId=\"more\"\n [tabindex]=\"leaf().accessibility.tabIndex\"\n [attr.aria-label]=\"'Action menu ' + leaf().alias\"\n [matMenuTriggerFor]=\"actionMenu\"\n (click)=\"onActionButtonClick($event)\"\n (keydown.space)=\"onActionButtonKeyDownSpaceOrEnter($event)\"\n (keydown.enter)=\"onActionButtonKeyDownSpaceOrEnter($event)\" />\n\n <mat-menu #actionMenu=\"matMenu\">\n @for (action of actionProjection; track action) {\n <button mat-menu-item>\n <ng-container\n [ngTemplateOutlet]=\"action\"\n [ngTemplateOutletContext]=\"{\n uid: leaf().uid\n }\" />\n </button>\n }\n </mat-menu>\n }\n\n @if (leaf().foldable) {\n <ap-symbol\n class=\"folding-button\"\n size=\"sm\"\n role=\"button\"\n [tabindex]=\"leaf().accessibility.tabIndex\"\n [attr.aria-label]=\"'Toggle ' + leaf().alias\"\n [symbolId]=\"foldSymbol()\"\n (click)=\"toggleFolding($event)\"\n (keydown.space)=\"toggleFolding($event)\"\n (keydown.enter)=\"toggleFolding($event)\" />\n }\n }\n </div>\n\n <div\n class=\"details-container\"\n [@accordion]=\"{\n value: animationState(),\n params: {\n maxHeight: maxHeight()\n }\n }\">\n @if (!foldedWithDelay()) {\n <ap-nav-selector-leaf-details [details]=\"leaf().details\" [leaf]=\"leaf()\"/>\n }\n </div>\n} @else {\n <div\n #menuTrigger=\"matMenuTrigger\"\n #minified\n class=\"nav-selector-leaf\"\n apTooltipPosition=\"right\"\n [matMenuTriggerFor]=\"menu\"\n [class.feature-locked]=\"leaf().displayFeatureLocked\"\n [class.selected]=\"leaf().selected\"\n [class.token-error]=\"leaf().displayTokenInvalid\"\n [class.disabled]=\"leaf().disabled\"\n [apTooltip]=\"tooltipContent()\"\n [apTooltipDisabled]=\"tooltipDisabled()\"\n [apTreeNodeAccessibility]=\"leaf()\"\n (menuOpened)=\"menuOpened()\"\n (keydown.space)=\"onSpaceOrEnterPressed($event)\"\n (keydown.enter)=\"onSpaceOrEnterPressed($event)\"\n (click)=\"onClick($event)\">\n @if (navSelectorLeafPresenter.isMultipleModeEnabled()) {\n <ap-checkbox\n [name]=\"leaf().uid\"\n [checked]=\"leaf().selected\"\n [disabled]=\"!leaf().selectable\" />\n }\n\n <div class=\"avatar-container\">\n <ap-avatar\n size=\"24\"\n [profilePicture]=\"leaf().pictureUrl ?? undefined\"\n [network]=\"$any(leaf().network)\"\n [showInitials]=\"initial()\" />\n\n <div class=\"status\">\n @if (leaf().displayCounter) {\n <ap-counter\n color=\"orange\"\n size=\"normal\"\n [notif]=\"true\"\n [background]=\"true\">\n {{ leaf().counter }}\n </ap-counter>\n }\n @if (leaf().displayTokenInvalid) {\n <ap-symbol\n size=\"sm\"\n symbolId=\"error_fill\" />\n }\n @if (leaf().displayFeatureLocked) {\n <ap-symbol\n size=\"sm\"\n symbolId=\"feature-lock\" />\n }\n </div>\n </div>\n <mat-menu\n #menu=\"matMenu\"\n class=\"nav-selector-leaf-menu\"\n xPosition=\"after\"\n [hasBackdrop]=\"false\">\n <div\n #menuContainer\n [class.not-displayable]=\"!leaf().detailsDisplayable\"\n (mouseenter)=\"mouseEnteredMenu()\"\n (mouseleave)=\"mouseLeftMenu(menuTrigger, $event)\">\n <button mat-menu-item>\n <span class=\"caption-bold\">{{ leaf().alias }}</span>\n </button>\n @for (detail of leaf().details; track detail.uid) {\n <button\n mat-menu-item\n [class.selected]=\"detail.selected\">\n <ap-nav-selector-leaf-detail\n [embedded]=\"true\"\n [detail]=\"detail\" />\n </button>\n }\n </div>\n </mat-menu>\n </div>\n}\n", styles: [":host{display:flex;gap:2px;flex-shrink:0;align-self:stretch;flex-direction:column}:host .details-container{align-self:stretch}:host .nav-selector-leaf{position:relative;display:flex;padding:0 var(--ref-spacing-xxs);height:36px;align-items:center;gap:var(--ref-spacing-xxs);flex-shrink:0;flex-grow:1;align-self:stretch}:host .caption{display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:1;flex:1 0 0;overflow:hidden;color:var(--ref-color-grey-100);text-overflow:ellipsis;font-family:Averta;font-size:var(--ref-font-size-xs);font-style:normal;font-weight:var(--ref-font-weight-regular);line-height:var(--ref-font-line-height-xs)}:host ap-symbol[symbol-id=error_fill]{color:var(--ref-color-red-100)}:host ap-symbol[symbol-id=feature-lock]{color:var(--ref-color-purple-100)}:host ap-symbol[symbol-id=chevron-down],:host ap-symbol[symbol-id=chevron-up]{color:var(--ref-color-grey-80)}:host .folding-button,:host .actions-menu{display:flex;width:24px;height:24px;justify-content:center;align-items:center;flex-shrink:0}:host .folding-button:hover,:host .actions-menu:hover{border-radius:var(--ref-border-radius-sm);background:var(--ref-color-electric-blue-20)}:host .folding-button:active,:host .actions-menu:active{border-radius:var(--ref-border-radius-sm);background:var(--ref-color-electric-blue-40)}:host .folding-button:focus,:host .actions-menu:focus{outline:none;border-radius:var(--ref-border-radius-sm);background:var(--ref-color-electric-blue-20);box-shadow:0 0 0 1px #fff,0 0 0 3px #178dfe}:host .nav-selector-leaf:not(.disabled){cursor:pointer}:host .nav-selector-leaf:not(.disabled):hover{border-radius:var(--ref-border-radius-sm);background:var(--ref-color-electric-blue-10)}:host .nav-selector-leaf:not(.disabled):active{border-radius:var(--ref-border-radius-sm);background:var(--ref-color-electric-blue-20)}:host .nav-selector-leaf:not(.disabled):focus{outline:none;border-radius:var(--ref-border-radius-sm);background:var(--ref-color-electric-blue-10);box-shadow:0 0 0 1px var(--ref-color-white),0 0 0 3px var(--ref-color-electric-blue-100)}:host .nav-selector-leaf:not(.disabled):focus-within{border-radius:var(--ref-border-radius-sm);background:var(--ref-color-electric-blue-20)}:host .nav-selector-leaf:not(.disabled).selected{border-radius:var(--ref-border-radius-sm);background:var(--ref-color-electric-blue-20)}:host .nav-selector-leaf:not(.disabled).selected:focus{box-shadow:0 0 0 1px var(--ref-color-white),0 0 0 3px var(--ref-color-electric-blue-100)}:host .nav-selector-leaf.feature-locked{border-radius:var(--ref-border-radius-sm)}:host .nav-selector-leaf.feature-locked:hover{background:var(--ref-color-purple-10)}:host .nav-selector-leaf.feature-locked:active{background:var(--ref-color-purple-20)}:host .nav-selector-leaf.feature-locked:focus{background:var(--ref-color-purple-10);box-shadow:0 0 0 1px var(--ref-color-white),0 0 0 3px var(--ref-color-purple-100)}:host .nav-selector-leaf.feature-locked.selected{background:var(--ref-color-purple-20)}:host .nav-selector-leaf.feature-locked.selected:focus{box-shadow:0 0 0 1px var(--ref-color-white),0 0 0 3px var(--ref-color-electric-blue-100)}:host .nav-selector-leaf.disabled{opacity:.5}:host .status{position:absolute;right:-4px;top:-6px}:host .avatar-container{position:relative}:host.minified .nav-selector-leaf{gap:var(--ref-spacing-xxxs);justify-content:center}:host.minified ::ng-deep ap-checkbox .checkbox .checkbox-container{padding:0}::ng-deep .nav-selector-leaf-menu{position:absolute;left:55px;top:-20%;width:225px}::ng-deep .nav-selector-leaf-menu .not-displayable{display:none}::ng-deep .nav-selector-leaf-menu .caption-bold{color:var(--ref-color-grey-100);font-family:Averta;font-size:var(--ref-font-size-xs);font-style:normal;font-weight:var(--ref-font-weight-bold);line-height:var(--ref-font-line-height-xs)}::ng-deep .nav-selector-leaf-menu.mat-mdc-menu-panel:not(.pop-menu) .mat-mdc-menu-item.selected{background:var(--ref-color-electric-blue-20)}::ng-deep .nav-selector-leaf-menu.mat-mdc-menu-panel:not(.pop-menu) .mat-mdc-menu-item ap-symbol{padding-right:0}\n"], dependencies: [{ kind: "component", type: AvatarComponent, selector: "ap-avatar", inputs: ["profilePicture", "alt", "network", "size", "username", "showInitials", "bigNetwork", "anonymous", "online", "youtubeAvatarMode", "rounded"] }, { kind: "component", type: CounterComponent, selector: "ap-counter", inputs: ["color", "size", "background", "notif"] }, { kind: "component", type: SymbolComponent, selector: "ap-symbol", inputs: ["symbolId", "color", "size"], outputs: ["sizeChange"] }, { kind: "component", type: NavSelectorLeafDetailsComponent, selector: "ap-nav-selector-leaf-details", inputs: ["leaf", "details"] }, { kind: "component", type: CheckboxComponent, selector: "ap-checkbox", inputs: ["aria-label", "aria-labelledby", "aria-describedby", "disabled", "indeterminate", "checked", "required", "name"], outputs: ["change"] }, { kind: "directive", type: TooltipDirective, selector: "[apTooltip]", inputs: ["apTooltip", "apTooltipPosition", "apTooltipShowDelay", "apTooltipHideDelay", "apTooltipDuration", "apTooltipDisabled", "apTooltipTruncatedTextOnly", "apTooltipTemplateContext", "apTooltipVirtualScrollElement"] }, { kind: "component", type: MatMenu, selector: "mat-menu", inputs: ["backdropClass", "aria-label", "aria-labelledby", "aria-describedby", "xPosition", "yPosition", "overlapTrigger", "hasBackdrop", "class", "classList"], outputs: ["closed", "close"], exportAs: ["matMenu"] }, { kind: "directive", type: MatMenuTrigger, selector: "[mat-menu-trigger-for], [matMenuTriggerFor]", inputs: ["mat-menu-trigger-for", "matMenuTriggerFor", "matMenuTriggerData", "matMenuTriggerRestoreFocus"], outputs: ["menuOpened", "onMenuOpen", "menuClosed", "onMenuClose"], exportAs: ["matMenuTrigger"] }, { kind: "component", type: MatMenuItem, selector: "[mat-menu-item]", inputs: ["role", "disabled", "disableRipple"], exportAs: ["matMenuItem"] }, { kind: "component", type: NavSelectorLeafDetailComponent, selector: "ap-nav-selector-leaf-detail", inputs: ["detail", "embedded"] }, { kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: TreeNodeAccessibilityDirective, selector: "[apTreeNodeAccessibility]", inputs: ["apTreeNodeAccessibility"] }], animations: [
|
|
1765
|
+
/**
|
|
1766
|
+
* Overflow hidden is put only during the animation and on the collapsed state because if it is put on the expanded state then children’s border will be cut (hover / focus)
|
|
1767
|
+
*/
|
|
1768
|
+
trigger('accordion', [
|
|
1769
|
+
state('collapsed', style({
|
|
1770
|
+
maxHeight: 0,
|
|
1771
|
+
overflow: 'hidden',
|
|
1772
|
+
})),
|
|
1773
|
+
state('expanded', style({
|
|
1774
|
+
maxHeight: 'initial',
|
|
1775
|
+
})),
|
|
1776
|
+
transition('collapsed => expanded', [
|
|
1777
|
+
animate('250ms cubic-bezier(.4, 0, .3, 1)', style({ overflow: 'hidden', maxHeight: '{{maxHeight}}' })),
|
|
1778
|
+
]),
|
|
1779
|
+
transition('expanded => collapsed', [
|
|
1780
|
+
animate('250ms cubic-bezier(.4, 0, .3, 1)', keyframes([style({ overflow: 'hidden', maxHeight: '{{maxHeight}}' }), style({ maxHeight: 0 })])),
|
|
1781
|
+
]),
|
|
1782
|
+
]),
|
|
1783
|
+
], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
1784
|
+
}
|
|
1785
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.9", ngImport: i0, type: NavSelectorLeafComponent, decorators: [{
|
|
1786
|
+
type: Component,
|
|
1787
|
+
args: [{ selector: 'ap-nav-selector-leaf', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, imports: [
|
|
1788
|
+
AvatarComponent,
|
|
1789
|
+
CounterComponent,
|
|
1790
|
+
SymbolComponent,
|
|
1791
|
+
NavSelectorLeafDetailsComponent,
|
|
1792
|
+
CheckboxComponent,
|
|
1793
|
+
TooltipDirective,
|
|
1794
|
+
MatMenu,
|
|
1795
|
+
MatMenuTrigger,
|
|
1796
|
+
MatMenuItem,
|
|
1797
|
+
NavSelectorLeafDetailComponent,
|
|
1798
|
+
NavSelectorLeafDetailComponent,
|
|
1799
|
+
NgTemplateOutlet,
|
|
1800
|
+
TreeNodeAccessibilityDirective,
|
|
1801
|
+
], providers: [withSymbols(apErrorFill, apFeatureLock, apChevronDown, apChevronUp, apMore), NavSelectorLeafPresenter], host: {
|
|
1802
|
+
'[class.minified]': '!navSelectorLeafPresenter.expanded()',
|
|
1803
|
+
role: 'treeitem',
|
|
1804
|
+
'(mouseenter)': 'mouseEntered()',
|
|
1805
|
+
'(mouseleave)': 'mouseLeft($event)',
|
|
1806
|
+
'(keydown.arrowLeft)': 'fold($event)',
|
|
1807
|
+
'(keydown.arrowRight)': 'unfold($event)',
|
|
1808
|
+
}, animations: [
|
|
1809
|
+
/**
|
|
1810
|
+
* Overflow hidden is put only during the animation and on the collapsed state because if it is put on the expanded state then children’s border will be cut (hover / focus)
|
|
1811
|
+
*/
|
|
1812
|
+
trigger('accordion', [
|
|
1813
|
+
state('collapsed', style({
|
|
1814
|
+
maxHeight: 0,
|
|
1815
|
+
overflow: 'hidden',
|
|
1816
|
+
})),
|
|
1817
|
+
state('expanded', style({
|
|
1818
|
+
maxHeight: 'initial',
|
|
1819
|
+
})),
|
|
1820
|
+
transition('collapsed => expanded', [
|
|
1821
|
+
animate('250ms cubic-bezier(.4, 0, .3, 1)', style({ overflow: 'hidden', maxHeight: '{{maxHeight}}' })),
|
|
1822
|
+
]),
|
|
1823
|
+
transition('expanded => collapsed', [
|
|
1824
|
+
animate('250ms cubic-bezier(.4, 0, .3, 1)', keyframes([style({ overflow: 'hidden', maxHeight: '{{maxHeight}}' }), style({ maxHeight: 0 })])),
|
|
1825
|
+
]),
|
|
1826
|
+
]),
|
|
1827
|
+
], template: "@if (navSelectorLeafPresenter.expandedAfterDelay()) {\n <div\n class=\"nav-selector-leaf\"\n apTooltipPosition=\"right\"\n role=\"treeitem\"\n [apTooltip]=\"tooltipContent()\"\n [apTooltipDisabled]=\"tooltipDisabled()\"\n [class.feature-locked]=\"leaf().displayFeatureLocked\"\n [class.selected]=\"leaf().selected\"\n [class.token-error]=\"leaf().displayTokenInvalid\"\n [class.disabled]=\"leaf().disabled\"\n [apTreeNodeAccessibility]=\"leaf()\"\n (keydown.space)=\"onSpaceOrEnterPressed($event)\"\n (keydown.enter)=\"onSpaceOrEnterPressed($event)\"\n (click)=\"onClick($event)\">\n @if (navSelectorLeafPresenter.isMultipleModeEnabled()) {\n <ap-checkbox\n [name]=\"leaf().uid\"\n [checked]=\"leaf().selected\"\n [disabled]=\"!leaf().selectable\"\n (change)=\"onCheckboxToggle()\" />\n }\n <ap-avatar\n size=\"24\"\n [profilePicture]=\"leaf().pictureUrl ?? undefined\"\n [network]=\"$any(leaf().network)\"\n [showInitials]=\"initial()\" />\n\n <span\n #alias\n class=\"caption\">\n {{ leaf().alias }}\n </span>\n\n @if (onlyButtonDisplayed()) {\n <a\n class=\"standalone\"\n role=\"button\"\n [attr.aria-label]=\"'Select only ' + leaf().alias\"\n [attr.tabindex]=\"leaf().accessibility.tabIndex\"\n (keydown.space)=\"selectOnly($event)\"\n (keydown.enter)=\"selectOnly($event)\"\n (click)=\"selectOnly($event)\">\n {{ navSelectorLeafPresenter.texts().only }}\n </a>\n } @else {\n @if (leaf().displayCounter) {\n <ap-counter\n color=\"orange\"\n size=\"normal\"\n [background]=\"false\">\n {{ leaf().counter }}\n </ap-counter>\n }\n @if (leaf().displayTokenInvalid) {\n <ap-symbol\n size=\"sm\"\n symbolId=\"error_fill\" />\n }\n @if (leaf().displayFeatureLocked) {\n <ap-symbol\n size=\"sm\"\n symbolId=\"feature-lock\" />\n }\n\n @let actionProjection = navSelectorLeafPresenter.leafActionProjection();\n @if (actionProjection?.length) {\n <ap-symbol\n #actionMenuTrigger=\"matMenuTrigger\"\n class=\"actions-menu\"\n size=\"sm\"\n symbolId=\"more\"\n [tabindex]=\"leaf().accessibility.tabIndex\"\n [attr.aria-label]=\"'Action menu ' + leaf().alias\"\n [matMenuTriggerFor]=\"actionMenu\"\n (click)=\"onActionButtonClick($event)\"\n (keydown.space)=\"onActionButtonKeyDownSpaceOrEnter($event)\"\n (keydown.enter)=\"onActionButtonKeyDownSpaceOrEnter($event)\" />\n\n <mat-menu #actionMenu=\"matMenu\">\n @for (action of actionProjection; track action) {\n <button mat-menu-item>\n <ng-container\n [ngTemplateOutlet]=\"action\"\n [ngTemplateOutletContext]=\"{\n uid: leaf().uid\n }\" />\n </button>\n }\n </mat-menu>\n }\n\n @if (leaf().foldable) {\n <ap-symbol\n class=\"folding-button\"\n size=\"sm\"\n role=\"button\"\n [tabindex]=\"leaf().accessibility.tabIndex\"\n [attr.aria-label]=\"'Toggle ' + leaf().alias\"\n [symbolId]=\"foldSymbol()\"\n (click)=\"toggleFolding($event)\"\n (keydown.space)=\"toggleFolding($event)\"\n (keydown.enter)=\"toggleFolding($event)\" />\n }\n }\n </div>\n\n <div\n class=\"details-container\"\n [@accordion]=\"{\n value: animationState(),\n params: {\n maxHeight: maxHeight()\n }\n }\">\n @if (!foldedWithDelay()) {\n <ap-nav-selector-leaf-details [details]=\"leaf().details\" [leaf]=\"leaf()\"/>\n }\n </div>\n} @else {\n <div\n #menuTrigger=\"matMenuTrigger\"\n #minified\n class=\"nav-selector-leaf\"\n apTooltipPosition=\"right\"\n [matMenuTriggerFor]=\"menu\"\n [class.feature-locked]=\"leaf().displayFeatureLocked\"\n [class.selected]=\"leaf().selected\"\n [class.token-error]=\"leaf().displayTokenInvalid\"\n [class.disabled]=\"leaf().disabled\"\n [apTooltip]=\"tooltipContent()\"\n [apTooltipDisabled]=\"tooltipDisabled()\"\n [apTreeNodeAccessibility]=\"leaf()\"\n (menuOpened)=\"menuOpened()\"\n (keydown.space)=\"onSpaceOrEnterPressed($event)\"\n (keydown.enter)=\"onSpaceOrEnterPressed($event)\"\n (click)=\"onClick($event)\">\n @if (navSelectorLeafPresenter.isMultipleModeEnabled()) {\n <ap-checkbox\n [name]=\"leaf().uid\"\n [checked]=\"leaf().selected\"\n [disabled]=\"!leaf().selectable\" />\n }\n\n <div class=\"avatar-container\">\n <ap-avatar\n size=\"24\"\n [profilePicture]=\"leaf().pictureUrl ?? undefined\"\n [network]=\"$any(leaf().network)\"\n [showInitials]=\"initial()\" />\n\n <div class=\"status\">\n @if (leaf().displayCounter) {\n <ap-counter\n color=\"orange\"\n size=\"normal\"\n [notif]=\"true\"\n [background]=\"true\">\n {{ leaf().counter }}\n </ap-counter>\n }\n @if (leaf().displayTokenInvalid) {\n <ap-symbol\n size=\"sm\"\n symbolId=\"error_fill\" />\n }\n @if (leaf().displayFeatureLocked) {\n <ap-symbol\n size=\"sm\"\n symbolId=\"feature-lock\" />\n }\n </div>\n </div>\n <mat-menu\n #menu=\"matMenu\"\n class=\"nav-selector-leaf-menu\"\n xPosition=\"after\"\n [hasBackdrop]=\"false\">\n <div\n #menuContainer\n [class.not-displayable]=\"!leaf().detailsDisplayable\"\n (mouseenter)=\"mouseEnteredMenu()\"\n (mouseleave)=\"mouseLeftMenu(menuTrigger, $event)\">\n <button mat-menu-item>\n <span class=\"caption-bold\">{{ leaf().alias }}</span>\n </button>\n @for (detail of leaf().details; track detail.uid) {\n <button\n mat-menu-item\n [class.selected]=\"detail.selected\">\n <ap-nav-selector-leaf-detail\n [embedded]=\"true\"\n [detail]=\"detail\" />\n </button>\n }\n </div>\n </mat-menu>\n </div>\n}\n", styles: [":host{display:flex;gap:2px;flex-shrink:0;align-self:stretch;flex-direction:column}:host .details-container{align-self:stretch}:host .nav-selector-leaf{position:relative;display:flex;padding:0 var(--ref-spacing-xxs);height:36px;align-items:center;gap:var(--ref-spacing-xxs);flex-shrink:0;flex-grow:1;align-self:stretch}:host .caption{display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:1;flex:1 0 0;overflow:hidden;color:var(--ref-color-grey-100);text-overflow:ellipsis;font-family:Averta;font-size:var(--ref-font-size-xs);font-style:normal;font-weight:var(--ref-font-weight-regular);line-height:var(--ref-font-line-height-xs)}:host ap-symbol[symbol-id=error_fill]{color:var(--ref-color-red-100)}:host ap-symbol[symbol-id=feature-lock]{color:var(--ref-color-purple-100)}:host ap-symbol[symbol-id=chevron-down],:host ap-symbol[symbol-id=chevron-up]{color:var(--ref-color-grey-80)}:host .folding-button,:host .actions-menu{display:flex;width:24px;height:24px;justify-content:center;align-items:center;flex-shrink:0}:host .folding-button:hover,:host .actions-menu:hover{border-radius:var(--ref-border-radius-sm);background:var(--ref-color-electric-blue-20)}:host .folding-button:active,:host .actions-menu:active{border-radius:var(--ref-border-radius-sm);background:var(--ref-color-electric-blue-40)}:host .folding-button:focus,:host .actions-menu:focus{outline:none;border-radius:var(--ref-border-radius-sm);background:var(--ref-color-electric-blue-20);box-shadow:0 0 0 1px #fff,0 0 0 3px #178dfe}:host .nav-selector-leaf:not(.disabled){cursor:pointer}:host .nav-selector-leaf:not(.disabled):hover{border-radius:var(--ref-border-radius-sm);background:var(--ref-color-electric-blue-10)}:host .nav-selector-leaf:not(.disabled):active{border-radius:var(--ref-border-radius-sm);background:var(--ref-color-electric-blue-20)}:host .nav-selector-leaf:not(.disabled):focus{outline:none;border-radius:var(--ref-border-radius-sm);background:var(--ref-color-electric-blue-10);box-shadow:0 0 0 1px var(--ref-color-white),0 0 0 3px var(--ref-color-electric-blue-100)}:host .nav-selector-leaf:not(.disabled):focus-within{border-radius:var(--ref-border-radius-sm);background:var(--ref-color-electric-blue-20)}:host .nav-selector-leaf:not(.disabled).selected{border-radius:var(--ref-border-radius-sm);background:var(--ref-color-electric-blue-20)}:host .nav-selector-leaf:not(.disabled).selected:focus{box-shadow:0 0 0 1px var(--ref-color-white),0 0 0 3px var(--ref-color-electric-blue-100)}:host .nav-selector-leaf.feature-locked{border-radius:var(--ref-border-radius-sm)}:host .nav-selector-leaf.feature-locked:hover{background:var(--ref-color-purple-10)}:host .nav-selector-leaf.feature-locked:active{background:var(--ref-color-purple-20)}:host .nav-selector-leaf.feature-locked:focus{background:var(--ref-color-purple-10);box-shadow:0 0 0 1px var(--ref-color-white),0 0 0 3px var(--ref-color-purple-100)}:host .nav-selector-leaf.feature-locked.selected{background:var(--ref-color-purple-20)}:host .nav-selector-leaf.feature-locked.selected:focus{box-shadow:0 0 0 1px var(--ref-color-white),0 0 0 3px var(--ref-color-electric-blue-100)}:host .nav-selector-leaf.disabled{opacity:.5}:host .status{position:absolute;right:-4px;top:-6px}:host .avatar-container{position:relative}:host.minified .nav-selector-leaf{gap:var(--ref-spacing-xxxs);justify-content:center}:host.minified ::ng-deep ap-checkbox .checkbox .checkbox-container{padding:0}::ng-deep .nav-selector-leaf-menu{position:absolute;left:55px;top:-20%;width:225px}::ng-deep .nav-selector-leaf-menu .not-displayable{display:none}::ng-deep .nav-selector-leaf-menu .caption-bold{color:var(--ref-color-grey-100);font-family:Averta;font-size:var(--ref-font-size-xs);font-style:normal;font-weight:var(--ref-font-weight-bold);line-height:var(--ref-font-line-height-xs)}::ng-deep .nav-selector-leaf-menu.mat-mdc-menu-panel:not(.pop-menu) .mat-mdc-menu-item.selected{background:var(--ref-color-electric-blue-20)}::ng-deep .nav-selector-leaf-menu.mat-mdc-menu-panel:not(.pop-menu) .mat-mdc-menu-item ap-symbol{padding-right:0}\n"] }]
|
|
1828
|
+
}], ctorParameters: () => [{ type: i0.ElementRef }, { type: NavSelectorLeafPresenter }] });
|
|
1829
|
+
|
|
1830
|
+
class NavSelectorGroupPresenter {
|
|
1831
|
+
navSelectorState;
|
|
1832
|
+
expanded = computed(() => this.navSelectorState.expanded());
|
|
1833
|
+
texts = computed(() => this.navSelectorState.texts());
|
|
1834
|
+
isMultipleModeEnabled = computed(() => this.navSelectorState.isMultipleModeEnabled());
|
|
1835
|
+
expandedAfterDelay = computed(() => this.navSelectorState.expandedAfterDelay());
|
|
1836
|
+
constructor(navSelectorState) {
|
|
1837
|
+
this.navSelectorState = navSelectorState;
|
|
1838
|
+
}
|
|
1839
|
+
onGroupSelected(group) {
|
|
1840
|
+
this.navSelectorState.onNodeSelect(group);
|
|
1841
|
+
}
|
|
1842
|
+
onGroupToggleFolding(group) {
|
|
1843
|
+
this.navSelectorState.onGroupToggleFolding(group);
|
|
1844
|
+
}
|
|
1845
|
+
fold(group) {
|
|
1846
|
+
this.navSelectorState.fold(group);
|
|
1847
|
+
}
|
|
1848
|
+
unfold(group) {
|
|
1849
|
+
this.navSelectorState.unfold(group);
|
|
1850
|
+
}
|
|
1851
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.9", ngImport: i0, type: NavSelectorGroupPresenter, deps: [{ token: NavSelectorState }], target: i0.ɵɵFactoryTarget.Injectable });
|
|
1852
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.9", ngImport: i0, type: NavSelectorGroupPresenter });
|
|
1853
|
+
}
|
|
1854
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.9", ngImport: i0, type: NavSelectorGroupPresenter, decorators: [{
|
|
1855
|
+
type: Injectable
|
|
1856
|
+
}], ctorParameters: () => [{ type: NavSelectorState }] });
|
|
1857
|
+
|
|
1858
|
+
class NavSelectorGroupComponent {
|
|
1859
|
+
el;
|
|
1860
|
+
navSelectorGroupPresenter;
|
|
1861
|
+
group = input.required();
|
|
1862
|
+
foldSymbol = computed(() => (this.group().folded ? 'chevron-down' : 'chevron-up'));
|
|
1863
|
+
aliasEl = viewChild('alias');
|
|
1864
|
+
aliasBoundedClientRect = signal({
|
|
1865
|
+
offsetWidth: 0,
|
|
1866
|
+
offsetHeight: 0,
|
|
1867
|
+
scrollWidth: 0,
|
|
1868
|
+
scrollHeight: 0,
|
|
1869
|
+
});
|
|
1870
|
+
tooltipContent = computed(() => {
|
|
1871
|
+
const content = [];
|
|
1872
|
+
const el = this.aliasBoundedClientRect();
|
|
1873
|
+
if (!this.navSelectorGroupPresenter.expanded() || el.offsetWidth < el.scrollWidth || el.offsetHeight < el.scrollHeight) {
|
|
1874
|
+
content.push(this.group().alias);
|
|
1875
|
+
}
|
|
1876
|
+
if (this.group().displayTokenInvalid) {
|
|
1877
|
+
content.push(this.navSelectorGroupPresenter.texts().tokenInvalid);
|
|
1878
|
+
}
|
|
1879
|
+
return content.join('<br>');
|
|
1880
|
+
});
|
|
1881
|
+
tooltipDisabled = computed(() => !this.tooltipContent().length);
|
|
1882
|
+
foldedWithDelay = signal(false);
|
|
1883
|
+
animationState = computed(() => (this.group().folded ? 'collapsed' : 'expanded'));
|
|
1884
|
+
constructor(el, navSelectorGroupPresenter) {
|
|
1885
|
+
this.el = el;
|
|
1886
|
+
this.navSelectorGroupPresenter = navSelectorGroupPresenter;
|
|
1887
|
+
afterNextRender(() => {
|
|
1888
|
+
this.maxHeight.set(`${this.el.nativeElement.scrollHeight}px`);
|
|
1889
|
+
const el = this.aliasEl()?.nativeElement;
|
|
1890
|
+
if (el) {
|
|
1891
|
+
this.aliasBoundedClientRect.set({
|
|
1892
|
+
offsetWidth: el.offsetWidth,
|
|
1893
|
+
offsetHeight: el.offsetHeight,
|
|
1894
|
+
scrollWidth: el.scrollWidth,
|
|
1895
|
+
scrollHeight: el.scrollHeight,
|
|
1896
|
+
});
|
|
1897
|
+
}
|
|
1898
|
+
});
|
|
1899
|
+
effect(() => {
|
|
1900
|
+
if (this.group().folded) {
|
|
1901
|
+
setTimeout(() => this.foldedWithDelay.set(true), 150);
|
|
1902
|
+
}
|
|
1903
|
+
else {
|
|
1904
|
+
this.foldedWithDelay.set(false);
|
|
1905
|
+
}
|
|
1906
|
+
}, { allowSignalWrites: true });
|
|
1907
|
+
}
|
|
1908
|
+
maxHeight = signal('0px');
|
|
1909
|
+
onKeydownSpaceOrEnter($event) {
|
|
1910
|
+
// Prevent to toggle folding when focus is on the checkbox
|
|
1911
|
+
if (document.activeElement === this.el.nativeElement.querySelector('.content')) {
|
|
1912
|
+
this.toggleFolding($event);
|
|
1913
|
+
}
|
|
1914
|
+
else {
|
|
1915
|
+
this.navSelectorGroupPresenter.onGroupSelected(this.group());
|
|
1916
|
+
}
|
|
1917
|
+
}
|
|
1918
|
+
toggleFolding(event) {
|
|
1919
|
+
event.stopImmediatePropagation();
|
|
1920
|
+
this.navSelectorGroupPresenter.onGroupToggleFolding(this.group());
|
|
1921
|
+
}
|
|
1922
|
+
fold(event) {
|
|
1923
|
+
event.stopImmediatePropagation();
|
|
1924
|
+
this.navSelectorGroupPresenter.fold(this.group());
|
|
1925
|
+
}
|
|
1926
|
+
unfold(event) {
|
|
1927
|
+
event.stopImmediatePropagation();
|
|
1928
|
+
this.navSelectorGroupPresenter.unfold(this.group());
|
|
1929
|
+
}
|
|
1930
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.9", ngImport: i0, type: NavSelectorGroupComponent, deps: [{ token: i0.ElementRef }, { token: NavSelectorGroupPresenter }], target: i0.ɵɵFactoryTarget.Component });
|
|
1931
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.9", type: NavSelectorGroupComponent, isStandalone: true, selector: "ap-nav-selector-group", inputs: { group: { classPropertyName: "group", publicName: "group", isSignal: true, isRequired: true, transformFunction: null } }, host: { listeners: { "keydown.arrowLeft": "fold($event)", "keydown.arrowRight": "unfold($event)" }, properties: { "class.minified": "!navSelectorGroupPresenter.expanded()" } }, providers: [withSymbols(apFolder, apErrorFill, apChevronDown, apChevronUp), NavSelectorGroupPresenter], viewQueries: [{ propertyName: "aliasEl", first: true, predicate: ["alias"], descendants: true, isSignal: true }], ngImport: i0, template: "@if (navSelectorGroupPresenter.expandedAfterDelay()) {\n <div\n class=\"content\"\n apTooltipPosition=\"right\"\n [apTooltip]=\"tooltipContent()\"\n [apTooltipDisabled]=\"tooltipDisabled()\"\n [apTreeNodeAccessibility]=\"group()\"\n (keydown.space)=\"onKeydownSpaceOrEnter($event)\"\n (keydown.enter)=\"onKeydownSpaceOrEnter($event)\">\n @if (navSelectorGroupPresenter.isMultipleModeEnabled()) {\n <ap-checkbox\n [name]=\"group().uid\"\n [checked]=\"group().selected\"\n [disabled]=\"!group().selectable\"\n [indeterminate]=\"group().undeterminedSelection\"\n (change)=\"navSelectorGroupPresenter.onGroupSelected(group())\" />\n }\n\n <ap-symbol\n symbolId=\"folder\"\n size=\"sm\" />\n\n <span\n #alias\n class=\"caption\">\n {{ group().alias }}\n </span>\n\n @if (group().displayTokenInvalid) {\n <ap-symbol\n symbolId=\"error_fill\"\n size=\"sm\" />\n }\n\n @if (group().displayCounter) {\n <ap-counter\n color=\"orange\"\n size=\"normal\"\n [background]=\"false\">\n {{ group().counter }}\n </ap-counter>\n }\n\n <ap-symbol\n size=\"sm\"\n class=\"folding-button\"\n [tabindex]=\"group().accessibility.tabIndex\"\n [attr.aria-label]=\"'Toggle ' + group().alias\"\n [symbolId]=\"foldSymbol()\"\n (keydown.space)=\"toggleFolding($event)\"\n (keydown.enter)=\"toggleFolding($event)\"\n (click)=\"toggleFolding($event)\" />\n </div>\n\n <div\n class=\"children-container\"\n [@accordion]=\"{\n value: animationState(),\n params: {\n maxHeight: maxHeight()\n }\n }\">\n @if (!foldedWithDelay()) {\n <div class=\"children\">\n @for (child of group().children; track child.uid) {\n @if (!child.hidden) {\n <ap-nav-selector-leaf [leaf]=\"child\" />\n }\n }\n </div>\n }\n </div>\n} @else {\n <div\n class=\"content\"\n apTooltipPosition=\"right\"\n [apTooltip]=\"tooltipContent()\"\n [apTooltipDisabled]=\"tooltipDisabled()\"\n [apTreeNodeAccessibility]=\"group()\"\n (click)=\"toggleFolding($event)\"\n (keydown.space)=\"onKeydownSpaceOrEnter($event)\"\n (keydown.enter)=\"onKeydownSpaceOrEnter($event)\">\n @if (navSelectorGroupPresenter.isMultipleModeEnabled()) {\n <ap-checkbox\n [name]=\"group().uid\"\n [checked]=\"group().selected\"\n [disabled]=\"!group().selectable\"\n [indeterminate]=\"group().undeterminedSelection\"\n (change)=\"navSelectorGroupPresenter.onGroupSelected(group())\" />\n }\n\n <div class=\"picture-url-sample-container\">\n <div class=\"picture-url-sample\">\n @for (pictureUrlSample of group().childrenPictureUrlSample; track pictureUrlSample) {\n <ap-avatar\n [size]=\"$any(12)\"\n [profilePicture]=\"pictureUrlSample.url ?? undefined\"\n [showInitials]=\"pictureUrlSample.initial\" />\n }\n\n <div class=\"status\">\n @if (group().displayCounter) {\n <ap-counter\n color=\"orange\"\n size=\"normal\"\n [notif]=\"true\"\n [background]=\"true\">\n {{ group().counter }}\n </ap-counter>\n }\n </div>\n </div>\n\n <div class=\"toggle\">\n <ap-symbol\n size=\"sm\"\n [symbolId]=\"foldSymbol()\" />\n </div>\n </div>\n </div>\n\n <div\n class=\"details-container\"\n [@accordion]=\"{\n value: animationState(),\n params: {\n maxHeight: maxHeight()\n }\n }\">\n @if (!foldedWithDelay()) {\n <div class=\"children\">\n @for (child of group().children; track child.uid) {\n @if (!child.hidden) {\n <ap-nav-selector-leaf [leaf]=\"child\" />\n }\n }\n </div>\n }\n </div>\n}\n", styles: [":host{display:flex;align-items:center;flex-shrink:0;align-self:stretch;flex-direction:column}:host .children-container{align-self:stretch}:host .content{padding:0 var(--ref-spacing-xxs);display:flex;height:36px;align-items:center;gap:var(--ref-spacing-xxs);flex-shrink:0;flex-grow:1;align-self:stretch;cursor:pointer}:host .content:hover{border-radius:var(--ref-border-radius-sm);background:var(--ref-color-electric-blue-10)}:host .content:active{border-radius:var(--ref-border-radius-sm);background:var(--ref-color-electric-blue-20)}:host .content:focus{outline:none;border-radius:var(--ref-border-radius-sm);background:var(--ref-color-electric-blue-10);box-shadow:0 0 0 1px var(--ref-color-white),0 0 0 3px var(--ref-color-electric-blue-100)}:host .content:focus-within{border-radius:var(--ref-border-radius-sm);background:var(--ref-color-electric-blue-20)}:host:not(.minified) ap-symbol[symbol-id=chevron-down],:host:not(.minified) ap-symbol[symbol-id=chevron-up]{color:var(--ref-color-grey-80)}:host:not(.minified) ap-symbol[symbol-id=chevron-down]:hover,:host:not(.minified) ap-symbol[symbol-id=chevron-up]:hover{border-radius:var(--ref-border-radius-sm);background:var(--ref-color-electric-blue-20)}:host:not(.minified) ap-symbol[symbol-id=chevron-down]:active,:host:not(.minified) ap-symbol[symbol-id=chevron-up]:active{border-radius:var(--ref-border-radius-sm);background:var(--ref-color-electric-blue-40)}:host:not(.minified) ap-symbol[symbol-id=chevron-down]:focus,:host:not(.minified) ap-symbol[symbol-id=chevron-up]:focus{outline:none;border-radius:var(--ref-border-radius-sm);background:var(--ref-color-electric-blue-20);box-shadow:0 0 0 1px #fff,0 0 0 3px #178dfe}:host ap-symbol[symbol-id=error_fill]{color:var(--ref-color-red-100)}:host ap-symbol[symbol-id=folder]{color:var(--ref-color-grey-100)}:host ap-symbol[symbol-id=chevron-down],:host ap-symbol[symbol-id=chevron-up]{color:var(--ref-color-grey-80)}:host .folding-button{display:flex;width:24px;height:24px;justify-content:center;align-items:center;flex-shrink:0}:host .folding-button:hover{border-radius:var(--ref-border-radius-sm);background:var(--ref-color-electric-blue-20)}:host .folding-button:active{border-radius:var(--ref-border-radius-sm);background:var(--ref-color-electric-blue-40)}:host .caption{display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:1;flex:1 0 0;overflow:hidden;color:var(--ref-color-grey-100);text-overflow:ellipsis;font-family:Averta;font-size:var(--ref-font-size-xs);font-style:normal;font-weight:var(--ref-font-weight-bold);line-height:var(--ref-font-line-height-xs)}:host .children{display:flex;flex-direction:column;align-items:flex-start;flex:1 0 0;align-self:stretch}:host .picture-url-sample-container{position:relative;width:26px}:host .picture-url-sample{display:flex;width:26px;align-items:center;align-content:center;gap:2px;flex-wrap:wrap}:host.minified .content{gap:var(--ref-spacing-xxxs);position:relative;justify-content:center}:host.minified .content .toggle{position:absolute;display:none}:host.minified .content:hover .toggle,:host.minified .content:focus .toggle{inset:0;display:flex;justify-content:center;align-items:center}:host.minified .content:hover .picture-url-sample,:host.minified .content:focus .picture-url-sample{display:none}:host.minified ::ng-deep ap-checkbox .checkbox .checkbox-container{padding:0}:host.minified .status{position:absolute;right:-4px;top:-6px}\n"], dependencies: [{ kind: "component", type: SymbolComponent, selector: "ap-symbol", inputs: ["symbolId", "color", "size"], outputs: ["sizeChange"] }, { kind: "component", type: CounterComponent, selector: "ap-counter", inputs: ["color", "size", "background", "notif"] }, { kind: "component", type: NavSelectorLeafComponent, selector: "ap-nav-selector-leaf", inputs: ["leaf"] }, { kind: "component", type: CheckboxComponent, selector: "ap-checkbox", inputs: ["aria-label", "aria-labelledby", "aria-describedby", "disabled", "indeterminate", "checked", "required", "name"], outputs: ["change"] }, { kind: "component", type: AvatarComponent, selector: "ap-avatar", inputs: ["profilePicture", "alt", "network", "size", "username", "showInitials", "bigNetwork", "anonymous", "online", "youtubeAvatarMode", "rounded"] }, { kind: "directive", type: TooltipDirective, selector: "[apTooltip]", inputs: ["apTooltip", "apTooltipPosition", "apTooltipShowDelay", "apTooltipHideDelay", "apTooltipDuration", "apTooltipDisabled", "apTooltipTruncatedTextOnly", "apTooltipTemplateContext", "apTooltipVirtualScrollElement"] }, { kind: "directive", type: TreeNodeAccessibilityDirective, selector: "[apTreeNodeAccessibility]", inputs: ["apTreeNodeAccessibility"] }], animations: [
|
|
1932
|
+
/**
|
|
1933
|
+
* Overflow hidden is put only during the animation and on the collapsed state because if it is put on the expanded state then children’s border will be cut (hover / focus)
|
|
1934
|
+
*/
|
|
1935
|
+
trigger('accordion', [
|
|
1936
|
+
state('collapsed', style({
|
|
1937
|
+
maxHeight: 0,
|
|
1938
|
+
overflow: 'hidden',
|
|
1939
|
+
})),
|
|
1940
|
+
state('expanded', style({
|
|
1941
|
+
maxHeight: 'initial',
|
|
1942
|
+
})),
|
|
1943
|
+
transition('collapsed => expanded', [
|
|
1944
|
+
animate('250ms cubic-bezier(.4, 0, .3, 1)', style({ maxHeight: '{{maxHeight}}', overflow: 'hidden' })),
|
|
1945
|
+
]),
|
|
1946
|
+
transition('expanded => collapsed', [
|
|
1947
|
+
animate('250ms cubic-bezier(.4, 0, .3, 1)', keyframes([style({ maxHeight: '{{maxHeight}}', overflow: 'hidden' }), style({ maxHeight: 0, overflow: 'hidden' })])),
|
|
1948
|
+
]),
|
|
1949
|
+
]),
|
|
1950
|
+
], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
1951
|
+
}
|
|
1952
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.9", ngImport: i0, type: NavSelectorGroupComponent, decorators: [{
|
|
1953
|
+
type: Component,
|
|
1954
|
+
args: [{ selector: 'ap-nav-selector-group', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, providers: [withSymbols(apFolder, apErrorFill, apChevronDown, apChevronUp), NavSelectorGroupPresenter], imports: [
|
|
1955
|
+
SymbolComponent,
|
|
1956
|
+
CounterComponent,
|
|
1957
|
+
NavSelectorLeafComponent,
|
|
1958
|
+
CheckboxComponent,
|
|
1959
|
+
AvatarComponent,
|
|
1960
|
+
TooltipDirective,
|
|
1961
|
+
TreeNodeAccessibilityDirective,
|
|
1962
|
+
], host: {
|
|
1963
|
+
'[class.minified]': '!navSelectorGroupPresenter.expanded()',
|
|
1964
|
+
'(keydown.arrowLeft)': 'fold($event)',
|
|
1965
|
+
'(keydown.arrowRight)': 'unfold($event)',
|
|
1966
|
+
}, animations: [
|
|
1967
|
+
/**
|
|
1968
|
+
* Overflow hidden is put only during the animation and on the collapsed state because if it is put on the expanded state then children’s border will be cut (hover / focus)
|
|
1969
|
+
*/
|
|
1970
|
+
trigger('accordion', [
|
|
1971
|
+
state('collapsed', style({
|
|
1972
|
+
maxHeight: 0,
|
|
1973
|
+
overflow: 'hidden',
|
|
1974
|
+
})),
|
|
1975
|
+
state('expanded', style({
|
|
1976
|
+
maxHeight: 'initial',
|
|
1977
|
+
})),
|
|
1978
|
+
transition('collapsed => expanded', [
|
|
1979
|
+
animate('250ms cubic-bezier(.4, 0, .3, 1)', style({ maxHeight: '{{maxHeight}}', overflow: 'hidden' })),
|
|
1980
|
+
]),
|
|
1981
|
+
transition('expanded => collapsed', [
|
|
1982
|
+
animate('250ms cubic-bezier(.4, 0, .3, 1)', keyframes([style({ maxHeight: '{{maxHeight}}', overflow: 'hidden' }), style({ maxHeight: 0, overflow: 'hidden' })])),
|
|
1983
|
+
]),
|
|
1984
|
+
]),
|
|
1985
|
+
], template: "@if (navSelectorGroupPresenter.expandedAfterDelay()) {\n <div\n class=\"content\"\n apTooltipPosition=\"right\"\n [apTooltip]=\"tooltipContent()\"\n [apTooltipDisabled]=\"tooltipDisabled()\"\n [apTreeNodeAccessibility]=\"group()\"\n (keydown.space)=\"onKeydownSpaceOrEnter($event)\"\n (keydown.enter)=\"onKeydownSpaceOrEnter($event)\">\n @if (navSelectorGroupPresenter.isMultipleModeEnabled()) {\n <ap-checkbox\n [name]=\"group().uid\"\n [checked]=\"group().selected\"\n [disabled]=\"!group().selectable\"\n [indeterminate]=\"group().undeterminedSelection\"\n (change)=\"navSelectorGroupPresenter.onGroupSelected(group())\" />\n }\n\n <ap-symbol\n symbolId=\"folder\"\n size=\"sm\" />\n\n <span\n #alias\n class=\"caption\">\n {{ group().alias }}\n </span>\n\n @if (group().displayTokenInvalid) {\n <ap-symbol\n symbolId=\"error_fill\"\n size=\"sm\" />\n }\n\n @if (group().displayCounter) {\n <ap-counter\n color=\"orange\"\n size=\"normal\"\n [background]=\"false\">\n {{ group().counter }}\n </ap-counter>\n }\n\n <ap-symbol\n size=\"sm\"\n class=\"folding-button\"\n [tabindex]=\"group().accessibility.tabIndex\"\n [attr.aria-label]=\"'Toggle ' + group().alias\"\n [symbolId]=\"foldSymbol()\"\n (keydown.space)=\"toggleFolding($event)\"\n (keydown.enter)=\"toggleFolding($event)\"\n (click)=\"toggleFolding($event)\" />\n </div>\n\n <div\n class=\"children-container\"\n [@accordion]=\"{\n value: animationState(),\n params: {\n maxHeight: maxHeight()\n }\n }\">\n @if (!foldedWithDelay()) {\n <div class=\"children\">\n @for (child of group().children; track child.uid) {\n @if (!child.hidden) {\n <ap-nav-selector-leaf [leaf]=\"child\" />\n }\n }\n </div>\n }\n </div>\n} @else {\n <div\n class=\"content\"\n apTooltipPosition=\"right\"\n [apTooltip]=\"tooltipContent()\"\n [apTooltipDisabled]=\"tooltipDisabled()\"\n [apTreeNodeAccessibility]=\"group()\"\n (click)=\"toggleFolding($event)\"\n (keydown.space)=\"onKeydownSpaceOrEnter($event)\"\n (keydown.enter)=\"onKeydownSpaceOrEnter($event)\">\n @if (navSelectorGroupPresenter.isMultipleModeEnabled()) {\n <ap-checkbox\n [name]=\"group().uid\"\n [checked]=\"group().selected\"\n [disabled]=\"!group().selectable\"\n [indeterminate]=\"group().undeterminedSelection\"\n (change)=\"navSelectorGroupPresenter.onGroupSelected(group())\" />\n }\n\n <div class=\"picture-url-sample-container\">\n <div class=\"picture-url-sample\">\n @for (pictureUrlSample of group().childrenPictureUrlSample; track pictureUrlSample) {\n <ap-avatar\n [size]=\"$any(12)\"\n [profilePicture]=\"pictureUrlSample.url ?? undefined\"\n [showInitials]=\"pictureUrlSample.initial\" />\n }\n\n <div class=\"status\">\n @if (group().displayCounter) {\n <ap-counter\n color=\"orange\"\n size=\"normal\"\n [notif]=\"true\"\n [background]=\"true\">\n {{ group().counter }}\n </ap-counter>\n }\n </div>\n </div>\n\n <div class=\"toggle\">\n <ap-symbol\n size=\"sm\"\n [symbolId]=\"foldSymbol()\" />\n </div>\n </div>\n </div>\n\n <div\n class=\"details-container\"\n [@accordion]=\"{\n value: animationState(),\n params: {\n maxHeight: maxHeight()\n }\n }\">\n @if (!foldedWithDelay()) {\n <div class=\"children\">\n @for (child of group().children; track child.uid) {\n @if (!child.hidden) {\n <ap-nav-selector-leaf [leaf]=\"child\" />\n }\n }\n </div>\n }\n </div>\n}\n", styles: [":host{display:flex;align-items:center;flex-shrink:0;align-self:stretch;flex-direction:column}:host .children-container{align-self:stretch}:host .content{padding:0 var(--ref-spacing-xxs);display:flex;height:36px;align-items:center;gap:var(--ref-spacing-xxs);flex-shrink:0;flex-grow:1;align-self:stretch;cursor:pointer}:host .content:hover{border-radius:var(--ref-border-radius-sm);background:var(--ref-color-electric-blue-10)}:host .content:active{border-radius:var(--ref-border-radius-sm);background:var(--ref-color-electric-blue-20)}:host .content:focus{outline:none;border-radius:var(--ref-border-radius-sm);background:var(--ref-color-electric-blue-10);box-shadow:0 0 0 1px var(--ref-color-white),0 0 0 3px var(--ref-color-electric-blue-100)}:host .content:focus-within{border-radius:var(--ref-border-radius-sm);background:var(--ref-color-electric-blue-20)}:host:not(.minified) ap-symbol[symbol-id=chevron-down],:host:not(.minified) ap-symbol[symbol-id=chevron-up]{color:var(--ref-color-grey-80)}:host:not(.minified) ap-symbol[symbol-id=chevron-down]:hover,:host:not(.minified) ap-symbol[symbol-id=chevron-up]:hover{border-radius:var(--ref-border-radius-sm);background:var(--ref-color-electric-blue-20)}:host:not(.minified) ap-symbol[symbol-id=chevron-down]:active,:host:not(.minified) ap-symbol[symbol-id=chevron-up]:active{border-radius:var(--ref-border-radius-sm);background:var(--ref-color-electric-blue-40)}:host:not(.minified) ap-symbol[symbol-id=chevron-down]:focus,:host:not(.minified) ap-symbol[symbol-id=chevron-up]:focus{outline:none;border-radius:var(--ref-border-radius-sm);background:var(--ref-color-electric-blue-20);box-shadow:0 0 0 1px #fff,0 0 0 3px #178dfe}:host ap-symbol[symbol-id=error_fill]{color:var(--ref-color-red-100)}:host ap-symbol[symbol-id=folder]{color:var(--ref-color-grey-100)}:host ap-symbol[symbol-id=chevron-down],:host ap-symbol[symbol-id=chevron-up]{color:var(--ref-color-grey-80)}:host .folding-button{display:flex;width:24px;height:24px;justify-content:center;align-items:center;flex-shrink:0}:host .folding-button:hover{border-radius:var(--ref-border-radius-sm);background:var(--ref-color-electric-blue-20)}:host .folding-button:active{border-radius:var(--ref-border-radius-sm);background:var(--ref-color-electric-blue-40)}:host .caption{display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:1;flex:1 0 0;overflow:hidden;color:var(--ref-color-grey-100);text-overflow:ellipsis;font-family:Averta;font-size:var(--ref-font-size-xs);font-style:normal;font-weight:var(--ref-font-weight-bold);line-height:var(--ref-font-line-height-xs)}:host .children{display:flex;flex-direction:column;align-items:flex-start;flex:1 0 0;align-self:stretch}:host .picture-url-sample-container{position:relative;width:26px}:host .picture-url-sample{display:flex;width:26px;align-items:center;align-content:center;gap:2px;flex-wrap:wrap}:host.minified .content{gap:var(--ref-spacing-xxxs);position:relative;justify-content:center}:host.minified .content .toggle{position:absolute;display:none}:host.minified .content:hover .toggle,:host.minified .content:focus .toggle{inset:0;display:flex;justify-content:center;align-items:center}:host.minified .content:hover .picture-url-sample,:host.minified .content:focus .picture-url-sample{display:none}:host.minified ::ng-deep ap-checkbox .checkbox .checkbox-container{padding:0}:host.minified .status{position:absolute;right:-4px;top:-6px}\n"] }]
|
|
1986
|
+
}], ctorParameters: () => [{ type: i0.ElementRef }, { type: NavSelectorGroupPresenter }] });
|
|
1987
|
+
|
|
1988
|
+
class NavSelectorCategoryPresenter {
|
|
1989
|
+
navSelectorState;
|
|
1990
|
+
expanded = computed(() => this.navSelectorState.expanded());
|
|
1991
|
+
expandedAfterDelay = computed(() => this.navSelectorState.expandedAfterDelay());
|
|
1992
|
+
constructor(navSelectorState) {
|
|
1993
|
+
this.navSelectorState = navSelectorState;
|
|
1994
|
+
}
|
|
1995
|
+
toggleFolding(event, category) {
|
|
1996
|
+
event.stopImmediatePropagation();
|
|
1997
|
+
this.navSelectorState.onGroupToggleFolding(category);
|
|
1998
|
+
}
|
|
1999
|
+
fold(event, category) {
|
|
2000
|
+
event.stopImmediatePropagation();
|
|
2001
|
+
this.navSelectorState.fold(category);
|
|
2002
|
+
}
|
|
2003
|
+
unfold(event, category) {
|
|
2004
|
+
event.stopImmediatePropagation();
|
|
2005
|
+
this.navSelectorState.unfold(category);
|
|
2006
|
+
}
|
|
2007
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.9", ngImport: i0, type: NavSelectorCategoryPresenter, deps: [{ token: NavSelectorState }], target: i0.ɵɵFactoryTarget.Injectable });
|
|
2008
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.9", ngImport: i0, type: NavSelectorCategoryPresenter });
|
|
2009
|
+
}
|
|
2010
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.9", ngImport: i0, type: NavSelectorCategoryPresenter, decorators: [{
|
|
2011
|
+
type: Injectable
|
|
2012
|
+
}], ctorParameters: () => [{ type: NavSelectorState }] });
|
|
2013
|
+
|
|
2014
|
+
class NavSelectorCategoryComponent {
|
|
2015
|
+
el;
|
|
2016
|
+
navSelectorCategoryPresenter;
|
|
2017
|
+
category = input.required();
|
|
2018
|
+
foldSymbol = computed(() => (this.category().folded ? 'chevron-down' : 'chevron-up'));
|
|
2019
|
+
foldedWithDelay = signal(false);
|
|
2020
|
+
animationState = computed(() => (this.category().folded ? 'collapsed' : 'expanded'));
|
|
2021
|
+
constructor(el, navSelectorCategoryPresenter) {
|
|
2022
|
+
this.el = el;
|
|
2023
|
+
this.navSelectorCategoryPresenter = navSelectorCategoryPresenter;
|
|
2024
|
+
afterNextRender(() => this.maxHeight.set(`${this.el.nativeElement.scrollHeight}px`));
|
|
2025
|
+
effect(() => {
|
|
2026
|
+
if (this.category().folded) {
|
|
2027
|
+
setTimeout(() => this.foldedWithDelay.set(true), 150);
|
|
2028
|
+
}
|
|
2029
|
+
else {
|
|
2030
|
+
this.foldedWithDelay.set(false);
|
|
2031
|
+
}
|
|
2032
|
+
}, { allowSignalWrites: true });
|
|
2033
|
+
}
|
|
2034
|
+
maxHeight = signal('0px');
|
|
2035
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.9", ngImport: i0, type: NavSelectorCategoryComponent, deps: [{ token: i0.ElementRef }, { token: NavSelectorCategoryPresenter }], target: i0.ɵɵFactoryTarget.Component });
|
|
2036
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.9", type: NavSelectorCategoryComponent, isStandalone: true, selector: "ap-nav-selector-category", inputs: { category: { classPropertyName: "category", publicName: "category", isSignal: true, isRequired: true, transformFunction: null } }, host: { listeners: { "keydown.arrowLeft": "navSelectorCategoryPresenter.fold($event, this.category())", "keydown.arrowRight": "navSelectorCategoryPresenter.unfold($event, this.category())" }, properties: { "class.minified": "!navSelectorCategoryPresenter.expanded()" } }, providers: [withSymbols(apChevronDown, apChevronUp), NavSelectorCategoryPresenter], ngImport: i0, template: "@if (navSelectorCategoryPresenter.expandedAfterDelay()) {\n <div\n class=\"content\"\n [apTreeNodeAccessibility]=\"category()\"\n (keydown.space.stop)=\"navSelectorCategoryPresenter.toggleFolding($event, this.category())\"\n (keydown.enter)=\"navSelectorCategoryPresenter.toggleFolding($event, this.category())\">\n <span class=\"caption\">{{ category().alias }}</span>\n\n <ap-symbol\n class=\"folding-button\"\n size=\"sm\"\n [attr.aria-label]=\"'Toggle ' + category().alias\"\n [symbolId]=\"foldSymbol()\"\n (click)=\"navSelectorCategoryPresenter.toggleFolding($event, this.category())\"\n (keydown.space)=\"navSelectorCategoryPresenter.toggleFolding($event, this.category())\"\n (keydown.enter)=\"navSelectorCategoryPresenter.toggleFolding($event, this.category())\" />\n </div>\n\n <div\n class=\"children-container\"\n [@accordion]=\"{\n value: animationState(),\n params: {\n maxHeight: maxHeight()\n }\n }\">\n @if (!foldedWithDelay()) {\n <div class=\"children\">\n @for (child of category().children; track child.uid) {\n @if (!child.hidden) {\n @if (child.type === 'LEAF') {\n <ap-nav-selector-leaf [leaf]=\"child\" />\n } @else if (child.type === 'GROUP') {\n <ap-nav-selector-group [group]=\"child\" />\n }\n }\n }\n </div>\n }\n </div>\n} @else {\n <div\n class=\"content\"\n [apTreeNodeAccessibility]=\"category()\"\n (click)=\"navSelectorCategoryPresenter.toggleFolding($event, this.category())\"\n (keydown.space)=\"navSelectorCategoryPresenter.toggleFolding($event, this.category())\"\n (keydown.enter)=\"navSelectorCategoryPresenter.toggleFolding($event, this.category())\">\n <div class=\"name-container\">\n <span class=\"caption\">{{ category().alias }}</span>\n <span>.</span>\n </div>\n\n <div class=\"toggle\">\n <ap-symbol\n size=\"sm\"\n [symbolId]=\"foldSymbol()\" />\n </div>\n </div>\n\n <div\n class=\"children-container\"\n [@accordion]=\"{\n value: animationState(),\n params: {\n maxHeight: maxHeight()\n }\n }\">\n @if (!foldedWithDelay()) {\n <div class=\"children\">\n @for (child of category().children; track child.uid) {\n @if (!child.hidden) {\n @if (child.type === 'LEAF') {\n <ap-nav-selector-leaf [leaf]=\"child\" />\n } @else if (child.type === 'GROUP') {\n <ap-nav-selector-group [group]=\"child\" />\n }\n }\n }\n </div>\n }\n </div>\n}\n", styles: [":host{display:flex;align-items:center;flex-shrink:0;align-self:stretch;flex-direction:column}:host .children-container{align-self:stretch}:host .folding-button{display:flex;width:24px;height:24px;justify-content:center;align-items:center;flex-shrink:0}:host .folding-button:hover{border-radius:var(--ref-border-radius-sm);background:var(--ref-color-electric-blue-20)}:host .folding-button:active{border-radius:var(--ref-border-radius-sm);background:var(--ref-color-electric-blue-40)}:host .content{padding:0 var(--ref-spacing-xxs);display:flex;height:36px;align-items:center;gap:var(--ref-spacing-xxs);flex-shrink:0;flex-grow:1;align-self:stretch;cursor:pointer}:host .content:hover{border-radius:var(--ref-border-radius-sm);background:var(--ref-color-electric-blue-10)}:host .content:active{border-radius:var(--ref-border-radius-sm);background:var(--ref-color-electric-blue-20)}:host .content:focus{outline:none;border-radius:var(--ref-border-radius-sm);background:var(--ref-color-electric-blue-10);box-shadow:0 0 0 1px var(--ref-color-white),0 0 0 3px var(--ref-color-electric-blue-100)}:host .content:focus-within{border-radius:var(--ref-border-radius-sm);background:var(--ref-color-electric-blue-20)}:host:not(.minified) ap-symbol[symbol-id=chevron-down],:host:not(.minified) ap-symbol[symbol-id=chevron-up]{color:var(--ref-color-grey-80)}:host:not(.minified) ap-symbol[symbol-id=chevron-down]:hover,:host:not(.minified) ap-symbol[symbol-id=chevron-up]:hover{border-radius:var(--ref-border-radius-sm);background:var(--ref-color-electric-blue-20)}:host:not(.minified) ap-symbol[symbol-id=chevron-down]:active,:host:not(.minified) ap-symbol[symbol-id=chevron-up]:active{border-radius:var(--ref-border-radius-sm);background:var(--ref-color-electric-blue-40)}:host:not(.minified) ap-symbol[symbol-id=chevron-down]:focus,:host:not(.minified) ap-symbol[symbol-id=chevron-up]:focus{outline:none;border-radius:var(--ref-border-radius-sm);background:var(--ref-color-electric-blue-20);box-shadow:0 0 0 1px #fff,0 0 0 3px #178dfe}:host ap-symbol[symbol-id=chevron-down],:host ap-symbol[symbol-id=chevron-up]{color:var(--ref-color-grey-80)}:host .caption{display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:1;flex:1 0 0;overflow:hidden;color:var(--ref-color-grey-100);text-overflow:ellipsis;font-family:Averta;font-size:var(--sys-text-style-h4-size);font-style:normal;font-weight:var(--ref-font-weight-bold);line-height:var(--ref-font-line-height-md)}:host .children{display:flex;flex-direction:column;align-items:flex-start;flex:1 0 0;align-self:stretch}:host.minified .name-container{overflow:hidden;display:flex}:host.minified .content{position:relative}:host.minified .content .toggle{position:absolute;display:none}:host.minified .content:hover .toggle,:host.minified .content:focus .toggle{inset:0;display:flex;justify-content:center;align-items:center}:host.minified .content:hover .name-container,:host.minified .content:focus .name-container{display:none}\n"], dependencies: [{ kind: "component", type: NavSelectorLeafComponent, selector: "ap-nav-selector-leaf", inputs: ["leaf"] }, { kind: "component", type: SymbolComponent, selector: "ap-symbol", inputs: ["symbolId", "color", "size"], outputs: ["sizeChange"] }, { kind: "component", type: NavSelectorGroupComponent, selector: "ap-nav-selector-group", inputs: ["group"] }, { kind: "ngmodule", type: EventPluginsModule }, { kind: "directive", type: TreeNodeAccessibilityDirective, selector: "[apTreeNodeAccessibility]", inputs: ["apTreeNodeAccessibility"] }], animations: [
|
|
2037
|
+
/**
|
|
2038
|
+
* Overflow hidden is put only during the animation and on the collapsed state because if it is put on the expanded state then children’s border will be cut (hover / focus)
|
|
2039
|
+
*/
|
|
2040
|
+
trigger('accordion', [
|
|
2041
|
+
state('collapsed', style({
|
|
2042
|
+
maxHeight: 0,
|
|
2043
|
+
overflow: 'hidden',
|
|
2044
|
+
})),
|
|
2045
|
+
state('expanded', style({
|
|
2046
|
+
maxHeight: 'initial',
|
|
2047
|
+
})),
|
|
2048
|
+
transition('collapsed => expanded', [
|
|
2049
|
+
animate('250ms cubic-bezier(.4, 0, .3, 1)', style({ overflow: 'hidden', maxHeight: '{{maxHeight}}' })),
|
|
2050
|
+
]),
|
|
2051
|
+
transition('expanded => collapsed', [
|
|
2052
|
+
animate('250ms cubic-bezier(.4, 0, .3, 1)', keyframes([style({ maxHeight: '{{maxHeight}}' }), style({ overflow: 'hidden', maxHeight: 0 })])),
|
|
2053
|
+
]),
|
|
2054
|
+
]),
|
|
2055
|
+
], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
2056
|
+
}
|
|
2057
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.9", ngImport: i0, type: NavSelectorCategoryComponent, decorators: [{
|
|
2058
|
+
type: Component,
|
|
2059
|
+
args: [{ selector: 'ap-nav-selector-category', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, imports: [NavSelectorLeafComponent, SymbolComponent, NavSelectorGroupComponent, EventPluginsModule, TreeNodeAccessibilityDirective], providers: [withSymbols(apChevronDown, apChevronUp), NavSelectorCategoryPresenter], host: {
|
|
2060
|
+
'[class.minified]': '!navSelectorCategoryPresenter.expanded()',
|
|
2061
|
+
'(keydown.arrowLeft)': 'navSelectorCategoryPresenter.fold($event, this.category())',
|
|
2062
|
+
'(keydown.arrowRight)': 'navSelectorCategoryPresenter.unfold($event, this.category())',
|
|
2063
|
+
}, animations: [
|
|
2064
|
+
/**
|
|
2065
|
+
* Overflow hidden is put only during the animation and on the collapsed state because if it is put on the expanded state then children’s border will be cut (hover / focus)
|
|
2066
|
+
*/
|
|
2067
|
+
trigger('accordion', [
|
|
2068
|
+
state('collapsed', style({
|
|
2069
|
+
maxHeight: 0,
|
|
2070
|
+
overflow: 'hidden',
|
|
2071
|
+
})),
|
|
2072
|
+
state('expanded', style({
|
|
2073
|
+
maxHeight: 'initial',
|
|
2074
|
+
})),
|
|
2075
|
+
transition('collapsed => expanded', [
|
|
2076
|
+
animate('250ms cubic-bezier(.4, 0, .3, 1)', style({ overflow: 'hidden', maxHeight: '{{maxHeight}}' })),
|
|
2077
|
+
]),
|
|
2078
|
+
transition('expanded => collapsed', [
|
|
2079
|
+
animate('250ms cubic-bezier(.4, 0, .3, 1)', keyframes([style({ maxHeight: '{{maxHeight}}' }), style({ overflow: 'hidden', maxHeight: 0 })])),
|
|
2080
|
+
]),
|
|
2081
|
+
]),
|
|
2082
|
+
], template: "@if (navSelectorCategoryPresenter.expandedAfterDelay()) {\n <div\n class=\"content\"\n [apTreeNodeAccessibility]=\"category()\"\n (keydown.space.stop)=\"navSelectorCategoryPresenter.toggleFolding($event, this.category())\"\n (keydown.enter)=\"navSelectorCategoryPresenter.toggleFolding($event, this.category())\">\n <span class=\"caption\">{{ category().alias }}</span>\n\n <ap-symbol\n class=\"folding-button\"\n size=\"sm\"\n [attr.aria-label]=\"'Toggle ' + category().alias\"\n [symbolId]=\"foldSymbol()\"\n (click)=\"navSelectorCategoryPresenter.toggleFolding($event, this.category())\"\n (keydown.space)=\"navSelectorCategoryPresenter.toggleFolding($event, this.category())\"\n (keydown.enter)=\"navSelectorCategoryPresenter.toggleFolding($event, this.category())\" />\n </div>\n\n <div\n class=\"children-container\"\n [@accordion]=\"{\n value: animationState(),\n params: {\n maxHeight: maxHeight()\n }\n }\">\n @if (!foldedWithDelay()) {\n <div class=\"children\">\n @for (child of category().children; track child.uid) {\n @if (!child.hidden) {\n @if (child.type === 'LEAF') {\n <ap-nav-selector-leaf [leaf]=\"child\" />\n } @else if (child.type === 'GROUP') {\n <ap-nav-selector-group [group]=\"child\" />\n }\n }\n }\n </div>\n }\n </div>\n} @else {\n <div\n class=\"content\"\n [apTreeNodeAccessibility]=\"category()\"\n (click)=\"navSelectorCategoryPresenter.toggleFolding($event, this.category())\"\n (keydown.space)=\"navSelectorCategoryPresenter.toggleFolding($event, this.category())\"\n (keydown.enter)=\"navSelectorCategoryPresenter.toggleFolding($event, this.category())\">\n <div class=\"name-container\">\n <span class=\"caption\">{{ category().alias }}</span>\n <span>.</span>\n </div>\n\n <div class=\"toggle\">\n <ap-symbol\n size=\"sm\"\n [symbolId]=\"foldSymbol()\" />\n </div>\n </div>\n\n <div\n class=\"children-container\"\n [@accordion]=\"{\n value: animationState(),\n params: {\n maxHeight: maxHeight()\n }\n }\">\n @if (!foldedWithDelay()) {\n <div class=\"children\">\n @for (child of category().children; track child.uid) {\n @if (!child.hidden) {\n @if (child.type === 'LEAF') {\n <ap-nav-selector-leaf [leaf]=\"child\" />\n } @else if (child.type === 'GROUP') {\n <ap-nav-selector-group [group]=\"child\" />\n }\n }\n }\n </div>\n }\n </div>\n}\n", styles: [":host{display:flex;align-items:center;flex-shrink:0;align-self:stretch;flex-direction:column}:host .children-container{align-self:stretch}:host .folding-button{display:flex;width:24px;height:24px;justify-content:center;align-items:center;flex-shrink:0}:host .folding-button:hover{border-radius:var(--ref-border-radius-sm);background:var(--ref-color-electric-blue-20)}:host .folding-button:active{border-radius:var(--ref-border-radius-sm);background:var(--ref-color-electric-blue-40)}:host .content{padding:0 var(--ref-spacing-xxs);display:flex;height:36px;align-items:center;gap:var(--ref-spacing-xxs);flex-shrink:0;flex-grow:1;align-self:stretch;cursor:pointer}:host .content:hover{border-radius:var(--ref-border-radius-sm);background:var(--ref-color-electric-blue-10)}:host .content:active{border-radius:var(--ref-border-radius-sm);background:var(--ref-color-electric-blue-20)}:host .content:focus{outline:none;border-radius:var(--ref-border-radius-sm);background:var(--ref-color-electric-blue-10);box-shadow:0 0 0 1px var(--ref-color-white),0 0 0 3px var(--ref-color-electric-blue-100)}:host .content:focus-within{border-radius:var(--ref-border-radius-sm);background:var(--ref-color-electric-blue-20)}:host:not(.minified) ap-symbol[symbol-id=chevron-down],:host:not(.minified) ap-symbol[symbol-id=chevron-up]{color:var(--ref-color-grey-80)}:host:not(.minified) ap-symbol[symbol-id=chevron-down]:hover,:host:not(.minified) ap-symbol[symbol-id=chevron-up]:hover{border-radius:var(--ref-border-radius-sm);background:var(--ref-color-electric-blue-20)}:host:not(.minified) ap-symbol[symbol-id=chevron-down]:active,:host:not(.minified) ap-symbol[symbol-id=chevron-up]:active{border-radius:var(--ref-border-radius-sm);background:var(--ref-color-electric-blue-40)}:host:not(.minified) ap-symbol[symbol-id=chevron-down]:focus,:host:not(.minified) ap-symbol[symbol-id=chevron-up]:focus{outline:none;border-radius:var(--ref-border-radius-sm);background:var(--ref-color-electric-blue-20);box-shadow:0 0 0 1px #fff,0 0 0 3px #178dfe}:host ap-symbol[symbol-id=chevron-down],:host ap-symbol[symbol-id=chevron-up]{color:var(--ref-color-grey-80)}:host .caption{display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:1;flex:1 0 0;overflow:hidden;color:var(--ref-color-grey-100);text-overflow:ellipsis;font-family:Averta;font-size:var(--sys-text-style-h4-size);font-style:normal;font-weight:var(--ref-font-weight-bold);line-height:var(--ref-font-line-height-md)}:host .children{display:flex;flex-direction:column;align-items:flex-start;flex:1 0 0;align-self:stretch}:host.minified .name-container{overflow:hidden;display:flex}:host.minified .content{position:relative}:host.minified .content .toggle{position:absolute;display:none}:host.minified .content:hover .toggle,:host.minified .content:focus .toggle{inset:0;display:flex;justify-content:center;align-items:center}:host.minified .content:hover .name-container,:host.minified .content:focus .name-container{display:none}\n"] }]
|
|
2083
|
+
}], ctorParameters: () => [{ type: i0.ElementRef }, { type: NavSelectorCategoryPresenter }] });
|
|
2084
|
+
|
|
2085
|
+
let nextUniqueId = 0;
|
|
2086
|
+
class NavSelectorComponent {
|
|
2087
|
+
navSelectorState;
|
|
2088
|
+
el;
|
|
2089
|
+
navSelectorEntries = input.required();
|
|
2090
|
+
translatedTexts = input.required();
|
|
2091
|
+
multipleModeEnabled = input(false);
|
|
2092
|
+
detailsDisplayedLimit = input(Number.MAX_SAFE_INTEGER);
|
|
2093
|
+
/**
|
|
2094
|
+
* If true, the nav selector will be expanded by default. Even if the width of the screen is smaller than 1280px.
|
|
2095
|
+
*/
|
|
2096
|
+
forceExpanded = input(false);
|
|
2097
|
+
selectedEntryUids = model.required();
|
|
2098
|
+
headerProjection = contentChild('header');
|
|
2099
|
+
footerProjection = contentChild('footer');
|
|
2100
|
+
displayFooter = computed(() => this.footerProjection() !== undefined);
|
|
2101
|
+
leafActionProjection = contentChildren('leafAction');
|
|
2102
|
+
expansionState = computed(() => (this.navSelectorState.expanded() ? 'expanded' : 'minified'));
|
|
2103
|
+
componentUid = `nav-selector-${nextUniqueId++}`;
|
|
2104
|
+
constructor(navSelectorState, el) {
|
|
2105
|
+
this.navSelectorState = navSelectorState;
|
|
2106
|
+
this.el = el;
|
|
2107
|
+
navSelectorState.registerOnSelectedUidsChange(selectedUids => {
|
|
2108
|
+
this.selectedEntryUids.set(selectedUids);
|
|
2109
|
+
});
|
|
2110
|
+
afterNextRender(() => {
|
|
2111
|
+
if (!this.forceExpanded() && document.body.clientWidth < 1200) {
|
|
2112
|
+
this.navSelectorState.toggleExpanded();
|
|
2113
|
+
}
|
|
2114
|
+
});
|
|
2115
|
+
effect(() => {
|
|
2116
|
+
this.navSelectorState.updateMultiModeEnabled(this.multipleModeEnabled());
|
|
2117
|
+
if (!this.navSelectorState.filteredEntries().length) {
|
|
2118
|
+
this.navSelectorState.updateEntries(this.navSelectorEntries(), this.selectedEntryUids(), this.detailsDisplayedLimit());
|
|
2119
|
+
}
|
|
2120
|
+
}, { allowSignalWrites: true });
|
|
2121
|
+
effect(() => {
|
|
2122
|
+
this.navSelectorState.updateDetailsDisplayedLimit(this.detailsDisplayedLimit());
|
|
2123
|
+
}, { allowSignalWrites: true });
|
|
2124
|
+
const leafActionProjectionEffect = effect(() => {
|
|
2125
|
+
if (this.leafActionProjection()) {
|
|
2126
|
+
this.navSelectorState.updateLeafAction(this.leafActionProjection());
|
|
2127
|
+
leafActionProjectionEffect.destroy();
|
|
2128
|
+
}
|
|
2129
|
+
}, { manualCleanup: true, allowSignalWrites: true });
|
|
2130
|
+
effect(() => {
|
|
2131
|
+
this.navSelectorState.onSelectionChange(this.selectedEntryUids());
|
|
2132
|
+
}, { allowSignalWrites: true });
|
|
2133
|
+
effect(() => {
|
|
2134
|
+
this.navSelectorState.updateTexts(this.translatedTexts());
|
|
2135
|
+
}, { allowSignalWrites: true });
|
|
2136
|
+
}
|
|
2137
|
+
onArrowDown($event) {
|
|
2138
|
+
if (this.el.nativeElement.querySelector('.nav-selector__content').contains(document.activeElement)) {
|
|
2139
|
+
$event.stopImmediatePropagation();
|
|
2140
|
+
this.navSelectorState.onArrowDown();
|
|
2141
|
+
setTimeout(() => this.el.nativeElement.querySelector('[role="treeitem"][tabindex="0"]').focus());
|
|
2142
|
+
}
|
|
2143
|
+
}
|
|
2144
|
+
onArrowUp($event) {
|
|
2145
|
+
if (this.el.nativeElement.querySelector('.nav-selector__content').contains(document.activeElement)) {
|
|
2146
|
+
$event.stopImmediatePropagation();
|
|
2147
|
+
this.navSelectorState.onArrowUp();
|
|
2148
|
+
setTimeout(() => this.el.nativeElement.querySelector('[role="treeitem"][tabindex="0"]').focus());
|
|
2149
|
+
}
|
|
2150
|
+
}
|
|
2151
|
+
TemplateRef = TemplateRef;
|
|
2152
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.9", ngImport: i0, type: NavSelectorComponent, deps: [{ token: NavSelectorState }, { token: i0.ElementRef }], target: i0.ɵɵFactoryTarget.Component });
|
|
2153
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.9", type: NavSelectorComponent, isStandalone: true, selector: "ap-nav-selector", inputs: { navSelectorEntries: { classPropertyName: "navSelectorEntries", publicName: "navSelectorEntries", isSignal: true, isRequired: true, transformFunction: null }, translatedTexts: { classPropertyName: "translatedTexts", publicName: "translatedTexts", isSignal: true, isRequired: true, transformFunction: null }, multipleModeEnabled: { classPropertyName: "multipleModeEnabled", publicName: "multipleModeEnabled", isSignal: true, isRequired: false, transformFunction: null }, detailsDisplayedLimit: { classPropertyName: "detailsDisplayedLimit", publicName: "detailsDisplayedLimit", isSignal: true, isRequired: false, transformFunction: null }, forceExpanded: { classPropertyName: "forceExpanded", publicName: "forceExpanded", isSignal: true, isRequired: false, transformFunction: null }, selectedEntryUids: { classPropertyName: "selectedEntryUids", publicName: "selectedEntryUids", isSignal: true, isRequired: true, transformFunction: null } }, outputs: { selectedEntryUids: "selectedEntryUidsChange" }, host: { attributes: { "role": "tree" }, listeners: { "keydown.arrowDown": "onArrowDown($event)", "keydown.arrowUp": "onArrowUp($event)" }, properties: { "class.minified": "!navSelectorState.expanded()" } }, providers: [NavSelectorState, withSymbols(apArrowExpand, apArrowReduce, apSearch)], queries: [{ propertyName: "headerProjection", first: true, predicate: ["header"], descendants: true, isSignal: true }, { propertyName: "footerProjection", first: true, predicate: ["footer"], descendants: true, isSignal: true }, { propertyName: "leafActionProjection", predicate: ["leafAction"], isSignal: true }], ngImport: i0, template: "<nav [@expand]=\"expansionState()\">\n @let headerProjectionNotNull = headerProjection();\n @let footerProjectionNotNull = footerProjection();\n\n @if (navSelectorState.expandedAfterDelay()) {\n <div class=\"nav-selector__header\">\n <span class=\"h3\">{{ translatedTexts().title }}</span>\n\n <button\n type=\"button\"\n class=\"expand-button expanded\"\n (click)=\"navSelectorState.toggleExpanded()\">\n <ap-symbol\n size=\"sm\"\n symbolId=\"arrow-reduce\" />\n </button>\n\n\n @if (headerProjectionNotNull) {\n <ng-container\n [ngTemplateOutlet]=\"headerProjectionNotNull\"\n [ngTemplateOutletContext]=\"{\n expanded: navSelectorState.expanded()\n }\" />\n }\n\n <ap-input-search\n [id]=\"componentUid + '_search'\"\n class=\"nav-selector-search\"\n [placeholder]=\"translatedTexts().searchPlaceholder\"\n [ngModel]=\"navSelectorState.search()\"\n (ngModelChange)=\"navSelectorState.search.set($event ?? '')\" />\n </div>\n\n <div\n class=\"nav-selector__content\"\n role=\"tree\">\n @for (entry of navSelectorState.filteredEntries(); track entry.uid) {\n @if (!entry.hidden) {\n <div class=\"entry\">\n @if (entry.type === 'LEAF') {\n <ap-nav-selector-leaf [leaf]=\"entry\" />\n } @else if (entry.type === 'GROUP') {\n <ap-nav-selector-group [group]=\"entry\" />\n } @else if (entry.type === 'CATEGORY') {\n <ap-nav-selector-category [category]=\"$any(entry)\" />\n }\n </div>\n }\n }\n @if (navSelectorState.noResults()) {\n <div class=\"no-result\">{{ translatedTexts().noResults }}</div>\n }\n </div>\n\n @if (displayFooter() && footerProjectionNotNull) {\n <div class=\"nav-selector__footer\">\n <ng-container\n [ngTemplateOutlet]=\"footerProjectionNotNull\"\n [ngTemplateOutletContext]=\"{\n expanded: navSelectorState.expanded()\n }\" />\n </div>\n }\n } @else {\n <div class=\"nav-selector__header\">\n <button\n type=\"button\"\n class=\"expand-button\"\n (click)=\"navSelectorState.toggleExpanded()\">\n <ap-symbol\n size=\"sm\"\n symbolId=\"arrow-expand\" />\n </button>\n @if (headerProjectionNotNull) {\n <ng-container\n [ngTemplateOutlet]=\"headerProjectionNotNull\"\n [ngTemplateOutletContext]=\"{\n expanded: navSelectorState.expanded()\n }\" />\n }\n\n <ap-icon-button (onClick)=\"navSelectorState.toggleExpanded()\">\n <ap-symbol symbolId=\"search\" />\n </ap-icon-button>\n </div>\n\n <div class=\"nav-selector__content\">\n @for (entry of navSelectorState.filteredEntries(); track entry.uid) {\n @if (!entry.hidden) {\n <div class=\"entry\">\n @if (entry.type === 'LEAF') {\n <ap-nav-selector-leaf [leaf]=\"entry\" />\n } @else if (entry.type === 'GROUP') {\n <ap-nav-selector-group [group]=\"entry\" />\n } @else if (entry.type === 'CATEGORY') {\n <ap-nav-selector-category [category]=\"entry\" />\n }\n </div>\n }\n }\n </div>\n\n @if (displayFooter() && footerProjectionNotNull) {\n <div class=\"nav-selector__footer\">\n <ng-container\n [ngTemplateOutlet]=\"footerProjectionNotNull\"\n [ngTemplateOutletContext]=\"{\n expanded: navSelectorState.expanded()\n }\" />\n </div>\n }\n }\n</nav>\n", styles: [":host{display:flex;height:100%;flex-direction:column;align-items:flex-start;flex-shrink:0;width:224px;max-width:224px}@media only screen and (min-device-width: 1400px){:host{width:100%;max-width:250px}}:host :hover .expand-button.expanded{animation-name:translateExpandButton}:host nav{display:flex;height:100%;width:100%;flex-direction:column;align-items:flex-start;flex-shrink:0;overflow:hidden;border-right:1px solid var(--ref-color-grey-10);background:var(--ref-color-white)}:host .nav-selector__header{position:relative;display:flex;padding:var(--ref-spacing-xs) var(--ref-spacing-sm);flex-direction:column;align-items:flex-start;gap:8px;align-self:stretch;border-bottom:1px solid var(--ref-color-grey-10);background:var(--ref-color-white)}:host .nav-selector__header .h3{color:var(--ref-color-grey-100);font-family:Averta;font-size:var(--sys-text-h3-size);font-style:normal;font-weight:var(--ref-font-weight-bold);line-height:var(--ref-font-line-height-lg)}:host .nav-selector__header .expand-button-container{position:absolute;right:0;top:var(--ref-spacing-xs)}:host .nav-selector__header .expand-button{animation-duration:70ms;animation-timing-function:cubic-bezier(0,0,.2,1);animation-fill-mode:forwards;display:flex;width:24px;height:24px;justify-content:center;align-items:center;background:none;border:1px solid var(--ref-color-grey-20);border-top-left-radius:var(--ref-border-radius-sm);border-bottom-left-radius:var(--ref-border-radius-sm);cursor:pointer}@keyframes translateExpandButton{0%{transform:translate(100%)}to{transform:translate(0)}}:host .nav-selector__header .expand-button.expanded{position:absolute;right:0;top:12px;transform:translate(100%)}:host .nav-selector__header .expand-button ap-symbol[symbol-id=arrow-reduce],:host .nav-selector__header .expand-button ap-symbol[symbol-id=arrow-expand]{color:var(--ref-color-grey-80)}:host .nav-selector__header .expand-button:focus{border-radius:var(--ref-border-radius-sm) 0px 0px var(--ref-border-radius-sm);border-top:1px solid var(--ref-color-grey-20);border-bottom:1px solid var(--ref-color-grey-20);border-left:1px solid var(--ref-color-grey-20);background:var(--ref-color-grey-10);box-shadow:0 0 0 1px #fff,0 0 0 3px #178dfe}:host .nav-selector__header .expand-button:focus.expanded{animation-name:translateExpandButton}:host .nav-selector__header .expand-button:hover{background-color:var(--ref-color-grey-10)}:host .nav-selector__header .expand-button:active{background-color:var(--ref-color-grey-20)}:host .nav-selector__header .nav-selector-search{width:100%}:host .nav-selector__content{display:flex;flex-direction:column;align-items:flex-start;flex:1 0 0;align-self:stretch;overflow:auto}:host .nav-selector__content .entry{padding:var(--ref-spacing-xxs);align-self:stretch;display:flex;flex-direction:column}:host .nav-selector__content .entry+.entry{border-top:1px solid var(--sys-border-color-default)}:host .nav-selector__content .no-result{display:flex;padding:var(--ref-spacing-sm);flex-direction:column;align-items:flex-start;flex:1 0 0;align-self:stretch;color:var(--ref-color-grey-80);font-family:Averta;font-size:var(--ref-font-size-sm);font-style:italic;font-weight:400;line-height:var(--ref-font-line-height-sm)}:host .nav-selector__footer{display:flex;padding:var(--ref-spacing-xs);flex-direction:column;align-items:flex-start;gap:var(--ref-spacing-xxs);align-self:stretch;border-top:1px solid var(--sys-border-color-default);background:var(--ref-color-white)}:host.minified nav{width:64px}:host.minified nav .nav-selector__header{align-items:center}:host.minified nav .nav-selector__content .entry{padding:var(--ref-spacing-xxxs)}:host.minified nav .nav-selector__footer{padding:var(--ref-spacing-xs) var(--ref-spacing-xxxs) var(--ref-spacing-xs) var(--ref-spacing-xxxs)}\n"], dependencies: [{ kind: "component", type: NavSelectorLeafComponent, selector: "ap-nav-selector-leaf", inputs: ["leaf"] }, { kind: "component", type: NavSelectorGroupComponent, selector: "ap-nav-selector-group", inputs: ["group"] }, { kind: "component", type: NavSelectorCategoryComponent, selector: "ap-nav-selector-category", inputs: ["category"] }, { kind: "component", type: InputSearchComponent, selector: "ap-input-search", inputs: ["id", "placeholder", "clearable"], outputs: ["focus", "blur", "keyup"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: SymbolComponent, selector: "ap-symbol", inputs: ["symbolId", "color", "size"], outputs: ["sizeChange"] }, { kind: "component", type: IconButtonComponent, selector: "ap-icon-button", inputs: ["ariaLabel", "name", "color", "disabled", "menuTrigger", "locked", "loading", "type"], outputs: ["onClick", "onFocus", "onBlur", "menuOpened", "menuClosed"] }, { kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "ngmodule", type: EventPluginsModule }], animations: [
|
|
2154
|
+
trigger('expand', [
|
|
2155
|
+
state('expanded', style({ width: '100%' })),
|
|
2156
|
+
state('minified', style({ with: '64px' })),
|
|
2157
|
+
transition('expanded => minified', animate('250ms cubic-bezier(.4, 0, .3, 1)')),
|
|
2158
|
+
transition('minified => expanded', animate('250ms cubic-bezier(.4, 0, .3, 1)',
|
|
2159
|
+
// Force animation to do not be with 100% instantly
|
|
2160
|
+
keyframes([style({ width: '64px' }), style({ width: '50%' }), style({ width: '100%' })]))),
|
|
2161
|
+
]),
|
|
2162
|
+
], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
2163
|
+
}
|
|
2164
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.9", ngImport: i0, type: NavSelectorComponent, decorators: [{
|
|
2165
|
+
type: Component,
|
|
2166
|
+
args: [{ selector: 'ap-nav-selector', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, imports: [
|
|
2167
|
+
NavSelectorLeafComponent,
|
|
2168
|
+
NavSelectorGroupComponent,
|
|
2169
|
+
NavSelectorCategoryComponent,
|
|
2170
|
+
InputSearchComponent,
|
|
2171
|
+
FormsModule,
|
|
2172
|
+
SymbolComponent,
|
|
2173
|
+
IconButtonComponent,
|
|
2174
|
+
NgTemplateOutlet,
|
|
2175
|
+
EventPluginsModule,
|
|
2176
|
+
], providers: [NavSelectorState, withSymbols(apArrowExpand, apArrowReduce, apSearch)], host: {
|
|
2177
|
+
'[class.minified]': '!navSelectorState.expanded()',
|
|
2178
|
+
role: 'tree',
|
|
2179
|
+
'(keydown.arrowDown)': 'onArrowDown($event)',
|
|
2180
|
+
'(keydown.arrowUp)': 'onArrowUp($event)',
|
|
2181
|
+
}, animations: [
|
|
2182
|
+
trigger('expand', [
|
|
2183
|
+
state('expanded', style({ width: '100%' })),
|
|
2184
|
+
state('minified', style({ with: '64px' })),
|
|
2185
|
+
transition('expanded => minified', animate('250ms cubic-bezier(.4, 0, .3, 1)')),
|
|
2186
|
+
transition('minified => expanded', animate('250ms cubic-bezier(.4, 0, .3, 1)',
|
|
2187
|
+
// Force animation to do not be with 100% instantly
|
|
2188
|
+
keyframes([style({ width: '64px' }), style({ width: '50%' }), style({ width: '100%' })]))),
|
|
2189
|
+
]),
|
|
2190
|
+
], template: "<nav [@expand]=\"expansionState()\">\n @let headerProjectionNotNull = headerProjection();\n @let footerProjectionNotNull = footerProjection();\n\n @if (navSelectorState.expandedAfterDelay()) {\n <div class=\"nav-selector__header\">\n <span class=\"h3\">{{ translatedTexts().title }}</span>\n\n <button\n type=\"button\"\n class=\"expand-button expanded\"\n (click)=\"navSelectorState.toggleExpanded()\">\n <ap-symbol\n size=\"sm\"\n symbolId=\"arrow-reduce\" />\n </button>\n\n\n @if (headerProjectionNotNull) {\n <ng-container\n [ngTemplateOutlet]=\"headerProjectionNotNull\"\n [ngTemplateOutletContext]=\"{\n expanded: navSelectorState.expanded()\n }\" />\n }\n\n <ap-input-search\n [id]=\"componentUid + '_search'\"\n class=\"nav-selector-search\"\n [placeholder]=\"translatedTexts().searchPlaceholder\"\n [ngModel]=\"navSelectorState.search()\"\n (ngModelChange)=\"navSelectorState.search.set($event ?? '')\" />\n </div>\n\n <div\n class=\"nav-selector__content\"\n role=\"tree\">\n @for (entry of navSelectorState.filteredEntries(); track entry.uid) {\n @if (!entry.hidden) {\n <div class=\"entry\">\n @if (entry.type === 'LEAF') {\n <ap-nav-selector-leaf [leaf]=\"entry\" />\n } @else if (entry.type === 'GROUP') {\n <ap-nav-selector-group [group]=\"entry\" />\n } @else if (entry.type === 'CATEGORY') {\n <ap-nav-selector-category [category]=\"$any(entry)\" />\n }\n </div>\n }\n }\n @if (navSelectorState.noResults()) {\n <div class=\"no-result\">{{ translatedTexts().noResults }}</div>\n }\n </div>\n\n @if (displayFooter() && footerProjectionNotNull) {\n <div class=\"nav-selector__footer\">\n <ng-container\n [ngTemplateOutlet]=\"footerProjectionNotNull\"\n [ngTemplateOutletContext]=\"{\n expanded: navSelectorState.expanded()\n }\" />\n </div>\n }\n } @else {\n <div class=\"nav-selector__header\">\n <button\n type=\"button\"\n class=\"expand-button\"\n (click)=\"navSelectorState.toggleExpanded()\">\n <ap-symbol\n size=\"sm\"\n symbolId=\"arrow-expand\" />\n </button>\n @if (headerProjectionNotNull) {\n <ng-container\n [ngTemplateOutlet]=\"headerProjectionNotNull\"\n [ngTemplateOutletContext]=\"{\n expanded: navSelectorState.expanded()\n }\" />\n }\n\n <ap-icon-button (onClick)=\"navSelectorState.toggleExpanded()\">\n <ap-symbol symbolId=\"search\" />\n </ap-icon-button>\n </div>\n\n <div class=\"nav-selector__content\">\n @for (entry of navSelectorState.filteredEntries(); track entry.uid) {\n @if (!entry.hidden) {\n <div class=\"entry\">\n @if (entry.type === 'LEAF') {\n <ap-nav-selector-leaf [leaf]=\"entry\" />\n } @else if (entry.type === 'GROUP') {\n <ap-nav-selector-group [group]=\"entry\" />\n } @else if (entry.type === 'CATEGORY') {\n <ap-nav-selector-category [category]=\"entry\" />\n }\n </div>\n }\n }\n </div>\n\n @if (displayFooter() && footerProjectionNotNull) {\n <div class=\"nav-selector__footer\">\n <ng-container\n [ngTemplateOutlet]=\"footerProjectionNotNull\"\n [ngTemplateOutletContext]=\"{\n expanded: navSelectorState.expanded()\n }\" />\n </div>\n }\n }\n</nav>\n", styles: [":host{display:flex;height:100%;flex-direction:column;align-items:flex-start;flex-shrink:0;width:224px;max-width:224px}@media only screen and (min-device-width: 1400px){:host{width:100%;max-width:250px}}:host :hover .expand-button.expanded{animation-name:translateExpandButton}:host nav{display:flex;height:100%;width:100%;flex-direction:column;align-items:flex-start;flex-shrink:0;overflow:hidden;border-right:1px solid var(--ref-color-grey-10);background:var(--ref-color-white)}:host .nav-selector__header{position:relative;display:flex;padding:var(--ref-spacing-xs) var(--ref-spacing-sm);flex-direction:column;align-items:flex-start;gap:8px;align-self:stretch;border-bottom:1px solid var(--ref-color-grey-10);background:var(--ref-color-white)}:host .nav-selector__header .h3{color:var(--ref-color-grey-100);font-family:Averta;font-size:var(--sys-text-h3-size);font-style:normal;font-weight:var(--ref-font-weight-bold);line-height:var(--ref-font-line-height-lg)}:host .nav-selector__header .expand-button-container{position:absolute;right:0;top:var(--ref-spacing-xs)}:host .nav-selector__header .expand-button{animation-duration:70ms;animation-timing-function:cubic-bezier(0,0,.2,1);animation-fill-mode:forwards;display:flex;width:24px;height:24px;justify-content:center;align-items:center;background:none;border:1px solid var(--ref-color-grey-20);border-top-left-radius:var(--ref-border-radius-sm);border-bottom-left-radius:var(--ref-border-radius-sm);cursor:pointer}@keyframes translateExpandButton{0%{transform:translate(100%)}to{transform:translate(0)}}:host .nav-selector__header .expand-button.expanded{position:absolute;right:0;top:12px;transform:translate(100%)}:host .nav-selector__header .expand-button ap-symbol[symbol-id=arrow-reduce],:host .nav-selector__header .expand-button ap-symbol[symbol-id=arrow-expand]{color:var(--ref-color-grey-80)}:host .nav-selector__header .expand-button:focus{border-radius:var(--ref-border-radius-sm) 0px 0px var(--ref-border-radius-sm);border-top:1px solid var(--ref-color-grey-20);border-bottom:1px solid var(--ref-color-grey-20);border-left:1px solid var(--ref-color-grey-20);background:var(--ref-color-grey-10);box-shadow:0 0 0 1px #fff,0 0 0 3px #178dfe}:host .nav-selector__header .expand-button:focus.expanded{animation-name:translateExpandButton}:host .nav-selector__header .expand-button:hover{background-color:var(--ref-color-grey-10)}:host .nav-selector__header .expand-button:active{background-color:var(--ref-color-grey-20)}:host .nav-selector__header .nav-selector-search{width:100%}:host .nav-selector__content{display:flex;flex-direction:column;align-items:flex-start;flex:1 0 0;align-self:stretch;overflow:auto}:host .nav-selector__content .entry{padding:var(--ref-spacing-xxs);align-self:stretch;display:flex;flex-direction:column}:host .nav-selector__content .entry+.entry{border-top:1px solid var(--sys-border-color-default)}:host .nav-selector__content .no-result{display:flex;padding:var(--ref-spacing-sm);flex-direction:column;align-items:flex-start;flex:1 0 0;align-self:stretch;color:var(--ref-color-grey-80);font-family:Averta;font-size:var(--ref-font-size-sm);font-style:italic;font-weight:400;line-height:var(--ref-font-line-height-sm)}:host .nav-selector__footer{display:flex;padding:var(--ref-spacing-xs);flex-direction:column;align-items:flex-start;gap:var(--ref-spacing-xxs);align-self:stretch;border-top:1px solid var(--sys-border-color-default);background:var(--ref-color-white)}:host.minified nav{width:64px}:host.minified nav .nav-selector__header{align-items:center}:host.minified nav .nav-selector__content .entry{padding:var(--ref-spacing-xxxs)}:host.minified nav .nav-selector__footer{padding:var(--ref-spacing-xs) var(--ref-spacing-xxxs) var(--ref-spacing-xs) var(--ref-spacing-xxxs)}\n"] }]
|
|
2191
|
+
}], ctorParameters: () => [{ type: NavSelectorState }, { type: i0.ElementRef }] });
|
|
2192
|
+
|
|
2193
|
+
/**
|
|
2194
|
+
* Generated bundle index. Do not edit.
|
|
2195
|
+
*/
|
|
2196
|
+
|
|
2197
|
+
export { NavSelectorComponent };
|
|
2198
|
+
//# sourceMappingURL=agorapulse-ui-components-nav-selector.mjs.map
|