@egose/shadcn-theme-ng-tw 0.5.3 → 0.6.1

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.
Files changed (61) hide show
  1. package/README.md +131 -12
  2. package/autocomplete/fesm2022/autocomplete.mjs +14 -4
  3. package/autocomplete/types/autocomplete.d.ts +4 -1
  4. package/checkbox/README.md +6 -2
  5. package/checkbox/fesm2022/checkbox.mjs +15 -9
  6. package/checkbox/types/checkbox.d.ts +6 -4
  7. package/combobox/fesm2022/combobox.mjs +22 -6
  8. package/combobox/types/combobox.d.ts +8 -2
  9. package/data-table/README.md +174 -0
  10. package/data-table/fesm2022/data-table.mjs +1485 -0
  11. package/data-table/package.json +25 -0
  12. package/data-table/types/data-table.d.ts +495 -0
  13. package/date-picker/README.md +41 -9
  14. package/date-picker/fesm2022/date-picker.mjs +265 -59
  15. package/date-picker/types/date-picker.d.ts +58 -27
  16. package/dropdown-menu/README.md +2 -0
  17. package/form-autocomplete/README.md +4 -2
  18. package/form-autocomplete/fesm2022/form-autocomplete.mjs +33 -8
  19. package/form-autocomplete/types/form-autocomplete.d.ts +9 -3
  20. package/form-combobox/README.md +4 -2
  21. package/form-combobox/fesm2022/form-combobox.mjs +65 -14
  22. package/form-combobox/types/form-combobox.d.ts +10 -3
  23. package/form-input-otp/README.md +7 -5
  24. package/form-input-otp/fesm2022/form-input-otp.mjs +28 -14
  25. package/form-input-otp/types/form-input-otp.d.ts +9 -3
  26. package/form-searchable-multiselect/README.md +15 -1
  27. package/form-searchable-multiselect/fesm2022/form-searchable-multiselect.mjs +23 -3
  28. package/form-searchable-multiselect/types/form-searchable-multiselect.d.ts +9 -1
  29. package/form-slider/README.md +3 -1
  30. package/form-slider/fesm2022/form-slider.mjs +21 -6
  31. package/form-slider/types/form-slider.d.ts +9 -3
  32. package/form-text-input/fesm2022/form-text-input.mjs +1 -1
  33. package/form-textarea/fesm2022/form-textarea.mjs +1 -1
  34. package/form-toggle/README.md +22 -18
  35. package/form-toggle/fesm2022/form-toggle.mjs +25 -8
  36. package/form-toggle/types/form-toggle.d.ts +6 -2
  37. package/input/README.md +7 -12
  38. package/input/fesm2022/input.mjs +7 -4
  39. package/input/types/input.d.ts +3 -1
  40. package/input-otp/README.md +33 -9
  41. package/input-otp/fesm2022/input-otp.mjs +127 -11
  42. package/input-otp/types/input-otp.d.ts +24 -4
  43. package/layout-simple/fesm2022/layout-simple.mjs +1 -1
  44. package/package.json +6 -1
  45. package/pagination/README.md +21 -12
  46. package/pagination/fesm2022/pagination.mjs +83 -75
  47. package/pagination/types/pagination.d.ts +21 -8
  48. package/phone-input/README.md +16 -0
  49. package/phone-input/fesm2022/phone-input.mjs +42 -4
  50. package/phone-input/types/phone-input.d.ts +5 -2
  51. package/searchable-multiselect/README.md +62 -40
  52. package/searchable-multiselect/fesm2022/searchable-multiselect.mjs +97 -36
  53. package/searchable-multiselect/types/searchable-multiselect.d.ts +23 -6
  54. package/slider/fesm2022/slider.mjs +15 -5
  55. package/slider/types/slider.d.ts +6 -2
  56. package/stepper/README.md +39 -19
  57. package/stepper/fesm2022/stepper.mjs +71 -17
  58. package/stepper/types/stepper.d.ts +12 -1
  59. package/table/README.md +2 -0
  60. package/table/fesm2022/table.mjs +12 -8
  61. package/table/types/table.d.ts +7 -2
