@star-ng/ui 0.1.0 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +14 -0
- package/fesm2022/star-ng-ui-autocomplete.mjs +8 -4
- package/fesm2022/star-ng-ui-autocomplete.mjs.map +1 -1
- package/fesm2022/star-ng-ui-core.mjs +93 -1
- package/fesm2022/star-ng-ui-core.mjs.map +1 -1
- package/fesm2022/star-ng-ui-data-display.mjs +361 -47
- package/fesm2022/star-ng-ui-data-display.mjs.map +1 -1
- package/fesm2022/star-ng-ui-listbox.mjs +11 -103
- package/fesm2022/star-ng-ui-listbox.mjs.map +1 -1
- package/fesm2022/star-ng-ui-select.mjs +78 -54
- package/fesm2022/star-ng-ui-select.mjs.map +1 -1
- package/fesm2022/star-ng-ui-table.mjs +77 -23
- package/fesm2022/star-ng-ui-table.mjs.map +1 -1
- package/fesm2022/star-ng-ui-tree.mjs +1 -1
- package/fesm2022/star-ng-ui-tree.mjs.map +1 -1
- package/package.json +5 -1
- package/styles/controls/_data-display.scss +6 -0
- package/styles/star-ng.css +4 -0
- package/styles/star-ng.min.css +1 -1
- package/types/star-ng-ui-core.d.ts +63 -0
- package/types/star-ng-ui-data-display.d.ts +110 -11
- package/types/star-ng-ui-listbox.d.ts +5 -32
- package/types/star-ng-ui-select.d.ts +38 -15
- package/types/star-ng-ui-table.d.ts +64 -8
- package/types/star-ng-ui-tree.d.ts +34 -1
|
@@ -1,56 +1,237 @@
|
|
|
1
1
|
import { _IdGenerator } from "@angular/cdk/a11y";
|
|
2
|
-
import { NgTemplateOutlet } from "@angular/common";
|
|
2
|
+
import { DOCUMENT, NgTemplateOutlet } from "@angular/common";
|
|
3
3
|
import * as i0 from "@angular/core";
|
|
4
|
-
import { ChangeDetectionStrategy, Component, Directive, TemplateRef, booleanAttribute, computed, contentChild, inject, input, model, output, signal } from "@angular/core";
|
|
4
|
+
import { ChangeDetectionStrategy, Component, Directive, TemplateRef, afterEveryRender, booleanAttribute, computed, contentChild, effect, inject, input, isDevMode, linkedSignal, model, numberAttribute, output, signal, untracked, viewChild } from "@angular/core";
|
|
5
5
|
import { STAR_UI_TEXT, optionText, readOption, starInlineKey } from "@star-ng/ui/core";
|
|
6
6
|
import { StarPaginator } from "@star-ng/ui/paginator";
|
|
7
|
+
import { flattenVisible, navigationTarget, parentsOf, rowIndexOf, scrollOffsetToReveal, stillFocusable } from "@star-ng/ui/tree";
|
|
8
|
+
function rowWindow(count, itemSize, scrollTop, viewportSize, bufferRows) {
|
|
9
|
+
if (count <= 0 || itemSize <= 0) return {
|
|
10
|
+
start: 0,
|
|
11
|
+
end: 0,
|
|
12
|
+
before: 0,
|
|
13
|
+
after: 0
|
|
14
|
+
};
|
|
15
|
+
const visible = Math.ceil(Math.max(0, viewportSize) / itemSize) + 1;
|
|
16
|
+
const first = Math.min(Math.max(0, Math.floor(Math.max(0, scrollTop) / itemSize)), Math.max(0, count - visible));
|
|
17
|
+
const start = Math.max(0, first - bufferRows);
|
|
18
|
+
const end = Math.min(count, first + visible + bufferRows);
|
|
19
|
+
return {
|
|
20
|
+
start,
|
|
21
|
+
end,
|
|
22
|
+
before: start * itemSize,
|
|
23
|
+
after: (count - end) * itemSize
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
function revealRowOffset(index, itemSize, scrollTop, viewportSize, headerSize) {
|
|
27
|
+
return scrollOffsetToReveal(index, itemSize, scrollTop, Math.max(itemSize, viewportSize - headerSize));
|
|
28
|
+
}
|
|
29
|
+
function ariaRowIndex(index) {
|
|
30
|
+
return index + 2;
|
|
31
|
+
}
|
|
32
|
+
function ariaRowCount(rowCount) {
|
|
33
|
+
return rowCount + 1;
|
|
34
|
+
}
|
|
35
|
+
const TREE_TABLE_ROW_HEIGHT = 53;
|
|
36
|
+
const BUFFER_ROWS = 8;
|
|
37
|
+
const FALLBACK_VIEWPORT = 600;
|
|
7
38
|
var StarTreeTable = class StarTreeTable {
|
|
8
39
|
text = inject(STAR_UI_TEXT);
|
|
40
|
+
doc = inject(DOCUMENT);
|
|
9
41
|
nodes = input([], ...ngDevMode ? [{ debugName: "nodes" }] : /* istanbul ignore next */ []);
|
|
10
42
|
columns = input.required(...ngDevMode ? [{ debugName: "columns" }] : /* istanbul ignore next */ []);
|
|
11
43
|
expanded = model([], ...ngDevMode ? [{ debugName: "expanded" }] : /* istanbul ignore next */ []);
|
|
12
44
|
ariaLabel = input(null, ...ngDevMode ? [{ debugName: "ariaLabel" }] : /* istanbul ignore next */ []);
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
45
|
+
scrollHeight = input(null, ...ngDevMode ? [{ debugName: "scrollHeight" }] : /* istanbul ignore next */ []);
|
|
46
|
+
virtualScroll = input(false, {
|
|
47
|
+
...ngDevMode ? { debugName: "virtualScroll" } : /* istanbul ignore next */ {},
|
|
48
|
+
transform: booleanAttribute
|
|
49
|
+
});
|
|
50
|
+
virtualItemSize = input(TREE_TABLE_ROW_HEIGHT, {
|
|
51
|
+
...ngDevMode ? { debugName: "virtualItemSize" } : /* istanbul ignore next */ {},
|
|
52
|
+
transform: numberAttribute
|
|
53
|
+
});
|
|
54
|
+
scroller = viewChild("scroller", ...ngDevMode ? [{ debugName: "scroller" }] : /* istanbul ignore next */ []);
|
|
55
|
+
header = viewChild("header", ...ngDevMode ? [{ debugName: "header" }] : /* istanbul ignore next */ []);
|
|
56
|
+
openKeys = computed(() => new Set(this.expanded()), ...ngDevMode ? [{ debugName: "openKeys" }] : /* istanbul ignore next */ []);
|
|
57
|
+
parents = computed(() => parentsOf(this.nodes()), ...ngDevMode ? [{ debugName: "parents" }] : /* istanbul ignore next */ []);
|
|
58
|
+
rows = computed(() => flattenVisible(this.nodes(), this.openKeys()), ...ngDevMode ? [{ debugName: "rows" }] : /* istanbul ignore next */ []);
|
|
59
|
+
rowIndex = computed(() => rowIndexOf(this.rows()), ...ngDevMode ? [{ debugName: "rowIndex" }] : /* istanbul ignore next */ []);
|
|
60
|
+
focusKey = linkedSignal({
|
|
61
|
+
...ngDevMode ? { debugName: "focusKey" } : /* istanbul ignore next */ {},
|
|
62
|
+
source: this.rows,
|
|
63
|
+
computation: (rows, previous) => stillFocusable(previous?.value, this.rowIndex(), this.parents(), rows[0]?.node.key ?? null)
|
|
64
|
+
});
|
|
65
|
+
windowed = computed(() => this.virtualScroll() && !!this.scrollHeight() && this.virtualItemSize() > 0, ...ngDevMode ? [{ debugName: "windowed" }] : /* istanbul ignore next */ []);
|
|
66
|
+
scrollTop = signal(0, ...ngDevMode ? [{ debugName: "scrollTop" }] : /* istanbul ignore next */ []);
|
|
67
|
+
viewportHeight = signal(0, ...ngDevMode ? [{ debugName: "viewportHeight" }] : /* istanbul ignore next */ []);
|
|
68
|
+
window = computed(() => {
|
|
69
|
+
if (!this.windowed()) return {
|
|
70
|
+
start: 0,
|
|
71
|
+
end: this.rows().length,
|
|
72
|
+
before: 0,
|
|
73
|
+
after: 0
|
|
74
|
+
};
|
|
75
|
+
return rowWindow(this.rows().length, this.virtualItemSize(), this.scrollTop(), this.viewportHeight() || FALLBACK_VIEWPORT, BUFFER_ROWS);
|
|
76
|
+
}, {
|
|
77
|
+
...ngDevMode ? { debugName: "window" } : /* istanbul ignore next */ {},
|
|
78
|
+
equal: (a, b) => a.start === b.start && a.end === b.end && a.before === b.before && a.after === b.after
|
|
79
|
+
});
|
|
80
|
+
entries = computed(() => {
|
|
81
|
+
const rows = this.rows();
|
|
82
|
+
if (!this.windowed()) return rows.map((row) => ({
|
|
83
|
+
row,
|
|
84
|
+
aria: null
|
|
85
|
+
}));
|
|
86
|
+
const { start, end } = this.window();
|
|
87
|
+
return rows.slice(start, end).map((row, i) => ({
|
|
88
|
+
row,
|
|
89
|
+
aria: ariaRowIndex(start + i)
|
|
90
|
+
}));
|
|
91
|
+
}, ...ngDevMode ? [{ debugName: "entries" }] : /* istanbul ignore next */ []);
|
|
92
|
+
activeRendered = computed(() => {
|
|
93
|
+
const index = this.rowIndex().get(this.focusKey() ?? "");
|
|
94
|
+
const { start, end } = this.window();
|
|
95
|
+
return index !== void 0 && index >= start && index < end;
|
|
96
|
+
}, ...ngDevMode ? [{ debugName: "activeRendered" }] : /* istanbul ignore next */ []);
|
|
97
|
+
ariaRowCount = ariaRowCount;
|
|
98
|
+
pendingFocus = null;
|
|
99
|
+
parked = false;
|
|
100
|
+
constructor() {
|
|
101
|
+
effect(() => {
|
|
102
|
+
const window = this.window();
|
|
103
|
+
this.rowIndex();
|
|
104
|
+
untracked(() => {
|
|
105
|
+
if (this.windowed()) this.parkFocus(window);
|
|
22
106
|
});
|
|
23
|
-
if (node.children?.length && open.has(node.key)) walk(node.children, level + 1);
|
|
24
107
|
});
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
108
|
+
effect((onCleanup) => {
|
|
109
|
+
const scroller = this.scroller()?.nativeElement;
|
|
110
|
+
if (!this.windowed() || !scroller || typeof ResizeObserver === "undefined") return;
|
|
111
|
+
const observer = new ResizeObserver(() => this.syncScroll());
|
|
112
|
+
observer.observe(scroller);
|
|
113
|
+
onCleanup(() => observer.disconnect());
|
|
114
|
+
});
|
|
115
|
+
afterEveryRender({ read: () => this.syncScroll() });
|
|
116
|
+
afterEveryRender(() => {
|
|
117
|
+
this.applyPendingFocus();
|
|
118
|
+
if (this.parked) this.restoreParkedFocus();
|
|
119
|
+
});
|
|
120
|
+
if (isDevMode()) effect(() => {
|
|
121
|
+
if (this.virtualScroll() && !this.scrollHeight()) console.warn("star-tree-table: virtualScroll needs scrollHeight. Without it the table renders all rows.");
|
|
122
|
+
});
|
|
123
|
+
}
|
|
29
124
|
isOpen(key) {
|
|
30
|
-
return this.
|
|
125
|
+
return this.openKeys().has(key);
|
|
31
126
|
}
|
|
32
127
|
toggle(key, open = !this.isOpen(key)) {
|
|
33
|
-
this.expanded.update((keys) =>
|
|
128
|
+
this.expanded.update((keys) => {
|
|
129
|
+
if (!open) return keys.filter((k) => k !== key);
|
|
130
|
+
return keys.includes(key) ? keys : [...keys, key];
|
|
131
|
+
});
|
|
132
|
+
}
|
|
133
|
+
syncScroll() {
|
|
134
|
+
const scroller = this.scroller()?.nativeElement;
|
|
135
|
+
if (!scroller || !this.windowed()) return;
|
|
136
|
+
this.scrollTop.set(scroller.scrollTop);
|
|
137
|
+
if (scroller.clientHeight) this.viewportHeight.set(scroller.clientHeight);
|
|
138
|
+
}
|
|
139
|
+
onRowFocus(event, key) {
|
|
140
|
+
this.focusKey.set(key);
|
|
141
|
+
this.pendingFocus = null;
|
|
142
|
+
this.parked = false;
|
|
143
|
+
if (event.target === event.currentTarget && this.windowed()) this.revealRow(key);
|
|
144
|
+
}
|
|
145
|
+
focusRow(key) {
|
|
146
|
+
if (!key) return;
|
|
147
|
+
this.focusKey.set(key);
|
|
148
|
+
this.pendingFocus = key;
|
|
149
|
+
if (this.windowed()) this.revealRow(key);
|
|
150
|
+
queueMicrotask(() => this.applyPendingFocus());
|
|
151
|
+
}
|
|
152
|
+
revealRow(key) {
|
|
153
|
+
const scroller = this.scroller()?.nativeElement;
|
|
154
|
+
const index = this.rowIndex().get(key);
|
|
155
|
+
if (!scroller || index === void 0) return;
|
|
156
|
+
const offset = revealRowOffset(index, this.virtualItemSize(), scroller.scrollTop, scroller.clientHeight, this.header()?.nativeElement.offsetHeight ?? 0);
|
|
157
|
+
if (offset === null) return;
|
|
158
|
+
scroller.scrollTop = offset;
|
|
159
|
+
this.syncScroll();
|
|
160
|
+
}
|
|
161
|
+
rowElement(key) {
|
|
162
|
+
return this.scroller()?.nativeElement.querySelector(`tbody > tr[data-key="${CSS.escape(key)}"]`) ?? null;
|
|
163
|
+
}
|
|
164
|
+
applyPendingFocus() {
|
|
165
|
+
const key = this.pendingFocus;
|
|
166
|
+
if (key === null) return;
|
|
167
|
+
if (!this.rowIndex().has(key)) {
|
|
168
|
+
this.pendingFocus = null;
|
|
169
|
+
return;
|
|
170
|
+
}
|
|
171
|
+
const row = this.rowElement(key);
|
|
172
|
+
if (!row) return;
|
|
173
|
+
this.pendingFocus = null;
|
|
174
|
+
row.focus({ preventScroll: this.windowed() });
|
|
175
|
+
}
|
|
176
|
+
parkFocus(window) {
|
|
177
|
+
const scroller = this.scroller()?.nativeElement;
|
|
178
|
+
const active = this.doc.activeElement;
|
|
179
|
+
if (!scroller || !active || active === scroller || !scroller.contains(active)) return;
|
|
180
|
+
const key = active.closest("tbody > tr[data-key]")?.dataset["key"];
|
|
181
|
+
const index = key === void 0 ? void 0 : this.rowIndex().get(key);
|
|
182
|
+
if (index !== void 0 && index >= window.start && index < window.end) return;
|
|
183
|
+
this.parked = true;
|
|
184
|
+
scroller.focus({ preventScroll: true });
|
|
185
|
+
}
|
|
186
|
+
restoreParkedFocus() {
|
|
187
|
+
const scroller = this.scroller()?.nativeElement;
|
|
188
|
+
if (!scroller || this.doc.activeElement !== scroller) {
|
|
189
|
+
this.parked = false;
|
|
190
|
+
return;
|
|
191
|
+
}
|
|
192
|
+
const key = this.focusKey();
|
|
193
|
+
if (key === null) return;
|
|
194
|
+
this.rowElement(key)?.focus({ preventScroll: true });
|
|
195
|
+
}
|
|
196
|
+
onScrollerFocus() {
|
|
197
|
+
if (this.windowed() && !this.parked) this.focusRow(this.focusKey());
|
|
198
|
+
}
|
|
199
|
+
onScrollerKeydown(event) {
|
|
200
|
+
if (!this.windowed() || event.target !== event.currentTarget) return;
|
|
201
|
+
const row = this.rows()[this.rowIndex().get(this.focusKey() ?? "") ?? -1];
|
|
202
|
+
if (row) this.onKeydown(event, row);
|
|
34
203
|
}
|
|
35
204
|
onKeydown(event, row) {
|
|
36
205
|
const rows = this.rows();
|
|
37
|
-
const
|
|
38
|
-
const
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
this.focusKey.set(target.node.key);
|
|
42
|
-
(event.currentTarget.closest("tbody")?.querySelector(`[data-key="${CSS.escape(target.node.key)}"]`))?.focus();
|
|
43
|
-
};
|
|
206
|
+
const item = this.pendingFocus === null ? row : rows[this.rowIndex().get(this.pendingFocus) ?? -1] ?? row;
|
|
207
|
+
const index = this.rowIndex().get(item.node.key) ?? -1;
|
|
208
|
+
const hasChildren = !!item.node.children?.length;
|
|
209
|
+
const expanded = hasChildren && this.isOpen(item.node.key);
|
|
44
210
|
const key = starInlineKey(event);
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
else if (key === "ArrowRight" && row.node.children?.length) {
|
|
211
|
+
const move = (target) => {
|
|
212
|
+
if (target === null) return;
|
|
48
213
|
event.preventDefault();
|
|
49
|
-
this.
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
214
|
+
this.focusRow(target);
|
|
215
|
+
};
|
|
216
|
+
switch (key) {
|
|
217
|
+
case "ArrowDown":
|
|
218
|
+
case "ArrowUp":
|
|
219
|
+
case "Home":
|
|
220
|
+
case "End": return move(navigationTarget(rows, index, key, {
|
|
221
|
+
hasChildren,
|
|
222
|
+
expanded
|
|
223
|
+
}));
|
|
224
|
+
case "ArrowRight":
|
|
225
|
+
if (hasChildren) {
|
|
226
|
+
event.preventDefault();
|
|
227
|
+
if (!expanded) this.toggle(item.node.key, true);
|
|
228
|
+
}
|
|
229
|
+
return;
|
|
230
|
+
case "ArrowLeft":
|
|
231
|
+
event.preventDefault();
|
|
232
|
+
if (expanded) this.toggle(item.node.key, false);
|
|
233
|
+
else move(item.parentKey);
|
|
234
|
+
return;
|
|
54
235
|
}
|
|
55
236
|
}
|
|
56
237
|
static ɵfac = i0.ɵɵngDeclareFactory({
|
|
@@ -95,16 +276,72 @@ var StarTreeTable = class StarTreeTable {
|
|
|
95
276
|
isSignal: true,
|
|
96
277
|
isRequired: false,
|
|
97
278
|
transformFunction: null
|
|
279
|
+
},
|
|
280
|
+
scrollHeight: {
|
|
281
|
+
classPropertyName: "scrollHeight",
|
|
282
|
+
publicName: "scrollHeight",
|
|
283
|
+
isSignal: true,
|
|
284
|
+
isRequired: false,
|
|
285
|
+
transformFunction: null
|
|
286
|
+
},
|
|
287
|
+
virtualScroll: {
|
|
288
|
+
classPropertyName: "virtualScroll",
|
|
289
|
+
publicName: "virtualScroll",
|
|
290
|
+
isSignal: true,
|
|
291
|
+
isRequired: false,
|
|
292
|
+
transformFunction: null
|
|
293
|
+
},
|
|
294
|
+
virtualItemSize: {
|
|
295
|
+
classPropertyName: "virtualItemSize",
|
|
296
|
+
publicName: "virtualItemSize",
|
|
297
|
+
isSignal: true,
|
|
298
|
+
isRequired: false,
|
|
299
|
+
transformFunction: null
|
|
98
300
|
}
|
|
99
301
|
},
|
|
100
302
|
outputs: { expanded: "expandedChange" },
|
|
101
|
-
host: {
|
|
303
|
+
host: {
|
|
304
|
+
properties: {
|
|
305
|
+
"class.star-table--sticky": "!!scrollHeight()",
|
|
306
|
+
"class.star-table--virtual": "windowed()",
|
|
307
|
+
"style.--star-table-row-height.px": "windowed() ? virtualItemSize() : null"
|
|
308
|
+
},
|
|
309
|
+
classAttribute: "star-table star-tree-table"
|
|
310
|
+
},
|
|
311
|
+
viewQueries: [{
|
|
312
|
+
propertyName: "scroller",
|
|
313
|
+
first: true,
|
|
314
|
+
predicate: ["scroller"],
|
|
315
|
+
descendants: true,
|
|
316
|
+
isSignal: true
|
|
317
|
+
}, {
|
|
318
|
+
propertyName: "header",
|
|
319
|
+
first: true,
|
|
320
|
+
predicate: ["header"],
|
|
321
|
+
descendants: true,
|
|
322
|
+
isSignal: true
|
|
323
|
+
}],
|
|
102
324
|
ngImport: i0,
|
|
103
325
|
template: `
|
|
104
|
-
<div
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
326
|
+
<div
|
|
327
|
+
#scroller
|
|
328
|
+
class="star-table__scroll"
|
|
329
|
+
[attr.role]="windowed() ? 'group' : null"
|
|
330
|
+
[attr.aria-label]="windowed() ? ariaLabel() : null"
|
|
331
|
+
[attr.tabindex]="windowed() ? (activeRendered() ? -1 : 0) : null"
|
|
332
|
+
[style.max-height]="scrollHeight()"
|
|
333
|
+
(scroll)="syncScroll()"
|
|
334
|
+
(focus)="onScrollerFocus()"
|
|
335
|
+
(blur)="parked = false"
|
|
336
|
+
(keydown)="onScrollerKeydown($event)"
|
|
337
|
+
>
|
|
338
|
+
<table
|
|
339
|
+
role="treegrid"
|
|
340
|
+
[attr.aria-label]="ariaLabel()"
|
|
341
|
+
[attr.aria-rowcount]="windowed() ? ariaRowCount(rows().length) : null"
|
|
342
|
+
>
|
|
343
|
+
<thead #header>
|
|
344
|
+
<tr [attr.aria-rowindex]="windowed() ? 1 : null">
|
|
108
345
|
@for (column of columns(); track column.field) {
|
|
109
346
|
<th
|
|
110
347
|
scope="col"
|
|
@@ -117,9 +354,16 @@ var StarTreeTable = class StarTreeTable {
|
|
|
117
354
|
</tr>
|
|
118
355
|
</thead>
|
|
119
356
|
<tbody>
|
|
120
|
-
@
|
|
357
|
+
@if (window().before > 0) {
|
|
358
|
+
<tr class="star-table__spacer" aria-hidden="true">
|
|
359
|
+
<td [attr.colspan]="columns().length" [style.height.px]="window().before"></td>
|
|
360
|
+
</tr>
|
|
361
|
+
}
|
|
362
|
+
@for (entry of entries(); track entry.row.node.key) {
|
|
363
|
+
@let row = entry.row;
|
|
121
364
|
<tr
|
|
122
365
|
class="star-table__row"
|
|
366
|
+
[attr.aria-rowindex]="entry.aria"
|
|
123
367
|
[attr.aria-level]="row.level"
|
|
124
368
|
[attr.aria-setsize]="row.setSize"
|
|
125
369
|
[attr.aria-posinset]="row.position"
|
|
@@ -127,7 +371,7 @@ var StarTreeTable = class StarTreeTable {
|
|
|
127
371
|
[attr.tabindex]="focusKey() === row.node.key ? 0 : -1"
|
|
128
372
|
[attr.data-key]="row.node.key"
|
|
129
373
|
(keydown)="onKeydown($event, row)"
|
|
130
|
-
(
|
|
374
|
+
(focusin)="onRowFocus($event, row.node.key)"
|
|
131
375
|
>
|
|
132
376
|
@for (column of columns(); track column.field; let first = $first) {
|
|
133
377
|
<td [class]="'star-table__cell--' + (column.align ?? 'start')">
|
|
@@ -159,6 +403,11 @@ var StarTreeTable = class StarTreeTable {
|
|
|
159
403
|
}
|
|
160
404
|
</tr>
|
|
161
405
|
}
|
|
406
|
+
@if (window().after > 0) {
|
|
407
|
+
<tr class="star-table__spacer" aria-hidden="true">
|
|
408
|
+
<td [attr.colspan]="columns().length" [style.height.px]="window().after"></td>
|
|
409
|
+
</tr>
|
|
410
|
+
}
|
|
162
411
|
</tbody>
|
|
163
412
|
</table>
|
|
164
413
|
</div>
|
|
@@ -177,12 +426,32 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
177
426
|
args: [{
|
|
178
427
|
selector: "star-tree-table",
|
|
179
428
|
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
180
|
-
host: {
|
|
429
|
+
host: {
|
|
430
|
+
class: "star-table star-tree-table",
|
|
431
|
+
"[class.star-table--sticky]": "!!scrollHeight()",
|
|
432
|
+
"[class.star-table--virtual]": "windowed()",
|
|
433
|
+
"[style.--star-table-row-height.px]": "windowed() ? virtualItemSize() : null"
|
|
434
|
+
},
|
|
181
435
|
template: `
|
|
182
|
-
<div
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
436
|
+
<div
|
|
437
|
+
#scroller
|
|
438
|
+
class="star-table__scroll"
|
|
439
|
+
[attr.role]="windowed() ? 'group' : null"
|
|
440
|
+
[attr.aria-label]="windowed() ? ariaLabel() : null"
|
|
441
|
+
[attr.tabindex]="windowed() ? (activeRendered() ? -1 : 0) : null"
|
|
442
|
+
[style.max-height]="scrollHeight()"
|
|
443
|
+
(scroll)="syncScroll()"
|
|
444
|
+
(focus)="onScrollerFocus()"
|
|
445
|
+
(blur)="parked = false"
|
|
446
|
+
(keydown)="onScrollerKeydown($event)"
|
|
447
|
+
>
|
|
448
|
+
<table
|
|
449
|
+
role="treegrid"
|
|
450
|
+
[attr.aria-label]="ariaLabel()"
|
|
451
|
+
[attr.aria-rowcount]="windowed() ? ariaRowCount(rows().length) : null"
|
|
452
|
+
>
|
|
453
|
+
<thead #header>
|
|
454
|
+
<tr [attr.aria-rowindex]="windowed() ? 1 : null">
|
|
186
455
|
@for (column of columns(); track column.field) {
|
|
187
456
|
<th
|
|
188
457
|
scope="col"
|
|
@@ -195,9 +464,16 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
195
464
|
</tr>
|
|
196
465
|
</thead>
|
|
197
466
|
<tbody>
|
|
198
|
-
@
|
|
467
|
+
@if (window().before > 0) {
|
|
468
|
+
<tr class="star-table__spacer" aria-hidden="true">
|
|
469
|
+
<td [attr.colspan]="columns().length" [style.height.px]="window().before"></td>
|
|
470
|
+
</tr>
|
|
471
|
+
}
|
|
472
|
+
@for (entry of entries(); track entry.row.node.key) {
|
|
473
|
+
@let row = entry.row;
|
|
199
474
|
<tr
|
|
200
475
|
class="star-table__row"
|
|
476
|
+
[attr.aria-rowindex]="entry.aria"
|
|
201
477
|
[attr.aria-level]="row.level"
|
|
202
478
|
[attr.aria-setsize]="row.setSize"
|
|
203
479
|
[attr.aria-posinset]="row.position"
|
|
@@ -205,7 +481,7 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
205
481
|
[attr.tabindex]="focusKey() === row.node.key ? 0 : -1"
|
|
206
482
|
[attr.data-key]="row.node.key"
|
|
207
483
|
(keydown)="onKeydown($event, row)"
|
|
208
|
-
(
|
|
484
|
+
(focusin)="onRowFocus($event, row.node.key)"
|
|
209
485
|
>
|
|
210
486
|
@for (column of columns(); track column.field; let first = $first) {
|
|
211
487
|
<td [class]="'star-table__cell--' + (column.align ?? 'start')">
|
|
@@ -237,12 +513,18 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
237
513
|
}
|
|
238
514
|
</tr>
|
|
239
515
|
}
|
|
516
|
+
@if (window().after > 0) {
|
|
517
|
+
<tr class="star-table__spacer" aria-hidden="true">
|
|
518
|
+
<td [attr.colspan]="columns().length" [style.height.px]="window().after"></td>
|
|
519
|
+
</tr>
|
|
520
|
+
}
|
|
240
521
|
</tbody>
|
|
241
522
|
</table>
|
|
242
523
|
</div>
|
|
243
524
|
`
|
|
244
525
|
}]
|
|
245
526
|
}],
|
|
527
|
+
ctorParameters: () => [],
|
|
246
528
|
propDecorators: {
|
|
247
529
|
nodes: [{
|
|
248
530
|
type: i0.Input,
|
|
@@ -278,6 +560,38 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
278
560
|
alias: "ariaLabel",
|
|
279
561
|
required: false
|
|
280
562
|
}]
|
|
563
|
+
}],
|
|
564
|
+
scrollHeight: [{
|
|
565
|
+
type: i0.Input,
|
|
566
|
+
args: [{
|
|
567
|
+
isSignal: true,
|
|
568
|
+
alias: "scrollHeight",
|
|
569
|
+
required: false
|
|
570
|
+
}]
|
|
571
|
+
}],
|
|
572
|
+
virtualScroll: [{
|
|
573
|
+
type: i0.Input,
|
|
574
|
+
args: [{
|
|
575
|
+
isSignal: true,
|
|
576
|
+
alias: "virtualScroll",
|
|
577
|
+
required: false
|
|
578
|
+
}]
|
|
579
|
+
}],
|
|
580
|
+
virtualItemSize: [{
|
|
581
|
+
type: i0.Input,
|
|
582
|
+
args: [{
|
|
583
|
+
isSignal: true,
|
|
584
|
+
alias: "virtualItemSize",
|
|
585
|
+
required: false
|
|
586
|
+
}]
|
|
587
|
+
}],
|
|
588
|
+
scroller: [{
|
|
589
|
+
type: i0.ViewChild,
|
|
590
|
+
args: ["scroller", { isSignal: true }]
|
|
591
|
+
}],
|
|
592
|
+
header: [{
|
|
593
|
+
type: i0.ViewChild,
|
|
594
|
+
args: ["header", { isSignal: true }]
|
|
281
595
|
}]
|
|
282
596
|
}
|
|
283
597
|
});
|