@egose/shadcn-theme-ng-tw 0.5.2 → 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +12 -11
- package/data-table/README.md +164 -0
- package/data-table/fesm2022/data-table.mjs +1449 -0
- package/data-table/package.json +25 -0
- package/data-table/types/data-table.d.ts +483 -0
- package/dropdown-menu/README.md +2 -0
- package/form-checkbox/README.md +22 -22
- package/form-text-input/fesm2022/form-text-input.mjs +1 -1
- package/form-textarea/fesm2022/form-textarea.mjs +1 -1
- package/input/README.md +7 -12
- package/input/fesm2022/input.mjs +7 -4
- package/input/types/input.d.ts +3 -1
- package/layout-simple/fesm2022/layout-simple.mjs +1 -1
- package/package.json +6 -1
- package/phone-input/fesm2022/phone-input.mjs +1 -1
- package/stepper/README.md +75 -52
- package/stepper/fesm2022/stepper.mjs +35 -5
- package/stepper/types/stepper.d.ts +22 -14
- package/table/README.md +2 -0
- package/table/fesm2022/table.mjs +12 -8
- package/table/types/table.d.ts +7 -2
|
@@ -0,0 +1,1449 @@
|
|
|
1
|
+
import * as i0 from '@angular/core';
|
|
2
|
+
import { input, computed, ChangeDetectionStrategy, Component, model, output, signal, linkedSignal, effect, NgModule } from '@angular/core';
|
|
3
|
+
import { NgTemplateOutlet } from '@angular/common';
|
|
4
|
+
import { HlmButton } from '@egose/shadcn-theme-ng-tw/button';
|
|
5
|
+
import { HlmCard, HlmCardContent } from '@egose/shadcn-theme-ng-tw/card';
|
|
6
|
+
import { HlmIcon } from '@egose/shadcn-theme-ng-tw/icon';
|
|
7
|
+
import { HlmInput } from '@egose/shadcn-theme-ng-tw/input';
|
|
8
|
+
import { HlmSpinner } from '@egose/shadcn-theme-ng-tw/spinner';
|
|
9
|
+
import * as i2 from '@egose/shadcn-theme-ng-tw/table';
|
|
10
|
+
import { HlmTableImports } from '@egose/shadcn-theme-ng-tw/table';
|
|
11
|
+
import { HlmToggleGroup, HlmToggleGroupItem } from '@egose/shadcn-theme-ng-tw/toggle-group';
|
|
12
|
+
import { hlm } from '@egose/shadcn-theme-ng-tw/utils';
|
|
13
|
+
import { NgIcon, provideIcons } from '@ng-icons/core';
|
|
14
|
+
import { lucideChevronsRight, lucideChevronsLeft, lucideChevronRight, lucideChevronLeft, lucideSettings2, lucideLayoutList, lucideLayoutGrid, lucideChevronsUpDown, lucideArrowUp, lucideArrowDown, lucideEyeOff } from '@ng-icons/lucide';
|
|
15
|
+
import * as i1$2 from '@tanstack/angular-table';
|
|
16
|
+
import { createFilteredRowModel, createPaginatedRowModel, createSortedRowModel, filterFn_includesString, sortFn_alphanumeric, sortFn_text, tableFeatures, rowSortingFeature, rowSelectionFeature, rowPaginationFeature, columnVisibilityFeature, columnFilteringFeature, injectTableContext, createColumnHelper, injectTable, TanStackTable, FlexRender } from '@tanstack/angular-table';
|
|
17
|
+
import * as i1 from '@egose/shadcn-theme-ng-tw/select';
|
|
18
|
+
import { HlmSelectImports } from '@egose/shadcn-theme-ng-tw/select';
|
|
19
|
+
import * as i1$1 from '@egose/shadcn-theme-ng-tw/dropdown-menu';
|
|
20
|
+
import { HlmDropdownMenuImports } from '@egose/shadcn-theme-ng-tw/dropdown-menu';
|
|
21
|
+
import { HlmCheckbox } from '@egose/shadcn-theme-ng-tw/checkbox';
|
|
22
|
+
|
|
23
|
+
// Explicit instantiations keep the inferred feature-registry type free of `any`
|
|
24
|
+
// (the factories default their generics to `any` when called bare, which would
|
|
25
|
+
// leak into our emitted declarations and trip package validation).
|
|
26
|
+
const filteredRowModel = createFilteredRowModel();
|
|
27
|
+
const paginatedRowModel = createPaginatedRowModel();
|
|
28
|
+
const sortedRowModel = createSortedRowModel();
|
|
29
|
+
const includesString = filterFn_includesString;
|
|
30
|
+
const alphanumeric = sortFn_alphanumeric;
|
|
31
|
+
const text = sortFn_text;
|
|
32
|
+
/**
|
|
33
|
+
* Default feature set for `EgDataTable`.
|
|
34
|
+
*
|
|
35
|
+
* Mirrors the Spartan data-table guide: filtering, visibility, pagination,
|
|
36
|
+
* selection and sorting are opted in, with the built-in `includesString`
|
|
37
|
+
* filter and `alphanumeric` / `text` sort functions registered. Anything a
|
|
38
|
+
* caller does not need can be dropped by passing a custom `features` input.
|
|
39
|
+
*
|
|
40
|
+
* Keep this reference stable (module scope) — `injectTable()` re-evaluates
|
|
41
|
+
* its initializer on every signal read, so recreating features per render
|
|
42
|
+
* would thrash the table instance.
|
|
43
|
+
*/
|
|
44
|
+
const defaultEgDataTableFeatures = tableFeatures({
|
|
45
|
+
columnFilteringFeature,
|
|
46
|
+
columnVisibilityFeature,
|
|
47
|
+
rowPaginationFeature,
|
|
48
|
+
rowSelectionFeature,
|
|
49
|
+
rowSortingFeature,
|
|
50
|
+
filteredRowModel,
|
|
51
|
+
paginatedRowModel,
|
|
52
|
+
sortedRowModel,
|
|
53
|
+
filterFns: { includesString },
|
|
54
|
+
sortFns: { alphanumeric, text },
|
|
55
|
+
columnMeta: {},
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
class EgDataTablePagination {
|
|
59
|
+
/** Show the `selected of total` status text. Set false when the host renders its own status. */
|
|
60
|
+
showStatus = input(true, /* @ts-ignore */
|
|
61
|
+
...(ngDevMode ? [{ debugName: "showStatus" }] : /* istanbul ignore next */ []));
|
|
62
|
+
/** Show the rows-per-page selector. */
|
|
63
|
+
showPageSize = input(true, /* @ts-ignore */
|
|
64
|
+
...(ngDevMode ? [{ debugName: "showPageSize" }] : /* istanbul ignore next */ []));
|
|
65
|
+
/** Page-size options. The table's current size is appended when absent. */
|
|
66
|
+
pageSizes = input([10, 20, 30, 40, 50], /* @ts-ignore */
|
|
67
|
+
...(ngDevMode ? [{ debugName: "pageSizes" }] : /* istanbul ignore next */ []));
|
|
68
|
+
/** Navigation-button content: icons only, text labels only, or both. */
|
|
69
|
+
navMode = input('icons', /* @ts-ignore */
|
|
70
|
+
...(ngDevMode ? [{ debugName: "navMode" }] : /* istanbul ignore next */ []));
|
|
71
|
+
/** Density of buttons, trigger, and meta texts. Type scale of buttons is untouched. */
|
|
72
|
+
size = input('default', /* @ts-ignore */
|
|
73
|
+
...(ngDevMode ? [{ debugName: "size" }] : /* istanbul ignore next */ []));
|
|
74
|
+
_table = injectTableContext();
|
|
75
|
+
_pageCount = computed(() => this._table().getPageCount(), /* @ts-ignore */
|
|
76
|
+
...(ngDevMode ? [{ debugName: "_pageCount" }] : /* istanbul ignore next */ []));
|
|
77
|
+
// `atoms` are signal-backed, so the pager stays in sync with the table.
|
|
78
|
+
_pageIndex = computed(() => this._table().atoms.pagination.get().pageIndex, /* @ts-ignore */
|
|
79
|
+
...(ngDevMode ? [{ debugName: "_pageIndex" }] : /* istanbul ignore next */ []));
|
|
80
|
+
_pageSize = computed(() => this._table().atoms.pagination.get().pageSize, /* @ts-ignore */
|
|
81
|
+
...(ngDevMode ? [{ debugName: "_pageSize" }] : /* istanbul ignore next */ []));
|
|
82
|
+
_canPrevious = computed(() => this._table().getCanPreviousPage(), /* @ts-ignore */
|
|
83
|
+
...(ngDevMode ? [{ debugName: "_canPrevious" }] : /* istanbul ignore next */ []));
|
|
84
|
+
_canNext = computed(() => this._table().getCanNextPage(), /* @ts-ignore */
|
|
85
|
+
...(ngDevMode ? [{ debugName: "_canNext" }] : /* istanbul ignore next */ []));
|
|
86
|
+
_showPager = computed(() => this._pageCount() > 1, /* @ts-ignore */
|
|
87
|
+
...(ngDevMode ? [{ debugName: "_showPager" }] : /* istanbul ignore next */ []));
|
|
88
|
+
/** Icon-only buttons stay square; labeled buttons size to their text. Merged by `hlmButton` via the `class` binding. */
|
|
89
|
+
_navButtonClass = computed(() => hlm(this.size() === 'sm' ? 'tw:h-7 tw:p-0' : this.size() === 'lg' ? 'tw:h-9 tw:p-0' : 'tw:h-8 tw:p-0', this.navMode() === 'icons'
|
|
90
|
+
? this.size() === 'sm'
|
|
91
|
+
? 'tw:w-7'
|
|
92
|
+
: this.size() === 'lg'
|
|
93
|
+
? 'tw:w-9'
|
|
94
|
+
: 'tw:w-8'
|
|
95
|
+
: 'tw:gap-1 tw:px-2'), /* @ts-ignore */
|
|
96
|
+
...(ngDevMode ? [{ debugName: "_navButtonClass" }] : /* istanbul ignore next */ []));
|
|
97
|
+
/** First/last buttons stay desktop-only. */
|
|
98
|
+
_edgeNavButtonClass = computed(() => hlm('tw:hidden tw:lg:flex', this._navButtonClass()), /* @ts-ignore */
|
|
99
|
+
...(ngDevMode ? [{ debugName: "_edgeNavButtonClass" }] : /* istanbul ignore next */ []));
|
|
100
|
+
/** Meta-text size per density (status, page indicator, rows-per-page label). */
|
|
101
|
+
_metaTextClass = computed(() => this.size() === 'sm' ? 'tw:text-xs' : this.size() === 'lg' ? 'tw:text-base' : 'tw:text-sm', /* @ts-ignore */
|
|
102
|
+
...(ngDevMode ? [{ debugName: "_metaTextClass" }] : /* istanbul ignore next */ []));
|
|
103
|
+
_pageSizeOptions = computed(() => {
|
|
104
|
+
const sizes = this.pageSizes();
|
|
105
|
+
const current = this._pageSize();
|
|
106
|
+
if (sizes.includes(current))
|
|
107
|
+
return sizes;
|
|
108
|
+
return [...sizes, current].sort((left, right) => left - right);
|
|
109
|
+
}, /* @ts-ignore */
|
|
110
|
+
...(ngDevMode ? [{ debugName: "_pageSizeOptions" }] : /* istanbul ignore next */ []));
|
|
111
|
+
_statusText = computed(() => {
|
|
112
|
+
const table = this._table();
|
|
113
|
+
const selected = table.getFilteredSelectedRowModel().rows.length;
|
|
114
|
+
const total = table.getFilteredRowModel().rows.length;
|
|
115
|
+
if (selected > 0)
|
|
116
|
+
return `${selected} of ${total} row(s) selected.`;
|
|
117
|
+
return `${total} row(s).`;
|
|
118
|
+
}, /* @ts-ignore */
|
|
119
|
+
...(ngDevMode ? [{ debugName: "_statusText" }] : /* istanbul ignore next */ []));
|
|
120
|
+
_onPageSizeChange(value) {
|
|
121
|
+
this._table().setPageSize(Number(value));
|
|
122
|
+
}
|
|
123
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: EgDataTablePagination, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
124
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.3", type: EgDataTablePagination, isStandalone: true, selector: "eg-data-table-pagination", inputs: { showStatus: { classPropertyName: "showStatus", publicName: "showStatus", isSignal: true, isRequired: false, transformFunction: null }, showPageSize: { classPropertyName: "showPageSize", publicName: "showPageSize", isSignal: true, isRequired: false, transformFunction: null }, pageSizes: { classPropertyName: "pageSizes", publicName: "pageSizes", isSignal: true, isRequired: false, transformFunction: null }, navMode: { classPropertyName: "navMode", publicName: "navMode", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null } }, providers: [provideIcons({ lucideChevronLeft, lucideChevronRight, lucideChevronsLeft, lucideChevronsRight })], ngImport: i0, template: `
|
|
125
|
+
<div class="tw:flex tw:flex-wrap tw:items-center tw:justify-between tw:gap-2 tw:px-2">
|
|
126
|
+
@if (showStatus()) {
|
|
127
|
+
<div class="tw:text-muted-foreground tw:flex-1 {{ _metaTextClass() }}">{{ _statusText() }}</div>
|
|
128
|
+
}
|
|
129
|
+
<div class="tw:flex tw:flex-wrap tw:items-center tw:gap-x-6 tw:gap-y-2 tw:lg:gap-x-8">
|
|
130
|
+
@if (showPageSize()) {
|
|
131
|
+
<div class="tw:flex tw:items-center tw:gap-2">
|
|
132
|
+
<p class="tw:font-medium {{ _metaTextClass() }}">Rows per page</p>
|
|
133
|
+
<div hlmSelect class="tw:inline-flex" [value]="_pageSize()" (valueChange)="_onPageSizeChange($event)">
|
|
134
|
+
<hlm-select-trigger class="tw:w-[70px]" [size]="size() === 'sm' ? 'sm' : 'default'">
|
|
135
|
+
<hlm-select-value />
|
|
136
|
+
</hlm-select-trigger>
|
|
137
|
+
<hlm-select-content *hlmSelectPortal>
|
|
138
|
+
@for (size of _pageSizeOptions(); track size) {
|
|
139
|
+
<hlm-select-item [value]="size">{{ size }}</hlm-select-item>
|
|
140
|
+
}
|
|
141
|
+
</hlm-select-content>
|
|
142
|
+
</div>
|
|
143
|
+
</div>
|
|
144
|
+
}
|
|
145
|
+
@if (_showPager()) {
|
|
146
|
+
<div class="tw:flex tw:w-[100px] tw:items-center tw:justify-center tw:font-medium {{ _metaTextClass() }}">
|
|
147
|
+
Page {{ _pageIndex() + 1 }} of {{ _pageCount() }}
|
|
148
|
+
</div>
|
|
149
|
+
<div class="tw:flex tw:items-center tw:gap-2">
|
|
150
|
+
<button
|
|
151
|
+
hlmButton
|
|
152
|
+
variant="secondary"
|
|
153
|
+
appearance="outline"
|
|
154
|
+
size="sm"
|
|
155
|
+
[class]="_edgeNavButtonClass()"
|
|
156
|
+
type="button"
|
|
157
|
+
[disabled]="!_canPrevious()"
|
|
158
|
+
(click)="_table().setPageIndex(0)"
|
|
159
|
+
aria-label="Go to first page"
|
|
160
|
+
>
|
|
161
|
+
@if (navMode() !== 'text') {
|
|
162
|
+
<ng-icon hlm size="sm" name="lucideChevronsLeft" />
|
|
163
|
+
}
|
|
164
|
+
@if (navMode() !== 'icons') {
|
|
165
|
+
<span>First</span>
|
|
166
|
+
}
|
|
167
|
+
</button>
|
|
168
|
+
<button
|
|
169
|
+
hlmButton
|
|
170
|
+
variant="secondary"
|
|
171
|
+
appearance="outline"
|
|
172
|
+
size="sm"
|
|
173
|
+
[class]="_navButtonClass()"
|
|
174
|
+
type="button"
|
|
175
|
+
[disabled]="!_canPrevious()"
|
|
176
|
+
(click)="_table().previousPage()"
|
|
177
|
+
aria-label="Go to previous page"
|
|
178
|
+
>
|
|
179
|
+
@if (navMode() !== 'text') {
|
|
180
|
+
<ng-icon hlm size="sm" name="lucideChevronLeft" />
|
|
181
|
+
}
|
|
182
|
+
@if (navMode() !== 'icons') {
|
|
183
|
+
<span>Previous</span>
|
|
184
|
+
}
|
|
185
|
+
</button>
|
|
186
|
+
<button
|
|
187
|
+
hlmButton
|
|
188
|
+
variant="secondary"
|
|
189
|
+
appearance="outline"
|
|
190
|
+
size="sm"
|
|
191
|
+
[class]="_navButtonClass()"
|
|
192
|
+
type="button"
|
|
193
|
+
[disabled]="!_canNext()"
|
|
194
|
+
(click)="_table().nextPage()"
|
|
195
|
+
aria-label="Go to next page"
|
|
196
|
+
>
|
|
197
|
+
@if (navMode() !== 'icons') {
|
|
198
|
+
<span>Next</span>
|
|
199
|
+
}
|
|
200
|
+
@if (navMode() !== 'text') {
|
|
201
|
+
<ng-icon hlm size="sm" name="lucideChevronRight" />
|
|
202
|
+
}
|
|
203
|
+
</button>
|
|
204
|
+
<button
|
|
205
|
+
hlmButton
|
|
206
|
+
variant="secondary"
|
|
207
|
+
appearance="outline"
|
|
208
|
+
size="sm"
|
|
209
|
+
[class]="_edgeNavButtonClass()"
|
|
210
|
+
type="button"
|
|
211
|
+
[disabled]="!_canNext()"
|
|
212
|
+
(click)="_table().setPageIndex(_pageCount() - 1)"
|
|
213
|
+
aria-label="Go to last page"
|
|
214
|
+
>
|
|
215
|
+
@if (navMode() !== 'icons') {
|
|
216
|
+
<span>Last</span>
|
|
217
|
+
}
|
|
218
|
+
@if (navMode() !== 'text') {
|
|
219
|
+
<ng-icon hlm size="sm" name="lucideChevronsRight" />
|
|
220
|
+
}
|
|
221
|
+
</button>
|
|
222
|
+
</div>
|
|
223
|
+
}
|
|
224
|
+
</div>
|
|
225
|
+
</div>
|
|
226
|
+
`, isInline: true, dependencies: [{ kind: "component", type: HlmButton, selector: "button[hlmButton], a[hlmButton]", inputs: ["variant", "size", "appearance", "loading", "icon", "iconPosition", "class", "spinnerUserClass", "disabled", "type"] }, { kind: "directive", type: HlmIcon, selector: "ng-icon[hlm]", inputs: ["size"] }, { kind: "directive", type: i1.HlmSelect, selector: "[hlmSelect],hlm-select" }, { kind: "component", type: i1.HlmSelectContent, selector: "hlm-select-content", inputs: ["showScroll"] }, { kind: "component", type: i1.HlmSelectItem, selector: "hlm-select-item" }, { kind: "directive", type: i1.HlmSelectPortal, selector: "[hlmSelectPortal]" }, { kind: "component", type: i1.HlmSelectTrigger, selector: "hlm-select-trigger", inputs: ["class", "buttonId", "ariaDescribedby", "wrapperDisabled", "size", "forceInvalid"] }, { kind: "directive", type: i1.HlmSelectValue, selector: "[hlmSelectValue],hlm-select-value" }, { kind: "component", type: NgIcon, selector: "ng-icon", inputs: ["name", "svg", "size", "strokeWidth", "color"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
227
|
+
}
|
|
228
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: EgDataTablePagination, decorators: [{
|
|
229
|
+
type: Component,
|
|
230
|
+
args: [{
|
|
231
|
+
selector: 'eg-data-table-pagination',
|
|
232
|
+
imports: [HlmButton, HlmIcon, HlmSelectImports, NgIcon],
|
|
233
|
+
providers: [provideIcons({ lucideChevronLeft, lucideChevronRight, lucideChevronsLeft, lucideChevronsRight })],
|
|
234
|
+
template: `
|
|
235
|
+
<div class="tw:flex tw:flex-wrap tw:items-center tw:justify-between tw:gap-2 tw:px-2">
|
|
236
|
+
@if (showStatus()) {
|
|
237
|
+
<div class="tw:text-muted-foreground tw:flex-1 {{ _metaTextClass() }}">{{ _statusText() }}</div>
|
|
238
|
+
}
|
|
239
|
+
<div class="tw:flex tw:flex-wrap tw:items-center tw:gap-x-6 tw:gap-y-2 tw:lg:gap-x-8">
|
|
240
|
+
@if (showPageSize()) {
|
|
241
|
+
<div class="tw:flex tw:items-center tw:gap-2">
|
|
242
|
+
<p class="tw:font-medium {{ _metaTextClass() }}">Rows per page</p>
|
|
243
|
+
<div hlmSelect class="tw:inline-flex" [value]="_pageSize()" (valueChange)="_onPageSizeChange($event)">
|
|
244
|
+
<hlm-select-trigger class="tw:w-[70px]" [size]="size() === 'sm' ? 'sm' : 'default'">
|
|
245
|
+
<hlm-select-value />
|
|
246
|
+
</hlm-select-trigger>
|
|
247
|
+
<hlm-select-content *hlmSelectPortal>
|
|
248
|
+
@for (size of _pageSizeOptions(); track size) {
|
|
249
|
+
<hlm-select-item [value]="size">{{ size }}</hlm-select-item>
|
|
250
|
+
}
|
|
251
|
+
</hlm-select-content>
|
|
252
|
+
</div>
|
|
253
|
+
</div>
|
|
254
|
+
}
|
|
255
|
+
@if (_showPager()) {
|
|
256
|
+
<div class="tw:flex tw:w-[100px] tw:items-center tw:justify-center tw:font-medium {{ _metaTextClass() }}">
|
|
257
|
+
Page {{ _pageIndex() + 1 }} of {{ _pageCount() }}
|
|
258
|
+
</div>
|
|
259
|
+
<div class="tw:flex tw:items-center tw:gap-2">
|
|
260
|
+
<button
|
|
261
|
+
hlmButton
|
|
262
|
+
variant="secondary"
|
|
263
|
+
appearance="outline"
|
|
264
|
+
size="sm"
|
|
265
|
+
[class]="_edgeNavButtonClass()"
|
|
266
|
+
type="button"
|
|
267
|
+
[disabled]="!_canPrevious()"
|
|
268
|
+
(click)="_table().setPageIndex(0)"
|
|
269
|
+
aria-label="Go to first page"
|
|
270
|
+
>
|
|
271
|
+
@if (navMode() !== 'text') {
|
|
272
|
+
<ng-icon hlm size="sm" name="lucideChevronsLeft" />
|
|
273
|
+
}
|
|
274
|
+
@if (navMode() !== 'icons') {
|
|
275
|
+
<span>First</span>
|
|
276
|
+
}
|
|
277
|
+
</button>
|
|
278
|
+
<button
|
|
279
|
+
hlmButton
|
|
280
|
+
variant="secondary"
|
|
281
|
+
appearance="outline"
|
|
282
|
+
size="sm"
|
|
283
|
+
[class]="_navButtonClass()"
|
|
284
|
+
type="button"
|
|
285
|
+
[disabled]="!_canPrevious()"
|
|
286
|
+
(click)="_table().previousPage()"
|
|
287
|
+
aria-label="Go to previous page"
|
|
288
|
+
>
|
|
289
|
+
@if (navMode() !== 'text') {
|
|
290
|
+
<ng-icon hlm size="sm" name="lucideChevronLeft" />
|
|
291
|
+
}
|
|
292
|
+
@if (navMode() !== 'icons') {
|
|
293
|
+
<span>Previous</span>
|
|
294
|
+
}
|
|
295
|
+
</button>
|
|
296
|
+
<button
|
|
297
|
+
hlmButton
|
|
298
|
+
variant="secondary"
|
|
299
|
+
appearance="outline"
|
|
300
|
+
size="sm"
|
|
301
|
+
[class]="_navButtonClass()"
|
|
302
|
+
type="button"
|
|
303
|
+
[disabled]="!_canNext()"
|
|
304
|
+
(click)="_table().nextPage()"
|
|
305
|
+
aria-label="Go to next page"
|
|
306
|
+
>
|
|
307
|
+
@if (navMode() !== 'icons') {
|
|
308
|
+
<span>Next</span>
|
|
309
|
+
}
|
|
310
|
+
@if (navMode() !== 'text') {
|
|
311
|
+
<ng-icon hlm size="sm" name="lucideChevronRight" />
|
|
312
|
+
}
|
|
313
|
+
</button>
|
|
314
|
+
<button
|
|
315
|
+
hlmButton
|
|
316
|
+
variant="secondary"
|
|
317
|
+
appearance="outline"
|
|
318
|
+
size="sm"
|
|
319
|
+
[class]="_edgeNavButtonClass()"
|
|
320
|
+
type="button"
|
|
321
|
+
[disabled]="!_canNext()"
|
|
322
|
+
(click)="_table().setPageIndex(_pageCount() - 1)"
|
|
323
|
+
aria-label="Go to last page"
|
|
324
|
+
>
|
|
325
|
+
@if (navMode() !== 'icons') {
|
|
326
|
+
<span>Last</span>
|
|
327
|
+
}
|
|
328
|
+
@if (navMode() !== 'text') {
|
|
329
|
+
<ng-icon hlm size="sm" name="lucideChevronsRight" />
|
|
330
|
+
}
|
|
331
|
+
</button>
|
|
332
|
+
</div>
|
|
333
|
+
}
|
|
334
|
+
</div>
|
|
335
|
+
</div>
|
|
336
|
+
`,
|
|
337
|
+
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
338
|
+
}]
|
|
339
|
+
}], propDecorators: { showStatus: [{ type: i0.Input, args: [{ isSignal: true, alias: "showStatus", required: false }] }], showPageSize: [{ type: i0.Input, args: [{ isSignal: true, alias: "showPageSize", required: false }] }], pageSizes: [{ type: i0.Input, args: [{ isSignal: true, alias: "pageSizes", required: false }] }], navMode: [{ type: i0.Input, args: [{ isSignal: true, alias: "navMode", required: false }] }], size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }] } });
|
|
340
|
+
|
|
341
|
+
/**
|
|
342
|
+
* Column-visibility toggle.
|
|
343
|
+
*
|
|
344
|
+
* Reads the table from the nearest `[tanStackTable]` directive — no table
|
|
345
|
+
* input or generics needed. Only columns with an `accessorFn` that can hide
|
|
346
|
+
* are listed (display columns like `select` / `actions` stay fixed).
|
|
347
|
+
*/
|
|
348
|
+
class EgDataTableViewOptions {
|
|
349
|
+
/** Density of the toggle button. */
|
|
350
|
+
size = input('default', /* @ts-ignore */
|
|
351
|
+
...(ngDevMode ? [{ debugName: "size" }] : /* istanbul ignore next */ []));
|
|
352
|
+
_table = injectTableContext();
|
|
353
|
+
/** Height per density; hidden below `lg` like the pager edge buttons. Merged by `hlmButton`. */
|
|
354
|
+
_buttonClass = computed(() => hlm('tw:ml-auto tw:hidden tw:lg:flex', this.size() === 'sm' ? 'tw:h-7' : this.size() === 'lg' ? 'tw:h-9' : 'tw:h-8'), /* @ts-ignore */
|
|
355
|
+
...(ngDevMode ? [{ debugName: "_buttonClass" }] : /* istanbul ignore next */ []));
|
|
356
|
+
_hidableColumns = computed(() => this._table()
|
|
357
|
+
.getAllColumns()
|
|
358
|
+
.filter((column) => typeof column.accessorFn !== 'undefined' && column.getCanHide()), /* @ts-ignore */
|
|
359
|
+
...(ngDevMode ? [{ debugName: "_hidableColumns" }] : /* istanbul ignore next */ []));
|
|
360
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: EgDataTableViewOptions, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
361
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.3", type: EgDataTableViewOptions, isStandalone: true, selector: "eg-data-table-view-options", inputs: { size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null } }, providers: [provideIcons({ lucideSettings2 })], ngImport: i0, template: `
|
|
362
|
+
<button
|
|
363
|
+
hlmButton
|
|
364
|
+
variant="secondary"
|
|
365
|
+
appearance="outline"
|
|
366
|
+
size="sm"
|
|
367
|
+
[class]="_buttonClass()"
|
|
368
|
+
type="button"
|
|
369
|
+
[hlmDropdownMenuTrigger]="_menu"
|
|
370
|
+
>
|
|
371
|
+
<ng-icon hlm name="lucideSettings2" />
|
|
372
|
+
View
|
|
373
|
+
</button>
|
|
374
|
+
<ng-template #_menu>
|
|
375
|
+
<div hlmDropdownMenu class="tw:w-[150px]">
|
|
376
|
+
<div hlmDropdownMenuLabel>Toggle columns</div>
|
|
377
|
+
<div hlmDropdownMenuSeparator></div>
|
|
378
|
+
@for (column of _hidableColumns(); track column.id) {
|
|
379
|
+
<button
|
|
380
|
+
hlmDropdownMenuCheckbox
|
|
381
|
+
class="tw:capitalize"
|
|
382
|
+
[checked]="column.getIsVisible()"
|
|
383
|
+
(triggered)="column.toggleVisibility()"
|
|
384
|
+
>
|
|
385
|
+
<hlm-dropdown-menu-checkbox-indicator />
|
|
386
|
+
{{ column.id }}
|
|
387
|
+
</button>
|
|
388
|
+
}
|
|
389
|
+
</div>
|
|
390
|
+
</ng-template>
|
|
391
|
+
`, isInline: true, dependencies: [{ kind: "component", type: HlmButton, selector: "button[hlmButton], a[hlmButton]", inputs: ["variant", "size", "appearance", "loading", "icon", "iconPosition", "class", "spinnerUserClass", "disabled", "type"] }, { kind: "directive", type: i1$1.HlmDropdownMenu, selector: "[hlmDropdownMenu],hlm-dropdown-menu", inputs: ["sideOffset"] }, { kind: "directive", type: i1$1.HlmDropdownMenuCheckbox, selector: "[hlmDropdownMenuCheckbox],[hlmDropdownMenuCheckboxItem]", inputs: ["inset"] }, { kind: "component", type: i1$1.HlmDropdownMenuCheckboxIndicator, selector: "hlm-dropdown-menu-checkbox-indicator" }, { kind: "directive", type: i1$1.HlmDropdownMenuLabel, selector: "[hlmDropdownMenuLabel],hlm-dropdown-menu-label", inputs: ["inset"] }, { kind: "directive", type: i1$1.HlmDropdownMenuSeparator, selector: "[hlmDropdownMenuSeparator],hlm-dropdown-menu-separator" }, { kind: "directive", type: i1$1.HlmDropdownMenuTrigger, selector: "[hlmDropdownMenuTrigger]", inputs: ["align", "side"] }, { kind: "component", type: NgIcon, selector: "ng-icon", inputs: ["name", "svg", "size", "strokeWidth", "color"] }, { kind: "directive", type: HlmIcon, selector: "ng-icon[hlm]", inputs: ["size"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
392
|
+
}
|
|
393
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: EgDataTableViewOptions, decorators: [{
|
|
394
|
+
type: Component,
|
|
395
|
+
args: [{
|
|
396
|
+
selector: 'eg-data-table-view-options',
|
|
397
|
+
imports: [HlmButton, HlmDropdownMenuImports, NgIcon, HlmIcon],
|
|
398
|
+
providers: [provideIcons({ lucideSettings2 })],
|
|
399
|
+
template: `
|
|
400
|
+
<button
|
|
401
|
+
hlmButton
|
|
402
|
+
variant="secondary"
|
|
403
|
+
appearance="outline"
|
|
404
|
+
size="sm"
|
|
405
|
+
[class]="_buttonClass()"
|
|
406
|
+
type="button"
|
|
407
|
+
[hlmDropdownMenuTrigger]="_menu"
|
|
408
|
+
>
|
|
409
|
+
<ng-icon hlm name="lucideSettings2" />
|
|
410
|
+
View
|
|
411
|
+
</button>
|
|
412
|
+
<ng-template #_menu>
|
|
413
|
+
<div hlmDropdownMenu class="tw:w-[150px]">
|
|
414
|
+
<div hlmDropdownMenuLabel>Toggle columns</div>
|
|
415
|
+
<div hlmDropdownMenuSeparator></div>
|
|
416
|
+
@for (column of _hidableColumns(); track column.id) {
|
|
417
|
+
<button
|
|
418
|
+
hlmDropdownMenuCheckbox
|
|
419
|
+
class="tw:capitalize"
|
|
420
|
+
[checked]="column.getIsVisible()"
|
|
421
|
+
(triggered)="column.toggleVisibility()"
|
|
422
|
+
>
|
|
423
|
+
<hlm-dropdown-menu-checkbox-indicator />
|
|
424
|
+
{{ column.id }}
|
|
425
|
+
</button>
|
|
426
|
+
}
|
|
427
|
+
</div>
|
|
428
|
+
</ng-template>
|
|
429
|
+
`,
|
|
430
|
+
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
431
|
+
}]
|
|
432
|
+
}], propDecorators: { size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }] } });
|
|
433
|
+
|
|
434
|
+
/**
|
|
435
|
+
* Header selection checkbox: toggles all page rows.
|
|
436
|
+
*
|
|
437
|
+
* Generic over `TData` so the same component works with any table; the table
|
|
438
|
+
* instance is passed explicitly (no DI needed inside column definitions).
|
|
439
|
+
* `HlmCheckbox.checked` accepts `'indeterminate'`, so the tri-state is derived
|
|
440
|
+
* via `computed` instead of a separate input.
|
|
441
|
+
*/
|
|
442
|
+
class EgTableHeadSelection {
|
|
443
|
+
table = input.required(/* @ts-ignore */
|
|
444
|
+
...(ngDevMode ? [{ debugName: "table" }] : /* istanbul ignore next */ []));
|
|
445
|
+
ariaLabel = input('Select all', /* @ts-ignore */
|
|
446
|
+
...(ngDevMode ? [{ debugName: "ariaLabel" }] : /* istanbul ignore next */ []));
|
|
447
|
+
_checked = computed(() => {
|
|
448
|
+
const table = this.table();
|
|
449
|
+
if (table.getIsAllPageRowsSelected())
|
|
450
|
+
return true;
|
|
451
|
+
if (table.getIsSomePageRowsSelected())
|
|
452
|
+
return 'indeterminate';
|
|
453
|
+
return false;
|
|
454
|
+
}, /* @ts-ignore */
|
|
455
|
+
...(ngDevMode ? [{ debugName: "_checked" }] : /* istanbul ignore next */ []));
|
|
456
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: EgTableHeadSelection, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
457
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "22.1.3", type: EgTableHeadSelection, isStandalone: true, selector: "eg-table-head-selection", inputs: { table: { classPropertyName: "table", publicName: "table", isSignal: true, isRequired: true, transformFunction: null }, ariaLabel: { classPropertyName: "ariaLabel", publicName: "ariaLabel", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "attr.aria-label": "ariaLabel()" }, classAttribute: "tw:flex" }, ngImport: i0, template: ` <hlm-checkbox [checked]="_checked()" (changed)="table().toggleAllPageRowsSelected($event)" /> `, isInline: true, dependencies: [{ kind: "component", type: HlmCheckbox, selector: "hlm-checkbox", inputs: ["class", "id", "aria-label", "aria-labelledby", "aria-describedby", "checked", "name", "required", "disabled", "wrapperDisabled"], outputs: ["checkedChange", "changed"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
458
|
+
}
|
|
459
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: EgTableHeadSelection, decorators: [{
|
|
460
|
+
type: Component,
|
|
461
|
+
args: [{
|
|
462
|
+
selector: 'eg-table-head-selection',
|
|
463
|
+
imports: [HlmCheckbox],
|
|
464
|
+
host: { class: 'tw:flex', '[attr.aria-label]': 'ariaLabel()' },
|
|
465
|
+
template: ` <hlm-checkbox [checked]="_checked()" (changed)="table().toggleAllPageRowsSelected($event)" /> `,
|
|
466
|
+
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
467
|
+
}]
|
|
468
|
+
}], propDecorators: { table: [{ type: i0.Input, args: [{ isSignal: true, alias: "table", required: true }] }], ariaLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "ariaLabel", required: false }] }] } });
|
|
469
|
+
/**
|
|
470
|
+
* Row selection checkbox: toggles a single row.
|
|
471
|
+
*/
|
|
472
|
+
class EgTableRowSelection {
|
|
473
|
+
row = input.required(/* @ts-ignore */
|
|
474
|
+
...(ngDevMode ? [{ debugName: "row" }] : /* istanbul ignore next */ []));
|
|
475
|
+
ariaLabel = input('Select row', /* @ts-ignore */
|
|
476
|
+
...(ngDevMode ? [{ debugName: "ariaLabel" }] : /* istanbul ignore next */ []));
|
|
477
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: EgTableRowSelection, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
478
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "22.1.3", type: EgTableRowSelection, isStandalone: true, selector: "eg-table-row-selection", inputs: { row: { classPropertyName: "row", publicName: "row", isSignal: true, isRequired: true, transformFunction: null }, ariaLabel: { classPropertyName: "ariaLabel", publicName: "ariaLabel", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "attr.aria-label": "ariaLabel()" }, classAttribute: "tw:flex" }, ngImport: i0, template: ` <hlm-checkbox [checked]="row().getIsSelected()" (changed)="row().toggleSelected($event)" /> `, isInline: true, dependencies: [{ kind: "component", type: HlmCheckbox, selector: "hlm-checkbox", inputs: ["class", "id", "aria-label", "aria-labelledby", "aria-describedby", "checked", "name", "required", "disabled", "wrapperDisabled"], outputs: ["checkedChange", "changed"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
479
|
+
}
|
|
480
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: EgTableRowSelection, decorators: [{
|
|
481
|
+
type: Component,
|
|
482
|
+
args: [{
|
|
483
|
+
selector: 'eg-table-row-selection',
|
|
484
|
+
imports: [HlmCheckbox],
|
|
485
|
+
host: { class: 'tw:flex', '[attr.aria-label]': 'ariaLabel()' },
|
|
486
|
+
template: ` <hlm-checkbox [checked]="row().getIsSelected()" (changed)="row().toggleSelected($event)" /> `,
|
|
487
|
+
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
488
|
+
}]
|
|
489
|
+
}], propDecorators: { row: [{ type: i0.Input, args: [{ isSignal: true, alias: "row", required: true }] }], ariaLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "ariaLabel", required: false }] }] } });
|
|
490
|
+
|
|
491
|
+
/**
|
|
492
|
+
* Generic data table with TanStack-powered sorting, filtering, pagination,
|
|
493
|
+
* selection, column visibility, plus a React-parity grid layout.
|
|
494
|
+
*
|
|
495
|
+
* The caller passes `columns` (and optionally `gridColumns`) — everything else
|
|
496
|
+
* is owned internally with change notifications via outputs:
|
|
497
|
+
*
|
|
498
|
+
* - Client mode: pass `data` as an array. Pagination/sorting/filtering run in-browser.
|
|
499
|
+
* `filterRows` can pre-filter the array before the built-in pipeline.
|
|
500
|
+
* - Server mode: pass `data` as a page slice (`{items,total,limit,offset,hasPrevious,hasNext}`)
|
|
501
|
+
* with `manualPagination` set. The slice renders as-is — sorting/filtering
|
|
502
|
+
* are not applied client-side. Page, sort and filter interactions emit
|
|
503
|
+
* `pageChange` / `pageSizeChange` / `sortingChange` / `filterChange`
|
|
504
|
+
* (`columnFiltersChange`) so the caller can fetch the next slice.
|
|
505
|
+
* - Selection: set `enableSelection` to auto-prepend a checkbox column;
|
|
506
|
+
* selected rows are emitted via `selectionChange` (array of `TData`).
|
|
507
|
+
* - Grid mode: pass `gridColumns` to enable the layout toggle. Columns with
|
|
508
|
+
* `meta: { hideInTable: true }` are table-hidden; `meta: { thumbnail: true }`
|
|
509
|
+
* renders as the card banner.
|
|
510
|
+
*/
|
|
511
|
+
class EgDataTable {
|
|
512
|
+
/** Column definitions for table layout (required). */
|
|
513
|
+
columns = input.required(/* @ts-ignore */
|
|
514
|
+
...(ngDevMode ? [{ debugName: "columns" }] : /* istanbul ignore next */ []));
|
|
515
|
+
/** Column definitions for grid layout; falls back to `columns` when omitted. */
|
|
516
|
+
gridColumns = input(/* @ts-ignore */
|
|
517
|
+
...(ngDevMode ? [undefined, { debugName: "gridColumns" }] : /* istanbul ignore next */ []));
|
|
518
|
+
/** Client rows, or a server page slice when `manualPagination` is set (`null` while loading). */
|
|
519
|
+
data = input([], /* @ts-ignore */
|
|
520
|
+
...(ngDevMode ? [{ debugName: "data" }] : /* istanbul ignore next */ []));
|
|
521
|
+
/** When true, `data` is a server page slice and the table uses TanStack `manualPagination`. Sorting and filtering are then display-only: the slice is shown as-is while `sortingChange` / `filterChange` (`columnFiltersChange`) notify the caller to refetch. */
|
|
522
|
+
manualPagination = input(false, /* @ts-ignore */
|
|
523
|
+
...(ngDevMode ? [{ debugName: "manualPagination" }] : /* istanbul ignore next */ []));
|
|
524
|
+
/** TanStack feature registry. Defaults to filtering + visibility + pagination + selection + sorting. */
|
|
525
|
+
features = input(defaultEgDataTableFeatures, /* @ts-ignore */
|
|
526
|
+
...(ngDevMode ? [{ debugName: "features" }] : /* istanbul ignore next */ []));
|
|
527
|
+
isLoading = input(false, /* @ts-ignore */
|
|
528
|
+
...(ngDevMode ? [{ debugName: "isLoading" }] : /* istanbul ignore next */ []));
|
|
529
|
+
emptyMessage = input('No results found.', /* @ts-ignore */
|
|
530
|
+
...(ngDevMode ? [{ debugName: "emptyMessage" }] : /* istanbul ignore next */ []));
|
|
531
|
+
/** When true, a checkbox column is auto-prepended and `selectionChange` emits the selected rows. */
|
|
532
|
+
enableSelection = input(false, /* @ts-ignore */
|
|
533
|
+
...(ngDevMode ? [{ debugName: "enableSelection" }] : /* istanbul ignore next */ []));
|
|
534
|
+
hideFooter = input(false, /* @ts-ignore */
|
|
535
|
+
...(ngDevMode ? [{ debugName: "hideFooter" }] : /* istanbul ignore next */ []));
|
|
536
|
+
/** Density of toolbar, table, and pagination chrome. Type scale is untouched. */
|
|
537
|
+
size = input('default', /* @ts-ignore */
|
|
538
|
+
...(ngDevMode ? [{ debugName: "size" }] : /* istanbul ignore next */ []));
|
|
539
|
+
/** Presentation mode. Two-way bindable: `[(layout)]`. Grid requires `gridColumns`. */
|
|
540
|
+
layout = model('table', /* @ts-ignore */
|
|
541
|
+
...(ngDevMode ? [{ debugName: "layout" }] : /* istanbul ignore next */ []));
|
|
542
|
+
/** Show the table/grid toggle (only rendered when `gridColumns` is set). */
|
|
543
|
+
showLayoutToggle = input(true, /* @ts-ignore */
|
|
544
|
+
...(ngDevMode ? [{ debugName: "showLayoutToggle" }] : /* istanbul ignore next */ []));
|
|
545
|
+
/** Show the toolbar (filter input, plus the column-visibility dropdown when `showColumnToggle` is set). */
|
|
546
|
+
showToolbar = input(false, /* @ts-ignore */
|
|
547
|
+
...(ngDevMode ? [{ debugName: "showToolbar" }] : /* istanbul ignore next */ []));
|
|
548
|
+
/** Column id the toolbar filter input writes to (e.g. `'email'`). Empty means client-side filtering is skipped and keystrokes only emit `filterChange` (server-side pattern). */
|
|
549
|
+
filterColumnId = input('', /* @ts-ignore */
|
|
550
|
+
...(ngDevMode ? [{ debugName: "filterColumnId" }] : /* istanbul ignore next */ []));
|
|
551
|
+
filterPlaceholder = input('Filter...', /* @ts-ignore */
|
|
552
|
+
...(ngDevMode ? [{ debugName: "filterPlaceholder" }] : /* istanbul ignore next */ []));
|
|
553
|
+
/** Show the column-visibility dropdown inside the toolbar. Off by default; opt in per table. */
|
|
554
|
+
showColumnToggle = input(false, /* @ts-ignore */
|
|
555
|
+
...(ngDevMode ? [{ debugName: "showColumnToggle" }] : /* istanbul ignore next */ []));
|
|
556
|
+
/** Custom right-side toolbar content (e.g. action buttons) as a template. Renders the toolbar row even when `showToolbar` is false; built-ins stay on the left. */
|
|
557
|
+
toolbarActions = input(undefined, /* @ts-ignore */
|
|
558
|
+
...(ngDevMode ? [{ debugName: "toolbarActions" }] : /* istanbul ignore next */ []));
|
|
559
|
+
/** Default client-side page size. Changing it later resets the pager to the new size. */
|
|
560
|
+
defaultPageSize = input(10, /* @ts-ignore */
|
|
561
|
+
...(ngDevMode ? [{ debugName: "defaultPageSize" }] : /* istanbul ignore next */ []));
|
|
562
|
+
/** Caller-provided frontend filter: receives all client rows, returns the kept rows. Runs before built-in filtering/sorting/pagination; ignored in server mode. Must be pure. */
|
|
563
|
+
filterRows = input(null, /* @ts-ignore */
|
|
564
|
+
...(ngDevMode ? [{ debugName: "filterRows" }] : /* istanbul ignore next */ []));
|
|
565
|
+
/** Seeds the sorting state once at creation. Later changes are ignored — use `sortingChange` to stay in sync. */
|
|
566
|
+
initialSorting = input([], /* @ts-ignore */
|
|
567
|
+
...(ngDevMode ? [{ debugName: "initialSorting" }] : /* istanbul ignore next */ []));
|
|
568
|
+
/** Seeds the column-filter state once at creation. Later changes are ignored. */
|
|
569
|
+
initialColumnFilters = input([], /* @ts-ignore */
|
|
570
|
+
...(ngDevMode ? [{ debugName: "initialColumnFilters" }] : /* istanbul ignore next */ []));
|
|
571
|
+
/** Seeds the column-visibility state once at creation. Later changes are ignored. */
|
|
572
|
+
initialColumnVisibility = input({}, /* @ts-ignore */
|
|
573
|
+
...(ngDevMode ? [{ debugName: "initialColumnVisibility" }] : /* istanbul ignore next */ []));
|
|
574
|
+
/** Seeds the row-selection state once at creation (keys are row ids). Later changes are ignored. */
|
|
575
|
+
initialRowSelection = input({}, /* @ts-ignore */
|
|
576
|
+
...(ngDevMode ? [{ debugName: "initialRowSelection" }] : /* istanbul ignore next */ []));
|
|
577
|
+
/** Show the rows-per-page selector in the footer pager. */
|
|
578
|
+
showPageSize = input(true, /* @ts-ignore */
|
|
579
|
+
...(ngDevMode ? [{ debugName: "showPageSize" }] : /* istanbul ignore next */ []));
|
|
580
|
+
/** Page-size options for the footer selector. The current size is appended when absent. */
|
|
581
|
+
pageSizes = input([10, 20, 30, 40, 50], /* @ts-ignore */
|
|
582
|
+
...(ngDevMode ? [{ debugName: "pageSizes" }] : /* istanbul ignore next */ []));
|
|
583
|
+
/** Footer navigation-button content: icons only, text labels only, or both. */
|
|
584
|
+
navMode = input('icons', /* @ts-ignore */
|
|
585
|
+
...(ngDevMode ? [{ debugName: "navMode" }] : /* istanbul ignore next */ []));
|
|
586
|
+
userClass = input('', { ...(ngDevMode ? { debugName: "userClass" } : /* istanbul ignore next */ {}), alias: 'class' });
|
|
587
|
+
/** Emits the selected rows whenever selection changes (requires `enableSelection`). */
|
|
588
|
+
selectionChange = output();
|
|
589
|
+
/** Emits the target page index on pager navigation (primary hook for server fetching). */
|
|
590
|
+
pageChange = output();
|
|
591
|
+
pageSizeChange = output();
|
|
592
|
+
/** Emits the row's data when a row (table) or card (grid) is clicked. Clicks from nested interactive elements (buttons, links, inputs, checkboxes, selects) are ignored. */
|
|
593
|
+
rowClick = output();
|
|
594
|
+
sortingChange = output();
|
|
595
|
+
columnFiltersChange = output();
|
|
596
|
+
/** Emits the toolbar filter string whenever it changes. Empty when cleared or unset. */
|
|
597
|
+
filterChange = output();
|
|
598
|
+
columnVisibilityChange = output();
|
|
599
|
+
_containerClass = computed(() => hlm('tw:space-y-2', this.userClass()), /* @ts-ignore */
|
|
600
|
+
...(ngDevMode ? [{ debugName: "_containerClass" }] : /* istanbul ignore next */ []));
|
|
601
|
+
/** Inline TH sort-button footprint per density. Merged by `hlmButton` via the `class` binding. */
|
|
602
|
+
_sortButtonClass = computed(() => hlm('tw:p-0', this.size() === 'sm' ? 'tw:h-5 tw:w-5' : this.size() === 'lg' ? 'tw:h-7 tw:w-7' : 'tw:h-6 tw:w-6'), /* @ts-ignore */
|
|
603
|
+
...(ngDevMode ? [{ debugName: "_sortButtonClass" }] : /* istanbul ignore next */ []));
|
|
604
|
+
_sorting = signal([], /* @ts-ignore */
|
|
605
|
+
...(ngDevMode ? [{ debugName: "_sorting" }] : /* istanbul ignore next */ []));
|
|
606
|
+
_columnFilters = signal([], /* @ts-ignore */
|
|
607
|
+
...(ngDevMode ? [{ debugName: "_columnFilters" }] : /* istanbul ignore next */ []));
|
|
608
|
+
_columnVisibility = signal({}, /* @ts-ignore */
|
|
609
|
+
...(ngDevMode ? [{ debugName: "_columnVisibility" }] : /* istanbul ignore next */ []));
|
|
610
|
+
_rowSelection = signal({}, /* @ts-ignore */
|
|
611
|
+
...(ngDevMode ? [{ debugName: "_rowSelection" }] : /* istanbul ignore next */ []));
|
|
612
|
+
_clientPageIndex = signal(0, /* @ts-ignore */
|
|
613
|
+
...(ngDevMode ? [{ debugName: "_clientPageIndex" }] : /* istanbul ignore next */ []));
|
|
614
|
+
// Linked so the bound `defaultPageSize` applies once inputs are set, while
|
|
615
|
+
// pager-driven `set()` writes below are preserved until it changes again.
|
|
616
|
+
_clientPageSize = linkedSignal(() => this.defaultPageSize(), /* @ts-ignore */
|
|
617
|
+
...(ngDevMode ? [{ debugName: "_clientPageSize" }] : /* istanbul ignore next */ []));
|
|
618
|
+
_isServer = computed(() => this.manualPagination(), /* @ts-ignore */
|
|
619
|
+
...(ngDevMode ? [{ debugName: "_isServer" }] : /* istanbul ignore next */ []));
|
|
620
|
+
/** The server page slice when in server mode; `null` for client data, misuse shapes, or `null` while loading. */
|
|
621
|
+
_page = computed(() => {
|
|
622
|
+
if (!this._isServer())
|
|
623
|
+
return null;
|
|
624
|
+
const data = this.data();
|
|
625
|
+
if (data !== null && typeof data === 'object' && 'items' in data) {
|
|
626
|
+
return data;
|
|
627
|
+
}
|
|
628
|
+
return null;
|
|
629
|
+
}, /* @ts-ignore */
|
|
630
|
+
...(ngDevMode ? [{ debugName: "_page" }] : /* istanbul ignore next */ []));
|
|
631
|
+
_items = computed(() => {
|
|
632
|
+
const page = this._page();
|
|
633
|
+
if (page)
|
|
634
|
+
return page.items;
|
|
635
|
+
const data = this.data();
|
|
636
|
+
const rows = Array.isArray(data)
|
|
637
|
+
? data
|
|
638
|
+
: (data?.items ?? []);
|
|
639
|
+
const filter = this.filterRows();
|
|
640
|
+
return filter ? filter(rows) : rows;
|
|
641
|
+
}, /* @ts-ignore */
|
|
642
|
+
...(ngDevMode ? [{ debugName: "_items" }] : /* istanbul ignore next */ []));
|
|
643
|
+
_serverPageCount = computed(() => {
|
|
644
|
+
const paginated = this._page();
|
|
645
|
+
if (!paginated || paginated.limit <= 0)
|
|
646
|
+
return 1;
|
|
647
|
+
return Math.max(1, Math.ceil(paginated.total / paginated.limit));
|
|
648
|
+
}, /* @ts-ignore */
|
|
649
|
+
...(ngDevMode ? [{ debugName: "_serverPageCount" }] : /* istanbul ignore next */ []));
|
|
650
|
+
_serverPageIndex = computed(() => {
|
|
651
|
+
const paginated = this._page();
|
|
652
|
+
if (!paginated || paginated.limit <= 0)
|
|
653
|
+
return 0;
|
|
654
|
+
return Math.floor(paginated.offset / paginated.limit);
|
|
655
|
+
}, /* @ts-ignore */
|
|
656
|
+
...(ngDevMode ? [{ debugName: "_serverPageIndex" }] : /* istanbul ignore next */ []));
|
|
657
|
+
_paginationState = computed(() => {
|
|
658
|
+
const paginated = this._page();
|
|
659
|
+
if (paginated)
|
|
660
|
+
return { pageIndex: this._serverPageIndex(), pageSize: paginated.limit };
|
|
661
|
+
return { pageIndex: this._clientPageIndex(), pageSize: this._clientPageSize() };
|
|
662
|
+
}, /* @ts-ignore */
|
|
663
|
+
...(ngDevMode ? [{ debugName: "_paginationState" }] : /* istanbul ignore next */ []));
|
|
664
|
+
_selectionHelper = computed(() => createColumnHelper(), /* @ts-ignore */
|
|
665
|
+
...(ngDevMode ? [{ debugName: "_selectionHelper" }] : /* istanbul ignore next */ []));
|
|
666
|
+
/** Caller columns + auto-injected selection column + layout filtering. */
|
|
667
|
+
_finalColumns = computed(() => {
|
|
668
|
+
const isGrid = this._effectiveLayout() === 'grid';
|
|
669
|
+
const base = isGrid ? (this.gridColumns() ?? this.columns()) : this.columns();
|
|
670
|
+
const visible = isGrid ? base : base.filter((column) => column.meta?.hideInTable !== true);
|
|
671
|
+
if (!this.enableSelection())
|
|
672
|
+
return [...visible];
|
|
673
|
+
const helper = this._selectionHelper();
|
|
674
|
+
const selectionColumn = helper.display({
|
|
675
|
+
id: 'select',
|
|
676
|
+
header: () => EgTableHeadSelection,
|
|
677
|
+
cell: () => EgTableRowSelection,
|
|
678
|
+
enableSorting: false,
|
|
679
|
+
enableHiding: false,
|
|
680
|
+
});
|
|
681
|
+
return [selectionColumn, ...visible];
|
|
682
|
+
}, /* @ts-ignore */
|
|
683
|
+
...(ngDevMode ? [{ debugName: "_finalColumns" }] : /* istanbul ignore next */ []));
|
|
684
|
+
_table = injectTable(() => {
|
|
685
|
+
const server = this._isServer();
|
|
686
|
+
return {
|
|
687
|
+
features: this.features(),
|
|
688
|
+
columns: this._finalColumns(),
|
|
689
|
+
data: [...this._items()],
|
|
690
|
+
manualPagination: server,
|
|
691
|
+
manualSorting: server,
|
|
692
|
+
manualFiltering: server,
|
|
693
|
+
...(server ? { pageCount: this._serverPageCount() } : {}),
|
|
694
|
+
state: {
|
|
695
|
+
sorting: this._sorting(),
|
|
696
|
+
columnFilters: this._columnFilters(),
|
|
697
|
+
columnVisibility: this._columnVisibility(),
|
|
698
|
+
rowSelection: this._rowSelection(),
|
|
699
|
+
pagination: this._paginationState(),
|
|
700
|
+
},
|
|
701
|
+
onSortingChange: (updater) => {
|
|
702
|
+
const next = typeof updater === 'function' ? updater(this._sorting()) : updater;
|
|
703
|
+
this._sorting.set(next);
|
|
704
|
+
this.sortingChange.emit(next);
|
|
705
|
+
},
|
|
706
|
+
onColumnFiltersChange: (updater) => {
|
|
707
|
+
const next = typeof updater === 'function' ? updater(this._columnFilters()) : updater;
|
|
708
|
+
this._columnFilters.set(next);
|
|
709
|
+
this.columnFiltersChange.emit(next);
|
|
710
|
+
const filterId = this.filterColumnId();
|
|
711
|
+
if (filterId) {
|
|
712
|
+
const value = next.find((filter) => filter.id === filterId)?.value;
|
|
713
|
+
this.filterChange.emit(typeof value === 'string' ? value : '');
|
|
714
|
+
}
|
|
715
|
+
},
|
|
716
|
+
onColumnVisibilityChange: (updater) => {
|
|
717
|
+
const next = typeof updater === 'function' ? updater(this._columnVisibility()) : updater;
|
|
718
|
+
this._columnVisibility.set(next);
|
|
719
|
+
this.columnVisibilityChange.emit(next);
|
|
720
|
+
},
|
|
721
|
+
onRowSelectionChange: (updater) => {
|
|
722
|
+
const next = typeof updater === 'function' ? updater(this._rowSelection()) : updater;
|
|
723
|
+
this._rowSelection.set(next);
|
|
724
|
+
},
|
|
725
|
+
onPaginationChange: (updater) => {
|
|
726
|
+
const current = this._paginationState();
|
|
727
|
+
const next = typeof updater === 'function' ? updater(current) : updater;
|
|
728
|
+
if (next.pageIndex !== current.pageIndex)
|
|
729
|
+
this.pageChange.emit(next.pageIndex);
|
|
730
|
+
if (next.pageSize !== current.pageSize)
|
|
731
|
+
this.pageSizeChange.emit(next.pageSize);
|
|
732
|
+
if (!this._isServer()) {
|
|
733
|
+
this._clientPageIndex.set(next.pageIndex);
|
|
734
|
+
this._clientPageSize.set(next.pageSize);
|
|
735
|
+
}
|
|
736
|
+
},
|
|
737
|
+
};
|
|
738
|
+
});
|
|
739
|
+
_emitSelection = effect(() => {
|
|
740
|
+
this._rowSelection();
|
|
741
|
+
const selected = this._table.getSelectedRowModel().rows.map((row) => row.original);
|
|
742
|
+
this.selectionChange.emit(selected);
|
|
743
|
+
}, /* @ts-ignore */
|
|
744
|
+
...(ngDevMode ? [{ debugName: "_emitSelection" }] : /* istanbul ignore next */ []));
|
|
745
|
+
/**
|
|
746
|
+
* Seeds internal state from the `initial*` inputs. Runs in `ngOnInit` (after
|
|
747
|
+
* first bindings, before first render) exactly once, so inline-literal
|
|
748
|
+
* bindings (new references every change detection) cannot clobber user
|
|
749
|
+
* interaction afterwards. Values are copied to avoid aliasing caller data.
|
|
750
|
+
*/
|
|
751
|
+
ngOnInit() {
|
|
752
|
+
this._sorting.set([...this.initialSorting()]);
|
|
753
|
+
this._columnFilters.set([...this.initialColumnFilters()]);
|
|
754
|
+
this._columnVisibility.set({ ...this.initialColumnVisibility() });
|
|
755
|
+
this._rowSelection.set({ ...this.initialRowSelection() });
|
|
756
|
+
}
|
|
757
|
+
_hasGrid = computed(() => this.gridColumns() !== undefined, /* @ts-ignore */
|
|
758
|
+
...(ngDevMode ? [{ debugName: "_hasGrid" }] : /* istanbul ignore next */ []));
|
|
759
|
+
_effectiveLayout = computed(() => this.layout() === 'grid' && this._hasGrid() ? 'grid' : 'table', /* @ts-ignore */
|
|
760
|
+
...(ngDevMode ? [{ debugName: "_effectiveLayout" }] : /* istanbul ignore next */ []));
|
|
761
|
+
_showLayoutToggle = computed(() => this.showLayoutToggle() && this._hasGrid(), /* @ts-ignore */
|
|
762
|
+
...(ngDevMode ? [{ debugName: "_showLayoutToggle" }] : /* istanbul ignore next */ []));
|
|
763
|
+
_visibleColumnCount = computed(() => {
|
|
764
|
+
const count = this._table.getVisibleLeafColumns().length;
|
|
765
|
+
return count > 0 ? count : 1;
|
|
766
|
+
}, /* @ts-ignore */
|
|
767
|
+
...(ngDevMode ? [{ debugName: "_visibleColumnCount" }] : /* istanbul ignore next */ []));
|
|
768
|
+
_statusText = computed(() => {
|
|
769
|
+
const paginated = this._page();
|
|
770
|
+
const table = this._table;
|
|
771
|
+
const selected = table.getFilteredSelectedRowModel().rows.length;
|
|
772
|
+
if (this.enableSelection() && selected > 0) {
|
|
773
|
+
const total = paginated ? paginated.total : table.getFilteredRowModel().rows.length;
|
|
774
|
+
return `${selected} of ${total} row(s) selected`;
|
|
775
|
+
}
|
|
776
|
+
if (paginated) {
|
|
777
|
+
const from = paginated.items.length === 0 ? 0 : paginated.offset + 1;
|
|
778
|
+
const to = paginated.offset + paginated.items.length;
|
|
779
|
+
return `Showing ${from} to ${to} of ${paginated.total} records`;
|
|
780
|
+
}
|
|
781
|
+
const total = table.getFilteredRowModel().rows.length;
|
|
782
|
+
return `${total} row(s).`;
|
|
783
|
+
}, /* @ts-ignore */
|
|
784
|
+
...(ngDevMode ? [{ debugName: "_statusText" }] : /* istanbul ignore next */ []));
|
|
785
|
+
_onLayoutToggle(value) {
|
|
786
|
+
if (value === 'table' || value === 'grid')
|
|
787
|
+
this.layout.set(value);
|
|
788
|
+
}
|
|
789
|
+
_onFilterInput(event) {
|
|
790
|
+
const value = event.target.value;
|
|
791
|
+
const id = this.filterColumnId();
|
|
792
|
+
if (!id) {
|
|
793
|
+
this.filterChange.emit(value);
|
|
794
|
+
return;
|
|
795
|
+
}
|
|
796
|
+
this._table.getColumn(id)?.setFilterValue(value);
|
|
797
|
+
}
|
|
798
|
+
/**
|
|
799
|
+
* Row/card click handler. Ignores clicks originating from nested interactive
|
|
800
|
+
* elements (selection checkboxes, action buttons, links, inputs) so those
|
|
801
|
+
* controls keep working without also firing `rowClick`.
|
|
802
|
+
*/
|
|
803
|
+
_onRowClick(event, row) {
|
|
804
|
+
const target = event.target;
|
|
805
|
+
if (target instanceof Element && target.closest('button, a, input, select, textarea, [role="checkbox"]')) {
|
|
806
|
+
return;
|
|
807
|
+
}
|
|
808
|
+
this.rowClick.emit(row.original);
|
|
809
|
+
}
|
|
810
|
+
/** Show the inline TH sort button only for sortable plain-string headers (component headers own their UI). */
|
|
811
|
+
_showHeaderSortButton(header) {
|
|
812
|
+
return header.column.getCanSort() && typeof header.column.columnDef.header === 'string';
|
|
813
|
+
}
|
|
814
|
+
_toggleHeaderSorting(header) {
|
|
815
|
+
header.column.toggleSorting(header.column.getIsSorted() === 'asc');
|
|
816
|
+
}
|
|
817
|
+
_selectionCell(row) {
|
|
818
|
+
return row.getVisibleCells().find((cell) => cell.column.id === 'select');
|
|
819
|
+
}
|
|
820
|
+
_thumbnailCell(row) {
|
|
821
|
+
return row.getVisibleCells().find((cell) => cell.column.columnDef.meta?.thumbnail === true);
|
|
822
|
+
}
|
|
823
|
+
_contentCells(row) {
|
|
824
|
+
return row
|
|
825
|
+
.getVisibleCells()
|
|
826
|
+
.filter((cell) => cell.column.id !== 'select' && cell.column.columnDef.meta?.thumbnail !== true);
|
|
827
|
+
}
|
|
828
|
+
_cellLabel(cell) {
|
|
829
|
+
const header = cell.column.columnDef.header;
|
|
830
|
+
if (typeof header === 'string')
|
|
831
|
+
return header;
|
|
832
|
+
return cell.column.id.replace(/_/g, ' ');
|
|
833
|
+
}
|
|
834
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: EgDataTable, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
835
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.3", type: EgDataTable, isStandalone: true, selector: "eg-data-table", inputs: { columns: { classPropertyName: "columns", publicName: "columns", isSignal: true, isRequired: true, transformFunction: null }, gridColumns: { classPropertyName: "gridColumns", publicName: "gridColumns", isSignal: true, isRequired: false, transformFunction: null }, data: { classPropertyName: "data", publicName: "data", isSignal: true, isRequired: false, transformFunction: null }, manualPagination: { classPropertyName: "manualPagination", publicName: "manualPagination", isSignal: true, isRequired: false, transformFunction: null }, features: { classPropertyName: "features", publicName: "features", isSignal: true, isRequired: false, transformFunction: null }, isLoading: { classPropertyName: "isLoading", publicName: "isLoading", isSignal: true, isRequired: false, transformFunction: null }, emptyMessage: { classPropertyName: "emptyMessage", publicName: "emptyMessage", isSignal: true, isRequired: false, transformFunction: null }, enableSelection: { classPropertyName: "enableSelection", publicName: "enableSelection", isSignal: true, isRequired: false, transformFunction: null }, hideFooter: { classPropertyName: "hideFooter", publicName: "hideFooter", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, layout: { classPropertyName: "layout", publicName: "layout", isSignal: true, isRequired: false, transformFunction: null }, showLayoutToggle: { classPropertyName: "showLayoutToggle", publicName: "showLayoutToggle", isSignal: true, isRequired: false, transformFunction: null }, showToolbar: { classPropertyName: "showToolbar", publicName: "showToolbar", isSignal: true, isRequired: false, transformFunction: null }, filterColumnId: { classPropertyName: "filterColumnId", publicName: "filterColumnId", isSignal: true, isRequired: false, transformFunction: null }, filterPlaceholder: { classPropertyName: "filterPlaceholder", publicName: "filterPlaceholder", isSignal: true, isRequired: false, transformFunction: null }, showColumnToggle: { classPropertyName: "showColumnToggle", publicName: "showColumnToggle", isSignal: true, isRequired: false, transformFunction: null }, toolbarActions: { classPropertyName: "toolbarActions", publicName: "toolbarActions", isSignal: true, isRequired: false, transformFunction: null }, defaultPageSize: { classPropertyName: "defaultPageSize", publicName: "defaultPageSize", isSignal: true, isRequired: false, transformFunction: null }, filterRows: { classPropertyName: "filterRows", publicName: "filterRows", isSignal: true, isRequired: false, transformFunction: null }, initialSorting: { classPropertyName: "initialSorting", publicName: "initialSorting", isSignal: true, isRequired: false, transformFunction: null }, initialColumnFilters: { classPropertyName: "initialColumnFilters", publicName: "initialColumnFilters", isSignal: true, isRequired: false, transformFunction: null }, initialColumnVisibility: { classPropertyName: "initialColumnVisibility", publicName: "initialColumnVisibility", isSignal: true, isRequired: false, transformFunction: null }, initialRowSelection: { classPropertyName: "initialRowSelection", publicName: "initialRowSelection", isSignal: true, isRequired: false, transformFunction: null }, showPageSize: { classPropertyName: "showPageSize", publicName: "showPageSize", isSignal: true, isRequired: false, transformFunction: null }, pageSizes: { classPropertyName: "pageSizes", publicName: "pageSizes", isSignal: true, isRequired: false, transformFunction: null }, navMode: { classPropertyName: "navMode", publicName: "navMode", isSignal: true, isRequired: false, transformFunction: null }, userClass: { classPropertyName: "userClass", publicName: "class", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { layout: "layoutChange", selectionChange: "selectionChange", pageChange: "pageChange", pageSizeChange: "pageSizeChange", rowClick: "rowClick", sortingChange: "sortingChange", columnFiltersChange: "columnFiltersChange", filterChange: "filterChange", columnVisibilityChange: "columnVisibilityChange" }, providers: [
|
|
836
|
+
provideIcons({ lucideArrowDown, lucideArrowUp, lucideChevronsUpDown, lucideLayoutGrid, lucideLayoutList }),
|
|
837
|
+
], ngImport: i0, template: `
|
|
838
|
+
<div [class]="_containerClass()">
|
|
839
|
+
@if (_showLayoutToggle()) {
|
|
840
|
+
<div class="tw:flex tw:items-center tw:justify-between">
|
|
841
|
+
<div hlmToggleGroup type="single" [value]="_effectiveLayout()" (valueChange)="_onLayoutToggle($event)">
|
|
842
|
+
<button hlmToggleGroupItem value="table" aria-label="Table view">
|
|
843
|
+
<ng-icon hlm name="lucideLayoutList" />
|
|
844
|
+
</button>
|
|
845
|
+
<button hlmToggleGroupItem value="grid" aria-label="Grid view">
|
|
846
|
+
<ng-icon hlm name="lucideLayoutGrid" />
|
|
847
|
+
</button>
|
|
848
|
+
</div>
|
|
849
|
+
<div></div>
|
|
850
|
+
</div>
|
|
851
|
+
}
|
|
852
|
+
|
|
853
|
+
@if (showToolbar() || toolbarActions()) {
|
|
854
|
+
<div class="tw:flex tw:flex-wrap tw:items-center tw:justify-between tw:gap-2 tw:py-1" [tanStackTable]="_table">
|
|
855
|
+
@if (showToolbar()) {
|
|
856
|
+
<div class="tw:flex tw:flex-wrap tw:items-center tw:gap-2">
|
|
857
|
+
<input
|
|
858
|
+
hlmInput
|
|
859
|
+
class="tw:w-full tw:min-w-0 tw:md:w-80"
|
|
860
|
+
[size]="size()"
|
|
861
|
+
[placeholder]="filterPlaceholder()"
|
|
862
|
+
(input)="_onFilterInput($event)"
|
|
863
|
+
/>
|
|
864
|
+
@if (showColumnToggle()) {
|
|
865
|
+
<eg-data-table-view-options [size]="size()" />
|
|
866
|
+
}
|
|
867
|
+
</div>
|
|
868
|
+
}
|
|
869
|
+
@if (toolbarActions()) {
|
|
870
|
+
<div class="tw:flex tw:flex-wrap tw:items-center tw:gap-2">
|
|
871
|
+
<ng-container *ngTemplateOutlet="toolbarActions()" />
|
|
872
|
+
</div>
|
|
873
|
+
}
|
|
874
|
+
</div>
|
|
875
|
+
}
|
|
876
|
+
|
|
877
|
+
@if (_effectiveLayout() === 'grid') {
|
|
878
|
+
<ng-container *ngTemplateOutlet="_gridView" />
|
|
879
|
+
} @else {
|
|
880
|
+
<ng-container *ngTemplateOutlet="_tableView" />
|
|
881
|
+
}
|
|
882
|
+
|
|
883
|
+
<ng-template #_tableView>
|
|
884
|
+
<div class="tw:overflow-hidden tw:rounded-md tw:border">
|
|
885
|
+
<div hlmTableContainer>
|
|
886
|
+
<table hlmTable>
|
|
887
|
+
<thead hlmTHead>
|
|
888
|
+
@for (headerGroup of _table.getHeaderGroups(); track headerGroup.id) {
|
|
889
|
+
<tr hlmTr>
|
|
890
|
+
@for (header of headerGroup.headers; track header.id) {
|
|
891
|
+
<th hlmTh [size]="size()" [attr.colSpan]="header.colSpan">
|
|
892
|
+
@if (!header.isPlaceholder) {
|
|
893
|
+
<div class="tw:flex tw:items-center tw:gap-1">
|
|
894
|
+
<ng-container
|
|
895
|
+
*flexRender="header.column.columnDef.header; props: header.getContext(); let headerText"
|
|
896
|
+
>
|
|
897
|
+
<div [innerHTML]="headerText"></div>
|
|
898
|
+
</ng-container>
|
|
899
|
+
@if (_showHeaderSortButton(header)) {
|
|
900
|
+
<button
|
|
901
|
+
hlmButton
|
|
902
|
+
variant="ghost"
|
|
903
|
+
size="sm"
|
|
904
|
+
[class]="_sortButtonClass()"
|
|
905
|
+
type="button"
|
|
906
|
+
[attr.aria-label]="'Sort by ' + header.column.id"
|
|
907
|
+
(click)="_toggleHeaderSorting(header)"
|
|
908
|
+
>
|
|
909
|
+
@switch (header.column.getIsSorted()) {
|
|
910
|
+
@case ('asc') {
|
|
911
|
+
<ng-icon hlm size="sm" name="lucideArrowUp" />
|
|
912
|
+
}
|
|
913
|
+
@case ('desc') {
|
|
914
|
+
<ng-icon hlm size="sm" name="lucideArrowDown" />
|
|
915
|
+
}
|
|
916
|
+
@default {
|
|
917
|
+
<ng-icon hlm size="sm" name="lucideChevronsUpDown" />
|
|
918
|
+
}
|
|
919
|
+
}
|
|
920
|
+
</button>
|
|
921
|
+
}
|
|
922
|
+
</div>
|
|
923
|
+
}
|
|
924
|
+
</th>
|
|
925
|
+
}
|
|
926
|
+
</tr>
|
|
927
|
+
}
|
|
928
|
+
</thead>
|
|
929
|
+
<tbody hlmTBody>
|
|
930
|
+
@if (isLoading()) {
|
|
931
|
+
<tr hlmTr>
|
|
932
|
+
<td hlmTd [attr.colspan]="_visibleColumnCount()" class="tw:h-24 tw:text-center">
|
|
933
|
+
<hlm-spinner class="tw:inline-flex" />
|
|
934
|
+
</td>
|
|
935
|
+
</tr>
|
|
936
|
+
} @else if (_table.getRowModel().rows.length === 0) {
|
|
937
|
+
<tr hlmTr>
|
|
938
|
+
<td hlmTd [attr.colspan]="_visibleColumnCount()" class="tw:h-24 tw:text-center">
|
|
939
|
+
{{ emptyMessage() }}
|
|
940
|
+
</td>
|
|
941
|
+
</tr>
|
|
942
|
+
} @else {
|
|
943
|
+
@for (row of _table.getRowModel().rows; track row.id) {
|
|
944
|
+
<tr
|
|
945
|
+
hlmTr
|
|
946
|
+
[attr.data-state]="row.getIsSelected() ? 'selected' : null"
|
|
947
|
+
(click)="_onRowClick($event, row)"
|
|
948
|
+
>
|
|
949
|
+
@for (cell of row.getVisibleCells(); track cell.id) {
|
|
950
|
+
<td hlmTd [size]="size()">
|
|
951
|
+
<ng-container
|
|
952
|
+
*flexRender="cell.column.columnDef.cell; props: cell.getContext(); let cellText"
|
|
953
|
+
>
|
|
954
|
+
<div [innerHTML]="cellText"></div>
|
|
955
|
+
</ng-container>
|
|
956
|
+
</td>
|
|
957
|
+
}
|
|
958
|
+
</tr>
|
|
959
|
+
}
|
|
960
|
+
}
|
|
961
|
+
</tbody>
|
|
962
|
+
</table>
|
|
963
|
+
</div>
|
|
964
|
+
</div>
|
|
965
|
+
</ng-template>
|
|
966
|
+
|
|
967
|
+
<ng-template #_gridView>
|
|
968
|
+
@if (isLoading()) {
|
|
969
|
+
<div
|
|
970
|
+
class="tw:flex tw:h-64 tw:items-center tw:justify-center tw:rounded-lg tw:border tw:border-dashed"
|
|
971
|
+
role="status"
|
|
972
|
+
>
|
|
973
|
+
<hlm-spinner />
|
|
974
|
+
</div>
|
|
975
|
+
} @else if (_table.getRowModel().rows.length === 0) {
|
|
976
|
+
<div
|
|
977
|
+
class="tw:text-muted-foreground tw:flex tw:h-64 tw:items-center tw:justify-center tw:rounded-lg tw:border tw:border-dashed"
|
|
978
|
+
>
|
|
979
|
+
{{ emptyMessage() }}
|
|
980
|
+
</div>
|
|
981
|
+
} @else {
|
|
982
|
+
<div class="tw:grid tw:grid-cols-1 tw:gap-4 tw:md:grid-cols-2 tw:xl:grid-cols-3 tw:2xl:grid-cols-4">
|
|
983
|
+
@for (row of _table.getRowModel().rows; track row.id) {
|
|
984
|
+
<div
|
|
985
|
+
hlmCard
|
|
986
|
+
class="tw:group tw:relative tw:transition-all tw:hover:shadow-md tw:data-[state=selected]:border-primary tw:data-[state=selected]:ring-1 tw:data-[state=selected]:ring-primary/20"
|
|
987
|
+
[attr.data-state]="row.getIsSelected() ? 'selected' : null"
|
|
988
|
+
(click)="_onRowClick($event, row)"
|
|
989
|
+
>
|
|
990
|
+
@if (_thumbnailCell(row); as thumbnail) {
|
|
991
|
+
<div class="tw:border-b tw:bg-muted/30">
|
|
992
|
+
<ng-container
|
|
993
|
+
*flexRender="thumbnail.column.columnDef.cell; props: thumbnail.getContext(); let thumbHtml"
|
|
994
|
+
>
|
|
995
|
+
<div [innerHTML]="thumbHtml"></div>
|
|
996
|
+
</ng-container>
|
|
997
|
+
</div>
|
|
998
|
+
}
|
|
999
|
+
@if (_selectionCell(row); as selection) {
|
|
1000
|
+
<div class="tw:absolute tw:top-4 tw:right-4">
|
|
1001
|
+
<ng-container
|
|
1002
|
+
*flexRender="selection.column.columnDef.cell; props: selection.getContext(); let selectHtml"
|
|
1003
|
+
>
|
|
1004
|
+
<div [innerHTML]="selectHtml"></div>
|
|
1005
|
+
</ng-container>
|
|
1006
|
+
</div>
|
|
1007
|
+
}
|
|
1008
|
+
<div hlmCardContent class="tw:space-y-3">
|
|
1009
|
+
@for (cell of _contentCells(row); track cell.id) {
|
|
1010
|
+
<div class="tw:flex tw:flex-col">
|
|
1011
|
+
<dt
|
|
1012
|
+
class="tw:text-[10px] tw:font-bold tw:tracking-wider tw:uppercase tw:text-muted-foreground/80"
|
|
1013
|
+
>
|
|
1014
|
+
{{ _cellLabel(cell) }}
|
|
1015
|
+
</dt>
|
|
1016
|
+
<dd class="tw:mt-0.5 tw:text-sm tw:leading-none tw:font-medium">
|
|
1017
|
+
<ng-container *flexRender="cell.column.columnDef.cell; props: cell.getContext(); let valueHtml">
|
|
1018
|
+
<div [innerHTML]="valueHtml"></div>
|
|
1019
|
+
</ng-container>
|
|
1020
|
+
</dd>
|
|
1021
|
+
</div>
|
|
1022
|
+
}
|
|
1023
|
+
</div>
|
|
1024
|
+
</div>
|
|
1025
|
+
}
|
|
1026
|
+
</div>
|
|
1027
|
+
}
|
|
1028
|
+
</ng-template>
|
|
1029
|
+
|
|
1030
|
+
@if (!hideFooter()) {
|
|
1031
|
+
<div
|
|
1032
|
+
class="tw:flex tw:flex-col tw:gap-2 tw:px-2 tw:py-4 tw:sm:flex-row tw:sm:items-center tw:sm:justify-between"
|
|
1033
|
+
[tanStackTable]="_table"
|
|
1034
|
+
>
|
|
1035
|
+
<div class="tw:text-muted-foreground tw:flex-1 tw:text-sm">{{ _statusText() }}</div>
|
|
1036
|
+
<eg-data-table-pagination
|
|
1037
|
+
[showStatus]="false"
|
|
1038
|
+
[showPageSize]="showPageSize()"
|
|
1039
|
+
[pageSizes]="pageSizes()"
|
|
1040
|
+
[navMode]="navMode()"
|
|
1041
|
+
[size]="size()"
|
|
1042
|
+
/>
|
|
1043
|
+
</div>
|
|
1044
|
+
}
|
|
1045
|
+
</div>
|
|
1046
|
+
`, isInline: true, dependencies: [{ kind: "directive", type: i1$2.FlexRenderDirective, selector: "ng-template[flexRender]", inputs: ["flexRender", "flexRenderProps", "flexRenderInjector"] }, { kind: "directive", type: TanStackTable, selector: "[tanStackTable]", inputs: ["tanStackTable"], exportAs: ["table"] }, { kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: i2.HlmTableContainer, selector: "div[hlmTableContainer]" }, { kind: "directive", type: i2.HlmTable, selector: "table[hlmTable]" }, { kind: "directive", type: i2.HlmTBody, selector: "tbody[hlmTBody],tbody[hlmTableBody]" }, { kind: "directive", type: i2.HlmTd, selector: "td[hlmTd],td[hlmTableCell]", inputs: ["size"] }, { kind: "directive", type: i2.HlmTh, selector: "th[hlmTh],th[hlmTableHead]", inputs: ["size"] }, { kind: "directive", type: i2.HlmTHead, selector: "thead[hlmTHead],thead[hlmTableHeader]" }, { kind: "directive", type: i2.HlmTr, selector: "tr[hlmTr],tr[hlmTableRow]" }, { kind: "component", type: HlmButton, selector: "button[hlmButton], a[hlmButton]", inputs: ["variant", "size", "appearance", "loading", "icon", "iconPosition", "class", "spinnerUserClass", "disabled", "type"] }, { kind: "directive", type: HlmCard, selector: "[hlmCard],hlm-card", inputs: ["size"] }, { kind: "directive", type: HlmCardContent, selector: "[hlmCardContent]" }, { kind: "directive", type: HlmIcon, selector: "ng-icon[hlm]", inputs: ["size"] }, { kind: "directive", type: HlmInput, selector: "[hlmInput]", inputs: ["ariaDescribedby", "size"] }, { kind: "component", type: HlmSpinner, selector: "hlm-spinner", inputs: ["size", "show", "class", "spinnerClass"] }, { kind: "directive", type: HlmToggleGroup, selector: "[hlmToggleGroup],hlm-toggle-group", inputs: ["variant", "size", "spacing", "orientation"] }, { kind: "directive", type: HlmToggleGroupItem, selector: "button[hlmToggleGroupItem]", inputs: ["variant", "size"] }, { kind: "component", type: NgIcon, selector: "ng-icon", inputs: ["name", "svg", "size", "strokeWidth", "color"] }, { kind: "component", type: EgDataTablePagination, selector: "eg-data-table-pagination", inputs: ["showStatus", "showPageSize", "pageSizes", "navMode", "size"] }, { kind: "component", type: EgDataTableViewOptions, selector: "eg-data-table-view-options", inputs: ["size"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
1047
|
+
}
|
|
1048
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: EgDataTable, decorators: [{
|
|
1049
|
+
type: Component,
|
|
1050
|
+
args: [{
|
|
1051
|
+
selector: 'eg-data-table',
|
|
1052
|
+
imports: [
|
|
1053
|
+
FlexRender,
|
|
1054
|
+
TanStackTable,
|
|
1055
|
+
NgTemplateOutlet,
|
|
1056
|
+
HlmTableImports,
|
|
1057
|
+
HlmButton,
|
|
1058
|
+
HlmCard,
|
|
1059
|
+
HlmCardContent,
|
|
1060
|
+
HlmIcon,
|
|
1061
|
+
HlmInput,
|
|
1062
|
+
HlmSpinner,
|
|
1063
|
+
HlmToggleGroup,
|
|
1064
|
+
HlmToggleGroupItem,
|
|
1065
|
+
NgIcon,
|
|
1066
|
+
EgDataTablePagination,
|
|
1067
|
+
EgDataTableViewOptions,
|
|
1068
|
+
],
|
|
1069
|
+
providers: [
|
|
1070
|
+
provideIcons({ lucideArrowDown, lucideArrowUp, lucideChevronsUpDown, lucideLayoutGrid, lucideLayoutList }),
|
|
1071
|
+
],
|
|
1072
|
+
template: `
|
|
1073
|
+
<div [class]="_containerClass()">
|
|
1074
|
+
@if (_showLayoutToggle()) {
|
|
1075
|
+
<div class="tw:flex tw:items-center tw:justify-between">
|
|
1076
|
+
<div hlmToggleGroup type="single" [value]="_effectiveLayout()" (valueChange)="_onLayoutToggle($event)">
|
|
1077
|
+
<button hlmToggleGroupItem value="table" aria-label="Table view">
|
|
1078
|
+
<ng-icon hlm name="lucideLayoutList" />
|
|
1079
|
+
</button>
|
|
1080
|
+
<button hlmToggleGroupItem value="grid" aria-label="Grid view">
|
|
1081
|
+
<ng-icon hlm name="lucideLayoutGrid" />
|
|
1082
|
+
</button>
|
|
1083
|
+
</div>
|
|
1084
|
+
<div></div>
|
|
1085
|
+
</div>
|
|
1086
|
+
}
|
|
1087
|
+
|
|
1088
|
+
@if (showToolbar() || toolbarActions()) {
|
|
1089
|
+
<div class="tw:flex tw:flex-wrap tw:items-center tw:justify-between tw:gap-2 tw:py-1" [tanStackTable]="_table">
|
|
1090
|
+
@if (showToolbar()) {
|
|
1091
|
+
<div class="tw:flex tw:flex-wrap tw:items-center tw:gap-2">
|
|
1092
|
+
<input
|
|
1093
|
+
hlmInput
|
|
1094
|
+
class="tw:w-full tw:min-w-0 tw:md:w-80"
|
|
1095
|
+
[size]="size()"
|
|
1096
|
+
[placeholder]="filterPlaceholder()"
|
|
1097
|
+
(input)="_onFilterInput($event)"
|
|
1098
|
+
/>
|
|
1099
|
+
@if (showColumnToggle()) {
|
|
1100
|
+
<eg-data-table-view-options [size]="size()" />
|
|
1101
|
+
}
|
|
1102
|
+
</div>
|
|
1103
|
+
}
|
|
1104
|
+
@if (toolbarActions()) {
|
|
1105
|
+
<div class="tw:flex tw:flex-wrap tw:items-center tw:gap-2">
|
|
1106
|
+
<ng-container *ngTemplateOutlet="toolbarActions()" />
|
|
1107
|
+
</div>
|
|
1108
|
+
}
|
|
1109
|
+
</div>
|
|
1110
|
+
}
|
|
1111
|
+
|
|
1112
|
+
@if (_effectiveLayout() === 'grid') {
|
|
1113
|
+
<ng-container *ngTemplateOutlet="_gridView" />
|
|
1114
|
+
} @else {
|
|
1115
|
+
<ng-container *ngTemplateOutlet="_tableView" />
|
|
1116
|
+
}
|
|
1117
|
+
|
|
1118
|
+
<ng-template #_tableView>
|
|
1119
|
+
<div class="tw:overflow-hidden tw:rounded-md tw:border">
|
|
1120
|
+
<div hlmTableContainer>
|
|
1121
|
+
<table hlmTable>
|
|
1122
|
+
<thead hlmTHead>
|
|
1123
|
+
@for (headerGroup of _table.getHeaderGroups(); track headerGroup.id) {
|
|
1124
|
+
<tr hlmTr>
|
|
1125
|
+
@for (header of headerGroup.headers; track header.id) {
|
|
1126
|
+
<th hlmTh [size]="size()" [attr.colSpan]="header.colSpan">
|
|
1127
|
+
@if (!header.isPlaceholder) {
|
|
1128
|
+
<div class="tw:flex tw:items-center tw:gap-1">
|
|
1129
|
+
<ng-container
|
|
1130
|
+
*flexRender="header.column.columnDef.header; props: header.getContext(); let headerText"
|
|
1131
|
+
>
|
|
1132
|
+
<div [innerHTML]="headerText"></div>
|
|
1133
|
+
</ng-container>
|
|
1134
|
+
@if (_showHeaderSortButton(header)) {
|
|
1135
|
+
<button
|
|
1136
|
+
hlmButton
|
|
1137
|
+
variant="ghost"
|
|
1138
|
+
size="sm"
|
|
1139
|
+
[class]="_sortButtonClass()"
|
|
1140
|
+
type="button"
|
|
1141
|
+
[attr.aria-label]="'Sort by ' + header.column.id"
|
|
1142
|
+
(click)="_toggleHeaderSorting(header)"
|
|
1143
|
+
>
|
|
1144
|
+
@switch (header.column.getIsSorted()) {
|
|
1145
|
+
@case ('asc') {
|
|
1146
|
+
<ng-icon hlm size="sm" name="lucideArrowUp" />
|
|
1147
|
+
}
|
|
1148
|
+
@case ('desc') {
|
|
1149
|
+
<ng-icon hlm size="sm" name="lucideArrowDown" />
|
|
1150
|
+
}
|
|
1151
|
+
@default {
|
|
1152
|
+
<ng-icon hlm size="sm" name="lucideChevronsUpDown" />
|
|
1153
|
+
}
|
|
1154
|
+
}
|
|
1155
|
+
</button>
|
|
1156
|
+
}
|
|
1157
|
+
</div>
|
|
1158
|
+
}
|
|
1159
|
+
</th>
|
|
1160
|
+
}
|
|
1161
|
+
</tr>
|
|
1162
|
+
}
|
|
1163
|
+
</thead>
|
|
1164
|
+
<tbody hlmTBody>
|
|
1165
|
+
@if (isLoading()) {
|
|
1166
|
+
<tr hlmTr>
|
|
1167
|
+
<td hlmTd [attr.colspan]="_visibleColumnCount()" class="tw:h-24 tw:text-center">
|
|
1168
|
+
<hlm-spinner class="tw:inline-flex" />
|
|
1169
|
+
</td>
|
|
1170
|
+
</tr>
|
|
1171
|
+
} @else if (_table.getRowModel().rows.length === 0) {
|
|
1172
|
+
<tr hlmTr>
|
|
1173
|
+
<td hlmTd [attr.colspan]="_visibleColumnCount()" class="tw:h-24 tw:text-center">
|
|
1174
|
+
{{ emptyMessage() }}
|
|
1175
|
+
</td>
|
|
1176
|
+
</tr>
|
|
1177
|
+
} @else {
|
|
1178
|
+
@for (row of _table.getRowModel().rows; track row.id) {
|
|
1179
|
+
<tr
|
|
1180
|
+
hlmTr
|
|
1181
|
+
[attr.data-state]="row.getIsSelected() ? 'selected' : null"
|
|
1182
|
+
(click)="_onRowClick($event, row)"
|
|
1183
|
+
>
|
|
1184
|
+
@for (cell of row.getVisibleCells(); track cell.id) {
|
|
1185
|
+
<td hlmTd [size]="size()">
|
|
1186
|
+
<ng-container
|
|
1187
|
+
*flexRender="cell.column.columnDef.cell; props: cell.getContext(); let cellText"
|
|
1188
|
+
>
|
|
1189
|
+
<div [innerHTML]="cellText"></div>
|
|
1190
|
+
</ng-container>
|
|
1191
|
+
</td>
|
|
1192
|
+
}
|
|
1193
|
+
</tr>
|
|
1194
|
+
}
|
|
1195
|
+
}
|
|
1196
|
+
</tbody>
|
|
1197
|
+
</table>
|
|
1198
|
+
</div>
|
|
1199
|
+
</div>
|
|
1200
|
+
</ng-template>
|
|
1201
|
+
|
|
1202
|
+
<ng-template #_gridView>
|
|
1203
|
+
@if (isLoading()) {
|
|
1204
|
+
<div
|
|
1205
|
+
class="tw:flex tw:h-64 tw:items-center tw:justify-center tw:rounded-lg tw:border tw:border-dashed"
|
|
1206
|
+
role="status"
|
|
1207
|
+
>
|
|
1208
|
+
<hlm-spinner />
|
|
1209
|
+
</div>
|
|
1210
|
+
} @else if (_table.getRowModel().rows.length === 0) {
|
|
1211
|
+
<div
|
|
1212
|
+
class="tw:text-muted-foreground tw:flex tw:h-64 tw:items-center tw:justify-center tw:rounded-lg tw:border tw:border-dashed"
|
|
1213
|
+
>
|
|
1214
|
+
{{ emptyMessage() }}
|
|
1215
|
+
</div>
|
|
1216
|
+
} @else {
|
|
1217
|
+
<div class="tw:grid tw:grid-cols-1 tw:gap-4 tw:md:grid-cols-2 tw:xl:grid-cols-3 tw:2xl:grid-cols-4">
|
|
1218
|
+
@for (row of _table.getRowModel().rows; track row.id) {
|
|
1219
|
+
<div
|
|
1220
|
+
hlmCard
|
|
1221
|
+
class="tw:group tw:relative tw:transition-all tw:hover:shadow-md tw:data-[state=selected]:border-primary tw:data-[state=selected]:ring-1 tw:data-[state=selected]:ring-primary/20"
|
|
1222
|
+
[attr.data-state]="row.getIsSelected() ? 'selected' : null"
|
|
1223
|
+
(click)="_onRowClick($event, row)"
|
|
1224
|
+
>
|
|
1225
|
+
@if (_thumbnailCell(row); as thumbnail) {
|
|
1226
|
+
<div class="tw:border-b tw:bg-muted/30">
|
|
1227
|
+
<ng-container
|
|
1228
|
+
*flexRender="thumbnail.column.columnDef.cell; props: thumbnail.getContext(); let thumbHtml"
|
|
1229
|
+
>
|
|
1230
|
+
<div [innerHTML]="thumbHtml"></div>
|
|
1231
|
+
</ng-container>
|
|
1232
|
+
</div>
|
|
1233
|
+
}
|
|
1234
|
+
@if (_selectionCell(row); as selection) {
|
|
1235
|
+
<div class="tw:absolute tw:top-4 tw:right-4">
|
|
1236
|
+
<ng-container
|
|
1237
|
+
*flexRender="selection.column.columnDef.cell; props: selection.getContext(); let selectHtml"
|
|
1238
|
+
>
|
|
1239
|
+
<div [innerHTML]="selectHtml"></div>
|
|
1240
|
+
</ng-container>
|
|
1241
|
+
</div>
|
|
1242
|
+
}
|
|
1243
|
+
<div hlmCardContent class="tw:space-y-3">
|
|
1244
|
+
@for (cell of _contentCells(row); track cell.id) {
|
|
1245
|
+
<div class="tw:flex tw:flex-col">
|
|
1246
|
+
<dt
|
|
1247
|
+
class="tw:text-[10px] tw:font-bold tw:tracking-wider tw:uppercase tw:text-muted-foreground/80"
|
|
1248
|
+
>
|
|
1249
|
+
{{ _cellLabel(cell) }}
|
|
1250
|
+
</dt>
|
|
1251
|
+
<dd class="tw:mt-0.5 tw:text-sm tw:leading-none tw:font-medium">
|
|
1252
|
+
<ng-container *flexRender="cell.column.columnDef.cell; props: cell.getContext(); let valueHtml">
|
|
1253
|
+
<div [innerHTML]="valueHtml"></div>
|
|
1254
|
+
</ng-container>
|
|
1255
|
+
</dd>
|
|
1256
|
+
</div>
|
|
1257
|
+
}
|
|
1258
|
+
</div>
|
|
1259
|
+
</div>
|
|
1260
|
+
}
|
|
1261
|
+
</div>
|
|
1262
|
+
}
|
|
1263
|
+
</ng-template>
|
|
1264
|
+
|
|
1265
|
+
@if (!hideFooter()) {
|
|
1266
|
+
<div
|
|
1267
|
+
class="tw:flex tw:flex-col tw:gap-2 tw:px-2 tw:py-4 tw:sm:flex-row tw:sm:items-center tw:sm:justify-between"
|
|
1268
|
+
[tanStackTable]="_table"
|
|
1269
|
+
>
|
|
1270
|
+
<div class="tw:text-muted-foreground tw:flex-1 tw:text-sm">{{ _statusText() }}</div>
|
|
1271
|
+
<eg-data-table-pagination
|
|
1272
|
+
[showStatus]="false"
|
|
1273
|
+
[showPageSize]="showPageSize()"
|
|
1274
|
+
[pageSizes]="pageSizes()"
|
|
1275
|
+
[navMode]="navMode()"
|
|
1276
|
+
[size]="size()"
|
|
1277
|
+
/>
|
|
1278
|
+
</div>
|
|
1279
|
+
}
|
|
1280
|
+
</div>
|
|
1281
|
+
`,
|
|
1282
|
+
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
1283
|
+
}]
|
|
1284
|
+
}], propDecorators: { columns: [{ type: i0.Input, args: [{ isSignal: true, alias: "columns", required: true }] }], gridColumns: [{ type: i0.Input, args: [{ isSignal: true, alias: "gridColumns", required: false }] }], data: [{ type: i0.Input, args: [{ isSignal: true, alias: "data", required: false }] }], manualPagination: [{ type: i0.Input, args: [{ isSignal: true, alias: "manualPagination", required: false }] }], features: [{ type: i0.Input, args: [{ isSignal: true, alias: "features", required: false }] }], isLoading: [{ type: i0.Input, args: [{ isSignal: true, alias: "isLoading", required: false }] }], emptyMessage: [{ type: i0.Input, args: [{ isSignal: true, alias: "emptyMessage", required: false }] }], enableSelection: [{ type: i0.Input, args: [{ isSignal: true, alias: "enableSelection", required: false }] }], hideFooter: [{ type: i0.Input, args: [{ isSignal: true, alias: "hideFooter", required: false }] }], size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }], layout: [{ type: i0.Input, args: [{ isSignal: true, alias: "layout", required: false }] }, { type: i0.Output, args: ["layoutChange"] }], showLayoutToggle: [{ type: i0.Input, args: [{ isSignal: true, alias: "showLayoutToggle", required: false }] }], showToolbar: [{ type: i0.Input, args: [{ isSignal: true, alias: "showToolbar", required: false }] }], filterColumnId: [{ type: i0.Input, args: [{ isSignal: true, alias: "filterColumnId", required: false }] }], filterPlaceholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "filterPlaceholder", required: false }] }], showColumnToggle: [{ type: i0.Input, args: [{ isSignal: true, alias: "showColumnToggle", required: false }] }], toolbarActions: [{ type: i0.Input, args: [{ isSignal: true, alias: "toolbarActions", required: false }] }], defaultPageSize: [{ type: i0.Input, args: [{ isSignal: true, alias: "defaultPageSize", required: false }] }], filterRows: [{ type: i0.Input, args: [{ isSignal: true, alias: "filterRows", required: false }] }], initialSorting: [{ type: i0.Input, args: [{ isSignal: true, alias: "initialSorting", required: false }] }], initialColumnFilters: [{ type: i0.Input, args: [{ isSignal: true, alias: "initialColumnFilters", required: false }] }], initialColumnVisibility: [{ type: i0.Input, args: [{ isSignal: true, alias: "initialColumnVisibility", required: false }] }], initialRowSelection: [{ type: i0.Input, args: [{ isSignal: true, alias: "initialRowSelection", required: false }] }], showPageSize: [{ type: i0.Input, args: [{ isSignal: true, alias: "showPageSize", required: false }] }], pageSizes: [{ type: i0.Input, args: [{ isSignal: true, alias: "pageSizes", required: false }] }], navMode: [{ type: i0.Input, args: [{ isSignal: true, alias: "navMode", required: false }] }], userClass: [{ type: i0.Input, args: [{ isSignal: true, alias: "class", required: false }] }], selectionChange: [{ type: i0.Output, args: ["selectionChange"] }], pageChange: [{ type: i0.Output, args: ["pageChange"] }], pageSizeChange: [{ type: i0.Output, args: ["pageSizeChange"] }], rowClick: [{ type: i0.Output, args: ["rowClick"] }], sortingChange: [{ type: i0.Output, args: ["sortingChange"] }], columnFiltersChange: [{ type: i0.Output, args: ["columnFiltersChange"] }], filterChange: [{ type: i0.Output, args: ["filterChange"] }], columnVisibilityChange: [{ type: i0.Output, args: ["columnVisibilityChange"] }] } });
|
|
1285
|
+
|
|
1286
|
+
/**
|
|
1287
|
+
* Sortable + hideable column header.
|
|
1288
|
+
*
|
|
1289
|
+
* Render via `flexRenderComponent(EgDataTableColumnHeader, { inputs: { column, title } })`
|
|
1290
|
+
* so the extra `title` input flows alongside the flex-render `column` context.
|
|
1291
|
+
* Non-sortable columns render a plain label.
|
|
1292
|
+
*/
|
|
1293
|
+
class EgDataTableColumnHeader {
|
|
1294
|
+
column = input.required(/* @ts-ignore */
|
|
1295
|
+
...(ngDevMode ? [{ debugName: "column" }] : /* istanbul ignore next */ []));
|
|
1296
|
+
title = input.required(/* @ts-ignore */
|
|
1297
|
+
...(ngDevMode ? [{ debugName: "title" }] : /* istanbul ignore next */ []));
|
|
1298
|
+
/** Density of the trigger button. */
|
|
1299
|
+
size = input('default', /* @ts-ignore */
|
|
1300
|
+
...(ngDevMode ? [{ debugName: "size" }] : /* istanbul ignore next */ []));
|
|
1301
|
+
_sorted = computed(() => this.column().getIsSorted(), /* @ts-ignore */
|
|
1302
|
+
...(ngDevMode ? [{ debugName: "_sorted" }] : /* istanbul ignore next */ []));
|
|
1303
|
+
/** Height per density. Merged by `hlmButton`. */
|
|
1304
|
+
_buttonClass = computed(() => hlm('tw:-ml-3', this.size() === 'sm' ? 'tw:h-7' : this.size() === 'lg' ? 'tw:h-9' : 'tw:h-8'), /* @ts-ignore */
|
|
1305
|
+
...(ngDevMode ? [{ debugName: "_buttonClass" }] : /* istanbul ignore next */ []));
|
|
1306
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: EgDataTableColumnHeader, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
1307
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.3", type: EgDataTableColumnHeader, isStandalone: true, selector: "eg-data-table-column-header", inputs: { column: { classPropertyName: "column", publicName: "column", isSignal: true, isRequired: true, transformFunction: null }, title: { classPropertyName: "title", publicName: "title", isSignal: true, isRequired: true, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null } }, providers: [provideIcons({ lucideArrowDown, lucideArrowUp, lucideChevronsUpDown, lucideEyeOff })], ngImport: i0, template: `
|
|
1308
|
+
@if (column().getCanSort()) {
|
|
1309
|
+
<div class="tw:flex tw:items-center tw:gap-2">
|
|
1310
|
+
<button
|
|
1311
|
+
hlmButton
|
|
1312
|
+
variant="ghost"
|
|
1313
|
+
size="sm"
|
|
1314
|
+
[class]="_buttonClass()"
|
|
1315
|
+
type="button"
|
|
1316
|
+
[hlmDropdownMenuTrigger]="_menu"
|
|
1317
|
+
>
|
|
1318
|
+
<span>{{ title() }}</span>
|
|
1319
|
+
@switch (_sorted()) {
|
|
1320
|
+
@case ('desc') {
|
|
1321
|
+
<ng-icon hlm size="sm" name="lucideArrowDown" />
|
|
1322
|
+
}
|
|
1323
|
+
@case ('asc') {
|
|
1324
|
+
<ng-icon hlm size="sm" name="lucideArrowUp" />
|
|
1325
|
+
}
|
|
1326
|
+
@default {
|
|
1327
|
+
<ng-icon hlm size="sm" name="lucideChevronsUpDown" />
|
|
1328
|
+
}
|
|
1329
|
+
}
|
|
1330
|
+
</button>
|
|
1331
|
+
<ng-template #_menu>
|
|
1332
|
+
<div hlmDropdownMenu>
|
|
1333
|
+
<button hlmDropdownMenuItem type="button" (click)="column().toggleSorting(false)">
|
|
1334
|
+
<ng-icon hlm size="sm" name="lucideArrowUp" />
|
|
1335
|
+
Asc
|
|
1336
|
+
</button>
|
|
1337
|
+
<button hlmDropdownMenuItem type="button" (click)="column().toggleSorting(true)">
|
|
1338
|
+
<ng-icon hlm size="sm" name="lucideArrowDown" />
|
|
1339
|
+
Desc
|
|
1340
|
+
</button>
|
|
1341
|
+
<div hlmDropdownMenuSeparator></div>
|
|
1342
|
+
<button hlmDropdownMenuItem type="button" (click)="column().toggleVisibility(false)">
|
|
1343
|
+
<ng-icon hlm size="sm" name="lucideEyeOff" />
|
|
1344
|
+
Hide
|
|
1345
|
+
</button>
|
|
1346
|
+
</div>
|
|
1347
|
+
</ng-template>
|
|
1348
|
+
</div>
|
|
1349
|
+
} @else {
|
|
1350
|
+
<div>{{ title() }}</div>
|
|
1351
|
+
}
|
|
1352
|
+
`, isInline: true, dependencies: [{ kind: "component", type: HlmButton, selector: "button[hlmButton], a[hlmButton]", inputs: ["variant", "size", "appearance", "loading", "icon", "iconPosition", "class", "spinnerUserClass", "disabled", "type"] }, { kind: "directive", type: i1$1.HlmDropdownMenu, selector: "[hlmDropdownMenu],hlm-dropdown-menu", inputs: ["sideOffset"] }, { kind: "directive", type: i1$1.HlmDropdownMenuItem, selector: "[hlmDropdownMenuItem],hlm-dropdown-menu-item", inputs: ["disabled", "variant", "inset"] }, { kind: "directive", type: i1$1.HlmDropdownMenuSeparator, selector: "[hlmDropdownMenuSeparator],hlm-dropdown-menu-separator" }, { kind: "directive", type: i1$1.HlmDropdownMenuTrigger, selector: "[hlmDropdownMenuTrigger]", inputs: ["align", "side"] }, { kind: "component", type: NgIcon, selector: "ng-icon", inputs: ["name", "svg", "size", "strokeWidth", "color"] }, { kind: "directive", type: HlmIcon, selector: "ng-icon[hlm]", inputs: ["size"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
1353
|
+
}
|
|
1354
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: EgDataTableColumnHeader, decorators: [{
|
|
1355
|
+
type: Component,
|
|
1356
|
+
args: [{
|
|
1357
|
+
selector: 'eg-data-table-column-header',
|
|
1358
|
+
imports: [HlmButton, HlmDropdownMenuImports, NgIcon, HlmIcon],
|
|
1359
|
+
providers: [provideIcons({ lucideArrowDown, lucideArrowUp, lucideChevronsUpDown, lucideEyeOff })],
|
|
1360
|
+
template: `
|
|
1361
|
+
@if (column().getCanSort()) {
|
|
1362
|
+
<div class="tw:flex tw:items-center tw:gap-2">
|
|
1363
|
+
<button
|
|
1364
|
+
hlmButton
|
|
1365
|
+
variant="ghost"
|
|
1366
|
+
size="sm"
|
|
1367
|
+
[class]="_buttonClass()"
|
|
1368
|
+
type="button"
|
|
1369
|
+
[hlmDropdownMenuTrigger]="_menu"
|
|
1370
|
+
>
|
|
1371
|
+
<span>{{ title() }}</span>
|
|
1372
|
+
@switch (_sorted()) {
|
|
1373
|
+
@case ('desc') {
|
|
1374
|
+
<ng-icon hlm size="sm" name="lucideArrowDown" />
|
|
1375
|
+
}
|
|
1376
|
+
@case ('asc') {
|
|
1377
|
+
<ng-icon hlm size="sm" name="lucideArrowUp" />
|
|
1378
|
+
}
|
|
1379
|
+
@default {
|
|
1380
|
+
<ng-icon hlm size="sm" name="lucideChevronsUpDown" />
|
|
1381
|
+
}
|
|
1382
|
+
}
|
|
1383
|
+
</button>
|
|
1384
|
+
<ng-template #_menu>
|
|
1385
|
+
<div hlmDropdownMenu>
|
|
1386
|
+
<button hlmDropdownMenuItem type="button" (click)="column().toggleSorting(false)">
|
|
1387
|
+
<ng-icon hlm size="sm" name="lucideArrowUp" />
|
|
1388
|
+
Asc
|
|
1389
|
+
</button>
|
|
1390
|
+
<button hlmDropdownMenuItem type="button" (click)="column().toggleSorting(true)">
|
|
1391
|
+
<ng-icon hlm size="sm" name="lucideArrowDown" />
|
|
1392
|
+
Desc
|
|
1393
|
+
</button>
|
|
1394
|
+
<div hlmDropdownMenuSeparator></div>
|
|
1395
|
+
<button hlmDropdownMenuItem type="button" (click)="column().toggleVisibility(false)">
|
|
1396
|
+
<ng-icon hlm size="sm" name="lucideEyeOff" />
|
|
1397
|
+
Hide
|
|
1398
|
+
</button>
|
|
1399
|
+
</div>
|
|
1400
|
+
</ng-template>
|
|
1401
|
+
</div>
|
|
1402
|
+
} @else {
|
|
1403
|
+
<div>{{ title() }}</div>
|
|
1404
|
+
}
|
|
1405
|
+
`,
|
|
1406
|
+
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
1407
|
+
}]
|
|
1408
|
+
}], propDecorators: { column: [{ type: i0.Input, args: [{ isSignal: true, alias: "column", required: true }] }], title: [{ type: i0.Input, args: [{ isSignal: true, alias: "title", required: true }] }], size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }] } });
|
|
1409
|
+
|
|
1410
|
+
/*
|
|
1411
|
+
* Public API Surface of data-table
|
|
1412
|
+
*/
|
|
1413
|
+
const EgDataTableImports = [
|
|
1414
|
+
EgDataTable,
|
|
1415
|
+
EgDataTableColumnHeader,
|
|
1416
|
+
EgDataTablePagination,
|
|
1417
|
+
EgDataTableViewOptions,
|
|
1418
|
+
EgTableHeadSelection,
|
|
1419
|
+
EgTableRowSelection,
|
|
1420
|
+
];
|
|
1421
|
+
class EgDataTableModule {
|
|
1422
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: EgDataTableModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
|
|
1423
|
+
static ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "22.1.3", ngImport: i0, type: EgDataTableModule, imports: [EgDataTable,
|
|
1424
|
+
EgDataTableColumnHeader,
|
|
1425
|
+
EgDataTablePagination,
|
|
1426
|
+
EgDataTableViewOptions,
|
|
1427
|
+
EgTableHeadSelection,
|
|
1428
|
+
EgTableRowSelection], exports: [EgDataTable,
|
|
1429
|
+
EgDataTableColumnHeader,
|
|
1430
|
+
EgDataTablePagination,
|
|
1431
|
+
EgDataTableViewOptions,
|
|
1432
|
+
EgTableHeadSelection,
|
|
1433
|
+
EgTableRowSelection] });
|
|
1434
|
+
static ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: EgDataTableModule, imports: [EgDataTableImports] });
|
|
1435
|
+
}
|
|
1436
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: EgDataTableModule, decorators: [{
|
|
1437
|
+
type: NgModule,
|
|
1438
|
+
args: [{
|
|
1439
|
+
imports: [...EgDataTableImports],
|
|
1440
|
+
exports: [...EgDataTableImports],
|
|
1441
|
+
}]
|
|
1442
|
+
}] });
|
|
1443
|
+
|
|
1444
|
+
/**
|
|
1445
|
+
* Generated bundle index. Do not edit.
|
|
1446
|
+
*/
|
|
1447
|
+
|
|
1448
|
+
export { EgDataTable, EgDataTableColumnHeader, EgDataTableImports, EgDataTableModule, EgDataTablePagination, EgDataTableViewOptions, EgTableHeadSelection, EgTableRowSelection, defaultEgDataTableFeatures };
|
|
1449
|
+
|