@rivinia/table 0.0.0-stage → 1.0.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/CHANGELOG.md +6 -0
- package/LICENSE +21 -0
- package/README.md +291 -2
- package/fesm2022/rivinia-table-ui.mjs +881 -0
- package/fesm2022/rivinia-table-ui.mjs.map +1 -0
- package/fesm2022/rivinia-table.mjs +813 -0
- package/fesm2022/rivinia-table.mjs.map +1 -0
- package/package.json +47 -3
- package/types/rivinia-table-ui.d.ts +508 -0
- package/types/rivinia-table.d.ts +490 -0
|
@@ -0,0 +1,881 @@
|
|
|
1
|
+
import { NgTemplateOutlet } from "@angular/common";
|
|
2
|
+
import * as i0 from "@angular/core";
|
|
3
|
+
import { ChangeDetectionStrategy, Component, Directive, ElementRef, TemplateRef, afterRenderEffect, computed, contentChildren, inject, input, isDevMode, model, output, signal, viewChild } from "@angular/core";
|
|
4
|
+
const TABLE_UI_LABELS_EN = {
|
|
5
|
+
grid: "Data grid",
|
|
6
|
+
loading: "Loading…",
|
|
7
|
+
error: "The data could not be loaded.",
|
|
8
|
+
empty: "No rows to show.",
|
|
9
|
+
keyboardHelp: "Use the arrow keys to move between cells, Home and End for the first and last cell of a row, Page Up and Page Down to move a screen at a time, Enter to open the focused row, and Space to select it."
|
|
10
|
+
};
|
|
11
|
+
const TABLE_UI_LABELS_AR = {
|
|
12
|
+
grid: "شبكة بيانات",
|
|
13
|
+
loading: "جارٍ التحميل…",
|
|
14
|
+
error: "تعذّر تحميل البيانات.",
|
|
15
|
+
empty: "لا توجد صفوف لعرضها.",
|
|
16
|
+
keyboardHelp: "استخدم مفاتيح الأسهم للتنقل بين الخلايا، و Home و End لأول خلية وآخر خلية في الصف، و Page Up و Page Down للتنقل شاشةً كاملة، و Enter لفتح الصف الذي عليه التركيز، ومسافة لتحديده."
|
|
17
|
+
};
|
|
18
|
+
function tableUiLabels(locale) {
|
|
19
|
+
return locale?.toLowerCase().startsWith("ar") ? TABLE_UI_LABELS_AR : TABLE_UI_LABELS_EN;
|
|
20
|
+
}
|
|
21
|
+
var RvTableCell = class RvTableCell {
|
|
22
|
+
columnId = input.required({
|
|
23
|
+
...ngDevMode ? { debugName: "columnId" } : /* istanbul ignore next */ {},
|
|
24
|
+
alias: "rvTableCell"
|
|
25
|
+
});
|
|
26
|
+
template = inject(TemplateRef);
|
|
27
|
+
static ɵfac = i0.ɵɵngDeclareFactory({
|
|
28
|
+
minVersion: "12.0.0",
|
|
29
|
+
version: "22.2.3",
|
|
30
|
+
ngImport: i0,
|
|
31
|
+
type: RvTableCell,
|
|
32
|
+
deps: [],
|
|
33
|
+
target: i0.ɵɵFactoryTarget.Directive
|
|
34
|
+
});
|
|
35
|
+
static ɵdir = i0.ɵɵngDeclareDirective({
|
|
36
|
+
minVersion: "17.1.0",
|
|
37
|
+
version: "22.2.3",
|
|
38
|
+
type: RvTableCell,
|
|
39
|
+
isStandalone: true,
|
|
40
|
+
selector: "[rvTableCell]",
|
|
41
|
+
inputs: { columnId: {
|
|
42
|
+
classPropertyName: "columnId",
|
|
43
|
+
publicName: "rvTableCell",
|
|
44
|
+
isSignal: true,
|
|
45
|
+
isRequired: true,
|
|
46
|
+
transformFunction: null
|
|
47
|
+
} },
|
|
48
|
+
ngImport: i0
|
|
49
|
+
});
|
|
50
|
+
};
|
|
51
|
+
i0.ɵɵngDeclareClassMetadata({
|
|
52
|
+
minVersion: "12.0.0",
|
|
53
|
+
version: "22.2.3",
|
|
54
|
+
ngImport: i0,
|
|
55
|
+
type: RvTableCell,
|
|
56
|
+
decorators: [{
|
|
57
|
+
type: Directive,
|
|
58
|
+
args: [{ selector: "[rvTableCell]" }]
|
|
59
|
+
}],
|
|
60
|
+
propDecorators: { columnId: [{
|
|
61
|
+
type: i0.Input,
|
|
62
|
+
args: [{
|
|
63
|
+
isSignal: true,
|
|
64
|
+
alias: "rvTableCell",
|
|
65
|
+
required: true
|
|
66
|
+
}]
|
|
67
|
+
}] }
|
|
68
|
+
});
|
|
69
|
+
let nextTableId = 0;
|
|
70
|
+
const DEFAULT_COLUMN_WIDTH = "10rem";
|
|
71
|
+
var RiviniaTableComponent = class RiviniaTableComponent {
|
|
72
|
+
host = inject(ElementRef);
|
|
73
|
+
scroller = viewChild("scroll", ...ngDevMode ? [{ debugName: "scroller" }] : /* istanbul ignore next */ []);
|
|
74
|
+
projectedCells = contentChildren(RvTableCell, ...ngDevMode ? [{ debugName: "projectedCells" }] : /* istanbul ignore next */ []);
|
|
75
|
+
columns = input.required(...ngDevMode ? [{ debugName: "columns" }] : /* istanbul ignore next */ []);
|
|
76
|
+
rows = input([], ...ngDevMode ? [{ debugName: "rows" }] : /* istanbul ignore next */ []);
|
|
77
|
+
spans = input(null, ...ngDevMode ? [{ debugName: "spans" }] : /* istanbul ignore next */ []);
|
|
78
|
+
loading = input(false, ...ngDevMode ? [{ debugName: "loading" }] : /* istanbul ignore next */ []);
|
|
79
|
+
skeletonRows = input("auto", ...ngDevMode ? [{ debugName: "skeletonRows" }] : /* istanbul ignore next */ []);
|
|
80
|
+
error = input(null, ...ngDevMode ? [{ debugName: "error" }] : /* istanbul ignore next */ []);
|
|
81
|
+
emptyMessage = input(void 0, ...ngDevMode ? [{ debugName: "emptyMessage" }] : /* istanbul ignore next */ []);
|
|
82
|
+
rowKey = input(void 0, ...ngDevMode ? [{ debugName: "rowKey" }] : /* istanbul ignore next */ []);
|
|
83
|
+
selectable = input(false, ...ngDevMode ? [{ debugName: "selectable" }] : /* istanbul ignore next */ []);
|
|
84
|
+
selected = model(/* @__PURE__ */ new Set(), ...ngDevMode ? [{ debugName: "selected" }] : /* istanbul ignore next */ []);
|
|
85
|
+
sort = model([], ...ngDevMode ? [{ debugName: "sort" }] : /* istanbul ignore next */ []);
|
|
86
|
+
density = input("default", ...ngDevMode ? [{ debugName: "density" }] : /* istanbul ignore next */ []);
|
|
87
|
+
stickyHeader = input(true, ...ngDevMode ? [{ debugName: "stickyHeader" }] : /* istanbul ignore next */ []);
|
|
88
|
+
totalRows = input(void 0, ...ngDevMode ? [{ debugName: "totalRows" }] : /* istanbul ignore next */ []);
|
|
89
|
+
ariaLabel = input(void 0, ...ngDevMode ? [{ debugName: "ariaLabel" }] : /* istanbul ignore next */ []);
|
|
90
|
+
labels = input(void 0, ...ngDevMode ? [{ debugName: "labels" }] : /* istanbul ignore next */ []);
|
|
91
|
+
rowActivate = output();
|
|
92
|
+
selectionChange = output();
|
|
93
|
+
instructionsId = `rv-table-help-${++nextTableId}`;
|
|
94
|
+
uid = nextTableId;
|
|
95
|
+
visibleColumns = computed(() => this.columns().filter((column) => column.hidden !== true), ...ngDevMode ? [{ debugName: "visibleColumns" }] : /* istanbul ignore next */ []);
|
|
96
|
+
columnCount = computed(() => this.visibleColumns().length, ...ngDevMode ? [{ debugName: "columnCount" }] : /* istanbul ignore next */ []);
|
|
97
|
+
columnTemplate = computed(() => {
|
|
98
|
+
const tracks = this.visibleColumns().map((column) => {
|
|
99
|
+
const width = column.width ?? DEFAULT_COLUMN_WIDTH;
|
|
100
|
+
const flex = column.flex ?? 0;
|
|
101
|
+
return flex > 0 ? `minmax(${width}, ${flex}fr)` : width;
|
|
102
|
+
});
|
|
103
|
+
return tracks.length > 0 ? tracks.join(" ") : "1fr";
|
|
104
|
+
}, ...ngDevMode ? [{ debugName: "columnTemplate" }] : /* istanbul ignore next */ []);
|
|
105
|
+
minWidth = computed(() => {
|
|
106
|
+
const widths = this.visibleColumns().map((column) => `(${column.width ?? DEFAULT_COLUMN_WIDTH})`);
|
|
107
|
+
return `calc(${widths.length > 0 ? widths.join(" + ") : "0px"})`;
|
|
108
|
+
}, ...ngDevMode ? [{ debugName: "minWidth" }] : /* istanbul ignore next */ []);
|
|
109
|
+
get hostLabel() {
|
|
110
|
+
const label = this.host.nativeElement.getAttribute("aria-label")?.trim();
|
|
111
|
+
return label ? label : void 0;
|
|
112
|
+
}
|
|
113
|
+
effectiveLabels = computed(() => ({
|
|
114
|
+
...tableUiLabels(this.locale()),
|
|
115
|
+
...this.labels()
|
|
116
|
+
}), ...ngDevMode ? [{ debugName: "effectiveLabels" }] : /* istanbul ignore next */ []);
|
|
117
|
+
locale = computed(() => {
|
|
118
|
+
const pageLanguage = typeof document !== "undefined" ? document.documentElement.lang : "";
|
|
119
|
+
if (pageLanguage) return pageLanguage;
|
|
120
|
+
return (typeof navigator !== "undefined" ? navigator.language : "") || "en-US";
|
|
121
|
+
}, ...ngDevMode ? [{ debugName: "locale" }] : /* istanbul ignore next */ []);
|
|
122
|
+
cellTemplates = computed(() => {
|
|
123
|
+
const templates = /* @__PURE__ */ new Map();
|
|
124
|
+
for (const directive of this.projectedCells()) templates.set(directive.columnId(), directive.template);
|
|
125
|
+
return templates;
|
|
126
|
+
}, ...ngDevMode ? [{ debugName: "cellTemplates" }] : /* istanbul ignore next */ []);
|
|
127
|
+
sortIndex = computed(() => {
|
|
128
|
+
const index = /* @__PURE__ */ new Map();
|
|
129
|
+
this.sort().forEach((entry, position) => index.set(entry.column, {
|
|
130
|
+
direction: entry.direction,
|
|
131
|
+
rank: position + 1
|
|
132
|
+
}));
|
|
133
|
+
return index;
|
|
134
|
+
}, ...ngDevMode ? [{ debugName: "sortIndex" }] : /* istanbul ignore next */ []);
|
|
135
|
+
renderedRows = computed(() => {
|
|
136
|
+
const templates = this.cellTemplates();
|
|
137
|
+
const selected = this.selected();
|
|
138
|
+
const ids = /* @__PURE__ */ new Map();
|
|
139
|
+
const rendered = this.rows().map((row, rowIndex) => {
|
|
140
|
+
const id = this.rowId(row);
|
|
141
|
+
const validId = typeof id === "string" && id.trim().length > 0 || typeof id === "number" && Number.isFinite(id);
|
|
142
|
+
const positions = validId ? ids.get(id) ?? [] : [];
|
|
143
|
+
if (validId) {
|
|
144
|
+
positions.push(rowIndex);
|
|
145
|
+
ids.set(id, positions);
|
|
146
|
+
} else if (isDevMode()) throw new Error(`[rivinia/table/ui] Invalid row ID ${String(id)} at row index ${rowIndex}.`);
|
|
147
|
+
return {
|
|
148
|
+
id,
|
|
149
|
+
identityValid: row.identityValid !== false && validId,
|
|
150
|
+
row,
|
|
151
|
+
rowIndex,
|
|
152
|
+
ariaRowIndex: (Number.isFinite(row.index) ? row.index : rowIndex) + 2,
|
|
153
|
+
selected: row.identityValid !== false && validId && selected.has(id),
|
|
154
|
+
cells: this.buildCells(row, rowIndex, templates)
|
|
155
|
+
};
|
|
156
|
+
});
|
|
157
|
+
for (const [id, positions] of ids) {
|
|
158
|
+
if (positions.length < 2) continue;
|
|
159
|
+
if (isDevMode()) throw new Error(`[rivinia/table/ui] Duplicate row ID ${JSON.stringify(id)} at row indices ${positions.join(", ")}.`);
|
|
160
|
+
for (const index of positions) rendered[index].identityValid = false;
|
|
161
|
+
}
|
|
162
|
+
return rendered;
|
|
163
|
+
}, ...ngDevMode ? [{ debugName: "renderedRows" }] : /* istanbul ignore next */ []);
|
|
164
|
+
skeletonList = computed(() => {
|
|
165
|
+
const requested = this.loading() ? this.skeletonRows() : 0;
|
|
166
|
+
const count = requested === "auto" ? Math.max(1, this.rows().length) : requested;
|
|
167
|
+
return Array.from({ length: Math.max(0, Math.floor(count)) });
|
|
168
|
+
}, ...ngDevMode ? [{ debugName: "skeletonList" }] : /* istanbul ignore next */ []);
|
|
169
|
+
state = computed(() => {
|
|
170
|
+
if (this.loading()) return null;
|
|
171
|
+
const error = this.error();
|
|
172
|
+
if (error !== null && error !== void 0) return {
|
|
173
|
+
kind: "error",
|
|
174
|
+
message: this.errorText(error)
|
|
175
|
+
};
|
|
176
|
+
if (this.rows().length === 0) return {
|
|
177
|
+
kind: "empty",
|
|
178
|
+
message: this.emptyMessage() ?? this.effectiveLabels().empty
|
|
179
|
+
};
|
|
180
|
+
return null;
|
|
181
|
+
}, ...ngDevMode ? [{ debugName: "state" }] : /* istanbul ignore next */ []);
|
|
182
|
+
bodyRows = computed(() => this.loading() || this.state() !== null ? [] : this.renderedRows(), ...ngDevMode ? [{ debugName: "bodyRows" }] : /* istanbul ignore next */ []);
|
|
183
|
+
rowCount = computed(() => {
|
|
184
|
+
const total = this.totalRows();
|
|
185
|
+
if (total !== void 0) return Math.max(0, Math.floor(total)) + 1;
|
|
186
|
+
const rows = this.rows();
|
|
187
|
+
let highest = rows.length;
|
|
188
|
+
for (const row of rows) if (Number.isFinite(row.index) && row.index + 1 > highest) highest = row.index + 1;
|
|
189
|
+
return highest + 1;
|
|
190
|
+
}, ...ngDevMode ? [{ debugName: "rowCount" }] : /* istanbul ignore next */ []);
|
|
191
|
+
active = signal({
|
|
192
|
+
row: -1,
|
|
193
|
+
column: 0
|
|
194
|
+
}, ...ngDevMode ? [{ debugName: "active" }] : /* istanbul ignore next */ []);
|
|
195
|
+
pendingFocus = false;
|
|
196
|
+
effectiveActive = computed(() => {
|
|
197
|
+
const active = this.active();
|
|
198
|
+
const columns = this.columnCount();
|
|
199
|
+
if (columns === 0) return {
|
|
200
|
+
row: -1,
|
|
201
|
+
column: 0
|
|
202
|
+
};
|
|
203
|
+
const column = Math.min(Math.max(active.column, 0), columns - 1);
|
|
204
|
+
const rowCount = this.bodyRows().length;
|
|
205
|
+
if (active.row < 0 || rowCount === 0) return {
|
|
206
|
+
row: -1,
|
|
207
|
+
column
|
|
208
|
+
};
|
|
209
|
+
return {
|
|
210
|
+
row: Math.min(active.row, rowCount - 1),
|
|
211
|
+
column
|
|
212
|
+
};
|
|
213
|
+
}, ...ngDevMode ? [{ debugName: "effectiveActive" }] : /* istanbul ignore next */ []);
|
|
214
|
+
constructor() {
|
|
215
|
+
afterRenderEffect(() => {
|
|
216
|
+
const active = this.effectiveActive();
|
|
217
|
+
this.columnTemplate();
|
|
218
|
+
if (!this.pendingFocus) return;
|
|
219
|
+
this.pendingFocus = false;
|
|
220
|
+
this.focusCell(active.row, active.column);
|
|
221
|
+
});
|
|
222
|
+
}
|
|
223
|
+
isActive(row, column) {
|
|
224
|
+
const active = this.effectiveActive();
|
|
225
|
+
return active.row === row && active.column === column;
|
|
226
|
+
}
|
|
227
|
+
isSortable(column) {
|
|
228
|
+
return column.sortable ?? column.accessor !== void 0;
|
|
229
|
+
}
|
|
230
|
+
sortRank(column) {
|
|
231
|
+
return this.sortIndex().get(column.id)?.rank ?? 0;
|
|
232
|
+
}
|
|
233
|
+
sortDirection(column) {
|
|
234
|
+
return this.sortIndex().get(column.id)?.direction ?? null;
|
|
235
|
+
}
|
|
236
|
+
ariaSort(column) {
|
|
237
|
+
if (!this.isSortable(column)) return null;
|
|
238
|
+
const entry = this.sortIndex().get(column.id);
|
|
239
|
+
if (!entry || entry.rank !== 1) return "none";
|
|
240
|
+
return entry.direction === "asc" ? "ascending" : "descending";
|
|
241
|
+
}
|
|
242
|
+
onHeaderClick(column, columnIndex, event) {
|
|
243
|
+
if (!this.isSortable(column)) return;
|
|
244
|
+
this.active.set({
|
|
245
|
+
row: -1,
|
|
246
|
+
column: columnIndex
|
|
247
|
+
});
|
|
248
|
+
this.pendingFocus = false;
|
|
249
|
+
this.focusCell(-1, columnIndex);
|
|
250
|
+
this.cycleSort(column, event.shiftKey);
|
|
251
|
+
}
|
|
252
|
+
rowId(row) {
|
|
253
|
+
const key = this.rowKey();
|
|
254
|
+
return key ? key(row.data) : row.id;
|
|
255
|
+
}
|
|
256
|
+
onRowActivate(item) {
|
|
257
|
+
this.rowActivate.emit(item.row);
|
|
258
|
+
}
|
|
259
|
+
onRowDoubleClick(item, event) {
|
|
260
|
+
if (event.target?.closest("button, a, input, select, textarea, label, [contenteditable=\"true\"]")) return;
|
|
261
|
+
this.onRowActivate(item);
|
|
262
|
+
}
|
|
263
|
+
onCellClick(item, cell, event) {
|
|
264
|
+
if (event.target?.closest("button, a, input, select, textarea, label, [contenteditable=\"true\"]")) return;
|
|
265
|
+
if (event.detail > 1) return;
|
|
266
|
+
this.active.set({
|
|
267
|
+
row: item.rowIndex,
|
|
268
|
+
column: cell.columnIndex
|
|
269
|
+
});
|
|
270
|
+
this.pendingFocus = false;
|
|
271
|
+
this.focusCell(item.rowIndex, cell.columnIndex);
|
|
272
|
+
if (this.selectable()) this.toggleRow(item);
|
|
273
|
+
}
|
|
274
|
+
onCellFocus(row, column) {
|
|
275
|
+
const active = this.active();
|
|
276
|
+
if (active.row === row && active.column === column) return;
|
|
277
|
+
this.pendingFocus = false;
|
|
278
|
+
this.active.set({
|
|
279
|
+
row,
|
|
280
|
+
column
|
|
281
|
+
});
|
|
282
|
+
}
|
|
283
|
+
onKeydown(event) {
|
|
284
|
+
if (event.defaultPrevented) return;
|
|
285
|
+
const target = event.target;
|
|
286
|
+
if (!target || !target.hasAttribute("data-rv-cell")) return;
|
|
287
|
+
const rows = this.bodyRows();
|
|
288
|
+
const active = this.effectiveActive();
|
|
289
|
+
const rtl = this.isRtl(target);
|
|
290
|
+
if ((event.ctrlKey || event.metaKey) && (event.key === "Home" || event.key === "End")) {
|
|
291
|
+
event.preventDefault();
|
|
292
|
+
if (rows.length === 0) return;
|
|
293
|
+
const row = event.key === "Home" ? 0 : rows.length - 1;
|
|
294
|
+
this.moveTo(row, event.key === "Home" ? this.firstColumn(row) : this.lastColumn(row));
|
|
295
|
+
return;
|
|
296
|
+
}
|
|
297
|
+
if (event.ctrlKey || event.metaKey || event.altKey) return;
|
|
298
|
+
if (active.row < 0) {
|
|
299
|
+
this.onHeaderKey(event, active.column, rows.length);
|
|
300
|
+
return;
|
|
301
|
+
}
|
|
302
|
+
switch (event.key) {
|
|
303
|
+
case "ArrowDown":
|
|
304
|
+
this.moveBy(1, 0);
|
|
305
|
+
break;
|
|
306
|
+
case "ArrowUp":
|
|
307
|
+
if (active.row === 0) this.moveTo(-1, active.column);
|
|
308
|
+
else this.moveBy(-1, 0);
|
|
309
|
+
break;
|
|
310
|
+
case "ArrowLeft":
|
|
311
|
+
this.moveBy(0, rtl ? 1 : -1);
|
|
312
|
+
break;
|
|
313
|
+
case "ArrowRight":
|
|
314
|
+
this.moveBy(0, rtl ? -1 : 1);
|
|
315
|
+
break;
|
|
316
|
+
case "Home":
|
|
317
|
+
this.moveTo(active.row, this.firstColumn(active.row));
|
|
318
|
+
break;
|
|
319
|
+
case "End":
|
|
320
|
+
this.moveTo(active.row, this.lastColumn(active.row));
|
|
321
|
+
break;
|
|
322
|
+
case "PageDown":
|
|
323
|
+
this.page(1);
|
|
324
|
+
break;
|
|
325
|
+
case "PageUp":
|
|
326
|
+
this.page(-1);
|
|
327
|
+
break;
|
|
328
|
+
case "Enter":
|
|
329
|
+
this.onRowActivate(rows[active.row]);
|
|
330
|
+
break;
|
|
331
|
+
case " ":
|
|
332
|
+
if (!this.selectable()) return;
|
|
333
|
+
this.toggleRow(rows[active.row]);
|
|
334
|
+
break;
|
|
335
|
+
default: return;
|
|
336
|
+
}
|
|
337
|
+
event.preventDefault();
|
|
338
|
+
}
|
|
339
|
+
onHeaderKey(event, column, rowCount) {
|
|
340
|
+
const rtl = this.isRtl(event.target);
|
|
341
|
+
switch (event.key) {
|
|
342
|
+
case "ArrowDown":
|
|
343
|
+
if (rowCount > 0) this.moveTo(0, column);
|
|
344
|
+
break;
|
|
345
|
+
case "ArrowLeft":
|
|
346
|
+
this.moveTo(-1, column + (rtl ? 1 : -1));
|
|
347
|
+
break;
|
|
348
|
+
case "ArrowRight":
|
|
349
|
+
this.moveTo(-1, column + (rtl ? -1 : 1));
|
|
350
|
+
break;
|
|
351
|
+
case "Home":
|
|
352
|
+
this.moveTo(-1, 0);
|
|
353
|
+
break;
|
|
354
|
+
case "End":
|
|
355
|
+
this.moveTo(-1, this.columnCount() - 1);
|
|
356
|
+
break;
|
|
357
|
+
case "Enter":
|
|
358
|
+
case " ": {
|
|
359
|
+
const definition = this.visibleColumns()[column];
|
|
360
|
+
if (definition) this.cycleSort(definition, event.shiftKey);
|
|
361
|
+
break;
|
|
362
|
+
}
|
|
363
|
+
default: return;
|
|
364
|
+
}
|
|
365
|
+
event.preventDefault();
|
|
366
|
+
}
|
|
367
|
+
cycleSort(column, additive) {
|
|
368
|
+
const current = this.sort();
|
|
369
|
+
const position = current.findIndex((entry) => entry.column === column.id);
|
|
370
|
+
const direction = position >= 0 ? current[position].direction : null;
|
|
371
|
+
if (additive) {
|
|
372
|
+
if (position < 0) this.sort.set([...current, {
|
|
373
|
+
column: column.id,
|
|
374
|
+
direction: "asc"
|
|
375
|
+
}]);
|
|
376
|
+
else if (direction === "asc") this.sort.set(current.map((entry, index) => index === position ? {
|
|
377
|
+
column: entry.column,
|
|
378
|
+
direction: "desc"
|
|
379
|
+
} : entry));
|
|
380
|
+
else this.sort.set(current.filter((_, index) => index !== position));
|
|
381
|
+
return;
|
|
382
|
+
}
|
|
383
|
+
if (current.length === 1 && position === 0) {
|
|
384
|
+
this.sort.set(direction === "asc" ? [{
|
|
385
|
+
column: column.id,
|
|
386
|
+
direction: "desc"
|
|
387
|
+
}] : []);
|
|
388
|
+
return;
|
|
389
|
+
}
|
|
390
|
+
this.sort.set([{
|
|
391
|
+
column: column.id,
|
|
392
|
+
direction: direction === "asc" ? "desc" : "asc"
|
|
393
|
+
}]);
|
|
394
|
+
}
|
|
395
|
+
page(direction) {
|
|
396
|
+
const rowCount = this.bodyRows().length;
|
|
397
|
+
if (rowCount === 0) return;
|
|
398
|
+
const active = this.effectiveActive();
|
|
399
|
+
const room = direction > 0 ? rowCount - 1 - active.row : active.row;
|
|
400
|
+
const step = direction * Math.min(this.pageRows(), Math.max(0, room));
|
|
401
|
+
if (step === 0) return;
|
|
402
|
+
this.moveBy(step, 0);
|
|
403
|
+
}
|
|
404
|
+
moveBy(deltaRow, deltaColumn) {
|
|
405
|
+
const active = this.effectiveActive();
|
|
406
|
+
const spans = this.spans();
|
|
407
|
+
if (spans) {
|
|
408
|
+
const target = spans.move(active.row, active.column, deltaRow, deltaColumn);
|
|
409
|
+
this.moveTo(target.row, target.column);
|
|
410
|
+
return;
|
|
411
|
+
}
|
|
412
|
+
this.moveTo(active.row + deltaRow, active.column + deltaColumn);
|
|
413
|
+
}
|
|
414
|
+
moveTo(row, column) {
|
|
415
|
+
const rows = this.bodyRows().length;
|
|
416
|
+
const columns = this.columnCount();
|
|
417
|
+
column = Math.min(Math.max(column, 0), Math.max(columns - 1, 0));
|
|
418
|
+
row = rows === 0 ? -1 : Math.min(Math.max(row, -1), rows - 1);
|
|
419
|
+
const spans = this.spans();
|
|
420
|
+
if (spans && row >= 0) {
|
|
421
|
+
const anchor = spans.at(row, column) ?? spans.owner(row, column);
|
|
422
|
+
if (anchor) {
|
|
423
|
+
row = anchor.row;
|
|
424
|
+
column = anchor.column;
|
|
425
|
+
}
|
|
426
|
+
}
|
|
427
|
+
const active = this.effectiveActive();
|
|
428
|
+
if (active.row === row && active.column === column) return;
|
|
429
|
+
this.pendingFocus = true;
|
|
430
|
+
this.active.set({
|
|
431
|
+
row,
|
|
432
|
+
column
|
|
433
|
+
});
|
|
434
|
+
}
|
|
435
|
+
firstColumn(row) {
|
|
436
|
+
const spans = this.spans();
|
|
437
|
+
if (!spans) return 0;
|
|
438
|
+
for (let column = 0; column < this.columnCount(); column++) if (spans.at(row, column) ?? spans.owner(row, column)) return column;
|
|
439
|
+
return 0;
|
|
440
|
+
}
|
|
441
|
+
lastColumn(row) {
|
|
442
|
+
const spans = this.spans();
|
|
443
|
+
const last = Math.max(this.columnCount() - 1, 0);
|
|
444
|
+
if (!spans) return last;
|
|
445
|
+
for (let column = last; column >= 0; column--) if (spans.at(row, column) ?? spans.owner(row, column)) return column;
|
|
446
|
+
return last;
|
|
447
|
+
}
|
|
448
|
+
pageRows() {
|
|
449
|
+
const viewport = this.scroller()?.nativeElement.clientHeight ?? 0;
|
|
450
|
+
const rowHeight = this.host.nativeElement.querySelector(".rv-table-body .rv-table-cell")?.getBoundingClientRect().height ?? 0;
|
|
451
|
+
if (!(viewport > 0) || !(rowHeight > 0)) return 10;
|
|
452
|
+
return Math.max(1, Math.floor(viewport / rowHeight) - 1);
|
|
453
|
+
}
|
|
454
|
+
focusCell(row, column) {
|
|
455
|
+
const element = this.host.nativeElement.querySelector(`[data-rv-cell="${row}:${column}"]`);
|
|
456
|
+
element?.focus({ preventScroll: true });
|
|
457
|
+
element?.scrollIntoView?.({
|
|
458
|
+
block: "nearest",
|
|
459
|
+
inline: "nearest"
|
|
460
|
+
});
|
|
461
|
+
}
|
|
462
|
+
isRtl(element) {
|
|
463
|
+
const declared = element.closest("[dir]")?.getAttribute("dir")?.toLowerCase();
|
|
464
|
+
if (declared === "rtl") return true;
|
|
465
|
+
if (declared === "ltr") return false;
|
|
466
|
+
if (typeof getComputedStyle !== "function") return false;
|
|
467
|
+
return getComputedStyle(element).direction === "rtl";
|
|
468
|
+
}
|
|
469
|
+
buildCells(row, rowIndex, templates) {
|
|
470
|
+
const spans = this.spans();
|
|
471
|
+
const cells = [];
|
|
472
|
+
this.visibleColumns().forEach((column, columnIndex) => {
|
|
473
|
+
let rowSpan = 1;
|
|
474
|
+
let colSpan = 1;
|
|
475
|
+
if (spans) {
|
|
476
|
+
const anchor = spans.at(rowIndex, columnIndex);
|
|
477
|
+
if (anchor) {
|
|
478
|
+
rowSpan = Math.max(1, anchor.rowSpan);
|
|
479
|
+
colSpan = Math.max(1, anchor.colSpan);
|
|
480
|
+
} else if (spans.owner(rowIndex, columnIndex)) return;
|
|
481
|
+
}
|
|
482
|
+
const value = this.readValue(column, row.data);
|
|
483
|
+
const template = templates.get(column.id) ?? null;
|
|
484
|
+
const text = template ? "" : column.format ? column.format(value, row.data, this.locale()) : value === null || value === void 0 ? "" : String(value);
|
|
485
|
+
const overflow = column.textOverflow ?? "nowrap";
|
|
486
|
+
const describedBy = text !== "" && overflow !== "wrap" ? `rv-table-${this.uid}-full-${rowIndex}-${columnIndex}` : null;
|
|
487
|
+
cells.push({
|
|
488
|
+
column,
|
|
489
|
+
columnIndex,
|
|
490
|
+
rowSpan,
|
|
491
|
+
colSpan,
|
|
492
|
+
spanned: rowSpan > 1 || colSpan > 1,
|
|
493
|
+
overflow,
|
|
494
|
+
lines: overflow === "clamp" ? column.lines ?? 2 : null,
|
|
495
|
+
text,
|
|
496
|
+
describedBy,
|
|
497
|
+
template,
|
|
498
|
+
gridRow: `${rowIndex + 1} / span ${rowSpan}`,
|
|
499
|
+
gridColumn: `${columnIndex + 1} / span ${colSpan}`,
|
|
500
|
+
context: {
|
|
501
|
+
$implicit: row,
|
|
502
|
+
row,
|
|
503
|
+
data: row.data,
|
|
504
|
+
value,
|
|
505
|
+
column,
|
|
506
|
+
rowIndex
|
|
507
|
+
}
|
|
508
|
+
});
|
|
509
|
+
});
|
|
510
|
+
return cells;
|
|
511
|
+
}
|
|
512
|
+
readValue(column, data) {
|
|
513
|
+
const accessor = column.accessor;
|
|
514
|
+
if (accessor === void 0) return void 0;
|
|
515
|
+
if (typeof accessor === "function") return accessor(data);
|
|
516
|
+
const record = data;
|
|
517
|
+
return record === null || record === void 0 ? void 0 : record[accessor];
|
|
518
|
+
}
|
|
519
|
+
toggleRow(item) {
|
|
520
|
+
if (!this.selectable() || !item.identityValid) return;
|
|
521
|
+
const id = item.id;
|
|
522
|
+
const selected = new Set(this.selected());
|
|
523
|
+
if (selected.has(id)) selected.delete(id);
|
|
524
|
+
else selected.add(id);
|
|
525
|
+
this.selected.set(selected);
|
|
526
|
+
this.selectionChange.emit({
|
|
527
|
+
selected,
|
|
528
|
+
row: item.row
|
|
529
|
+
});
|
|
530
|
+
}
|
|
531
|
+
errorText(error) {
|
|
532
|
+
if (error instanceof Error && error.message) return error.message;
|
|
533
|
+
if (typeof error === "string" && error) return error;
|
|
534
|
+
return this.effectiveLabels().error;
|
|
535
|
+
}
|
|
536
|
+
static ɵfac = i0.ɵɵngDeclareFactory({
|
|
537
|
+
minVersion: "12.0.0",
|
|
538
|
+
version: "22.2.3",
|
|
539
|
+
ngImport: i0,
|
|
540
|
+
type: RiviniaTableComponent,
|
|
541
|
+
deps: [],
|
|
542
|
+
target: i0.ɵɵFactoryTarget.Component
|
|
543
|
+
});
|
|
544
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({
|
|
545
|
+
minVersion: "17.0.0",
|
|
546
|
+
version: "22.2.3",
|
|
547
|
+
type: RiviniaTableComponent,
|
|
548
|
+
isStandalone: true,
|
|
549
|
+
selector: "rv-table",
|
|
550
|
+
inputs: {
|
|
551
|
+
columns: {
|
|
552
|
+
classPropertyName: "columns",
|
|
553
|
+
publicName: "columns",
|
|
554
|
+
isSignal: true,
|
|
555
|
+
isRequired: true,
|
|
556
|
+
transformFunction: null
|
|
557
|
+
},
|
|
558
|
+
rows: {
|
|
559
|
+
classPropertyName: "rows",
|
|
560
|
+
publicName: "rows",
|
|
561
|
+
isSignal: true,
|
|
562
|
+
isRequired: false,
|
|
563
|
+
transformFunction: null
|
|
564
|
+
},
|
|
565
|
+
spans: {
|
|
566
|
+
classPropertyName: "spans",
|
|
567
|
+
publicName: "spans",
|
|
568
|
+
isSignal: true,
|
|
569
|
+
isRequired: false,
|
|
570
|
+
transformFunction: null
|
|
571
|
+
},
|
|
572
|
+
loading: {
|
|
573
|
+
classPropertyName: "loading",
|
|
574
|
+
publicName: "loading",
|
|
575
|
+
isSignal: true,
|
|
576
|
+
isRequired: false,
|
|
577
|
+
transformFunction: null
|
|
578
|
+
},
|
|
579
|
+
skeletonRows: {
|
|
580
|
+
classPropertyName: "skeletonRows",
|
|
581
|
+
publicName: "skeletonRows",
|
|
582
|
+
isSignal: true,
|
|
583
|
+
isRequired: false,
|
|
584
|
+
transformFunction: null
|
|
585
|
+
},
|
|
586
|
+
error: {
|
|
587
|
+
classPropertyName: "error",
|
|
588
|
+
publicName: "error",
|
|
589
|
+
isSignal: true,
|
|
590
|
+
isRequired: false,
|
|
591
|
+
transformFunction: null
|
|
592
|
+
},
|
|
593
|
+
emptyMessage: {
|
|
594
|
+
classPropertyName: "emptyMessage",
|
|
595
|
+
publicName: "emptyMessage",
|
|
596
|
+
isSignal: true,
|
|
597
|
+
isRequired: false,
|
|
598
|
+
transformFunction: null
|
|
599
|
+
},
|
|
600
|
+
rowKey: {
|
|
601
|
+
classPropertyName: "rowKey",
|
|
602
|
+
publicName: "rowKey",
|
|
603
|
+
isSignal: true,
|
|
604
|
+
isRequired: false,
|
|
605
|
+
transformFunction: null
|
|
606
|
+
},
|
|
607
|
+
selectable: {
|
|
608
|
+
classPropertyName: "selectable",
|
|
609
|
+
publicName: "selectable",
|
|
610
|
+
isSignal: true,
|
|
611
|
+
isRequired: false,
|
|
612
|
+
transformFunction: null
|
|
613
|
+
},
|
|
614
|
+
selected: {
|
|
615
|
+
classPropertyName: "selected",
|
|
616
|
+
publicName: "selected",
|
|
617
|
+
isSignal: true,
|
|
618
|
+
isRequired: false,
|
|
619
|
+
transformFunction: null
|
|
620
|
+
},
|
|
621
|
+
sort: {
|
|
622
|
+
classPropertyName: "sort",
|
|
623
|
+
publicName: "sort",
|
|
624
|
+
isSignal: true,
|
|
625
|
+
isRequired: false,
|
|
626
|
+
transformFunction: null
|
|
627
|
+
},
|
|
628
|
+
density: {
|
|
629
|
+
classPropertyName: "density",
|
|
630
|
+
publicName: "density",
|
|
631
|
+
isSignal: true,
|
|
632
|
+
isRequired: false,
|
|
633
|
+
transformFunction: null
|
|
634
|
+
},
|
|
635
|
+
stickyHeader: {
|
|
636
|
+
classPropertyName: "stickyHeader",
|
|
637
|
+
publicName: "stickyHeader",
|
|
638
|
+
isSignal: true,
|
|
639
|
+
isRequired: false,
|
|
640
|
+
transformFunction: null
|
|
641
|
+
},
|
|
642
|
+
totalRows: {
|
|
643
|
+
classPropertyName: "totalRows",
|
|
644
|
+
publicName: "totalRows",
|
|
645
|
+
isSignal: true,
|
|
646
|
+
isRequired: false,
|
|
647
|
+
transformFunction: null
|
|
648
|
+
},
|
|
649
|
+
ariaLabel: {
|
|
650
|
+
classPropertyName: "ariaLabel",
|
|
651
|
+
publicName: "ariaLabel",
|
|
652
|
+
isSignal: true,
|
|
653
|
+
isRequired: false,
|
|
654
|
+
transformFunction: null
|
|
655
|
+
},
|
|
656
|
+
labels: {
|
|
657
|
+
classPropertyName: "labels",
|
|
658
|
+
publicName: "labels",
|
|
659
|
+
isSignal: true,
|
|
660
|
+
isRequired: false,
|
|
661
|
+
transformFunction: null
|
|
662
|
+
}
|
|
663
|
+
},
|
|
664
|
+
outputs: {
|
|
665
|
+
selected: "selectedChange",
|
|
666
|
+
sort: "sortChange",
|
|
667
|
+
rowActivate: "rowActivate",
|
|
668
|
+
selectionChange: "selectionChange"
|
|
669
|
+
},
|
|
670
|
+
host: { properties: {
|
|
671
|
+
"attr.data-density": "density()",
|
|
672
|
+
"attr.data-loading": "loading() ? \"true\" : null",
|
|
673
|
+
"attr.data-sticky": "stickyHeader() ? \"true\" : \"false\"",
|
|
674
|
+
"attr.data-selectable": "selectable() ? \"true\" : null"
|
|
675
|
+
} },
|
|
676
|
+
queries: [{
|
|
677
|
+
propertyName: "projectedCells",
|
|
678
|
+
predicate: RvTableCell,
|
|
679
|
+
isSignal: true
|
|
680
|
+
}],
|
|
681
|
+
viewQueries: [{
|
|
682
|
+
propertyName: "scroller",
|
|
683
|
+
first: true,
|
|
684
|
+
predicate: ["scroll"],
|
|
685
|
+
descendants: true,
|
|
686
|
+
isSignal: true
|
|
687
|
+
}],
|
|
688
|
+
ngImport: i0,
|
|
689
|
+
template: "<!--\n The screen-reader instructions live OUTSIDE the grid and are referenced by\n `aria-describedby`: a helper paragraph INSIDE a role=\"grid\" would be content\n the grid did not declare and would be announced as a row.\n-->\n<p class=\"rv-table-sr-only\" [id]=\"instructionsId\">{{ effectiveLabels().keyboardHelp }}</p>\n\n<div class=\"rv-table-scroller\" #scroll>\n <!--\n `min-inline-size` is the sum of the declared column widths and the column\n template is one custom property, so the header and the body cannot drift:\n they read the same value from this element.\n -->\n <div\n class=\"rv-table-grid\"\n role=\"grid\"\n [attr.aria-label]=\"ariaLabel() ?? hostLabel ?? effectiveLabels().grid\"\n [attr.aria-describedby]=\"instructionsId\"\n [attr.aria-rowcount]=\"rowCount()\"\n [attr.aria-colcount]=\"columnCount()\"\n [attr.aria-multiselectable]=\"selectable() ? 'true' : null\"\n [attr.aria-busy]=\"loading() ? 'true' : null\"\n [style.--rv-table-columns]=\"columnTemplate()\"\n [style.min-inline-size]=\"minWidth()\"\n (keydown)=\"onKeydown($event)\"\n >\n <!--\n The header is its own rowgroup, so it can be sticky without the body\n participating in the same scroll offset. The row is the CSS grid: each\n header cell is a direct grid item at its column.\n -->\n <div class=\"rv-table-head\" role=\"rowgroup\">\n <div class=\"rv-table-row\" role=\"row\" aria-rowindex=\"1\">\n @for (column of visibleColumns(); track column.id; let index = $index) {\n <div\n class=\"rv-table-cell rv-table-head-cell\"\n role=\"columnheader\"\n [attr.aria-colindex]=\"index + 1\"\n [attr.aria-sort]=\"ariaSort(column)\"\n [attr.tabindex]=\"isActive(-1, index) ? 0 : -1\"\n [attr.data-rv-cell]=\"'-1:' + index\"\n [attr.data-sortable]=\"isSortable(column) ? 'true' : null\"\n [attr.data-sorted]=\"sortRank(column) > 0 ? 'true' : null\"\n [attr.data-sort-direction]=\"sortDirection(column)\"\n [attr.data-sort-rank]=\"sortRank(column) > 1 ? sortRank(column) : null\"\n [attr.data-align]=\"column.align ?? 'start'\"\n (click)=\"onHeaderClick(column, index, $event)\"\n (focus)=\"onCellFocus(-1, index)\"\n >\n <!--\n A real button, but NOT a tab stop: the cell owns the roving\n tabindex, so the grid keeps exactly one. Enter/Space on the cell\n sorts; the button keeps pointer and AT \"click\" working.\n -->\n <button type=\"button\" class=\"rv-table-head-button\" tabindex=\"-1\">\n <span class=\"rv-table-text rv-table-head-label\" dir=\"auto\">{{ column.header }}</span>\n @if (isSortable(column)) {\n <span\n class=\"rv-table-sort\"\n aria-hidden=\"true\"\n [attr.data-direction]=\"sortDirection(column) ?? 'none'\"\n >\n <svg viewBox=\"0 0 10 6\" width=\"10\" height=\"6\" focusable=\"false\">\n <path\n d=\"M1 5 5 1l4 4\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"1.5\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n />\n </svg>\n </span>\n @if (sortRank(column) > 1) {\n <span class=\"rv-table-sort-rank\" aria-hidden=\"true\">{{ sortRank(column) }}</span>\n }\n }\n </button>\n </div>\n }\n </div>\n </div>\n\n <!--\n One CSS grid for the whole body. A row wrapper is `display: contents`,\n so its cells are grid items of THIS grid and a real `grid-row: span N`\n can cross rows at any row height. Covered positions render no element.\n -->\n <div class=\"rv-table-body\" role=\"rowgroup\">\n @if (loading()) {\n @for (skeleton of skeletonList(); track $index; let rowIndex = $index) {\n <!-- Decorative: the polite status below announces the load once. -->\n <div class=\"rv-table-row rv-table-row--skeleton\" aria-hidden=\"true\">\n @for (column of visibleColumns(); track column.id; let columnIndex = $index) {\n <div\n class=\"rv-table-cell rv-table-skeleton\"\n [style.grid-row]=\"(rowIndex + 1) + ' / span 1'\"\n [style.grid-column]=\"(columnIndex + 1) + ' / span 1'\"\n [attr.data-col]=\"columnIndex\"\n >\n <span class=\"rv-table-skeleton-bar\"></span>\n </div>\n }\n </div>\n }\n } @else {\n @for (item of bodyRows(); track item.row) {\n <div\n class=\"rv-table-row\"\n role=\"row\"\n [attr.aria-rowindex]=\"item.ariaRowIndex\"\n [attr.aria-selected]=\"selectable() && item.identityValid ? (item.selected ? 'true' : 'false') : null\"\n [attr.data-selected]=\"item.selected ? 'true' : null\"\n [attr.data-row]=\"item.rowIndex\"\n (dblclick)=\"onRowDoubleClick(item, $event)\"\n >\n @for (cell of item.cells; track cell.columnIndex; let isFirst = $first) {\n <div\n class=\"rv-table-cell\"\n role=\"gridcell\"\n [attr.aria-colindex]=\"cell.columnIndex + 1\"\n [attr.aria-rowspan]=\"cell.rowSpan > 1 ? cell.rowSpan : null\"\n [attr.aria-colspan]=\"cell.colSpan > 1 ? cell.colSpan : null\"\n [attr.aria-describedby]=\"cell.describedBy\"\n [attr.tabindex]=\"isActive(item.rowIndex, cell.columnIndex) ? 0 : -1\"\n [attr.data-rv-cell]=\"item.rowIndex + ':' + cell.columnIndex\"\n [attr.data-row]=\"item.rowIndex\"\n [attr.data-col]=\"cell.columnIndex\"\n [attr.data-span]=\"cell.spanned ? 'true' : null\"\n [attr.data-align]=\"cell.column.align ?? 'start'\"\n [attr.data-overflow]=\"cell.overflow\"\n [style.grid-row]=\"cell.gridRow\"\n [style.grid-column]=\"cell.gridColumn\"\n (click)=\"onCellClick(item, cell, $event)\"\n (focus)=\"onCellFocus(item.rowIndex, cell.columnIndex)\"\n >\n @if (selectable() && isFirst) {\n <!--\n Decorative, deliberately: `aria-selected` on the row is the\n semantics, and a second real checkbox would announce the\n same state twice. Clicking it bubbles to the cell, which is\n what toggles the row.\n -->\n <span\n class=\"rv-table-select\"\n aria-hidden=\"true\"\n [attr.data-checked]=\"item.selected ? 'true' : null\"\n ></span>\n }\n @if (cell.template; as template) {\n <ng-container\n [ngTemplateOutlet]=\"template\"\n [ngTemplateOutletContext]=\"cell.context\"\n />\n } @else {\n <!--\n `dir=\"auto\"`: the grid's direction is the page's, but the\n VALUE's direction is the value's. Without it an English\n client name in an Arabic table renders with its full stop\n moved to the front (\".Nile Trading Co\"), which is correct\n bidi for an RTL paragraph and wrong for the data.\n -->\n <span\n class=\"rv-table-text\"\n dir=\"auto\"\n [attr.data-overflow]=\"cell.overflow\"\n [style.--rv-table-clamp-lines]=\"cell.lines\"\n >{{ cell.text }}</span\n >\n }\n <!--\n The untruncated text, exposed through `aria-describedby` and\n hidden from the browse-order so it is not read twice. There is\n deliberately no `title`: the visual tooltip is the consumer's.\n -->\n @if (cell.describedBy) {\n <span class=\"rv-table-sr-only\" [id]=\"cell.describedBy\" aria-hidden=\"true\">{{\n cell.text\n }}</span>\n }\n </div>\n }\n </div>\n }\n }\n </div>\n </div>\n\n <!--\n Inside the scroller (it belongs to the frame) but outside the grid (a grid\n may only own rows). `position: sticky` on the inline axis keeps it in view\n while the header scrolls horizontally.\n -->\n @if (state(); as current) {\n <div\n class=\"rv-table-state\"\n [attr.role]=\"current.kind === 'error' ? 'alert' : 'status'\"\n [attr.data-state]=\"current.kind\"\n >\n <span class=\"rv-table-state-art\" aria-hidden=\"true\">\n @if (current.kind === 'error') {\n <svg viewBox=\"0 0 24 24\" width=\"24\" height=\"24\" focusable=\"false\">\n <path\n d=\"M12 7v6m0 4h.01M12 3l9 16H3l9-16Z\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"1.6\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n />\n </svg>\n } @else {\n <svg viewBox=\"0 0 24 24\" width=\"24\" height=\"24\" focusable=\"false\">\n <path\n d=\"M4 6h16M4 12h16M4 18h10\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"1.6\"\n stroke-linecap=\"round\"\n />\n </svg>\n }\n </span>\n <p class=\"rv-table-state-text\">{{ current.message }}</p>\n </div>\n }\n</div>\n\n<!-- Always present, so the text change is announced by the live region. -->\n<p class=\"rv-table-sr-only\" role=\"status\">{{ loading() ? effectiveLabels().loading : '' }}</p>\n\n<!--\n The cell templates are never rendered here: they are looked up by column id\n and instantiated per row. Projecting them explicitly keeps the contract\n visible in the DOM (and avoids keeping unprojected content around).\n-->\n<ng-content select=\"[rvTableCell]\" />\n",
|
|
690
|
+
styles: [":host{display:block;font-size:var(--rv-table-font-size, .875rem);color:var(--rv-table-fg, var(--rv-fg, light-dark(#111827, #f4f4f5)));-webkit-text-size-adjust:100%}.rv-table-scroller,.rv-table-scroller *,.rv-table-scroller *:before,.rv-table-scroller *:after{box-sizing:border-box}.rv-table-scroller{position:relative;overflow:auto;max-block-size:var(--rv-table-max-height, none);overscroll-behavior:contain;border:1px solid var(--rv-table-border, var(--rv-border, light-dark(#e5e7eb, #2f2f36)));border-radius:var(--rv-table-radius, var(--rv-radius, .5rem));background:var(--rv-table-bg, var(--rv-bg, light-dark(#ffffff, #17171b)));scrollbar-width:thin;scrollbar-color:var(--rv-table-scrollbar, light-dark(#cbd5e1, #3f3f46)) transparent}.rv-table-grid{display:block}.rv-table-head{position:relative;z-index:2;background:var( --rv-table-header-bg, color-mix( in oklab, var(--rv-table-bg, var(--rv-bg, light-dark(#ffffff, #17171b))) 92%, var(--rv-table-fg, var(--rv-fg, light-dark(#111827, #f4f4f5))) ) );border-block-end:1px solid var(--rv-table-header-border, var(--rv-border, light-dark(#d1d5db, #3f3f46)))}:host([data-sticky=\"true\"]) .rv-table-head{position:sticky;inset-block-start:0}.rv-table-head .rv-table-row{display:grid;grid-template-columns:var(--rv-table-columns, 1fr)}.rv-table-head-cell{min-block-size:var(--rv-table-head-height, 2.75rem);border-block-end:0;color:var(--rv-table-header-fg, var(--rv-muted, light-dark(#52525b, #a1a1aa)));font-size:var(--rv-table-header-font-size, .75rem);font-weight:var(--rv-table-header-font-weight, 700);letter-spacing:.02em;-webkit-user-select:none;user-select:none}.rv-table-head-cell[data-sortable=true]{cursor:pointer}.rv-table-head-cell[data-sortable=true]:hover{background:var( --rv-table-header-hover, color-mix( in oklab, var(--rv-table-bg, var(--rv-bg, light-dark(#ffffff, #17171b))) 86%, var(--rv-table-fg, var(--rv-fg, light-dark(#111827, #f4f4f5))) ) );color:var(--rv-table-header-fg-active, var(--rv-fg, light-dark(#111827, #f4f4f5)))}.rv-table-head-cell[data-sorted=true]{color:var(--rv-table-header-fg-active, var(--rv-fg, light-dark(#111827, #f4f4f5)))}.rv-table-head-button{display:flex;align-items:center;gap:.375rem;inline-size:100%;min-inline-size:0;margin:0;padding:0;border:0;background:none;color:inherit;font:inherit;letter-spacing:inherit;text-align:inherit;cursor:inherit}.rv-table-head-button:focus{outline:none}.rv-table-head-label{min-inline-size:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.rv-table-sort{display:inline-flex;flex:0 0 auto;align-items:center;justify-content:center;inline-size:1rem;block-size:1rem;color:var(--rv-table-sort-fg, var(--rv-accent, light-dark(#5b5bd6, #8b8bf0)));opacity:0;transition:opacity .12s ease,transform .12s ease}.rv-table-head-cell[data-sortable=true]:hover .rv-table-sort{opacity:.45}.rv-table-head-cell[data-sorted=true] .rv-table-sort{opacity:1}.rv-table-sort[data-direction=desc]{transform:rotate(180deg)}.rv-table-sort-rank{display:inline-grid;flex:0 0 auto;place-items:center;min-inline-size:1rem;block-size:1rem;padding-inline:.2rem;border-radius:999px;background:color-mix(in oklab,var(--rv-table-sort-fg, var(--rv-accent, light-dark(#5b5bd6, #8b8bf0))) 16%,transparent);color:var(--rv-table-sort-fg, var(--rv-accent, light-dark(#5b5bd6, #8b8bf0)));font-size:.6875rem;font-weight:700;font-variant-numeric:tabular-nums;line-height:1}.rv-table-body{display:grid;grid-template-columns:var(--rv-table-columns, 1fr);grid-auto-rows:minmax(var(--rv-table-row-height, 2.5rem),auto)}.rv-table-row{display:contents}.rv-table-cell{position:relative;display:flex;align-items:center;gap:.375rem;min-inline-size:0;padding:var(--rv-table-cell-padding, .5rem .75rem);border-block-end:1px solid var(--rv-table-border, var(--rv-border, light-dark(#e5e7eb, #2f2f36)));background:transparent;transition:background-color .12s ease}.rv-table-row:hover>.rv-table-cell{background:var( --rv-table-row-hover, color-mix( in oklab, var(--rv-table-bg, var(--rv-bg, light-dark(#ffffff, #17171b))) 94%, var(--rv-table-fg, var(--rv-fg, light-dark(#111827, #f4f4f5))) ) )}.rv-table-select{display:inline-grid;place-items:center;flex:none;inline-size:1rem;block-size:1rem;border:1px solid var(--rv-table-select-border, var(--rv-border, light-dark(#9ca3af, #52525b)));border-radius:var(--rv-table-select-radius, .25rem);background:var(--rv-table-select-bg, var(--rv-bg, light-dark(#ffffff, #17171b)));transition:background-color .12s ease,border-color .12s ease}.rv-table-select:after{content:\"\";inline-size:.5rem;block-size:.3rem;border-inline-start:2px solid var(--rv-table-select-mark, var(--rv-bg, light-dark(#ffffff, #17171b)));border-block-end:2px solid var(--rv-table-select-mark, var(--rv-bg, light-dark(#ffffff, #17171b)));transform:translateY(-.06rem) rotate(-45deg) scale(0);transition:transform .12s ease}.rv-table-select[data-checked=true]{border-color:var(--rv-table-accent, var(--rv-accent, light-dark(#5b5bd6, #8b8bf0)));background:var(--rv-table-accent, var(--rv-accent, light-dark(#5b5bd6, #8b8bf0)))}.rv-table-select[data-checked=true]:after{transform:translateY(-.06rem) rotate(-45deg) scale(1)}@media(prefers-reduced-motion:reduce){.rv-table-select,.rv-table-select:after{transition:none}}.rv-table-row[aria-selected=true]>.rv-table-cell{background:var( --rv-table-row-selected, color-mix( in oklab, var(--rv-table-accent, var(--rv-accent, light-dark(#5b5bd6, #8b8bf0))) 12%, var(--rv-table-bg, var(--rv-bg, light-dark(#ffffff, #17171b))) ) )}.rv-table-row[aria-selected=true]>.rv-table-cell[data-col=\"0\"]:before{content:\"\";position:absolute;inset-block:0;inset-inline-start:0;inline-size:var(--rv-table-selected-rail, 3px);background:var(--rv-table-accent, var(--rv-accent, light-dark(#5b5bd6, #8b8bf0)))}.rv-table-cell[data-align=center]{justify-content:center;text-align:center}.rv-table-cell[data-align=end]{justify-content:flex-end;text-align:end}.rv-table-cell[data-span]{align-items:flex-start}.rv-table-cell:focus{outline:none}.rv-table-cell:focus-visible{outline:2px solid var(--rv-table-focus, var(--rv-accent, light-dark(#5b5bd6, #8b8bf0)));outline-offset:-2px;z-index:1}.rv-table-text{min-inline-size:0;max-inline-size:100%}.rv-table-text[data-overflow=nowrap]{overflow:hidden;white-space:nowrap;text-overflow:ellipsis}.rv-table-text[data-overflow=wrap]{overflow-wrap:anywhere;white-space:normal}.rv-table-text[data-overflow=clamp]{display:-webkit-box;overflow:hidden;overflow-wrap:anywhere;-webkit-box-orient:vertical;-webkit-line-clamp:var(--rv-table-clamp-lines, 2);line-clamp:var(--rv-table-clamp-lines, 2)}.rv-table-skeleton{pointer-events:none}.rv-table-skeleton-bar{display:block;inline-size:64%;block-size:.625rem;border-radius:.3125rem;background:linear-gradient(90deg,var(--rv-table-skeleton, light-dark(#eceff3, #26262d)) 25%,var(--rv-table-skeleton-highlight, light-dark(#f6f8fa, #31313a)) 37%,var(--rv-table-skeleton, light-dark(#eceff3, #26262d)) 63%);background-size:400% 100%;animation:rv-table-shimmer 1.4s ease-in-out infinite}.rv-table-skeleton:nth-child(3n+2) .rv-table-skeleton-bar{inline-size:82%}.rv-table-skeleton:nth-child(3n) .rv-table-skeleton-bar{inline-size:46%}@keyframes rv-table-shimmer{0%{background-position:100% 0}to{background-position:0 0}}.rv-table-state{position:sticky;inset-inline-start:0;display:flex;flex-direction:column;align-items:center;gap:.5rem;inline-size:100%;padding:var(--rv-table-state-padding, 3rem 1.25rem);text-align:center;background:var(--rv-table-bg, var(--rv-bg, light-dark(#ffffff, #17171b)));color:var(--rv-table-state-fg, var(--rv-muted, light-dark(#52525b, #a1a1aa)))}.rv-table-state-art{display:grid;place-items:center;inline-size:3rem;block-size:3rem;border-radius:1rem;background:color-mix(in oklab,var(--rv-table-state-fg, var(--rv-muted, light-dark(#52525b, #a1a1aa))) 10%,transparent)}.rv-table-state[data-state=error] .rv-table-state-art{background:color-mix(in oklab,var(--rv-table-state-error, var(--rv-danger, light-dark(#dc2626, #f87171))) 14%,transparent);color:var(--rv-table-state-error, var(--rv-danger, light-dark(#dc2626, #f87171)))}.rv-table-state-text{margin:0;max-inline-size:34rem;color:var(--rv-table-state-text, var(--rv-fg, light-dark(#111827, #f4f4f5)));font-size:.9375rem;line-height:1.5}.rv-table-sr-only{position:absolute;inline-size:1px;block-size:1px;margin:-1px;padding:0;overflow:hidden;clip-path:inset(50%);white-space:nowrap;border:0}:host([data-density=\"compact\"]) .rv-table-body{grid-auto-rows:minmax(var(--rv-table-row-height, 2rem),auto)}:host([data-density=\"compact\"]) .rv-table-cell{padding:var(--rv-table-cell-padding, .25rem .5rem)}:host([data-density=\"compact\"]) .rv-table-head-cell{min-block-size:var(--rv-table-head-height, 2.25rem)}:host([data-density=\"compact\"]) .rv-table-skeleton-bar{block-size:.5rem}:host([data-density=\"comfortable\"]) .rv-table-body{grid-auto-rows:minmax(var(--rv-table-row-height, 3rem),auto)}:host([data-density=\"comfortable\"]) .rv-table-cell{padding:var(--rv-table-cell-padding, .75rem 1rem)}:host([data-density=\"comfortable\"]) .rv-table-head-cell{min-block-size:var(--rv-table-head-height, 3.25rem)}@media(prefers-reduced-motion:reduce){.rv-table-cell,.rv-table-sort{transition:none}.rv-table-skeleton-bar{animation:none}}@media(forced-colors:active){.rv-table-cell:focus-visible{outline-color:Highlight}.rv-table-skeleton-bar{background:GrayText}.rv-table-row[aria-selected=true]>.rv-table-cell[data-col=\"0\"]:before{background:Highlight}}\n"],
|
|
691
|
+
dependencies: [{
|
|
692
|
+
kind: "directive",
|
|
693
|
+
type: NgTemplateOutlet,
|
|
694
|
+
selector: "[ngTemplateOutlet]",
|
|
695
|
+
inputs: [
|
|
696
|
+
"ngTemplateOutletContext",
|
|
697
|
+
"ngTemplateOutlet",
|
|
698
|
+
"ngTemplateOutletInjector"
|
|
699
|
+
]
|
|
700
|
+
}],
|
|
701
|
+
changeDetection: i0.ChangeDetectionStrategy.OnPush
|
|
702
|
+
});
|
|
703
|
+
};
|
|
704
|
+
i0.ɵɵngDeclareClassMetadata({
|
|
705
|
+
minVersion: "12.0.0",
|
|
706
|
+
version: "22.2.3",
|
|
707
|
+
ngImport: i0,
|
|
708
|
+
type: RiviniaTableComponent,
|
|
709
|
+
decorators: [{
|
|
710
|
+
type: Component,
|
|
711
|
+
args: [{
|
|
712
|
+
selector: "rv-table",
|
|
713
|
+
imports: [NgTemplateOutlet],
|
|
714
|
+
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
715
|
+
host: {
|
|
716
|
+
"[attr.data-density]": "density()",
|
|
717
|
+
"[attr.data-loading]": "loading() ? \"true\" : null",
|
|
718
|
+
"[attr.data-sticky]": "stickyHeader() ? \"true\" : \"false\"",
|
|
719
|
+
"[attr.data-selectable]": "selectable() ? \"true\" : null"
|
|
720
|
+
},
|
|
721
|
+
template: "<!--\n The screen-reader instructions live OUTSIDE the grid and are referenced by\n `aria-describedby`: a helper paragraph INSIDE a role=\"grid\" would be content\n the grid did not declare and would be announced as a row.\n-->\n<p class=\"rv-table-sr-only\" [id]=\"instructionsId\">{{ effectiveLabels().keyboardHelp }}</p>\n\n<div class=\"rv-table-scroller\" #scroll>\n <!--\n `min-inline-size` is the sum of the declared column widths and the column\n template is one custom property, so the header and the body cannot drift:\n they read the same value from this element.\n -->\n <div\n class=\"rv-table-grid\"\n role=\"grid\"\n [attr.aria-label]=\"ariaLabel() ?? hostLabel ?? effectiveLabels().grid\"\n [attr.aria-describedby]=\"instructionsId\"\n [attr.aria-rowcount]=\"rowCount()\"\n [attr.aria-colcount]=\"columnCount()\"\n [attr.aria-multiselectable]=\"selectable() ? 'true' : null\"\n [attr.aria-busy]=\"loading() ? 'true' : null\"\n [style.--rv-table-columns]=\"columnTemplate()\"\n [style.min-inline-size]=\"minWidth()\"\n (keydown)=\"onKeydown($event)\"\n >\n <!--\n The header is its own rowgroup, so it can be sticky without the body\n participating in the same scroll offset. The row is the CSS grid: each\n header cell is a direct grid item at its column.\n -->\n <div class=\"rv-table-head\" role=\"rowgroup\">\n <div class=\"rv-table-row\" role=\"row\" aria-rowindex=\"1\">\n @for (column of visibleColumns(); track column.id; let index = $index) {\n <div\n class=\"rv-table-cell rv-table-head-cell\"\n role=\"columnheader\"\n [attr.aria-colindex]=\"index + 1\"\n [attr.aria-sort]=\"ariaSort(column)\"\n [attr.tabindex]=\"isActive(-1, index) ? 0 : -1\"\n [attr.data-rv-cell]=\"'-1:' + index\"\n [attr.data-sortable]=\"isSortable(column) ? 'true' : null\"\n [attr.data-sorted]=\"sortRank(column) > 0 ? 'true' : null\"\n [attr.data-sort-direction]=\"sortDirection(column)\"\n [attr.data-sort-rank]=\"sortRank(column) > 1 ? sortRank(column) : null\"\n [attr.data-align]=\"column.align ?? 'start'\"\n (click)=\"onHeaderClick(column, index, $event)\"\n (focus)=\"onCellFocus(-1, index)\"\n >\n <!--\n A real button, but NOT a tab stop: the cell owns the roving\n tabindex, so the grid keeps exactly one. Enter/Space on the cell\n sorts; the button keeps pointer and AT \"click\" working.\n -->\n <button type=\"button\" class=\"rv-table-head-button\" tabindex=\"-1\">\n <span class=\"rv-table-text rv-table-head-label\" dir=\"auto\">{{ column.header }}</span>\n @if (isSortable(column)) {\n <span\n class=\"rv-table-sort\"\n aria-hidden=\"true\"\n [attr.data-direction]=\"sortDirection(column) ?? 'none'\"\n >\n <svg viewBox=\"0 0 10 6\" width=\"10\" height=\"6\" focusable=\"false\">\n <path\n d=\"M1 5 5 1l4 4\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"1.5\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n />\n </svg>\n </span>\n @if (sortRank(column) > 1) {\n <span class=\"rv-table-sort-rank\" aria-hidden=\"true\">{{ sortRank(column) }}</span>\n }\n }\n </button>\n </div>\n }\n </div>\n </div>\n\n <!--\n One CSS grid for the whole body. A row wrapper is `display: contents`,\n so its cells are grid items of THIS grid and a real `grid-row: span N`\n can cross rows at any row height. Covered positions render no element.\n -->\n <div class=\"rv-table-body\" role=\"rowgroup\">\n @if (loading()) {\n @for (skeleton of skeletonList(); track $index; let rowIndex = $index) {\n <!-- Decorative: the polite status below announces the load once. -->\n <div class=\"rv-table-row rv-table-row--skeleton\" aria-hidden=\"true\">\n @for (column of visibleColumns(); track column.id; let columnIndex = $index) {\n <div\n class=\"rv-table-cell rv-table-skeleton\"\n [style.grid-row]=\"(rowIndex + 1) + ' / span 1'\"\n [style.grid-column]=\"(columnIndex + 1) + ' / span 1'\"\n [attr.data-col]=\"columnIndex\"\n >\n <span class=\"rv-table-skeleton-bar\"></span>\n </div>\n }\n </div>\n }\n } @else {\n @for (item of bodyRows(); track item.row) {\n <div\n class=\"rv-table-row\"\n role=\"row\"\n [attr.aria-rowindex]=\"item.ariaRowIndex\"\n [attr.aria-selected]=\"selectable() && item.identityValid ? (item.selected ? 'true' : 'false') : null\"\n [attr.data-selected]=\"item.selected ? 'true' : null\"\n [attr.data-row]=\"item.rowIndex\"\n (dblclick)=\"onRowDoubleClick(item, $event)\"\n >\n @for (cell of item.cells; track cell.columnIndex; let isFirst = $first) {\n <div\n class=\"rv-table-cell\"\n role=\"gridcell\"\n [attr.aria-colindex]=\"cell.columnIndex + 1\"\n [attr.aria-rowspan]=\"cell.rowSpan > 1 ? cell.rowSpan : null\"\n [attr.aria-colspan]=\"cell.colSpan > 1 ? cell.colSpan : null\"\n [attr.aria-describedby]=\"cell.describedBy\"\n [attr.tabindex]=\"isActive(item.rowIndex, cell.columnIndex) ? 0 : -1\"\n [attr.data-rv-cell]=\"item.rowIndex + ':' + cell.columnIndex\"\n [attr.data-row]=\"item.rowIndex\"\n [attr.data-col]=\"cell.columnIndex\"\n [attr.data-span]=\"cell.spanned ? 'true' : null\"\n [attr.data-align]=\"cell.column.align ?? 'start'\"\n [attr.data-overflow]=\"cell.overflow\"\n [style.grid-row]=\"cell.gridRow\"\n [style.grid-column]=\"cell.gridColumn\"\n (click)=\"onCellClick(item, cell, $event)\"\n (focus)=\"onCellFocus(item.rowIndex, cell.columnIndex)\"\n >\n @if (selectable() && isFirst) {\n <!--\n Decorative, deliberately: `aria-selected` on the row is the\n semantics, and a second real checkbox would announce the\n same state twice. Clicking it bubbles to the cell, which is\n what toggles the row.\n -->\n <span\n class=\"rv-table-select\"\n aria-hidden=\"true\"\n [attr.data-checked]=\"item.selected ? 'true' : null\"\n ></span>\n }\n @if (cell.template; as template) {\n <ng-container\n [ngTemplateOutlet]=\"template\"\n [ngTemplateOutletContext]=\"cell.context\"\n />\n } @else {\n <!--\n `dir=\"auto\"`: the grid's direction is the page's, but the\n VALUE's direction is the value's. Without it an English\n client name in an Arabic table renders with its full stop\n moved to the front (\".Nile Trading Co\"), which is correct\n bidi for an RTL paragraph and wrong for the data.\n -->\n <span\n class=\"rv-table-text\"\n dir=\"auto\"\n [attr.data-overflow]=\"cell.overflow\"\n [style.--rv-table-clamp-lines]=\"cell.lines\"\n >{{ cell.text }}</span\n >\n }\n <!--\n The untruncated text, exposed through `aria-describedby` and\n hidden from the browse-order so it is not read twice. There is\n deliberately no `title`: the visual tooltip is the consumer's.\n -->\n @if (cell.describedBy) {\n <span class=\"rv-table-sr-only\" [id]=\"cell.describedBy\" aria-hidden=\"true\">{{\n cell.text\n }}</span>\n }\n </div>\n }\n </div>\n }\n }\n </div>\n </div>\n\n <!--\n Inside the scroller (it belongs to the frame) but outside the grid (a grid\n may only own rows). `position: sticky` on the inline axis keeps it in view\n while the header scrolls horizontally.\n -->\n @if (state(); as current) {\n <div\n class=\"rv-table-state\"\n [attr.role]=\"current.kind === 'error' ? 'alert' : 'status'\"\n [attr.data-state]=\"current.kind\"\n >\n <span class=\"rv-table-state-art\" aria-hidden=\"true\">\n @if (current.kind === 'error') {\n <svg viewBox=\"0 0 24 24\" width=\"24\" height=\"24\" focusable=\"false\">\n <path\n d=\"M12 7v6m0 4h.01M12 3l9 16H3l9-16Z\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"1.6\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n />\n </svg>\n } @else {\n <svg viewBox=\"0 0 24 24\" width=\"24\" height=\"24\" focusable=\"false\">\n <path\n d=\"M4 6h16M4 12h16M4 18h10\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"1.6\"\n stroke-linecap=\"round\"\n />\n </svg>\n }\n </span>\n <p class=\"rv-table-state-text\">{{ current.message }}</p>\n </div>\n }\n</div>\n\n<!-- Always present, so the text change is announced by the live region. -->\n<p class=\"rv-table-sr-only\" role=\"status\">{{ loading() ? effectiveLabels().loading : '' }}</p>\n\n<!--\n The cell templates are never rendered here: they are looked up by column id\n and instantiated per row. Projecting them explicitly keeps the contract\n visible in the DOM (and avoids keeping unprojected content around).\n-->\n<ng-content select=\"[rvTableCell]\" />\n",
|
|
722
|
+
styles: [":host{display:block;font-size:var(--rv-table-font-size, .875rem);color:var(--rv-table-fg, var(--rv-fg, light-dark(#111827, #f4f4f5)));-webkit-text-size-adjust:100%}.rv-table-scroller,.rv-table-scroller *,.rv-table-scroller *:before,.rv-table-scroller *:after{box-sizing:border-box}.rv-table-scroller{position:relative;overflow:auto;max-block-size:var(--rv-table-max-height, none);overscroll-behavior:contain;border:1px solid var(--rv-table-border, var(--rv-border, light-dark(#e5e7eb, #2f2f36)));border-radius:var(--rv-table-radius, var(--rv-radius, .5rem));background:var(--rv-table-bg, var(--rv-bg, light-dark(#ffffff, #17171b)));scrollbar-width:thin;scrollbar-color:var(--rv-table-scrollbar, light-dark(#cbd5e1, #3f3f46)) transparent}.rv-table-grid{display:block}.rv-table-head{position:relative;z-index:2;background:var( --rv-table-header-bg, color-mix( in oklab, var(--rv-table-bg, var(--rv-bg, light-dark(#ffffff, #17171b))) 92%, var(--rv-table-fg, var(--rv-fg, light-dark(#111827, #f4f4f5))) ) );border-block-end:1px solid var(--rv-table-header-border, var(--rv-border, light-dark(#d1d5db, #3f3f46)))}:host([data-sticky=\"true\"]) .rv-table-head{position:sticky;inset-block-start:0}.rv-table-head .rv-table-row{display:grid;grid-template-columns:var(--rv-table-columns, 1fr)}.rv-table-head-cell{min-block-size:var(--rv-table-head-height, 2.75rem);border-block-end:0;color:var(--rv-table-header-fg, var(--rv-muted, light-dark(#52525b, #a1a1aa)));font-size:var(--rv-table-header-font-size, .75rem);font-weight:var(--rv-table-header-font-weight, 700);letter-spacing:.02em;-webkit-user-select:none;user-select:none}.rv-table-head-cell[data-sortable=true]{cursor:pointer}.rv-table-head-cell[data-sortable=true]:hover{background:var( --rv-table-header-hover, color-mix( in oklab, var(--rv-table-bg, var(--rv-bg, light-dark(#ffffff, #17171b))) 86%, var(--rv-table-fg, var(--rv-fg, light-dark(#111827, #f4f4f5))) ) );color:var(--rv-table-header-fg-active, var(--rv-fg, light-dark(#111827, #f4f4f5)))}.rv-table-head-cell[data-sorted=true]{color:var(--rv-table-header-fg-active, var(--rv-fg, light-dark(#111827, #f4f4f5)))}.rv-table-head-button{display:flex;align-items:center;gap:.375rem;inline-size:100%;min-inline-size:0;margin:0;padding:0;border:0;background:none;color:inherit;font:inherit;letter-spacing:inherit;text-align:inherit;cursor:inherit}.rv-table-head-button:focus{outline:none}.rv-table-head-label{min-inline-size:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.rv-table-sort{display:inline-flex;flex:0 0 auto;align-items:center;justify-content:center;inline-size:1rem;block-size:1rem;color:var(--rv-table-sort-fg, var(--rv-accent, light-dark(#5b5bd6, #8b8bf0)));opacity:0;transition:opacity .12s ease,transform .12s ease}.rv-table-head-cell[data-sortable=true]:hover .rv-table-sort{opacity:.45}.rv-table-head-cell[data-sorted=true] .rv-table-sort{opacity:1}.rv-table-sort[data-direction=desc]{transform:rotate(180deg)}.rv-table-sort-rank{display:inline-grid;flex:0 0 auto;place-items:center;min-inline-size:1rem;block-size:1rem;padding-inline:.2rem;border-radius:999px;background:color-mix(in oklab,var(--rv-table-sort-fg, var(--rv-accent, light-dark(#5b5bd6, #8b8bf0))) 16%,transparent);color:var(--rv-table-sort-fg, var(--rv-accent, light-dark(#5b5bd6, #8b8bf0)));font-size:.6875rem;font-weight:700;font-variant-numeric:tabular-nums;line-height:1}.rv-table-body{display:grid;grid-template-columns:var(--rv-table-columns, 1fr);grid-auto-rows:minmax(var(--rv-table-row-height, 2.5rem),auto)}.rv-table-row{display:contents}.rv-table-cell{position:relative;display:flex;align-items:center;gap:.375rem;min-inline-size:0;padding:var(--rv-table-cell-padding, .5rem .75rem);border-block-end:1px solid var(--rv-table-border, var(--rv-border, light-dark(#e5e7eb, #2f2f36)));background:transparent;transition:background-color .12s ease}.rv-table-row:hover>.rv-table-cell{background:var( --rv-table-row-hover, color-mix( in oklab, var(--rv-table-bg, var(--rv-bg, light-dark(#ffffff, #17171b))) 94%, var(--rv-table-fg, var(--rv-fg, light-dark(#111827, #f4f4f5))) ) )}.rv-table-select{display:inline-grid;place-items:center;flex:none;inline-size:1rem;block-size:1rem;border:1px solid var(--rv-table-select-border, var(--rv-border, light-dark(#9ca3af, #52525b)));border-radius:var(--rv-table-select-radius, .25rem);background:var(--rv-table-select-bg, var(--rv-bg, light-dark(#ffffff, #17171b)));transition:background-color .12s ease,border-color .12s ease}.rv-table-select:after{content:\"\";inline-size:.5rem;block-size:.3rem;border-inline-start:2px solid var(--rv-table-select-mark, var(--rv-bg, light-dark(#ffffff, #17171b)));border-block-end:2px solid var(--rv-table-select-mark, var(--rv-bg, light-dark(#ffffff, #17171b)));transform:translateY(-.06rem) rotate(-45deg) scale(0);transition:transform .12s ease}.rv-table-select[data-checked=true]{border-color:var(--rv-table-accent, var(--rv-accent, light-dark(#5b5bd6, #8b8bf0)));background:var(--rv-table-accent, var(--rv-accent, light-dark(#5b5bd6, #8b8bf0)))}.rv-table-select[data-checked=true]:after{transform:translateY(-.06rem) rotate(-45deg) scale(1)}@media(prefers-reduced-motion:reduce){.rv-table-select,.rv-table-select:after{transition:none}}.rv-table-row[aria-selected=true]>.rv-table-cell{background:var( --rv-table-row-selected, color-mix( in oklab, var(--rv-table-accent, var(--rv-accent, light-dark(#5b5bd6, #8b8bf0))) 12%, var(--rv-table-bg, var(--rv-bg, light-dark(#ffffff, #17171b))) ) )}.rv-table-row[aria-selected=true]>.rv-table-cell[data-col=\"0\"]:before{content:\"\";position:absolute;inset-block:0;inset-inline-start:0;inline-size:var(--rv-table-selected-rail, 3px);background:var(--rv-table-accent, var(--rv-accent, light-dark(#5b5bd6, #8b8bf0)))}.rv-table-cell[data-align=center]{justify-content:center;text-align:center}.rv-table-cell[data-align=end]{justify-content:flex-end;text-align:end}.rv-table-cell[data-span]{align-items:flex-start}.rv-table-cell:focus{outline:none}.rv-table-cell:focus-visible{outline:2px solid var(--rv-table-focus, var(--rv-accent, light-dark(#5b5bd6, #8b8bf0)));outline-offset:-2px;z-index:1}.rv-table-text{min-inline-size:0;max-inline-size:100%}.rv-table-text[data-overflow=nowrap]{overflow:hidden;white-space:nowrap;text-overflow:ellipsis}.rv-table-text[data-overflow=wrap]{overflow-wrap:anywhere;white-space:normal}.rv-table-text[data-overflow=clamp]{display:-webkit-box;overflow:hidden;overflow-wrap:anywhere;-webkit-box-orient:vertical;-webkit-line-clamp:var(--rv-table-clamp-lines, 2);line-clamp:var(--rv-table-clamp-lines, 2)}.rv-table-skeleton{pointer-events:none}.rv-table-skeleton-bar{display:block;inline-size:64%;block-size:.625rem;border-radius:.3125rem;background:linear-gradient(90deg,var(--rv-table-skeleton, light-dark(#eceff3, #26262d)) 25%,var(--rv-table-skeleton-highlight, light-dark(#f6f8fa, #31313a)) 37%,var(--rv-table-skeleton, light-dark(#eceff3, #26262d)) 63%);background-size:400% 100%;animation:rv-table-shimmer 1.4s ease-in-out infinite}.rv-table-skeleton:nth-child(3n+2) .rv-table-skeleton-bar{inline-size:82%}.rv-table-skeleton:nth-child(3n) .rv-table-skeleton-bar{inline-size:46%}@keyframes rv-table-shimmer{0%{background-position:100% 0}to{background-position:0 0}}.rv-table-state{position:sticky;inset-inline-start:0;display:flex;flex-direction:column;align-items:center;gap:.5rem;inline-size:100%;padding:var(--rv-table-state-padding, 3rem 1.25rem);text-align:center;background:var(--rv-table-bg, var(--rv-bg, light-dark(#ffffff, #17171b)));color:var(--rv-table-state-fg, var(--rv-muted, light-dark(#52525b, #a1a1aa)))}.rv-table-state-art{display:grid;place-items:center;inline-size:3rem;block-size:3rem;border-radius:1rem;background:color-mix(in oklab,var(--rv-table-state-fg, var(--rv-muted, light-dark(#52525b, #a1a1aa))) 10%,transparent)}.rv-table-state[data-state=error] .rv-table-state-art{background:color-mix(in oklab,var(--rv-table-state-error, var(--rv-danger, light-dark(#dc2626, #f87171))) 14%,transparent);color:var(--rv-table-state-error, var(--rv-danger, light-dark(#dc2626, #f87171)))}.rv-table-state-text{margin:0;max-inline-size:34rem;color:var(--rv-table-state-text, var(--rv-fg, light-dark(#111827, #f4f4f5)));font-size:.9375rem;line-height:1.5}.rv-table-sr-only{position:absolute;inline-size:1px;block-size:1px;margin:-1px;padding:0;overflow:hidden;clip-path:inset(50%);white-space:nowrap;border:0}:host([data-density=\"compact\"]) .rv-table-body{grid-auto-rows:minmax(var(--rv-table-row-height, 2rem),auto)}:host([data-density=\"compact\"]) .rv-table-cell{padding:var(--rv-table-cell-padding, .25rem .5rem)}:host([data-density=\"compact\"]) .rv-table-head-cell{min-block-size:var(--rv-table-head-height, 2.25rem)}:host([data-density=\"compact\"]) .rv-table-skeleton-bar{block-size:.5rem}:host([data-density=\"comfortable\"]) .rv-table-body{grid-auto-rows:minmax(var(--rv-table-row-height, 3rem),auto)}:host([data-density=\"comfortable\"]) .rv-table-cell{padding:var(--rv-table-cell-padding, .75rem 1rem)}:host([data-density=\"comfortable\"]) .rv-table-head-cell{min-block-size:var(--rv-table-head-height, 3.25rem)}@media(prefers-reduced-motion:reduce){.rv-table-cell,.rv-table-sort{transition:none}.rv-table-skeleton-bar{animation:none}}@media(forced-colors:active){.rv-table-cell:focus-visible{outline-color:Highlight}.rv-table-skeleton-bar{background:GrayText}.rv-table-row[aria-selected=true]>.rv-table-cell[data-col=\"0\"]:before{background:Highlight}}\n"]
|
|
723
|
+
}]
|
|
724
|
+
}],
|
|
725
|
+
ctorParameters: () => [],
|
|
726
|
+
propDecorators: {
|
|
727
|
+
scroller: [{
|
|
728
|
+
type: i0.ViewChild,
|
|
729
|
+
args: ["scroll", { isSignal: true }]
|
|
730
|
+
}],
|
|
731
|
+
projectedCells: [{
|
|
732
|
+
type: i0.ContentChildren,
|
|
733
|
+
args: [i0.forwardRef(() => RvTableCell), { isSignal: true }]
|
|
734
|
+
}],
|
|
735
|
+
columns: [{
|
|
736
|
+
type: i0.Input,
|
|
737
|
+
args: [{
|
|
738
|
+
isSignal: true,
|
|
739
|
+
alias: "columns",
|
|
740
|
+
required: true
|
|
741
|
+
}]
|
|
742
|
+
}],
|
|
743
|
+
rows: [{
|
|
744
|
+
type: i0.Input,
|
|
745
|
+
args: [{
|
|
746
|
+
isSignal: true,
|
|
747
|
+
alias: "rows",
|
|
748
|
+
required: false
|
|
749
|
+
}]
|
|
750
|
+
}],
|
|
751
|
+
spans: [{
|
|
752
|
+
type: i0.Input,
|
|
753
|
+
args: [{
|
|
754
|
+
isSignal: true,
|
|
755
|
+
alias: "spans",
|
|
756
|
+
required: false
|
|
757
|
+
}]
|
|
758
|
+
}],
|
|
759
|
+
loading: [{
|
|
760
|
+
type: i0.Input,
|
|
761
|
+
args: [{
|
|
762
|
+
isSignal: true,
|
|
763
|
+
alias: "loading",
|
|
764
|
+
required: false
|
|
765
|
+
}]
|
|
766
|
+
}],
|
|
767
|
+
skeletonRows: [{
|
|
768
|
+
type: i0.Input,
|
|
769
|
+
args: [{
|
|
770
|
+
isSignal: true,
|
|
771
|
+
alias: "skeletonRows",
|
|
772
|
+
required: false
|
|
773
|
+
}]
|
|
774
|
+
}],
|
|
775
|
+
error: [{
|
|
776
|
+
type: i0.Input,
|
|
777
|
+
args: [{
|
|
778
|
+
isSignal: true,
|
|
779
|
+
alias: "error",
|
|
780
|
+
required: false
|
|
781
|
+
}]
|
|
782
|
+
}],
|
|
783
|
+
emptyMessage: [{
|
|
784
|
+
type: i0.Input,
|
|
785
|
+
args: [{
|
|
786
|
+
isSignal: true,
|
|
787
|
+
alias: "emptyMessage",
|
|
788
|
+
required: false
|
|
789
|
+
}]
|
|
790
|
+
}],
|
|
791
|
+
rowKey: [{
|
|
792
|
+
type: i0.Input,
|
|
793
|
+
args: [{
|
|
794
|
+
isSignal: true,
|
|
795
|
+
alias: "rowKey",
|
|
796
|
+
required: false
|
|
797
|
+
}]
|
|
798
|
+
}],
|
|
799
|
+
selectable: [{
|
|
800
|
+
type: i0.Input,
|
|
801
|
+
args: [{
|
|
802
|
+
isSignal: true,
|
|
803
|
+
alias: "selectable",
|
|
804
|
+
required: false
|
|
805
|
+
}]
|
|
806
|
+
}],
|
|
807
|
+
selected: [{
|
|
808
|
+
type: i0.Input,
|
|
809
|
+
args: [{
|
|
810
|
+
isSignal: true,
|
|
811
|
+
alias: "selected",
|
|
812
|
+
required: false
|
|
813
|
+
}]
|
|
814
|
+
}, {
|
|
815
|
+
type: i0.Output,
|
|
816
|
+
args: ["selectedChange"]
|
|
817
|
+
}],
|
|
818
|
+
sort: [{
|
|
819
|
+
type: i0.Input,
|
|
820
|
+
args: [{
|
|
821
|
+
isSignal: true,
|
|
822
|
+
alias: "sort",
|
|
823
|
+
required: false
|
|
824
|
+
}]
|
|
825
|
+
}, {
|
|
826
|
+
type: i0.Output,
|
|
827
|
+
args: ["sortChange"]
|
|
828
|
+
}],
|
|
829
|
+
density: [{
|
|
830
|
+
type: i0.Input,
|
|
831
|
+
args: [{
|
|
832
|
+
isSignal: true,
|
|
833
|
+
alias: "density",
|
|
834
|
+
required: false
|
|
835
|
+
}]
|
|
836
|
+
}],
|
|
837
|
+
stickyHeader: [{
|
|
838
|
+
type: i0.Input,
|
|
839
|
+
args: [{
|
|
840
|
+
isSignal: true,
|
|
841
|
+
alias: "stickyHeader",
|
|
842
|
+
required: false
|
|
843
|
+
}]
|
|
844
|
+
}],
|
|
845
|
+
totalRows: [{
|
|
846
|
+
type: i0.Input,
|
|
847
|
+
args: [{
|
|
848
|
+
isSignal: true,
|
|
849
|
+
alias: "totalRows",
|
|
850
|
+
required: false
|
|
851
|
+
}]
|
|
852
|
+
}],
|
|
853
|
+
ariaLabel: [{
|
|
854
|
+
type: i0.Input,
|
|
855
|
+
args: [{
|
|
856
|
+
isSignal: true,
|
|
857
|
+
alias: "ariaLabel",
|
|
858
|
+
required: false
|
|
859
|
+
}]
|
|
860
|
+
}],
|
|
861
|
+
labels: [{
|
|
862
|
+
type: i0.Input,
|
|
863
|
+
args: [{
|
|
864
|
+
isSignal: true,
|
|
865
|
+
alias: "labels",
|
|
866
|
+
required: false
|
|
867
|
+
}]
|
|
868
|
+
}],
|
|
869
|
+
rowActivate: [{
|
|
870
|
+
type: i0.Output,
|
|
871
|
+
args: ["rowActivate"]
|
|
872
|
+
}],
|
|
873
|
+
selectionChange: [{
|
|
874
|
+
type: i0.Output,
|
|
875
|
+
args: ["selectionChange"]
|
|
876
|
+
}]
|
|
877
|
+
}
|
|
878
|
+
});
|
|
879
|
+
export { RiviniaTableComponent, RvTableCell, TABLE_UI_LABELS_AR, TABLE_UI_LABELS_EN };
|
|
880
|
+
|
|
881
|
+
//# sourceMappingURL=rivinia-table-ui.mjs.map
|