@aurelia-ui-toolkits/headless 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/dist/alert/ui-alert.html +19 -0
- package/dist/alert/ui-alert.js +67 -0
- package/dist/alert/ui-alert.js.map +1 -0
- package/dist/alert-service/alert-configuration.js +11 -0
- package/dist/alert-service/alert-configuration.js.map +1 -0
- package/dist/alert-service/alert-modal/alert-modal.html +12 -0
- package/dist/alert-service/alert-modal/alert-modal.js +31 -0
- package/dist/alert-service/alert-modal/alert-modal.js.map +1 -0
- package/dist/alert-service/alert-modal/i-alert-modal-payload.js +2 -0
- package/dist/alert-service/alert-modal/i-alert-modal-payload.js.map +1 -0
- package/dist/alert-service/alert-service.js +108 -0
- package/dist/alert-service/alert-service.js.map +1 -0
- package/dist/alert-service/decorators/confirm-action.js +14 -0
- package/dist/alert-service/decorators/confirm-action.js.map +1 -0
- package/dist/alert-service/decorators/using-progress.js +23 -0
- package/dist/alert-service/decorators/using-progress.js.map +1 -0
- package/dist/alert-service/exceptions-tracker.js +4 -0
- package/dist/alert-service/exceptions-tracker.js.map +1 -0
- package/dist/alert-service/prompt-dialog/prompt-dialog.html +13 -0
- package/dist/alert-service/prompt-dialog/prompt-dialog.js +39 -0
- package/dist/alert-service/prompt-dialog/prompt-dialog.js.map +1 -0
- package/dist/badge/ui-badge.html +6 -0
- package/dist/badge/ui-badge.js +44 -0
- package/dist/badge/ui-badge.js.map +1 -0
- package/dist/base/boolean-attr.js +4 -0
- package/dist/base/boolean-attr.js.map +1 -0
- package/dist/base/i-validated-element.js +2 -0
- package/dist/base/i-validated-element.js.map +1 -0
- package/dist/base/keys.js +14 -0
- package/dist/base/keys.js.map +1 -0
- package/dist/breadcrumbs/ui-breadcrumbs.html +10 -0
- package/dist/breadcrumbs/ui-breadcrumbs.js +31 -0
- package/dist/breadcrumbs/ui-breadcrumbs.js.map +1 -0
- package/dist/button/enhance-ui-button.js +25 -0
- package/dist/button/enhance-ui-button.js.map +1 -0
- package/dist/button/ui-button.html +20 -0
- package/dist/button/ui-button.js +77 -0
- package/dist/button/ui-button.js.map +1 -0
- package/dist/button/ui-icon-button.html +20 -0
- package/dist/button/ui-icon-button.js +77 -0
- package/dist/button/ui-icon-button.js.map +1 -0
- package/dist/checkbox/ui-checkbox.html +32 -0
- package/dist/checkbox/ui-checkbox.js +186 -0
- package/dist/checkbox/ui-checkbox.js.map +1 -0
- package/dist/chip/ui-chip.html +32 -0
- package/dist/chip/ui-chip.js +129 -0
- package/dist/chip/ui-chip.js.map +1 -0
- package/dist/combobox/enhance-ui-combobox.js +26 -0
- package/dist/combobox/enhance-ui-combobox.js.map +1 -0
- package/dist/combobox/ui-combobox.html +76 -0
- package/dist/combobox/ui-combobox.js +478 -0
- package/dist/combobox/ui-combobox.js.map +1 -0
- package/dist/disclosure/ui-disclosure.html +28 -0
- package/dist/disclosure/ui-disclosure.js +75 -0
- package/dist/disclosure/ui-disclosure.js.map +1 -0
- package/dist/drawer/ui-drawer.html +35 -0
- package/dist/drawer/ui-drawer.js +246 -0
- package/dist/drawer/ui-drawer.js.map +1 -0
- package/dist/index.js +135 -0
- package/dist/index.js.map +1 -0
- package/dist/input/enhance-ui-input.js +26 -0
- package/dist/input/enhance-ui-input.js.map +1 -0
- package/dist/input/ui-input.html +56 -0
- package/dist/input/ui-input.js +259 -0
- package/dist/input/ui-input.js.map +1 -0
- package/dist/list/ui-list-item.html +22 -0
- package/dist/list/ui-list-item.js +59 -0
- package/dist/list/ui-list-item.js.map +1 -0
- package/dist/list/ui-list.html +10 -0
- package/dist/list/ui-list.js +316 -0
- package/dist/list/ui-list.js.map +1 -0
- package/dist/menu/ui-menu.html +20 -0
- package/dist/menu/ui-menu.js +154 -0
- package/dist/menu/ui-menu.js.map +1 -0
- package/dist/popup/ui-popup.html +16 -0
- package/dist/popup/ui-popup.js +397 -0
- package/dist/popup/ui-popup.js.map +1 -0
- package/dist/progress/ui-progress.html +17 -0
- package/dist/progress/ui-progress.js +76 -0
- package/dist/progress/ui-progress.js.map +1 -0
- package/dist/radio/ui-radio-group.html +27 -0
- package/dist/radio/ui-radio-group.js +259 -0
- package/dist/radio/ui-radio-group.js.map +1 -0
- package/dist/radio/ui-radio.html +11 -0
- package/dist/radio/ui-radio.js +55 -0
- package/dist/radio/ui-radio.js.map +1 -0
- package/dist/segmented-control/ui-segment.html +10 -0
- package/dist/segmented-control/ui-segment.js +44 -0
- package/dist/segmented-control/ui-segment.js.map +1 -0
- package/dist/segmented-control/ui-segmented-control.html +9 -0
- package/dist/segmented-control/ui-segmented-control.js +134 -0
- package/dist/segmented-control/ui-segmented-control.js.map +1 -0
- package/dist/select/enhance-ui-select.js +26 -0
- package/dist/select/enhance-ui-select.js.map +1 -0
- package/dist/select/ui-select.html +70 -0
- package/dist/select/ui-select.js +323 -0
- package/dist/select/ui-select.js.map +1 -0
- package/dist/slider/ui-slider.html +69 -0
- package/dist/slider/ui-slider.js +362 -0
- package/dist/slider/ui-slider.js.map +1 -0
- package/dist/splitter/ui-splitter.html +14 -0
- package/dist/splitter/ui-splitter.js +257 -0
- package/dist/splitter/ui-splitter.js.map +1 -0
- package/dist/switch/ui-switch.html +23 -0
- package/dist/switch/ui-switch.js +121 -0
- package/dist/switch/ui-switch.js.map +1 -0
- package/dist/table/enhance-ui-table.js +25 -0
- package/dist/table/enhance-ui-table.js.map +1 -0
- package/dist/table/ui-table-column.html +17 -0
- package/dist/table/ui-table-column.js +127 -0
- package/dist/table/ui-table-column.js.map +1 -0
- package/dist/table/ui-table.html +56 -0
- package/dist/table/ui-table.js +225 -0
- package/dist/table/ui-table.js.map +1 -0
- package/dist/tabs/ui-tab.html +10 -0
- package/dist/tabs/ui-tab.js +52 -0
- package/dist/tabs/ui-tab.js.map +1 -0
- package/dist/tabs/ui-tabs.html +3 -0
- package/dist/tabs/ui-tabs.js +112 -0
- package/dist/tabs/ui-tabs.js.map +1 -0
- package/dist/toast/ui-toast-region.html +11 -0
- package/dist/toast/ui-toast-region.js +38 -0
- package/dist/toast/ui-toast-region.js.map +1 -0
- package/dist/toast/ui-toast-service.js +70 -0
- package/dist/toast/ui-toast-service.js.map +1 -0
- package/dist/tooltip/ui-tooltip-service.js +63 -0
- package/dist/tooltip/ui-tooltip-service.js.map +1 -0
- package/dist/tooltip/ui-tooltip.js +221 -0
- package/dist/tooltip/ui-tooltip.js.map +1 -0
- package/dist/top-app-bar/ui-top-app-bar.html +24 -0
- package/dist/top-app-bar/ui-top-app-bar.js +68 -0
- package/dist/top-app-bar/ui-top-app-bar.js.map +1 -0
- package/dist/tree/ui-tree.html +38 -0
- package/dist/tree/ui-tree.js +340 -0
- package/dist/tree/ui-tree.js.map +1 -0
- package/dist/types/alert/ui-alert.d.ts +11 -0
- package/dist/types/alert-service/alert-configuration.d.ts +8 -0
- package/dist/types/alert-service/alert-modal/alert-modal.d.ts +7 -0
- package/dist/types/alert-service/alert-modal/i-alert-modal-payload.d.ts +14 -0
- package/dist/types/alert-service/alert-service.d.ts +17 -0
- package/dist/types/alert-service/decorators/confirm-action.d.ts +3 -0
- package/dist/types/alert-service/decorators/using-progress.d.ts +6 -0
- package/dist/types/alert-service/exceptions-tracker.d.ts +3 -0
- package/dist/types/alert-service/prompt-dialog/prompt-dialog.d.ts +17 -0
- package/dist/types/badge/ui-badge.d.ts +7 -0
- package/dist/types/base/boolean-attr.d.ts +1 -0
- package/dist/types/base/i-validated-element.d.ts +10 -0
- package/dist/types/base/keys.d.ts +12 -0
- package/dist/types/breadcrumbs/ui-breadcrumbs.d.ts +8 -0
- package/dist/types/button/enhance-ui-button.d.ts +3 -0
- package/dist/types/button/ui-button.d.ts +16 -0
- package/dist/types/button/ui-icon-button.d.ts +18 -0
- package/dist/types/checkbox/ui-checkbox.d.ts +32 -0
- package/dist/types/chip/ui-chip.d.ts +26 -0
- package/dist/types/combobox/enhance-ui-combobox.d.ts +3 -0
- package/dist/types/combobox/ui-combobox.d.ts +79 -0
- package/dist/types/disclosure/ui-disclosure.d.ts +18 -0
- package/dist/types/drawer/ui-drawer.d.ts +38 -0
- package/dist/types/index.d.ts +91 -0
- package/dist/types/input/enhance-ui-input.d.ts +3 -0
- package/dist/types/input/ui-input.d.ts +44 -0
- package/dist/types/list/ui-list-item.d.ts +10 -0
- package/dist/types/list/ui-list.d.ts +45 -0
- package/dist/types/menu/ui-menu.d.ts +29 -0
- package/dist/types/popup/ui-popup.d.ts +61 -0
- package/dist/types/progress/ui-progress.d.ts +15 -0
- package/dist/types/radio/ui-radio-group.d.ts +37 -0
- package/dist/types/radio/ui-radio.d.ts +11 -0
- package/dist/types/segmented-control/ui-segment.d.ts +8 -0
- package/dist/types/segmented-control/ui-segmented-control.d.ts +17 -0
- package/dist/types/select/enhance-ui-select.d.ts +3 -0
- package/dist/types/select/ui-select.d.ts +50 -0
- package/dist/types/slider/ui-slider.d.ts +58 -0
- package/dist/types/splitter/ui-splitter.d.ts +39 -0
- package/dist/types/switch/ui-switch.d.ts +23 -0
- package/dist/types/table/enhance-ui-table.d.ts +3 -0
- package/dist/types/table/ui-table-column.d.ts +22 -0
- package/dist/types/table/ui-table.d.ts +51 -0
- package/dist/types/tabs/ui-tab.d.ts +10 -0
- package/dist/types/tabs/ui-tabs.d.ts +16 -0
- package/dist/types/toast/ui-toast-region.d.ts +6 -0
- package/dist/types/toast/ui-toast-service.d.ts +28 -0
- package/dist/types/tooltip/ui-tooltip-service.d.ts +23 -0
- package/dist/types/tooltip/ui-tooltip.d.ts +35 -0
- package/dist/types/top-app-bar/ui-top-app-bar.d.ts +9 -0
- package/dist/types/tree/ui-tree.d.ts +70 -0
- package/dist/types/validation/ui-validation-controller-factory.d.ts +7 -0
- package/dist/types/validation/ui-validation-result-presenter.d.ts +4 -0
- package/dist/types/validation/validate.d.ts +13 -0
- package/dist/validation/ui-validation-controller-factory.js +17 -0
- package/dist/validation/ui-validation-controller-factory.js.map +1 -0
- package/dist/validation/ui-validation-result-presenter.js +23 -0
- package/dist/validation/ui-validation-result-presenter.js.map +1 -0
- package/dist/validation/validate.js +24 -0
- package/dist/validation/validate.js.map +1 -0
- package/package.json +50 -0
- package/src/alert/ui-alert.html +19 -0
- package/src/alert/ui-alert.ts +33 -0
- package/src/alert-service/alert-configuration.ts +11 -0
- package/src/alert-service/alert-modal/alert-modal.html +12 -0
- package/src/alert-service/alert-modal/alert-modal.ts +19 -0
- package/src/alert-service/alert-modal/i-alert-modal-payload.ts +14 -0
- package/src/alert-service/alert-service.ts +116 -0
- package/src/alert-service/decorators/confirm-action.ts +18 -0
- package/src/alert-service/decorators/using-progress.ts +32 -0
- package/src/alert-service/exceptions-tracker.ts +3 -0
- package/src/alert-service/prompt-dialog/prompt-dialog.html +13 -0
- package/src/alert-service/prompt-dialog/prompt-dialog.ts +37 -0
- package/src/badge/ui-badge.html +6 -0
- package/src/badge/ui-badge.ts +17 -0
- package/src/base/boolean-attr.ts +3 -0
- package/src/base/i-validated-element.ts +11 -0
- package/src/base/keys.ts +12 -0
- package/src/breadcrumbs/ui-breadcrumbs.html +10 -0
- package/src/breadcrumbs/ui-breadcrumbs.ts +14 -0
- package/src/button/enhance-ui-button.ts +9 -0
- package/src/button/ui-button.html +20 -0
- package/src/button/ui-button.ts +60 -0
- package/src/button/ui-icon-button.html +20 -0
- package/src/button/ui-icon-button.ts +62 -0
- package/src/checkbox/ui-checkbox.html +32 -0
- package/src/checkbox/ui-checkbox.ts +188 -0
- package/src/chip/ui-chip.html +32 -0
- package/src/chip/ui-chip.ts +118 -0
- package/src/combobox/enhance-ui-combobox.ts +10 -0
- package/src/combobox/ui-combobox.html +76 -0
- package/src/combobox/ui-combobox.ts +450 -0
- package/src/disclosure/ui-disclosure.html +28 -0
- package/src/disclosure/ui-disclosure.ts +68 -0
- package/src/drawer/ui-drawer.html +35 -0
- package/src/drawer/ui-drawer.ts +219 -0
- package/src/index.ts +152 -0
- package/src/input/enhance-ui-input.ts +10 -0
- package/src/input/ui-input.html +56 -0
- package/src/input/ui-input.ts +225 -0
- package/src/list/ui-list-item.html +22 -0
- package/src/list/ui-list-item.ts +25 -0
- package/src/list/ui-list.html +10 -0
- package/src/list/ui-list.ts +330 -0
- package/src/menu/ui-menu.html +20 -0
- package/src/menu/ui-menu.ts +103 -0
- package/src/popup/ui-popup.html +16 -0
- package/src/popup/ui-popup.ts +391 -0
- package/src/progress/ui-progress.html +17 -0
- package/src/progress/ui-progress.ts +51 -0
- package/src/radio/ui-radio-group.html +27 -0
- package/src/radio/ui-radio-group.ts +250 -0
- package/src/radio/ui-radio.html +11 -0
- package/src/radio/ui-radio.ts +35 -0
- package/src/resource.d.ts +4 -0
- package/src/segmented-control/ui-segment.html +10 -0
- package/src/segmented-control/ui-segment.ts +20 -0
- package/src/segmented-control/ui-segmented-control.html +9 -0
- package/src/segmented-control/ui-segmented-control.ts +119 -0
- package/src/select/enhance-ui-select.ts +10 -0
- package/src/select/ui-select.html +70 -0
- package/src/select/ui-select.ts +294 -0
- package/src/slider/ui-slider.html +69 -0
- package/src/slider/ui-slider.ts +329 -0
- package/src/splitter/ui-splitter.html +14 -0
- package/src/splitter/ui-splitter.ts +249 -0
- package/src/switch/ui-switch.html +23 -0
- package/src/switch/ui-switch.ts +121 -0
- package/src/table/enhance-ui-table.ts +9 -0
- package/src/table/ui-table-column.html +17 -0
- package/src/table/ui-table-column.ts +108 -0
- package/src/table/ui-table.html +56 -0
- package/src/table/ui-table.ts +209 -0
- package/src/tabs/ui-tab.html +10 -0
- package/src/tabs/ui-tab.ts +30 -0
- package/src/tabs/ui-tabs.html +3 -0
- package/src/tabs/ui-tabs.ts +105 -0
- package/src/toast/ui-toast-region.html +11 -0
- package/src/toast/ui-toast-region.ts +18 -0
- package/src/toast/ui-toast-service.ts +100 -0
- package/src/tooltip/ui-tooltip-service.ts +84 -0
- package/src/tooltip/ui-tooltip.ts +200 -0
- package/src/top-app-bar/ui-top-app-bar.html +24 -0
- package/src/top-app-bar/ui-top-app-bar.ts +27 -0
- package/src/tree/ui-tree.html +38 -0
- package/src/tree/ui-tree.ts +363 -0
- package/src/validation/ui-validation-controller-factory.ts +20 -0
- package/src/validation/ui-validation-result-presenter.ts +26 -0
- package/src/validation/validate.ts +35 -0
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
import { bindable, BindingMode, customElement, INode, resolve } from 'aurelia';
|
|
2
|
+
import { booleanAttr } from '../base/boolean-attr';
|
|
3
|
+
import type { UiTableColumn } from './ui-table-column';
|
|
4
|
+
import template from './ui-table.html?raw';
|
|
5
|
+
|
|
6
|
+
type TableSort = { column: string; direction: 'asc' | 'desc' };
|
|
7
|
+
type ColumnSort = { column: string; columnViewModel: UiTableColumn; direction: 'asc' | 'desc' | undefined; multiple: boolean };
|
|
8
|
+
|
|
9
|
+
@customElement({ name: 'ui-table', template })
|
|
10
|
+
export class UiTable {
|
|
11
|
+
private readonly host = resolve(INode) as HTMLElement;
|
|
12
|
+
private columnSizes: Record<string, number> = {};
|
|
13
|
+
private readonly sortedColumns = new Map<string, UiTableColumn>();
|
|
14
|
+
|
|
15
|
+
@bindable({ mode: BindingMode.twoWay })
|
|
16
|
+
sort: TableSort[] = [];
|
|
17
|
+
sortChanged(): void {
|
|
18
|
+
this.updateColumnSortState();
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
@bindable({ mode: BindingMode.twoWay })
|
|
22
|
+
page: number = 1;
|
|
23
|
+
|
|
24
|
+
@bindable({ mode: BindingMode.twoWay })
|
|
25
|
+
pageSize: number = 10;
|
|
26
|
+
|
|
27
|
+
@bindable
|
|
28
|
+
total: number = 0;
|
|
29
|
+
totalChanged(): void {
|
|
30
|
+
this.updateTotalPages();
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
totalPages = 1;
|
|
34
|
+
pageOptions: number[] = [1];
|
|
35
|
+
|
|
36
|
+
@bindable
|
|
37
|
+
storageKey: string | undefined;
|
|
38
|
+
storageKeyChanged(): void {
|
|
39
|
+
this.loadColumnSizes();
|
|
40
|
+
this.applyColumnSizes();
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
@bindable({ set: booleanAttr })
|
|
44
|
+
pagination: boolean = true;
|
|
45
|
+
|
|
46
|
+
@bindable({ set: booleanAttr })
|
|
47
|
+
progress: boolean = false;
|
|
48
|
+
|
|
49
|
+
@bindable
|
|
50
|
+
pageSizeOptions: number[] = [10, 25, 50];
|
|
51
|
+
|
|
52
|
+
@bindable
|
|
53
|
+
paginationText: string = 'Custom';
|
|
54
|
+
|
|
55
|
+
attaching(): void {
|
|
56
|
+
this.loadColumnSizes();
|
|
57
|
+
this.updateTotalPages();
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
setColumnWidth(columnId: string, width: number, persist = false): void {
|
|
61
|
+
this.columnSizes[columnId] = width;
|
|
62
|
+
const column = this.host.querySelector<HTMLElement>(`#${columnId}`);
|
|
63
|
+
if (column) {
|
|
64
|
+
this.applyColumnWidth(column, width);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
if (persist) {
|
|
68
|
+
this.persistColumnSizes();
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
onColumnSort(event: CustomEvent<ColumnSort>): void {
|
|
73
|
+
event.stopPropagation();
|
|
74
|
+
this.sortedColumns.set(event.detail.column, event.detail.columnViewModel);
|
|
75
|
+
const next = event.detail.multiple ? this.sort.filter(sort => sort.column !== event.detail.column) : [];
|
|
76
|
+
if (event.detail.direction) {
|
|
77
|
+
next.push({ column: event.detail.column, direction: event.detail.direction });
|
|
78
|
+
}
|
|
79
|
+
this.sort = next;
|
|
80
|
+
this.updateColumnSortState();
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
private updateColumnSortState(): void {
|
|
84
|
+
for (const column of this.sortedColumns.values()) {
|
|
85
|
+
column.direction = undefined;
|
|
86
|
+
column.sortOrder = undefined;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
for (let index = 0; index < this.sort.length; index++) {
|
|
90
|
+
const sort = this.sort[index];
|
|
91
|
+
const column = this.sortedColumns.get(sort.column);
|
|
92
|
+
if (column) {
|
|
93
|
+
column.direction = sort.direction;
|
|
94
|
+
column.sortOrder = this.sort.length > 1 ? index + 1 : undefined;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
pageSizeChanged(): void {
|
|
100
|
+
this.updateTotalPages();
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
nextPage(): void {
|
|
104
|
+
const next = this.page + 1;
|
|
105
|
+
if (next <= this.totalPages) {
|
|
106
|
+
this.setPage(next);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
firstPage(): void {
|
|
111
|
+
this.setPage(1);
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
lastPage(): void {
|
|
115
|
+
this.setPage(this.totalPages);
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
previousPage(): void {
|
|
119
|
+
this.setPage(Math.max(1, this.page - 1));
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
setPage(page: number): void {
|
|
123
|
+
const next = Math.max(1, Math.min(this.totalPages, Number(page) || 1));
|
|
124
|
+
if (this.page === next) {
|
|
125
|
+
return;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
this.page = next;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
setPageSize(pageSize: number): void {
|
|
132
|
+
const next = Math.max(1, Number(pageSize) || 1);
|
|
133
|
+
if (this.pageSize === next) {
|
|
134
|
+
this.updateTotalPages();
|
|
135
|
+
return;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
this.pageSize = next;
|
|
139
|
+
this.page = 1;
|
|
140
|
+
this.updateTotalPages();
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
onPageSizeChange(event: Event): void {
|
|
144
|
+
const target = event.target as { value?: unknown } | null;
|
|
145
|
+
this.setPageSize(Number(target?.value));
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
onPageChange(event: Event): void {
|
|
149
|
+
const target = event.target as { value?: unknown } | null;
|
|
150
|
+
this.setPage(Number(target?.value));
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
private updateTotalPages(): void {
|
|
154
|
+
this.totalPages = Math.max(1, Math.ceil(this.total / this.pageSize));
|
|
155
|
+
this.pageOptions = Array.from({ length: this.totalPages }, (_, index) => index + 1);
|
|
156
|
+
this.page = Math.max(1, Math.min(this.totalPages, Number(this.page) || 1));
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
private applyColumnSizes(): void {
|
|
160
|
+
for (const column of this.host.querySelectorAll<HTMLElement>('.ui-table-column')) {
|
|
161
|
+
this.applyColumnWidth(column, this.columnSizes[column.id]);
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
getColumnWidth(columnId: string): number | undefined {
|
|
166
|
+
return this.columnSizes[columnId];
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
private applyColumnWidth(column: HTMLElement, width: number | undefined): void {
|
|
170
|
+
if (width === undefined) {
|
|
171
|
+
column.style.removeProperty('width');
|
|
172
|
+
column.style.removeProperty('min-width');
|
|
173
|
+
return;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
column.style.width = `${width}px`;
|
|
177
|
+
column.style.minWidth = `${width}px`;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
private loadColumnSizes(): void {
|
|
181
|
+
this.columnSizes = {};
|
|
182
|
+
if (!this.storageKey) {
|
|
183
|
+
return;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
try {
|
|
187
|
+
const value = localStorage.getItem(this.storageId);
|
|
188
|
+
this.columnSizes = value ? JSON.parse(value) : {};
|
|
189
|
+
} catch {
|
|
190
|
+
this.columnSizes = {};
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
private persistColumnSizes(): void {
|
|
195
|
+
if (!this.storageKey) {
|
|
196
|
+
return;
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
try {
|
|
200
|
+
localStorage.setItem(this.storageId, JSON.stringify(this.columnSizes));
|
|
201
|
+
} catch {
|
|
202
|
+
// Ignore unavailable storage.
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
private get storageId(): string {
|
|
207
|
+
return `ui-table:${this.storageKey}:columns`;
|
|
208
|
+
}
|
|
209
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
<template class="ui-tab"
|
|
2
|
+
role="tab"
|
|
3
|
+
tabindex.bind="tabIndex"
|
|
4
|
+
aria-selected.attr="selected ? 'true' : 'false'"
|
|
5
|
+
aria-disabled.attr="disabled ? '' : null"
|
|
6
|
+
data-selected.attr="selected ? '' : null"
|
|
7
|
+
data-disabled.attr="disabled ? '' : null"
|
|
8
|
+
click.trigger="onClick()">
|
|
9
|
+
<au-slot></au-slot>
|
|
10
|
+
</template>
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { bindable, customElement, INode, resolve } from 'aurelia';
|
|
2
|
+
import { booleanAttr } from '../base/boolean-attr';
|
|
3
|
+
import { UiTabs } from './ui-tabs';
|
|
4
|
+
import template from './ui-tab.html?raw';
|
|
5
|
+
|
|
6
|
+
@customElement({ name: 'ui-tab', template })
|
|
7
|
+
export class UiTab {
|
|
8
|
+
readonly element = resolve(INode) as HTMLElement;
|
|
9
|
+
readonly parentTabs = resolve(UiTabs);
|
|
10
|
+
|
|
11
|
+
@bindable
|
|
12
|
+
value: unknown = this;
|
|
13
|
+
|
|
14
|
+
@bindable({ set: booleanAttr })
|
|
15
|
+
disabled: boolean = false;
|
|
16
|
+
|
|
17
|
+
get selected(): boolean {
|
|
18
|
+
return this.parentTabs.isSelected(this);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
get tabIndex(): number {
|
|
22
|
+
return !this.disabled && this.selected ? 0 : -1;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
onClick(): void {
|
|
26
|
+
if (!this.disabled) {
|
|
27
|
+
this.parentTabs.select(this.value);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
}
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import { bindable, BindingMode, children, customElement, INode, resolve } from 'aurelia';
|
|
2
|
+
import { Keys } from '../base/keys';
|
|
3
|
+
import { UiTab } from './ui-tab';
|
|
4
|
+
import template from './ui-tabs.html?raw';
|
|
5
|
+
|
|
6
|
+
@customElement({ name: 'ui-tabs', template })
|
|
7
|
+
export class UiTabs {
|
|
8
|
+
private readonly element = resolve(INode) as HTMLElement;
|
|
9
|
+
|
|
10
|
+
@bindable({ mode: BindingMode.twoWay })
|
|
11
|
+
value: unknown;
|
|
12
|
+
|
|
13
|
+
@children({
|
|
14
|
+
query: 'ui-tab',
|
|
15
|
+
map: (_node, viewModel) => viewModel
|
|
16
|
+
})
|
|
17
|
+
tabs: UiTab[] = [];
|
|
18
|
+
tabsChanged(): void {
|
|
19
|
+
this.selectInitialTab();
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
attached(): void {
|
|
23
|
+
this.selectInitialTab();
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
select(value: unknown): void {
|
|
27
|
+
if (this.value === value) {
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
this.value = value;
|
|
32
|
+
this.dispatchValueEvent('input');
|
|
33
|
+
this.dispatchValueEvent('change');
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
isSelected(tab: UiTab): boolean {
|
|
37
|
+
return this.value === tab.value;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
onKeyDown(event: KeyboardEvent): void {
|
|
41
|
+
const tabs = this.enabledTabs;
|
|
42
|
+
if (!tabs.length) {
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
if (event.key === Keys.Home) {
|
|
47
|
+
event.preventDefault();
|
|
48
|
+
this.focusTab(tabs[0]);
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
if (event.key === Keys.End) {
|
|
53
|
+
event.preventDefault();
|
|
54
|
+
this.focusTab(tabs[tabs.length - 1]);
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
const direction = this.getNavigationDirection(event.key);
|
|
59
|
+
if (!direction) {
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
event.preventDefault();
|
|
64
|
+
const active = this.tabs.find(tab => tab.element === document.activeElement) ?? this.tabs.find(tab => this.isSelected(tab));
|
|
65
|
+
const index = active ? tabs.indexOf(active) : -1;
|
|
66
|
+
const next = tabs[(index + direction + tabs.length) % tabs.length];
|
|
67
|
+
this.focusTab(next);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
private get enabledTabs(): UiTab[] {
|
|
71
|
+
return this.tabs.filter(tab => !tab.disabled);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
private selectInitialTab(): void {
|
|
75
|
+
if (this.value !== undefined || !this.tabs.length) {
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
const first = this.enabledTabs[0];
|
|
80
|
+
if (first) {
|
|
81
|
+
this.value = first.value;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
private focusTab(tab: UiTab): void {
|
|
86
|
+
this.select(tab.value);
|
|
87
|
+
tab.element.focus();
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
private getNavigationDirection(key: string): 1 | -1 | undefined {
|
|
91
|
+
if (key === Keys.ArrowRight || key === Keys.ArrowDown) {
|
|
92
|
+
return 1;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
if (key === Keys.ArrowLeft || key === Keys.ArrowUp) {
|
|
96
|
+
return -1;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
return undefined;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
private dispatchValueEvent(type: 'input' | 'change'): void {
|
|
103
|
+
this.element.dispatchEvent(new Event(type, { bubbles: true }));
|
|
104
|
+
}
|
|
105
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
<template class="ui-toast-region" role="region" aria-label="Notifications">
|
|
2
|
+
<ui-alert repeat.for="toast of toasts"
|
|
3
|
+
class="ui-toast-region__toast"
|
|
4
|
+
tone.bind="toast.tone"
|
|
5
|
+
title.bind="toast.title"
|
|
6
|
+
role.bind="toast.tone === 'danger' ? 'alert' : 'status'"
|
|
7
|
+
dismissible
|
|
8
|
+
alert-close.trigger="close(toast)">
|
|
9
|
+
${toast.message}
|
|
10
|
+
</ui-alert>
|
|
11
|
+
</template>
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { bindable, customElement, INode, resolve } from 'aurelia';
|
|
2
|
+
import { UiToastMessage } from './ui-toast-service';
|
|
3
|
+
import template from './ui-toast-region.html?raw';
|
|
4
|
+
|
|
5
|
+
@customElement({ name: 'ui-toast-region', template })
|
|
6
|
+
export class UiToastRegion {
|
|
7
|
+
private readonly host = resolve(INode) as HTMLElement;
|
|
8
|
+
|
|
9
|
+
@bindable
|
|
10
|
+
toasts: UiToastMessage[] = [];
|
|
11
|
+
|
|
12
|
+
close(toast: UiToastMessage): void {
|
|
13
|
+
this.host.dispatchEvent(new CustomEvent('toast-close', {
|
|
14
|
+
bubbles: true,
|
|
15
|
+
detail: toast.id
|
|
16
|
+
}));
|
|
17
|
+
}
|
|
18
|
+
}
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import { Aurelia, IContainer, resolve } from 'aurelia';
|
|
2
|
+
import { AlertTone } from '../alert/ui-alert';
|
|
3
|
+
|
|
4
|
+
type EnhancedView = { deactivate(): void | Promise<void> };
|
|
5
|
+
|
|
6
|
+
export interface UiToastOptions {
|
|
7
|
+
tone?: AlertTone;
|
|
8
|
+
title?: string;
|
|
9
|
+
message: string;
|
|
10
|
+
duration?: number;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export interface UiToastMessage extends Required<Pick<UiToastOptions, 'tone' | 'message' | 'duration'>> {
|
|
14
|
+
id: number;
|
|
15
|
+
title?: string;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export class UiToastService {
|
|
19
|
+
private readonly container = resolve(IContainer);
|
|
20
|
+
private host: HTMLElement | undefined;
|
|
21
|
+
private enhanced: EnhancedView | undefined;
|
|
22
|
+
private nextId = 0;
|
|
23
|
+
private timers = new Map<number, ReturnType<typeof setTimeout>>();
|
|
24
|
+
|
|
25
|
+
toasts: UiToastMessage[] = [];
|
|
26
|
+
|
|
27
|
+
async show(options: string | UiToastOptions): Promise<number> {
|
|
28
|
+
await this.ensureEnhanced();
|
|
29
|
+
const toast = this.createToast(options);
|
|
30
|
+
this.toasts = [...this.toasts, toast];
|
|
31
|
+
|
|
32
|
+
if (toast.duration > 0) {
|
|
33
|
+
this.timers.set(toast.id, setTimeout(() => this.remove(toast.id), toast.duration));
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
return toast.id;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
info(message: string, title?: string): Promise<number> {
|
|
40
|
+
return this.show({ tone: 'info', title, message });
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
success(message: string, title?: string): Promise<number> {
|
|
44
|
+
return this.show({ tone: 'success', title, message });
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
warning(message: string, title?: string): Promise<number> {
|
|
48
|
+
return this.show({ tone: 'warning', title, message });
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
danger(message: string, title?: string): Promise<number> {
|
|
52
|
+
return this.show({ tone: 'danger', title, message, duration: 7000 });
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
remove(id: number): void {
|
|
56
|
+
const timer = this.timers.get(id);
|
|
57
|
+
if (timer) {
|
|
58
|
+
clearTimeout(timer);
|
|
59
|
+
this.timers.delete(id);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
this.toasts = this.toasts.filter(toast => toast.id !== id);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
clear(): void {
|
|
66
|
+
for (const timer of this.timers.values()) {
|
|
67
|
+
clearTimeout(timer);
|
|
68
|
+
}
|
|
69
|
+
this.timers.clear();
|
|
70
|
+
this.toasts = [];
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
private createToast(options: string | UiToastOptions): UiToastMessage {
|
|
74
|
+
const normalized = typeof options === 'string' ? { message: options } : options;
|
|
75
|
+
return {
|
|
76
|
+
id: ++this.nextId,
|
|
77
|
+
tone: normalized.tone ?? 'info',
|
|
78
|
+
title: normalized.title,
|
|
79
|
+
message: normalized.message,
|
|
80
|
+
duration: normalized.duration ?? 5000
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
private async ensureEnhanced(): Promise<void> {
|
|
85
|
+
if (this.enhanced) {
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
this.host = document.createElement('div');
|
|
90
|
+
this.host.className = 'ui-toast-host';
|
|
91
|
+
this.host.innerHTML = `<ui-toast-region toasts.bind="toasts" toast-close.trigger="remove($event.detail)"></ui-toast-region>`;
|
|
92
|
+
document.body.append(this.host);
|
|
93
|
+
|
|
94
|
+
this.enhanced = await Aurelia.enhance({
|
|
95
|
+
host: this.host,
|
|
96
|
+
component: this,
|
|
97
|
+
container: this.container
|
|
98
|
+
}) as EnhancedView;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import { Aurelia, IContainer, resolve } from 'aurelia';
|
|
2
|
+
|
|
3
|
+
type TooltipPlacement = 'bottom-start' | 'bottom-end' | 'top-start' | 'top-end';
|
|
4
|
+
type EnhancedView = { deactivate(): void | Promise<void> };
|
|
5
|
+
|
|
6
|
+
let nextTooltipId = 0;
|
|
7
|
+
|
|
8
|
+
interface TooltipOptions {
|
|
9
|
+
anchor: HTMLElement;
|
|
10
|
+
text: string;
|
|
11
|
+
placement: TooltipPlacement;
|
|
12
|
+
offset: number;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export class UiTooltipService {
|
|
16
|
+
private readonly container = resolve(IContainer);
|
|
17
|
+
private host: HTMLElement | undefined;
|
|
18
|
+
private enhanced: EnhancedView | undefined;
|
|
19
|
+
private request = 0;
|
|
20
|
+
|
|
21
|
+
open = false;
|
|
22
|
+
anchor: HTMLElement | undefined;
|
|
23
|
+
text = '';
|
|
24
|
+
placement: TooltipPlacement = 'top-start';
|
|
25
|
+
offset = 6;
|
|
26
|
+
tooltipId = `ui-tooltip-${++nextTooltipId}`;
|
|
27
|
+
|
|
28
|
+
async show(options: TooltipOptions): Promise<void> {
|
|
29
|
+
const request = ++this.request;
|
|
30
|
+
await this.ensureEnhanced();
|
|
31
|
+
if (request !== this.request) {
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
this.anchor = options.anchor;
|
|
36
|
+
this.text = options.text;
|
|
37
|
+
this.placement = options.placement;
|
|
38
|
+
this.offset = options.offset;
|
|
39
|
+
this.open = true;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
hide(anchor: HTMLElement): void {
|
|
43
|
+
if (this.anchor !== anchor) {
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
this.request++;
|
|
48
|
+
this.open = false;
|
|
49
|
+
this.anchor = undefined;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
private async ensureEnhanced(): Promise<void> {
|
|
53
|
+
if (this.enhanced) {
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
this.host = document.createElement('div');
|
|
58
|
+
this.host.className = 'ui-tooltip';
|
|
59
|
+
this.host.innerHTML = `
|
|
60
|
+
<ui-popup
|
|
61
|
+
open.bind="open"
|
|
62
|
+
anchor.bind="anchor"
|
|
63
|
+
placement.bind="placement"
|
|
64
|
+
offset.bind="offset"
|
|
65
|
+
focus-on-open.bind="false"
|
|
66
|
+
restore-focus.bind="false"
|
|
67
|
+
close-on-outside.bind="false"
|
|
68
|
+
close-on-escape.bind="false"
|
|
69
|
+
panel-role="tooltip"
|
|
70
|
+
panel-id.bind="tooltipId">
|
|
71
|
+
<span class="ui-tooltip__content">\${text}</span>
|
|
72
|
+
</ui-popup>
|
|
73
|
+
`;
|
|
74
|
+
document.body.append(this.host);
|
|
75
|
+
|
|
76
|
+
this.enhanced = await Aurelia.enhance({
|
|
77
|
+
host: this.host,
|
|
78
|
+
component: this,
|
|
79
|
+
container: this.container
|
|
80
|
+
}) as EnhancedView;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
export type { TooltipPlacement, TooltipOptions };
|