@@ -0,0 +1,1485 @@
1
+ import * as i0 from '@angular/core';
2
+ import { input, computed, ChangeDetectionStrategy, Component, model, output, signal, linkedSignal, effect, untracked, 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
+ /**
522
+ * Pure stable identity callback, e.g. `(record) => record.id`. Return a unique
523
+ * string per entity, independent of position, and keep the callback reference stable.
524
+ * Selection survives refreshes only for IDs still in the supplied rows (after
525
+ * `filterRows`); server selection is limited to the loaded slice. Without this
526
+ * callback, IDs are positional and replacing the rows clears selection.
527
+ * Changing the callback clears selection. Update data immutably.
528
+ */
529
+ getRowId = input(/* @ts-ignore */
530
+ ...(ngDevMode ? [undefined, { debugName: "getRowId" }] : /* istanbul ignore next */ []));
531
+ /** 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. */
532
+ manualPagination = input(false, /* @ts-ignore */
533
+ ...(ngDevMode ? [{ debugName: "manualPagination" }] : /* istanbul ignore next */ []));
534
+ /** TanStack feature registry. Defaults to filtering + visibility + pagination + selection + sorting. */
535
+ features = input(defaultEgDataTableFeatures, /* @ts-ignore */
536
+ ...(ngDevMode ? [{ debugName: "features" }] : /* istanbul ignore next */ []));
537
+ isLoading = input(false, /* @ts-ignore */
538
+ ...(ngDevMode ? [{ debugName: "isLoading" }] : /* istanbul ignore next */ []));
539
+ emptyMessage = input('No results found.', /* @ts-ignore */
540
+ ...(ngDevMode ? [{ debugName: "emptyMessage" }] : /* istanbul ignore next */ []));
541
+ /** When true, a checkbox column is auto-prepended and `selectionChange` emits the selected rows. */
542
+ enableSelection = input(false, /* @ts-ignore */
543
+ ...(ngDevMode ? [{ debugName: "enableSelection" }] : /* istanbul ignore next */ []));
544
+ hideFooter = input(false, /* @ts-ignore */
545
+ ...(ngDevMode ? [{ debugName: "hideFooter" }] : /* istanbul ignore next */ []));
546
+ /** Density of toolbar, table, and pagination chrome. Type scale is untouched. */
547
+ size = input('default', /* @ts-ignore */
548
+ ...(ngDevMode ? [{ debugName: "size" }] : /* istanbul ignore next */ []));
549
+ /** Presentation mode. Two-way bindable: `[(layout)]`. Grid requires `gridColumns`. */
550
+ layout = model('table', /* @ts-ignore */
551
+ ...(ngDevMode ? [{ debugName: "layout" }] : /* istanbul ignore next */ []));
552
+ /** Show the table/grid toggle (only rendered when `gridColumns` is set). */
553
+ showLayoutToggle = input(true, /* @ts-ignore */
554
+ ...(ngDevMode ? [{ debugName: "showLayoutToggle" }] : /* istanbul ignore next */ []));
555
+ /** Show the toolbar (filter input, plus the column-visibility dropdown when `showColumnToggle` is set). */
556
+ showToolbar = input(false, /* @ts-ignore */
557
+ ...(ngDevMode ? [{ debugName: "showToolbar" }] : /* istanbul ignore next */ []));
558
+ /** 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). */
559
+ filterColumnId = input('', /* @ts-ignore */
560
+ ...(ngDevMode ? [{ debugName: "filterColumnId" }] : /* istanbul ignore next */ []));
561
+ filterPlaceholder = input('Filter...', /* @ts-ignore */
562
+ ...(ngDevMode ? [{ debugName: "filterPlaceholder" }] : /* istanbul ignore next */ []));
563
+ /** Show the column-visibility dropdown inside the toolbar. Off by default; opt in per table. */
564
+ showColumnToggle = input(false, /* @ts-ignore */
565
+ ...(ngDevMode ? [{ debugName: "showColumnToggle" }] : /* istanbul ignore next */ []));
566
+ /** 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. */
567
+ toolbarActions = input(undefined, /* @ts-ignore */
568
+ ...(ngDevMode ? [{ debugName: "toolbarActions" }] : /* istanbul ignore next */ []));
569
+ /** Default client-side page size. Changing it later resets the pager to the new size. */
570
+ defaultPageSize = input(10, /* @ts-ignore */
571
+ ...(ngDevMode ? [{ debugName: "defaultPageSize" }] : /* istanbul ignore next */ []));
572
+ /** 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. */
573
+ filterRows = input(null, /* @ts-ignore */
574
+ ...(ngDevMode ? [{ debugName: "filterRows" }] : /* istanbul ignore next */ []));
575
+ /** Seeds the sorting state once at creation. Later changes are ignored — use `sortingChange` to stay in sync. */
576
+ initialSorting = input([], /* @ts-ignore */
577
+ ...(ngDevMode ? [{ debugName: "initialSorting" }] : /* istanbul ignore next */ []));
578
+ /** Seeds the column-filter state once at creation. Later changes are ignored. */
579
+ initialColumnFilters = input([], /* @ts-ignore */
580
+ ...(ngDevMode ? [{ debugName: "initialColumnFilters" }] : /* istanbul ignore next */ []));
581
+ /** Seeds the column-visibility state once at creation. Later changes are ignored. */
582
+ initialColumnVisibility = input({}, /* @ts-ignore */
583
+ ...(ngDevMode ? [{ debugName: "initialColumnVisibility" }] : /* istanbul ignore next */ []));
584
+ /** Seeds selection once for current rows: keys come from `getRowId`, or positional indices without it. Missing IDs are discarded. Later changes are ignored. */
585
+ initialRowSelection = input({}, /* @ts-ignore */
586
+ ...(ngDevMode ? [{ debugName: "initialRowSelection" }] : /* istanbul ignore next */ []));
587
+ /** Show the rows-per-page selector in the footer pager. */
588
+ showPageSize = input(true, /* @ts-ignore */
589
+ ...(ngDevMode ? [{ debugName: "showPageSize" }] : /* istanbul ignore next */ []));
590
+ /** Page-size options for the footer selector. The current size is appended when absent. */
591
+ pageSizes = input([10, 20, 30, 40, 50], /* @ts-ignore */
592
+ ...(ngDevMode ? [{ debugName: "pageSizes" }] : /* istanbul ignore next */ []));
593
+ /** Footer navigation-button content: icons only, text labels only, or both. */
594
+ navMode = input('icons', /* @ts-ignore */
595
+ ...(ngDevMode ? [{ debugName: "navMode" }] : /* istanbul ignore next */ []));
596
+ userClass = input('', { ...(ngDevMode ? { debugName: "userClass" } : /* istanbul ignore next */ {}), alias: 'class' });
597
+ /** Emits on init and when selected row identities/order or object references change. Includes rows hidden by built-in filters/client pagination, but never rows absent from `data`/`filterRows`. */
598
+ selectionChange = output();
599
+ /** Emits the target page index on pager navigation (primary hook for server fetching). */
600
+ pageChange = output();
601
+ pageSizeChange = output();
602
+ /** 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. */
603
+ rowClick = output();
604
+ sortingChange = output();
605
+ columnFiltersChange = output();
606
+ /** Emits the toolbar filter string whenever it changes. Empty when cleared or unset. */
607
+ filterChange = output();
608
+ columnVisibilityChange = output();
609
+ _containerClass = computed(() => hlm('tw:space-y-2', this.userClass()), /* @ts-ignore */
610
+ ...(ngDevMode ? [{ debugName: "_containerClass" }] : /* istanbul ignore next */ []));
611
+ /** Inline TH sort-button footprint per density. Merged by `hlmButton` via the `class` binding. */
612
+ _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 */
613
+ ...(ngDevMode ? [{ debugName: "_sortButtonClass" }] : /* istanbul ignore next */ []));
614
+ _sorting = signal([], /* @ts-ignore */
615
+ ...(ngDevMode ? [{ debugName: "_sorting" }] : /* istanbul ignore next */ []));
616
+ _columnFilters = signal([], /* @ts-ignore */
617
+ ...(ngDevMode ? [{ debugName: "_columnFilters" }] : /* istanbul ignore next */ []));
618
+ _columnVisibility = signal({}, /* @ts-ignore */
619
+ ...(ngDevMode ? [{ debugName: "_columnVisibility" }] : /* istanbul ignore next */ []));
620
+ _clientPageIndex = signal(0, /* @ts-ignore */
621
+ ...(ngDevMode ? [{ debugName: "_clientPageIndex" }] : /* istanbul ignore next */ []));
622
+ // Linked so the bound `defaultPageSize` applies once inputs are set, while
623
+ // pager-driven `set()` writes below are preserved until it changes again.
624
+ _clientPageSize = linkedSignal(() => this.defaultPageSize(), /* @ts-ignore */
625
+ ...(ngDevMode ? [{ debugName: "_clientPageSize" }] : /* istanbul ignore next */ []));
626
+ _isServer = computed(() => this.manualPagination(), /* @ts-ignore */
627
+ ...(ngDevMode ? [{ debugName: "_isServer" }] : /* istanbul ignore next */ []));
628
+ /** The server page slice when in server mode; `null` for client data, misuse shapes, or `null` while loading. */
629
+ _page = computed(() => {
630
+ if (!this._isServer())
631
+ return null;
632
+ const data = this.data();
633
+ if (data !== null && typeof data === 'object' && 'items' in data) {
634
+ return data;
635
+ }
636
+ return null;
637
+ }, /* @ts-ignore */
638
+ ...(ngDevMode ? [{ debugName: "_page" }] : /* istanbul ignore next */ []));
639
+ _items = computed(() => {
640
+ const page = this._page();
641
+ if (page)
642
+ return page.items;
643
+ const data = this.data();
644
+ const rows = Array.isArray(data)
645
+ ? data
646
+ : (data?.items ?? []);
647
+ const filter = this.filterRows();
648
+ return filter ? filter(rows) : rows;
649
+ }, /* @ts-ignore */
650
+ ...(ngDevMode ? [{ debugName: "_items" }] : /* istanbul ignore next */ []));
651
+ // TanStack uses data-reference changes to reset pagination. State/layout
652
+ // updates must not look like a new data set (including selecting page rows).
653
+ _tableItems = computed(() => {
654
+ // A different identity function must also rebuild TanStack's cached rows.
655
+ this.getRowId();
656
+ return [...this._items()];
657
+ }, /* @ts-ignore */
658
+ ...(ngDevMode ? [{ debugName: "_tableItems" }] : /* istanbul ignore next */ []));
659
+ // Reconcile synchronously with the data source, before either TanStack or the
660
+ // output can observe old positional keys against new records. An effect-based
661
+ // reset would permit a transient wrong-entity selection.
662
+ _rowSelection = linkedSignal({ ...(ngDevMode ? { debugName: "_rowSelection" } : /* istanbul ignore next */ {}), source: () => ({ items: this._items(), getRowId: this.getRowId() }),
663
+ computation: (source, previous) => {
664
+ if (!previous || source.getRowId !== previous.source.getRowId)
665
+ return {};
666
+ if (!source.getRowId && source.items !== previous.source.items)
667
+ return {};
668
+ return this._keepCurrentSelection(previous.value);
669
+ } });
670
+ _keepCurrentSelection(selection) {
671
+ const getRowId = this.getRowId();
672
+ return Object.fromEntries(this._items()
673
+ .map((row, index) => (getRowId ? getRowId(row) : String(index)))
674
+ .filter((id) => Object.hasOwn(selection, id) && selection[id])
675
+ .map((id) => [id, true]));
676
+ }
677
+ _serverPageCount = computed(() => {
678
+ const paginated = this._page();
679
+ if (!paginated || paginated.limit <= 0)
680
+ return 1;
681
+ return Math.max(1, Math.ceil(paginated.total / paginated.limit));
682
+ }, /* @ts-ignore */
683
+ ...(ngDevMode ? [{ debugName: "_serverPageCount" }] : /* istanbul ignore next */ []));
684
+ _serverPageIndex = computed(() => {
685
+ const paginated = this._page();
686
+ if (!paginated || paginated.limit <= 0)
687
+ return 0;
688
+ return Math.floor(paginated.offset / paginated.limit);
689
+ }, /* @ts-ignore */
690
+ ...(ngDevMode ? [{ debugName: "_serverPageIndex" }] : /* istanbul ignore next */ []));
691
+ _paginationState = computed(() => {
692
+ const paginated = this._page();
693
+ if (paginated)
694
+ return { pageIndex: this._serverPageIndex(), pageSize: paginated.limit };
695
+ return { pageIndex: this._clientPageIndex(), pageSize: this._clientPageSize() };
696
+ }, /* @ts-ignore */
697
+ ...(ngDevMode ? [{ debugName: "_paginationState" }] : /* istanbul ignore next */ []));
698
+ _selectionHelper = computed(() => createColumnHelper(), /* @ts-ignore */
699
+ ...(ngDevMode ? [{ debugName: "_selectionHelper" }] : /* istanbul ignore next */ []));
700
+ /** Caller columns + auto-injected selection column + layout filtering. */
701
+ _finalColumns = computed(() => {
702
+ const isGrid = this._effectiveLayout() === 'grid';
703
+ const base = isGrid ? (this.gridColumns() ?? this.columns()) : this.columns();
704
+ const visible = isGrid ? base : base.filter((column) => column.meta?.hideInTable !== true);
705
+ if (!this.enableSelection())
706
+ return [...visible];
707
+ const helper = this._selectionHelper();
708
+ const selectionColumn = helper.display({
709
+ id: 'select',
710
+ header: () => EgTableHeadSelection,
711
+ cell: () => EgTableRowSelection,
712
+ enableSorting: false,
713
+ enableHiding: false,
714
+ });
715
+ return [selectionColumn, ...visible];
716
+ }, /* @ts-ignore */
717
+ ...(ngDevMode ? [{ debugName: "_finalColumns" }] : /* istanbul ignore next */ []));
718
+ _table = injectTable(() => {
719
+ const server = this._isServer();
720
+ return {
721
+ features: this.features(),
722
+ columns: this._finalColumns(),
723
+ data: this._tableItems(),
724
+ getRowId: this.getRowId(),
725
+ manualPagination: server,
726
+ manualSorting: server,
727
+ manualFiltering: server,
728
+ ...(server ? { pageCount: this._serverPageCount() } : {}),
729
+ state: {
730
+ sorting: this._sorting(),
731
+ columnFilters: this._columnFilters(),
732
+ columnVisibility: this._columnVisibility(),
733
+ rowSelection: this._rowSelection(),
734
+ pagination: this._paginationState(),
735
+ },
736
+ onSortingChange: (updater) => {
737
+ const next = typeof updater === 'function' ? updater(this._sorting()) : updater;
738
+ this._sorting.set(next);
739
+ this.sortingChange.emit(next);
740
+ },
741
+ onColumnFiltersChange: (updater) => {
742
+ const next = typeof updater === 'function' ? updater(this._columnFilters()) : updater;
743
+ this._columnFilters.set(next);
744
+ this.columnFiltersChange.emit(next);
745
+ const filterId = this.filterColumnId();
746
+ if (filterId) {
747
+ const value = next.find((filter) => filter.id === filterId)?.value;
748
+ this.filterChange.emit(typeof value === 'string' ? value : '');
749
+ }
750
+ },
751
+ onColumnVisibilityChange: (updater) => {
752
+ const next = typeof updater === 'function' ? updater(this._columnVisibility()) : updater;
753
+ this._columnVisibility.set(next);
754
+ this.columnVisibilityChange.emit(next);
755
+ },
756
+ onRowSelectionChange: (updater) => {
757
+ const next = typeof updater === 'function' ? updater(this._rowSelection()) : updater;
758
+ this._rowSelection.set(next);
759
+ },
760
+ onPaginationChange: (updater) => {
761
+ const current = this._paginationState();
762
+ const next = typeof updater === 'function' ? updater(current) : updater;
763
+ if (next.pageIndex !== current.pageIndex)
764
+ this.pageChange.emit(next.pageIndex);
765
+ if (next.pageSize !== current.pageSize)
766
+ this.pageSizeChange.emit(next.pageSize);
767
+ if (!this._isServer()) {
768
+ this._clientPageIndex.set(next.pageIndex);
769
+ this._clientPageSize.set(next.pageSize);
770
+ }
771
+ },
772
+ };
773
+ });
774
+ _selectedRows = computed(() => this._table.getSelectedRowModel().rows.map((row) => row.original), { ...(ngDevMode ? { debugName: "_selectedRows" } : /* istanbul ignore next */ {}), equal: (a, b) => a.length === b.length && a.every((row, index) => row === b[index]) });
775
+ _emitSelection = effect(() => {
776
+ const selected = this._selectedRows();
777
+ // Consumer handlers may read signals; those reads must not retrigger us.
778
+ untracked(() => this.selectionChange.emit(selected));
779
+ }, /* @ts-ignore */
780
+ ...(ngDevMode ? [{ debugName: "_emitSelection" }] : /* istanbul ignore next */ []));
781
+ /**
782
+ * Seeds internal state from the `initial*` inputs. Runs in `ngOnInit` (after
783
+ * first bindings, before first render) exactly once, so inline-literal
784
+ * bindings (new references every change detection) cannot clobber user
785
+ * interaction afterwards. Values are copied to avoid aliasing caller data.
786
+ */
787
+ ngOnInit() {
788
+ this._sorting.set([...this.initialSorting()]);
789
+ this._columnFilters.set([...this.initialColumnFilters()]);
790
+ this._columnVisibility.set({ ...this.initialColumnVisibility() });
791
+ this._rowSelection.set(this._keepCurrentSelection(this.initialRowSelection()));
792
+ }
793
+ _hasGrid = computed(() => this.gridColumns() !== undefined, /* @ts-ignore */
794
+ ...(ngDevMode ? [{ debugName: "_hasGrid" }] : /* istanbul ignore next */ []));
795
+ _effectiveLayout = computed(() => this.layout() === 'grid' && this._hasGrid() ? 'grid' : 'table', /* @ts-ignore */
796
+ ...(ngDevMode ? [{ debugName: "_effectiveLayout" }] : /* istanbul ignore next */ []));
797
+ _showLayoutToggle = computed(() => this.showLayoutToggle() && this._hasGrid(), /* @ts-ignore */
798
+ ...(ngDevMode ? [{ debugName: "_showLayoutToggle" }] : /* istanbul ignore next */ []));
799
+ _visibleColumnCount = computed(() => {
800
+ const count = this._table.getVisibleLeafColumns().length;
801
+ return count > 0 ? count : 1;
802
+ }, /* @ts-ignore */
803
+ ...(ngDevMode ? [{ debugName: "_visibleColumnCount" }] : /* istanbul ignore next */ []));
804
+ _statusText = computed(() => {
805
+ const paginated = this._page();
806
+ const table = this._table;
807
+ const selected = table.getFilteredSelectedRowModel().rows.length;
808
+ if (this.enableSelection() && selected > 0) {
809
+ const total = paginated ? paginated.total : table.getFilteredRowModel().rows.length;
810
+ return `${selected} of ${total} row(s) selected`;
811
+ }
812
+ if (paginated) {
813
+ const from = paginated.items.length === 0 ? 0 : paginated.offset + 1;
814
+ const to = paginated.offset + paginated.items.length;
815
+ return `Showing ${from} to ${to} of ${paginated.total} records`;
816
+ }
817
+ const total = table.getFilteredRowModel().rows.length;
818
+ return `${total} row(s).`;
819
+ }, /* @ts-ignore */
820
+ ...(ngDevMode ? [{ debugName: "_statusText" }] : /* istanbul ignore next */ []));
821
+ _onLayoutToggle(value) {
822
+ if (value === 'table' || value === 'grid')
823
+ this.layout.set(value);
824
+ }
825
+ _onFilterInput(event) {
826
+ const value = event.target.value;
827
+ const id = this.filterColumnId();
828
+ if (!id) {
829
+ this.filterChange.emit(value);
830
+ return;
831
+ }
832
+ this._table.getColumn(id)?.setFilterValue(value);
833
+ }
834
+ /**
835
+ * Row/card click handler. Ignores clicks originating from nested interactive
836
+ * elements (selection checkboxes, action buttons, links, inputs) so those
837
+ * controls keep working without also firing `rowClick`.
838
+ */
839
+ _onRowClick(event, row) {
840
+ const target = event.target;
841
+ if (target instanceof Element && target.closest('button, a, input, select, textarea, [role="checkbox"]')) {
842
+ return;
843
+ }
844
+ this.rowClick.emit(row.original);
845
+ }
846
+ /** Show the inline TH sort button only for sortable plain-string headers (component headers own their UI). */
847
+ _showHeaderSortButton(header) {
848
+ return header.column.getCanSort() && typeof header.column.columnDef.header === 'string';
849
+ }
850
+ _toggleHeaderSorting(header) {
851
+ header.column.toggleSorting(header.column.getIsSorted() === 'asc');
852
+ }
853
+ _selectionCell(row) {
854
+ return row.getVisibleCells().find((cell) => cell.column.id === 'select');
855
+ }
856
+ _thumbnailCell(row) {
857
+ return row.getVisibleCells().find((cell) => cell.column.columnDef.meta?.thumbnail === true);
858
+ }
859
+ _contentCells(row) {
860
+ return row
861
+ .getVisibleCells()
862
+ .filter((cell) => cell.column.id !== 'select' && cell.column.columnDef.meta?.thumbnail !== true);
863
+ }
864
+ _cellLabel(cell) {
865
+ const header = cell.column.columnDef.header;
866
+ if (typeof header === 'string')
867
+ return header;
868
+ return cell.column.id.replace(/_/g, ' ');
869
+ }
870
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: EgDataTable, deps: [], target: i0.ɵɵFactoryTarget.Component });
871
+ 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 }, getRowId: { classPropertyName: "getRowId", publicName: "getRowId", 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: [
872
+ provideIcons({ lucideArrowDown, lucideArrowUp, lucideChevronsUpDown, lucideLayoutGrid, lucideLayoutList }),
873
+ ], ngImport: i0, template: `
874
+ <div [class]="_containerClass()">
875
+ @if (_showLayoutToggle()) {
876
+ <div class="tw:flex tw:items-center tw:justify-between">
877
+ <div hlmToggleGroup type="single" [value]="_effectiveLayout()" (valueChange)="_onLayoutToggle($event)">
878
+ <button hlmToggleGroupItem value="table" aria-label="Table view">
879
+ <ng-icon hlm name="lucideLayoutList" />
880
+ </button>
881
+ <button hlmToggleGroupItem value="grid" aria-label="Grid view">
882
+ <ng-icon hlm name="lucideLayoutGrid" />
883
+ </button>
884
+ </div>
885
+ <div></div>
886
+ </div>
887
+ }
888
+
889
+ @if (showToolbar() || toolbarActions()) {
890
+ <div class="tw:flex tw:flex-wrap tw:items-center tw:justify-between tw:gap-2 tw:py-1" [tanStackTable]="_table">
891
+ @if (showToolbar()) {
892
+ <div class="tw:flex tw:flex-wrap tw:items-center tw:gap-2">
893
+ <input
894
+ hlmInput
895
+ class="tw:w-full tw:min-w-0 tw:md:w-80"
896
+ [size]="size()"
897
+ [placeholder]="filterPlaceholder()"
898
+ (input)="_onFilterInput($event)"
899
+ />
900
+ @if (showColumnToggle()) {
901
+ <eg-data-table-view-options [size]="size()" />
902
+ }
903
+ </div>
904
+ }
905
+ @if (toolbarActions()) {
906
+ <div class="tw:flex tw:flex-wrap tw:items-center tw:gap-2">
907
+ <ng-container *ngTemplateOutlet="toolbarActions()" />
908
+ </div>
909
+ }
910
+ </div>
911
+ }
912
+
913
+ @if (_effectiveLayout() === 'grid') {
914
+ <ng-container *ngTemplateOutlet="_gridView" />
915
+ } @else {
916
+ <ng-container *ngTemplateOutlet="_tableView" />
917
+ }
918
+
919
+ <ng-template #_tableView>
920
+ <div class="tw:overflow-hidden tw:rounded-md tw:border">
921
+ <div hlmTableContainer>
922
+ <table hlmTable>
923
+ <thead hlmTHead>
924
+ @for (headerGroup of _table.getHeaderGroups(); track headerGroup.id) {
925
+ <tr hlmTr>
926
+ @for (header of headerGroup.headers; track header.id) {
927
+ <th hlmTh [size]="size()" [attr.colSpan]="header.colSpan">
928
+ @if (!header.isPlaceholder) {
929
+ <div class="tw:flex tw:items-center tw:gap-1">
930
+ <ng-container
931
+ *flexRender="header.column.columnDef.header; props: header.getContext(); let headerText"
932
+ >
933
+ <div [innerHTML]="headerText"></div>
934
+ </ng-container>
935
+ @if (_showHeaderSortButton(header)) {
936
+ <button
937
+ hlmButton
938
+ variant="ghost"
939
+ size="sm"
940
+ [class]="_sortButtonClass()"
941
+ type="button"
942
+ [attr.aria-label]="'Sort by ' + header.column.id"
943
+ (click)="_toggleHeaderSorting(header)"
944
+ >
945
+ @switch (header.column.getIsSorted()) {
946
+ @case ('asc') {
947
+ <ng-icon hlm size="sm" name="lucideArrowUp" />
948
+ }
949
+ @case ('desc') {
950
+ <ng-icon hlm size="sm" name="lucideArrowDown" />
951
+ }
952
+ @default {
953
+ <ng-icon hlm size="sm" name="lucideChevronsUpDown" />
954
+ }
955
+ }
956
+ </button>
957
+ }
958
+ </div>
959
+ }
960
+ </th>
961
+ }
962
+ </tr>
963
+ }
964
+ </thead>
965
+ <tbody hlmTBody>
966
+ @if (isLoading()) {
967
+ <tr hlmTr>
968
+ <td hlmTd [attr.colspan]="_visibleColumnCount()" class="tw:h-24 tw:text-center">
969
+ <hlm-spinner class="tw:inline-flex" />
970
+ </td>
971
+ </tr>
972
+ } @else if (_table.getRowModel().rows.length === 0) {
973
+ <tr hlmTr>
974
+ <td hlmTd [attr.colspan]="_visibleColumnCount()" class="tw:h-24 tw:text-center">
975
+ {{ emptyMessage() }}
976
+ </td>
977
+ </tr>
978
+ } @else {
979
+ @for (row of _table.getRowModel().rows; track row.id) {
980
+ <tr
981
+ hlmTr
982
+ [attr.data-state]="row.getIsSelected() ? 'selected' : null"
983
+ (click)="_onRowClick($event, row)"
984
+ >
985
+ @for (cell of row.getVisibleCells(); track cell.id) {
986
+ <td hlmTd [size]="size()">
987
+ <ng-container
988
+ *flexRender="cell.column.columnDef.cell; props: cell.getContext(); let cellText"
989
+ >
990
+ <div [innerHTML]="cellText"></div>
991
+ </ng-container>
992
+ </td>
993
+ }
994
+ </tr>
995
+ }
996
+ }
997
+ </tbody>
998
+ </table>
999
+ </div>
1000
+ </div>
1001
+ </ng-template>
1002
+
1003
+ <ng-template #_gridView>
1004
+ @if (isLoading()) {
1005
+ <div
1006
+ class="tw:flex tw:h-64 tw:items-center tw:justify-center tw:rounded-lg tw:border tw:border-dashed"
1007
+ role="status"
1008
+ >
1009
+ <hlm-spinner />
1010
+ </div>
1011
+ } @else if (_table.getRowModel().rows.length === 0) {
1012
+ <div
1013
+ class="tw:text-muted-foreground tw:flex tw:h-64 tw:items-center tw:justify-center tw:rounded-lg tw:border tw:border-dashed"
1014
+ >
1015
+ {{ emptyMessage() }}
1016
+ </div>
1017
+ } @else {
1018
+ <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">
1019
+ @for (row of _table.getRowModel().rows; track row.id) {
1020
+ <div
1021
+ hlmCard
1022
+ 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"
1023
+ [attr.data-state]="row.getIsSelected() ? 'selected' : null"
1024
+ (click)="_onRowClick($event, row)"
1025
+ >
1026
+ @if (_thumbnailCell(row); as thumbnail) {
1027
+ <div class="tw:border-b tw:bg-muted/30">
1028
+ <ng-container
1029
+ *flexRender="thumbnail.column.columnDef.cell; props: thumbnail.getContext(); let thumbHtml"
1030
+ >
1031
+ <div [innerHTML]="thumbHtml"></div>
1032
+ </ng-container>
1033
+ </div>
1034
+ }
1035
+ @if (_selectionCell(row); as selection) {
1036
+ <div class="tw:absolute tw:top-4 tw:right-4">
1037
+ <ng-container
1038
+ *flexRender="selection.column.columnDef.cell; props: selection.getContext(); let selectHtml"
1039
+ >
1040
+ <div [innerHTML]="selectHtml"></div>
1041
+ </ng-container>
1042
+ </div>
1043
+ }
1044
+ <div hlmCardContent class="tw:space-y-3">
1045
+ @for (cell of _contentCells(row); track cell.id) {
1046
+ <div class="tw:flex tw:flex-col">
1047
+ <dt
1048
+ class="tw:text-[10px] tw:font-bold tw:tracking-wider tw:uppercase tw:text-muted-foreground/80"
1049
+ >
1050
+ {{ _cellLabel(cell) }}
1051
+ </dt>
1052
+ <dd class="tw:mt-0.5 tw:text-sm tw:leading-none tw:font-medium">
1053
+ <ng-container *flexRender="cell.column.columnDef.cell; props: cell.getContext(); let valueHtml">
1054
+ <div [innerHTML]="valueHtml"></div>
1055
+ </ng-container>
1056
+ </dd>
1057
+ </div>
1058
+ }
1059
+ </div>
1060
+ </div>
1061
+ }
1062
+ </div>
1063
+ }
1064
+ </ng-template>
1065
+
1066
+ @if (!hideFooter()) {
1067
+ <div
1068
+ 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"
1069
+ [tanStackTable]="_table"
1070
+ >
1071
+ <div class="tw:text-muted-foreground tw:flex-1 tw:text-sm">{{ _statusText() }}</div>
1072
+ <eg-data-table-pagination
1073
+ [showStatus]="false"
1074
+ [showPageSize]="showPageSize()"
1075
+ [pageSizes]="pageSizes()"
1076
+ [navMode]="navMode()"
1077
+ [size]="size()"
1078
+ />
1079
+ </div>
1080
+ }
1081
+ </div>
1082
+ `, 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 });
1083
+ }
1084
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: EgDataTable, decorators: [{
1085
+ type: Component,
1086
+ args: [{
1087
+ selector: 'eg-data-table',
1088
+ imports: [
1089
+ FlexRender,
1090
+ TanStackTable,
1091
+ NgTemplateOutlet,
1092
+ HlmTableImports,
1093
+ HlmButton,
1094
+ HlmCard,
1095
+ HlmCardContent,
1096
+ HlmIcon,
1097
+ HlmInput,
1098
+ HlmSpinner,
1099
+ HlmToggleGroup,
1100
+ HlmToggleGroupItem,
1101
+ NgIcon,
1102
+ EgDataTablePagination,
1103
+ EgDataTableViewOptions,
1104
+ ],
1105
+ providers: [
1106
+ provideIcons({ lucideArrowDown, lucideArrowUp, lucideChevronsUpDown, lucideLayoutGrid, lucideLayoutList }),
1107
+ ],
1108
+ template: `
1109
+ <div [class]="_containerClass()">
1110
+ @if (_showLayoutToggle()) {
1111
+ <div class="tw:flex tw:items-center tw:justify-between">
1112
+ <div hlmToggleGroup type="single" [value]="_effectiveLayout()" (valueChange)="_onLayoutToggle($event)">
1113
+ <button hlmToggleGroupItem value="table" aria-label="Table view">
1114
+ <ng-icon hlm name="lucideLayoutList" />
1115
+ </button>
1116
+ <button hlmToggleGroupItem value="grid" aria-label="Grid view">
1117
+ <ng-icon hlm name="lucideLayoutGrid" />
1118
+ </button>
1119
+ </div>
1120
+ <div></div>
1121
+ </div>
1122
+ }
1123
+
1124
+ @if (showToolbar() || toolbarActions()) {
1125
+ <div class="tw:flex tw:flex-wrap tw:items-center tw:justify-between tw:gap-2 tw:py-1" [tanStackTable]="_table">
1126
+ @if (showToolbar()) {
1127
+ <div class="tw:flex tw:flex-wrap tw:items-center tw:gap-2">
1128
+ <input
1129
+ hlmInput
1130
+ class="tw:w-full tw:min-w-0 tw:md:w-80"
1131
+ [size]="size()"
1132
+ [placeholder]="filterPlaceholder()"
1133
+ (input)="_onFilterInput($event)"
1134
+ />
1135
+ @if (showColumnToggle()) {
1136
+ <eg-data-table-view-options [size]="size()" />
1137
+ }
1138
+ </div>
1139
+ }
1140
+ @if (toolbarActions()) {
1141
+ <div class="tw:flex tw:flex-wrap tw:items-center tw:gap-2">
1142
+ <ng-container *ngTemplateOutlet="toolbarActions()" />
1143
+ </div>
1144
+ }
1145
+ </div>
1146
+ }
1147
+
1148
+ @if (_effectiveLayout() === 'grid') {
1149
+ <ng-container *ngTemplateOutlet="_gridView" />
1150
+ } @else {
1151
+ <ng-container *ngTemplateOutlet="_tableView" />
1152
+ }
1153
+
1154
+ <ng-template #_tableView>
1155
+ <div class="tw:overflow-hidden tw:rounded-md tw:border">
1156
+ <div hlmTableContainer>
1157
+ <table hlmTable>
1158
+ <thead hlmTHead>
1159
+ @for (headerGroup of _table.getHeaderGroups(); track headerGroup.id) {
1160
+ <tr hlmTr>
1161
+ @for (header of headerGroup.headers; track header.id) {
1162
+ <th hlmTh [size]="size()" [attr.colSpan]="header.colSpan">
1163
+ @if (!header.isPlaceholder) {
1164
+ <div class="tw:flex tw:items-center tw:gap-1">
1165
+ <ng-container
1166
+ *flexRender="header.column.columnDef.header; props: header.getContext(); let headerText"
1167
+ >
1168
+ <div [innerHTML]="headerText"></div>
1169
+ </ng-container>
1170
+ @if (_showHeaderSortButton(header)) {
1171
+ <button
1172
+ hlmButton
1173
+ variant="ghost"
1174
+ size="sm"
1175
+ [class]="_sortButtonClass()"
1176
+ type="button"
1177
+ [attr.aria-label]="'Sort by ' + header.column.id"
1178
+ (click)="_toggleHeaderSorting(header)"
1179
+ >
1180
+ @switch (header.column.getIsSorted()) {
1181
+ @case ('asc') {
1182
+ <ng-icon hlm size="sm" name="lucideArrowUp" />
1183
+ }
1184
+ @case ('desc') {
1185
+ <ng-icon hlm size="sm" name="lucideArrowDown" />
1186
+ }
1187
+ @default {
1188
+ <ng-icon hlm size="sm" name="lucideChevronsUpDown" />
1189
+ }
1190
+ }
1191
+ </button>
1192
+ }
1193
+ </div>
1194
+ }
1195
+ </th>
1196
+ }
1197
+ </tr>
1198
+ }
1199
+ </thead>
1200
+ <tbody hlmTBody>
1201
+ @if (isLoading()) {
1202
+ <tr hlmTr>
1203
+ <td hlmTd [attr.colspan]="_visibleColumnCount()" class="tw:h-24 tw:text-center">
1204
+ <hlm-spinner class="tw:inline-flex" />
1205
+ </td>
1206
+ </tr>
1207
+ } @else if (_table.getRowModel().rows.length === 0) {
1208
+ <tr hlmTr>
1209
+ <td hlmTd [attr.colspan]="_visibleColumnCount()" class="tw:h-24 tw:text-center">
1210
+ {{ emptyMessage() }}
1211
+ </td>
1212
+ </tr>
1213
+ } @else {
1214
+ @for (row of _table.getRowModel().rows; track row.id) {
1215
+ <tr
1216
+ hlmTr
1217
+ [attr.data-state]="row.getIsSelected() ? 'selected' : null"
1218
+ (click)="_onRowClick($event, row)"
1219
+ >
1220
+ @for (cell of row.getVisibleCells(); track cell.id) {
1221
+ <td hlmTd [size]="size()">
1222
+ <ng-container
1223
+ *flexRender="cell.column.columnDef.cell; props: cell.getContext(); let cellText"
1224
+ >
1225
+ <div [innerHTML]="cellText"></div>
1226
+ </ng-container>
1227
+ </td>
1228
+ }
1229
+ </tr>
1230
+ }
1231
+ }
1232
+ </tbody>
1233
+ </table>
1234
+ </div>
1235
+ </div>
1236
+ </ng-template>
1237
+
1238
+ <ng-template #_gridView>
1239
+ @if (isLoading()) {
1240
+ <div
1241
+ class="tw:flex tw:h-64 tw:items-center tw:justify-center tw:rounded-lg tw:border tw:border-dashed"
1242
+ role="status"
1243
+ >
1244
+ <hlm-spinner />
1245
+ </div>
1246
+ } @else if (_table.getRowModel().rows.length === 0) {
1247
+ <div
1248
+ class="tw:text-muted-foreground tw:flex tw:h-64 tw:items-center tw:justify-center tw:rounded-lg tw:border tw:border-dashed"
1249
+ >
1250
+ {{ emptyMessage() }}
1251
+ </div>
1252
+ } @else {
1253
+ <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">
1254
+ @for (row of _table.getRowModel().rows; track row.id) {
1255
+ <div
1256
+ hlmCard
1257
+ 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"
1258
+ [attr.data-state]="row.getIsSelected() ? 'selected' : null"
1259
+ (click)="_onRowClick($event, row)"
1260
+ >
1261
+ @if (_thumbnailCell(row); as thumbnail) {
1262
+ <div class="tw:border-b tw:bg-muted/30">
1263
+ <ng-container
1264
+ *flexRender="thumbnail.column.columnDef.cell; props: thumbnail.getContext(); let thumbHtml"
1265
+ >
1266
+ <div [innerHTML]="thumbHtml"></div>
1267
+ </ng-container>
1268
+ </div>
1269
+ }
1270
+ @if (_selectionCell(row); as selection) {
1271
+ <div class="tw:absolute tw:top-4 tw:right-4">
1272
+ <ng-container
1273
+ *flexRender="selection.column.columnDef.cell; props: selection.getContext(); let selectHtml"
1274
+ >
1275
+ <div [innerHTML]="selectHtml"></div>
1276
+ </ng-container>
1277
+ </div>
1278
+ }
1279
+ <div hlmCardContent class="tw:space-y-3">
1280
+ @for (cell of _contentCells(row); track cell.id) {
1281
+ <div class="tw:flex tw:flex-col">
1282
+ <dt
1283
+ class="tw:text-[10px] tw:font-bold tw:tracking-wider tw:uppercase tw:text-muted-foreground/80"
1284
+ >
1285
+ {{ _cellLabel(cell) }}
1286
+ </dt>
1287
+ <dd class="tw:mt-0.5 tw:text-sm tw:leading-none tw:font-medium">
1288
+ <ng-container *flexRender="cell.column.columnDef.cell; props: cell.getContext(); let valueHtml">
1289
+ <div [innerHTML]="valueHtml"></div>
1290
+ </ng-container>
1291
+ </dd>
1292
+ </div>
1293
+ }
1294
+ </div>
1295
+ </div>
1296
+ }
1297
+ </div>
1298
+ }
1299
+ </ng-template>
1300
+
1301
+ @if (!hideFooter()) {
1302
+ <div
1303
+ 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"
1304
+ [tanStackTable]="_table"
1305
+ >
1306
+ <div class="tw:text-muted-foreground tw:flex-1 tw:text-sm">{{ _statusText() }}</div>
1307
+ <eg-data-table-pagination
1308
+ [showStatus]="false"
1309
+ [showPageSize]="showPageSize()"
1310
+ [pageSizes]="pageSizes()"
1311
+ [navMode]="navMode()"
1312
+ [size]="size()"
1313
+ />
1314
+ </div>
1315
+ }
1316
+ </div>
1317
+ `,
1318
+ changeDetection: ChangeDetectionStrategy.OnPush,
1319
+ }]
1320
+ }], 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 }] }], getRowId: [{ type: i0.Input, args: [{ isSignal: true, alias: "getRowId", 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"] }] } });
1321
+
1322
+ /**
1323
+ * Sortable + hideable column header.
1324
+ *
1325
+ * Render via `flexRenderComponent(EgDataTableColumnHeader, { inputs: { column, title } })`
1326
+ * so the extra `title` input flows alongside the flex-render `column` context.
1327
+ * Non-sortable columns render a plain label.
1328
+ */
1329
+ class EgDataTableColumnHeader {
1330
+ column = input.required(/* @ts-ignore */
1331
+ ...(ngDevMode ? [{ debugName: "column" }] : /* istanbul ignore next */ []));
1332
+ title = input.required(/* @ts-ignore */
1333
+ ...(ngDevMode ? [{ debugName: "title" }] : /* istanbul ignore next */ []));
1334
+ /** Density of the trigger button. */
1335
+ size = input('default', /* @ts-ignore */
1336
+ ...(ngDevMode ? [{ debugName: "size" }] : /* istanbul ignore next */ []));
1337
+ _sorted = computed(() => this.column().getIsSorted(), /* @ts-ignore */
1338
+ ...(ngDevMode ? [{ debugName: "_sorted" }] : /* istanbul ignore next */ []));
1339
+ /** Height per density. Merged by `hlmButton`. */
1340
+ _buttonClass = computed(() => hlm('tw:-ml-3', this.size() === 'sm' ? 'tw:h-7' : this.size() === 'lg' ? 'tw:h-9' : 'tw:h-8'), /* @ts-ignore */
1341
+ ...(ngDevMode ? [{ debugName: "_buttonClass" }] : /* istanbul ignore next */ []));
1342
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: EgDataTableColumnHeader, deps: [], target: i0.ɵɵFactoryTarget.Component });
1343
+ 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: `
1344
+ @if (column().getCanSort()) {
1345
+ <div class="tw:flex tw:items-center tw:gap-2">
1346
+ <button
1347
+ hlmButton
1348
+ variant="ghost"
1349
+ size="sm"
1350
+ [class]="_buttonClass()"
1351
+ type="button"
1352
+ [hlmDropdownMenuTrigger]="_menu"
1353
+ >
1354
+ <span>{{ title() }}</span>
1355
+ @switch (_sorted()) {
1356
+ @case ('desc') {
1357
+ <ng-icon hlm size="sm" name="lucideArrowDown" />
1358
+ }
1359
+ @case ('asc') {
1360
+ <ng-icon hlm size="sm" name="lucideArrowUp" />
1361
+ }
1362
+ @default {
1363
+ <ng-icon hlm size="sm" name="lucideChevronsUpDown" />
1364
+ }
1365
+ }
1366
+ </button>
1367
+ <ng-template #_menu>
1368
+ <div hlmDropdownMenu>
1369
+ <button hlmDropdownMenuItem type="button" (click)="column().toggleSorting(false)">
1370
+ <ng-icon hlm size="sm" name="lucideArrowUp" />
1371
+ Asc
1372
+ </button>
1373
+ <button hlmDropdownMenuItem type="button" (click)="column().toggleSorting(true)">
1374
+ <ng-icon hlm size="sm" name="lucideArrowDown" />
1375
+ Desc
1376
+ </button>
1377
+ <div hlmDropdownMenuSeparator></div>
1378
+ <button hlmDropdownMenuItem type="button" (click)="column().toggleVisibility(false)">
1379
+ <ng-icon hlm size="sm" name="lucideEyeOff" />
1380
+ Hide
1381
+ </button>
1382
+ </div>
1383
+ </ng-template>
1384
+ </div>
1385
+ } @else {
1386
+ <div>{{ title() }}</div>
1387
+ }
1388
+ `, 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 });
1389
+ }
1390
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: EgDataTableColumnHeader, decorators: [{
1391
+ type: Component,
1392
+ args: [{
1393
+ selector: 'eg-data-table-column-header',
1394
+ imports: [HlmButton, HlmDropdownMenuImports, NgIcon, HlmIcon],
1395
+ providers: [provideIcons({ lucideArrowDown, lucideArrowUp, lucideChevronsUpDown, lucideEyeOff })],
1396
+ template: `
1397
+ @if (column().getCanSort()) {
1398
+ <div class="tw:flex tw:items-center tw:gap-2">
1399
+ <button
1400
+ hlmButton
1401
+ variant="ghost"
1402
+ size="sm"
1403
+ [class]="_buttonClass()"
1404
+ type="button"
1405
+ [hlmDropdownMenuTrigger]="_menu"
1406
+ >
1407
+ <span>{{ title() }}</span>
1408
+ @switch (_sorted()) {
1409
+ @case ('desc') {
1410
+ <ng-icon hlm size="sm" name="lucideArrowDown" />
1411
+ }
1412
+ @case ('asc') {
1413
+ <ng-icon hlm size="sm" name="lucideArrowUp" />
1414
+ }
1415
+ @default {
1416
+ <ng-icon hlm size="sm" name="lucideChevronsUpDown" />
1417
+ }
1418
+ }
1419
+ </button>
1420
+ <ng-template #_menu>
1421
+ <div hlmDropdownMenu>
1422
+ <button hlmDropdownMenuItem type="button" (click)="column().toggleSorting(false)">
1423
+ <ng-icon hlm size="sm" name="lucideArrowUp" />
1424
+ Asc
1425
+ </button>
1426
+ <button hlmDropdownMenuItem type="button" (click)="column().toggleSorting(true)">
1427
+ <ng-icon hlm size="sm" name="lucideArrowDown" />
1428
+ Desc
1429
+ </button>
1430
+ <div hlmDropdownMenuSeparator></div>
1431
+ <button hlmDropdownMenuItem type="button" (click)="column().toggleVisibility(false)">
1432
+ <ng-icon hlm size="sm" name="lucideEyeOff" />
1433
+ Hide
1434
+ </button>
1435
+ </div>
1436
+ </ng-template>
1437
+ </div>
1438
+ } @else {
1439
+ <div>{{ title() }}</div>
1440
+ }
1441
+ `,
1442
+ changeDetection: ChangeDetectionStrategy.OnPush,
1443
+ }]
1444
+ }], 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 }] }] } });
1445
+
1446
+ /*
1447
+ * Public API Surface of data-table
1448
+ */
1449
+ const EgDataTableImports = [
1450
+ EgDataTable,
1451
+ EgDataTableColumnHeader,
1452
+ EgDataTablePagination,
1453
+ EgDataTableViewOptions,
1454
+ EgTableHeadSelection,
1455
+ EgTableRowSelection,
1456
+ ];
1457
+ class EgDataTableModule {
1458
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: EgDataTableModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
1459
+ static ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "22.1.3", ngImport: i0, type: EgDataTableModule, imports: [EgDataTable,
1460
+ EgDataTableColumnHeader,
1461
+ EgDataTablePagination,
1462
+ EgDataTableViewOptions,
1463
+ EgTableHeadSelection,
1464
+ EgTableRowSelection], exports: [EgDataTable,
1465
+ EgDataTableColumnHeader,
1466
+ EgDataTablePagination,
1467
+ EgDataTableViewOptions,
1468
+ EgTableHeadSelection,
1469
+ EgTableRowSelection] });
1470
+ static ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: EgDataTableModule, imports: [EgDataTableImports] });
1471
+ }
1472
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: EgDataTableModule, decorators: [{
1473
+ type: NgModule,
1474
+ args: [{
1475
+ imports: [...EgDataTableImports],
1476
+ exports: [...EgDataTableImports],
1477
+ }]
1478
+ }] });
1479
+
1480
+ /**
1481
+ * Generated bundle index. Do not edit.
1482
+ */
1483
+
1484
+ export { EgDataTable, EgDataTableColumnHeader, EgDataTableImports, EgDataTableModule, EgDataTablePagination, EgDataTableViewOptions, EgTableHeadSelection, EgTableRowSelection, defaultEgDataTableFeatures };
1485
+