@egose/shadcn-theme-ng 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 +11 -7
  6. package/checkbox/types/checkbox.d.ts +6 -4
  7. package/combobox/fesm2022/combobox.mjs +13 -7
  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 +713 -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 +19 -6
  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 +23 -6
  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 +20 -8
  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 +15 -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 +19 -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 +22 -9
  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 +73 -65
  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 +59 -32
  53. package/searchable-multiselect/types/searchable-multiselect.d.ts +23 -6
  54. package/slider/fesm2022/slider.mjs +9 -5
  55. package/slider/types/slider.d.ts +6 -2
  56. package/stepper/README.md +39 -19
  57. package/stepper/fesm2022/stepper.mjs +64 -12
  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,713 @@
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/button';
5
+ import { HlmCard, HlmCardContent } from '@egose/shadcn-theme-ng/card';
6
+ import { HlmIcon } from '@egose/shadcn-theme-ng/icon';
7
+ import { HlmInput } from '@egose/shadcn-theme-ng/input';
8
+ import { HlmSpinner } from '@egose/shadcn-theme-ng/spinner';
9
+ import * as i2 from '@egose/shadcn-theme-ng/table';
10
+ import { HlmTableImports } from '@egose/shadcn-theme-ng/table';
11
+ import { HlmToggleGroup, HlmToggleGroupItem } from '@egose/shadcn-theme-ng/toggle-group';
12
+ import { hlm } from '@egose/shadcn-theme-ng/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/select';
18
+ import { HlmSelectImports } from '@egose/shadcn-theme-ng/select';
19
+ import * as i1$1 from '@egose/shadcn-theme-ng/dropdown-menu';
20
+ import { HlmDropdownMenuImports } from '@egose/shadcn-theme-ng/dropdown-menu';
21
+ import { HlmCheckbox } from '@egose/shadcn-theme-ng/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' ? "h-7 p-0" : this.size() === 'lg' ? "h-9 p-0" : "h-8 p-0", this.navMode() === 'icons'
90
+ ? this.size() === 'sm'
91
+ ? "w-7"
92
+ : this.size() === 'lg'
93
+ ? "w-9"
94
+ : "w-8"
95
+ : "gap-1 px-2"), /* @ts-ignore */
96
+ ...(ngDevMode ? [{ debugName: "_navButtonClass" }] : /* istanbul ignore next */ []));
97
+ /** First/last buttons stay desktop-only. */
98
+ _edgeNavButtonClass = computed(() => hlm("hidden 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' ? "text-xs" : this.size() === 'lg' ? "text-base" : "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: "\n <div class=\"flex flex-wrap items-center justify-between gap-2 px-2\">\n @if (showStatus()) {\n <div class=\"text-muted-foreground flex-1 {{ _metaTextClass() }}\">{{ _statusText() }}</div>\n }\n <div class=\"flex flex-wrap items-center gap-x-6 gap-y-2 lg:gap-x-8\">\n @if (showPageSize()) {\n <div class=\"flex items-center gap-2\">\n <p class=\"font-medium {{ _metaTextClass() }}\">Rows per page</p>\n <div hlmSelect class=\"inline-flex\" [value]=\"_pageSize()\" (valueChange)=\"_onPageSizeChange($event)\">\n <hlm-select-trigger class=\"w-[70px]\" [size]=\"size() === 'sm' ? 'sm' : 'default'\">\n <hlm-select-value />\n </hlm-select-trigger>\n <hlm-select-content *hlmSelectPortal>\n @for (size of _pageSizeOptions(); track size) {\n <hlm-select-item [value]=\"size\">{{ size }}</hlm-select-item>\n }\n </hlm-select-content>\n </div>\n </div>\n }\n @if (_showPager()) {\n <div class=\"flex w-[100px] items-center justify-center font-medium {{ _metaTextClass() }}\">\n Page {{ _pageIndex() + 1 }} of {{ _pageCount() }}\n </div>\n <div class=\"flex items-center gap-2\">\n <button\n hlmButton\n variant=\"secondary\"\n appearance=\"outline\"\n size=\"sm\"\n [class]=\"_edgeNavButtonClass()\"\n type=\"button\"\n [disabled]=\"!_canPrevious()\"\n (click)=\"_table().setPageIndex(0)\"\n aria-label=\"Go to first page\"\n >\n @if (navMode() !== 'text') {\n <ng-icon hlm size=\"sm\" name=\"lucideChevronsLeft\" />\n }\n @if (navMode() !== 'icons') {\n <span>First</span>\n }\n </button>\n <button\n hlmButton\n variant=\"secondary\"\n appearance=\"outline\"\n size=\"sm\"\n [class]=\"_navButtonClass()\"\n type=\"button\"\n [disabled]=\"!_canPrevious()\"\n (click)=\"_table().previousPage()\"\n aria-label=\"Go to previous page\"\n >\n @if (navMode() !== 'text') {\n <ng-icon hlm size=\"sm\" name=\"lucideChevronLeft\" />\n }\n @if (navMode() !== 'icons') {\n <span>Previous</span>\n }\n </button>\n <button\n hlmButton\n variant=\"secondary\"\n appearance=\"outline\"\n size=\"sm\"\n [class]=\"_navButtonClass()\"\n type=\"button\"\n [disabled]=\"!_canNext()\"\n (click)=\"_table().nextPage()\"\n aria-label=\"Go to next page\"\n >\n @if (navMode() !== 'icons') {\n <span>Next</span>\n }\n @if (navMode() !== 'text') {\n <ng-icon hlm size=\"sm\" name=\"lucideChevronRight\" />\n }\n </button>\n <button\n hlmButton\n variant=\"secondary\"\n appearance=\"outline\"\n size=\"sm\"\n [class]=\"_edgeNavButtonClass()\"\n type=\"button\"\n [disabled]=\"!_canNext()\"\n (click)=\"_table().setPageIndex(_pageCount() - 1)\"\n aria-label=\"Go to last page\"\n >\n @if (navMode() !== 'icons') {\n <span>Last</span>\n }\n @if (navMode() !== 'text') {\n <ng-icon hlm size=\"sm\" name=\"lucideChevronsRight\" />\n }\n </button>\n </div>\n }\n </div>\n </div>\n ", 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 });
125
+ }
126
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: EgDataTablePagination, decorators: [{
127
+ type: Component,
128
+ args: [{
129
+ selector: 'eg-data-table-pagination',
130
+ imports: [HlmButton, HlmIcon, HlmSelectImports, NgIcon],
131
+ providers: [provideIcons({ lucideChevronLeft, lucideChevronRight, lucideChevronsLeft, lucideChevronsRight })],
132
+ template: "\n <div class=\"flex flex-wrap items-center justify-between gap-2 px-2\">\n @if (showStatus()) {\n <div class=\"text-muted-foreground flex-1 {{ _metaTextClass() }}\">{{ _statusText() }}</div>\n }\n <div class=\"flex flex-wrap items-center gap-x-6 gap-y-2 lg:gap-x-8\">\n @if (showPageSize()) {\n <div class=\"flex items-center gap-2\">\n <p class=\"font-medium {{ _metaTextClass() }}\">Rows per page</p>\n <div hlmSelect class=\"inline-flex\" [value]=\"_pageSize()\" (valueChange)=\"_onPageSizeChange($event)\">\n <hlm-select-trigger class=\"w-[70px]\" [size]=\"size() === 'sm' ? 'sm' : 'default'\">\n <hlm-select-value />\n </hlm-select-trigger>\n <hlm-select-content *hlmSelectPortal>\n @for (size of _pageSizeOptions(); track size) {\n <hlm-select-item [value]=\"size\">{{ size }}</hlm-select-item>\n }\n </hlm-select-content>\n </div>\n </div>\n }\n @if (_showPager()) {\n <div class=\"flex w-[100px] items-center justify-center font-medium {{ _metaTextClass() }}\">\n Page {{ _pageIndex() + 1 }} of {{ _pageCount() }}\n </div>\n <div class=\"flex items-center gap-2\">\n <button\n hlmButton\n variant=\"secondary\"\n appearance=\"outline\"\n size=\"sm\"\n [class]=\"_edgeNavButtonClass()\"\n type=\"button\"\n [disabled]=\"!_canPrevious()\"\n (click)=\"_table().setPageIndex(0)\"\n aria-label=\"Go to first page\"\n >\n @if (navMode() !== 'text') {\n <ng-icon hlm size=\"sm\" name=\"lucideChevronsLeft\" />\n }\n @if (navMode() !== 'icons') {\n <span>First</span>\n }\n </button>\n <button\n hlmButton\n variant=\"secondary\"\n appearance=\"outline\"\n size=\"sm\"\n [class]=\"_navButtonClass()\"\n type=\"button\"\n [disabled]=\"!_canPrevious()\"\n (click)=\"_table().previousPage()\"\n aria-label=\"Go to previous page\"\n >\n @if (navMode() !== 'text') {\n <ng-icon hlm size=\"sm\" name=\"lucideChevronLeft\" />\n }\n @if (navMode() !== 'icons') {\n <span>Previous</span>\n }\n </button>\n <button\n hlmButton\n variant=\"secondary\"\n appearance=\"outline\"\n size=\"sm\"\n [class]=\"_navButtonClass()\"\n type=\"button\"\n [disabled]=\"!_canNext()\"\n (click)=\"_table().nextPage()\"\n aria-label=\"Go to next page\"\n >\n @if (navMode() !== 'icons') {\n <span>Next</span>\n }\n @if (navMode() !== 'text') {\n <ng-icon hlm size=\"sm\" name=\"lucideChevronRight\" />\n }\n </button>\n <button\n hlmButton\n variant=\"secondary\"\n appearance=\"outline\"\n size=\"sm\"\n [class]=\"_edgeNavButtonClass()\"\n type=\"button\"\n [disabled]=\"!_canNext()\"\n (click)=\"_table().setPageIndex(_pageCount() - 1)\"\n aria-label=\"Go to last page\"\n >\n @if (navMode() !== 'icons') {\n <span>Last</span>\n }\n @if (navMode() !== 'text') {\n <ng-icon hlm size=\"sm\" name=\"lucideChevronsRight\" />\n }\n </button>\n </div>\n }\n </div>\n </div>\n ",
133
+ changeDetection: ChangeDetectionStrategy.OnPush,
134
+ }]
135
+ }], 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 }] }] } });
136
+
137
+ /**
138
+ * Column-visibility toggle.
139
+ *
140
+ * Reads the table from the nearest `[tanStackTable]` directive — no table
141
+ * input or generics needed. Only columns with an `accessorFn` that can hide
142
+ * are listed (display columns like `select` / `actions` stay fixed).
143
+ */
144
+ class EgDataTableViewOptions {
145
+ /** Density of the toggle button. */
146
+ size = input('default', /* @ts-ignore */
147
+ ...(ngDevMode ? [{ debugName: "size" }] : /* istanbul ignore next */ []));
148
+ _table = injectTableContext();
149
+ /** Height per density; hidden below `lg` like the pager edge buttons. Merged by `hlmButton`. */
150
+ _buttonClass = computed(() => hlm("ml-auto hidden lg:flex", this.size() === 'sm' ? "h-7" : this.size() === 'lg' ? "h-9" : "h-8"), /* @ts-ignore */
151
+ ...(ngDevMode ? [{ debugName: "_buttonClass" }] : /* istanbul ignore next */ []));
152
+ _hidableColumns = computed(() => this._table()
153
+ .getAllColumns()
154
+ .filter((column) => typeof column.accessorFn !== 'undefined' && column.getCanHide()), /* @ts-ignore */
155
+ ...(ngDevMode ? [{ debugName: "_hidableColumns" }] : /* istanbul ignore next */ []));
156
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: EgDataTableViewOptions, deps: [], target: i0.ɵɵFactoryTarget.Component });
157
+ 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: "\n <button\n hlmButton\n variant=\"secondary\"\n appearance=\"outline\"\n size=\"sm\"\n [class]=\"_buttonClass()\"\n type=\"button\"\n [hlmDropdownMenuTrigger]=\"_menu\"\n >\n <ng-icon hlm name=\"lucideSettings2\" />\n View\n </button>\n <ng-template #_menu>\n <div hlmDropdownMenu class=\"w-[150px]\">\n <div hlmDropdownMenuLabel>Toggle columns</div>\n <div hlmDropdownMenuSeparator></div>\n @for (column of _hidableColumns(); track column.id) {\n <button\n hlmDropdownMenuCheckbox\n class=\"capitalize\"\n [checked]=\"column.getIsVisible()\"\n (triggered)=\"column.toggleVisibility()\"\n >\n <hlm-dropdown-menu-checkbox-indicator />\n {{ column.id }}\n </button>\n }\n </div>\n </ng-template>\n ", 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 });
158
+ }
159
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: EgDataTableViewOptions, decorators: [{
160
+ type: Component,
161
+ args: [{
162
+ selector: 'eg-data-table-view-options',
163
+ imports: [HlmButton, HlmDropdownMenuImports, NgIcon, HlmIcon],
164
+ providers: [provideIcons({ lucideSettings2 })],
165
+ template: "\n <button\n hlmButton\n variant=\"secondary\"\n appearance=\"outline\"\n size=\"sm\"\n [class]=\"_buttonClass()\"\n type=\"button\"\n [hlmDropdownMenuTrigger]=\"_menu\"\n >\n <ng-icon hlm name=\"lucideSettings2\" />\n View\n </button>\n <ng-template #_menu>\n <div hlmDropdownMenu class=\"w-[150px]\">\n <div hlmDropdownMenuLabel>Toggle columns</div>\n <div hlmDropdownMenuSeparator></div>\n @for (column of _hidableColumns(); track column.id) {\n <button\n hlmDropdownMenuCheckbox\n class=\"capitalize\"\n [checked]=\"column.getIsVisible()\"\n (triggered)=\"column.toggleVisibility()\"\n >\n <hlm-dropdown-menu-checkbox-indicator />\n {{ column.id }}\n </button>\n }\n </div>\n </ng-template>\n ",
166
+ changeDetection: ChangeDetectionStrategy.OnPush,
167
+ }]
168
+ }], propDecorators: { size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }] } });
169
+
170
+ /**
171
+ * Header selection checkbox: toggles all page rows.
172
+ *
173
+ * Generic over `TData` so the same component works with any table; the table
174
+ * instance is passed explicitly (no DI needed inside column definitions).
175
+ * `HlmCheckbox.checked` accepts `'indeterminate'`, so the tri-state is derived
176
+ * via `computed` instead of a separate input.
177
+ */
178
+ class EgTableHeadSelection {
179
+ table = input.required(/* @ts-ignore */
180
+ ...(ngDevMode ? [{ debugName: "table" }] : /* istanbul ignore next */ []));
181
+ ariaLabel = input('Select all', /* @ts-ignore */
182
+ ...(ngDevMode ? [{ debugName: "ariaLabel" }] : /* istanbul ignore next */ []));
183
+ _checked = computed(() => {
184
+ const table = this.table();
185
+ if (table.getIsAllPageRowsSelected())
186
+ return true;
187
+ if (table.getIsSomePageRowsSelected())
188
+ return 'indeterminate';
189
+ return false;
190
+ }, /* @ts-ignore */
191
+ ...(ngDevMode ? [{ debugName: "_checked" }] : /* istanbul ignore next */ []));
192
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: EgTableHeadSelection, deps: [], target: i0.ɵɵFactoryTarget.Component });
193
+ 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: "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 });
194
+ }
195
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: EgTableHeadSelection, decorators: [{
196
+ type: Component,
197
+ args: [{
198
+ selector: 'eg-table-head-selection',
199
+ imports: [HlmCheckbox],
200
+ host: { class: "flex", '[attr.aria-label]': 'ariaLabel()' },
201
+ template: ` <hlm-checkbox [checked]="_checked()" (changed)="table().toggleAllPageRowsSelected($event)" /> `,
202
+ changeDetection: ChangeDetectionStrategy.OnPush,
203
+ }]
204
+ }], propDecorators: { table: [{ type: i0.Input, args: [{ isSignal: true, alias: "table", required: true }] }], ariaLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "ariaLabel", required: false }] }] } });
205
+ /**
206
+ * Row selection checkbox: toggles a single row.
207
+ */
208
+ class EgTableRowSelection {
209
+ row = input.required(/* @ts-ignore */
210
+ ...(ngDevMode ? [{ debugName: "row" }] : /* istanbul ignore next */ []));
211
+ ariaLabel = input('Select row', /* @ts-ignore */
212
+ ...(ngDevMode ? [{ debugName: "ariaLabel" }] : /* istanbul ignore next */ []));
213
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: EgTableRowSelection, deps: [], target: i0.ɵɵFactoryTarget.Component });
214
+ 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: "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 });
215
+ }
216
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: EgTableRowSelection, decorators: [{
217
+ type: Component,
218
+ args: [{
219
+ selector: 'eg-table-row-selection',
220
+ imports: [HlmCheckbox],
221
+ host: { class: "flex", '[attr.aria-label]': 'ariaLabel()' },
222
+ template: ` <hlm-checkbox [checked]="row().getIsSelected()" (changed)="row().toggleSelected($event)" /> `,
223
+ changeDetection: ChangeDetectionStrategy.OnPush,
224
+ }]
225
+ }], propDecorators: { row: [{ type: i0.Input, args: [{ isSignal: true, alias: "row", required: true }] }], ariaLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "ariaLabel", required: false }] }] } });
226
+
227
+ /**
228
+ * Generic data table with TanStack-powered sorting, filtering, pagination,
229
+ * selection, column visibility, plus a React-parity grid layout.
230
+ *
231
+ * The caller passes `columns` (and optionally `gridColumns`) — everything else
232
+ * is owned internally with change notifications via outputs:
233
+ *
234
+ * - Client mode: pass `data` as an array. Pagination/sorting/filtering run in-browser.
235
+ * `filterRows` can pre-filter the array before the built-in pipeline.
236
+ * - Server mode: pass `data` as a page slice (`{items,total,limit,offset,hasPrevious,hasNext}`)
237
+ * with `manualPagination` set. The slice renders as-is — sorting/filtering
238
+ * are not applied client-side. Page, sort and filter interactions emit
239
+ * `pageChange` / `pageSizeChange` / `sortingChange` / `filterChange`
240
+ * (`columnFiltersChange`) so the caller can fetch the next slice.
241
+ * - Selection: set `enableSelection` to auto-prepend a checkbox column;
242
+ * selected rows are emitted via `selectionChange` (array of `TData`).
243
+ * - Grid mode: pass `gridColumns` to enable the layout toggle. Columns with
244
+ * `meta: { hideInTable: true }` are table-hidden; `meta: { thumbnail: true }`
245
+ * renders as the card banner.
246
+ */
247
+ class EgDataTable {
248
+ /** Column definitions for table layout (required). */
249
+ columns = input.required(/* @ts-ignore */
250
+ ...(ngDevMode ? [{ debugName: "columns" }] : /* istanbul ignore next */ []));
251
+ /** Column definitions for grid layout; falls back to `columns` when omitted. */
252
+ gridColumns = input(/* @ts-ignore */
253
+ ...(ngDevMode ? [undefined, { debugName: "gridColumns" }] : /* istanbul ignore next */ []));
254
+ /** Client rows, or a server page slice when `manualPagination` is set (`null` while loading). */
255
+ data = input([], /* @ts-ignore */
256
+ ...(ngDevMode ? [{ debugName: "data" }] : /* istanbul ignore next */ []));
257
+ /**
258
+ * Pure stable identity callback, e.g. `(record) => record.id`. Return a unique
259
+ * string per entity, independent of position, and keep the callback reference stable.
260
+ * Selection survives refreshes only for IDs still in the supplied rows (after
261
+ * `filterRows`); server selection is limited to the loaded slice. Without this
262
+ * callback, IDs are positional and replacing the rows clears selection.
263
+ * Changing the callback clears selection. Update data immutably.
264
+ */
265
+ getRowId = input(/* @ts-ignore */
266
+ ...(ngDevMode ? [undefined, { debugName: "getRowId" }] : /* istanbul ignore next */ []));
267
+ /** 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. */
268
+ manualPagination = input(false, /* @ts-ignore */
269
+ ...(ngDevMode ? [{ debugName: "manualPagination" }] : /* istanbul ignore next */ []));
270
+ /** TanStack feature registry. Defaults to filtering + visibility + pagination + selection + sorting. */
271
+ features = input(defaultEgDataTableFeatures, /* @ts-ignore */
272
+ ...(ngDevMode ? [{ debugName: "features" }] : /* istanbul ignore next */ []));
273
+ isLoading = input(false, /* @ts-ignore */
274
+ ...(ngDevMode ? [{ debugName: "isLoading" }] : /* istanbul ignore next */ []));
275
+ emptyMessage = input('No results found.', /* @ts-ignore */
276
+ ...(ngDevMode ? [{ debugName: "emptyMessage" }] : /* istanbul ignore next */ []));
277
+ /** When true, a checkbox column is auto-prepended and `selectionChange` emits the selected rows. */
278
+ enableSelection = input(false, /* @ts-ignore */
279
+ ...(ngDevMode ? [{ debugName: "enableSelection" }] : /* istanbul ignore next */ []));
280
+ hideFooter = input(false, /* @ts-ignore */
281
+ ...(ngDevMode ? [{ debugName: "hideFooter" }] : /* istanbul ignore next */ []));
282
+ /** Density of toolbar, table, and pagination chrome. Type scale is untouched. */
283
+ size = input('default', /* @ts-ignore */
284
+ ...(ngDevMode ? [{ debugName: "size" }] : /* istanbul ignore next */ []));
285
+ /** Presentation mode. Two-way bindable: `[(layout)]`. Grid requires `gridColumns`. */
286
+ layout = model('table', /* @ts-ignore */
287
+ ...(ngDevMode ? [{ debugName: "layout" }] : /* istanbul ignore next */ []));
288
+ /** Show the table/grid toggle (only rendered when `gridColumns` is set). */
289
+ showLayoutToggle = input(true, /* @ts-ignore */
290
+ ...(ngDevMode ? [{ debugName: "showLayoutToggle" }] : /* istanbul ignore next */ []));
291
+ /** Show the toolbar (filter input, plus the column-visibility dropdown when `showColumnToggle` is set). */
292
+ showToolbar = input(false, /* @ts-ignore */
293
+ ...(ngDevMode ? [{ debugName: "showToolbar" }] : /* istanbul ignore next */ []));
294
+ /** 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). */
295
+ filterColumnId = input('', /* @ts-ignore */
296
+ ...(ngDevMode ? [{ debugName: "filterColumnId" }] : /* istanbul ignore next */ []));
297
+ filterPlaceholder = input('Filter...', /* @ts-ignore */
298
+ ...(ngDevMode ? [{ debugName: "filterPlaceholder" }] : /* istanbul ignore next */ []));
299
+ /** Show the column-visibility dropdown inside the toolbar. Off by default; opt in per table. */
300
+ showColumnToggle = input(false, /* @ts-ignore */
301
+ ...(ngDevMode ? [{ debugName: "showColumnToggle" }] : /* istanbul ignore next */ []));
302
+ /** 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. */
303
+ toolbarActions = input(undefined, /* @ts-ignore */
304
+ ...(ngDevMode ? [{ debugName: "toolbarActions" }] : /* istanbul ignore next */ []));
305
+ /** Default client-side page size. Changing it later resets the pager to the new size. */
306
+ defaultPageSize = input(10, /* @ts-ignore */
307
+ ...(ngDevMode ? [{ debugName: "defaultPageSize" }] : /* istanbul ignore next */ []));
308
+ /** 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. */
309
+ filterRows = input(null, /* @ts-ignore */
310
+ ...(ngDevMode ? [{ debugName: "filterRows" }] : /* istanbul ignore next */ []));
311
+ /** Seeds the sorting state once at creation. Later changes are ignored — use `sortingChange` to stay in sync. */
312
+ initialSorting = input([], /* @ts-ignore */
313
+ ...(ngDevMode ? [{ debugName: "initialSorting" }] : /* istanbul ignore next */ []));
314
+ /** Seeds the column-filter state once at creation. Later changes are ignored. */
315
+ initialColumnFilters = input([], /* @ts-ignore */
316
+ ...(ngDevMode ? [{ debugName: "initialColumnFilters" }] : /* istanbul ignore next */ []));
317
+ /** Seeds the column-visibility state once at creation. Later changes are ignored. */
318
+ initialColumnVisibility = input({}, /* @ts-ignore */
319
+ ...(ngDevMode ? [{ debugName: "initialColumnVisibility" }] : /* istanbul ignore next */ []));
320
+ /** Seeds selection once for current rows: keys come from `getRowId`, or positional indices without it. Missing IDs are discarded. Later changes are ignored. */
321
+ initialRowSelection = input({}, /* @ts-ignore */
322
+ ...(ngDevMode ? [{ debugName: "initialRowSelection" }] : /* istanbul ignore next */ []));
323
+ /** Show the rows-per-page selector in the footer pager. */
324
+ showPageSize = input(true, /* @ts-ignore */
325
+ ...(ngDevMode ? [{ debugName: "showPageSize" }] : /* istanbul ignore next */ []));
326
+ /** Page-size options for the footer selector. The current size is appended when absent. */
327
+ pageSizes = input([10, 20, 30, 40, 50], /* @ts-ignore */
328
+ ...(ngDevMode ? [{ debugName: "pageSizes" }] : /* istanbul ignore next */ []));
329
+ /** Footer navigation-button content: icons only, text labels only, or both. */
330
+ navMode = input('icons', /* @ts-ignore */
331
+ ...(ngDevMode ? [{ debugName: "navMode" }] : /* istanbul ignore next */ []));
332
+ userClass = input('', { ...(ngDevMode ? { debugName: "userClass" } : /* istanbul ignore next */ {}), alias: 'class' });
333
+ /** 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`. */
334
+ selectionChange = output();
335
+ /** Emits the target page index on pager navigation (primary hook for server fetching). */
336
+ pageChange = output();
337
+ pageSizeChange = output();
338
+ /** 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. */
339
+ rowClick = output();
340
+ sortingChange = output();
341
+ columnFiltersChange = output();
342
+ /** Emits the toolbar filter string whenever it changes. Empty when cleared or unset. */
343
+ filterChange = output();
344
+ columnVisibilityChange = output();
345
+ _containerClass = computed(() => hlm("space-y-2", this.userClass()), /* @ts-ignore */
346
+ ...(ngDevMode ? [{ debugName: "_containerClass" }] : /* istanbul ignore next */ []));
347
+ /** Inline TH sort-button footprint per density. Merged by `hlmButton` via the `class` binding. */
348
+ _sortButtonClass = computed(() => hlm("p-0", this.size() === 'sm' ? "h-5 w-5" : this.size() === 'lg' ? "h-7 w-7" : "h-6 w-6"), /* @ts-ignore */
349
+ ...(ngDevMode ? [{ debugName: "_sortButtonClass" }] : /* istanbul ignore next */ []));
350
+ _sorting = signal([], /* @ts-ignore */
351
+ ...(ngDevMode ? [{ debugName: "_sorting" }] : /* istanbul ignore next */ []));
352
+ _columnFilters = signal([], /* @ts-ignore */
353
+ ...(ngDevMode ? [{ debugName: "_columnFilters" }] : /* istanbul ignore next */ []));
354
+ _columnVisibility = signal({}, /* @ts-ignore */
355
+ ...(ngDevMode ? [{ debugName: "_columnVisibility" }] : /* istanbul ignore next */ []));
356
+ _clientPageIndex = signal(0, /* @ts-ignore */
357
+ ...(ngDevMode ? [{ debugName: "_clientPageIndex" }] : /* istanbul ignore next */ []));
358
+ // Linked so the bound `defaultPageSize` applies once inputs are set, while
359
+ // pager-driven `set()` writes below are preserved until it changes again.
360
+ _clientPageSize = linkedSignal(() => this.defaultPageSize(), /* @ts-ignore */
361
+ ...(ngDevMode ? [{ debugName: "_clientPageSize" }] : /* istanbul ignore next */ []));
362
+ _isServer = computed(() => this.manualPagination(), /* @ts-ignore */
363
+ ...(ngDevMode ? [{ debugName: "_isServer" }] : /* istanbul ignore next */ []));
364
+ /** The server page slice when in server mode; `null` for client data, misuse shapes, or `null` while loading. */
365
+ _page = computed(() => {
366
+ if (!this._isServer())
367
+ return null;
368
+ const data = this.data();
369
+ if (data !== null && typeof data === 'object' && 'items' in data) {
370
+ return data;
371
+ }
372
+ return null;
373
+ }, /* @ts-ignore */
374
+ ...(ngDevMode ? [{ debugName: "_page" }] : /* istanbul ignore next */ []));
375
+ _items = computed(() => {
376
+ const page = this._page();
377
+ if (page)
378
+ return page.items;
379
+ const data = this.data();
380
+ const rows = Array.isArray(data)
381
+ ? data
382
+ : (data?.items ?? []);
383
+ const filter = this.filterRows();
384
+ return filter ? filter(rows) : rows;
385
+ }, /* @ts-ignore */
386
+ ...(ngDevMode ? [{ debugName: "_items" }] : /* istanbul ignore next */ []));
387
+ // TanStack uses data-reference changes to reset pagination. State/layout
388
+ // updates must not look like a new data set (including selecting page rows).
389
+ _tableItems = computed(() => {
390
+ // A different identity function must also rebuild TanStack's cached rows.
391
+ this.getRowId();
392
+ return [...this._items()];
393
+ }, /* @ts-ignore */
394
+ ...(ngDevMode ? [{ debugName: "_tableItems" }] : /* istanbul ignore next */ []));
395
+ // Reconcile synchronously with the data source, before either TanStack or the
396
+ // output can observe old positional keys against new records. An effect-based
397
+ // reset would permit a transient wrong-entity selection.
398
+ _rowSelection = linkedSignal({ ...(ngDevMode ? { debugName: "_rowSelection" } : /* istanbul ignore next */ {}), source: () => ({ items: this._items(), getRowId: this.getRowId() }),
399
+ computation: (source, previous) => {
400
+ if (!previous || source.getRowId !== previous.source.getRowId)
401
+ return {};
402
+ if (!source.getRowId && source.items !== previous.source.items)
403
+ return {};
404
+ return this._keepCurrentSelection(previous.value);
405
+ } });
406
+ _keepCurrentSelection(selection) {
407
+ const getRowId = this.getRowId();
408
+ return Object.fromEntries(this._items()
409
+ .map((row, index) => (getRowId ? getRowId(row) : String(index)))
410
+ .filter((id) => Object.hasOwn(selection, id) && selection[id])
411
+ .map((id) => [id, true]));
412
+ }
413
+ _serverPageCount = computed(() => {
414
+ const paginated = this._page();
415
+ if (!paginated || paginated.limit <= 0)
416
+ return 1;
417
+ return Math.max(1, Math.ceil(paginated.total / paginated.limit));
418
+ }, /* @ts-ignore */
419
+ ...(ngDevMode ? [{ debugName: "_serverPageCount" }] : /* istanbul ignore next */ []));
420
+ _serverPageIndex = computed(() => {
421
+ const paginated = this._page();
422
+ if (!paginated || paginated.limit <= 0)
423
+ return 0;
424
+ return Math.floor(paginated.offset / paginated.limit);
425
+ }, /* @ts-ignore */
426
+ ...(ngDevMode ? [{ debugName: "_serverPageIndex" }] : /* istanbul ignore next */ []));
427
+ _paginationState = computed(() => {
428
+ const paginated = this._page();
429
+ if (paginated)
430
+ return { pageIndex: this._serverPageIndex(), pageSize: paginated.limit };
431
+ return { pageIndex: this._clientPageIndex(), pageSize: this._clientPageSize() };
432
+ }, /* @ts-ignore */
433
+ ...(ngDevMode ? [{ debugName: "_paginationState" }] : /* istanbul ignore next */ []));
434
+ _selectionHelper = computed(() => createColumnHelper(), /* @ts-ignore */
435
+ ...(ngDevMode ? [{ debugName: "_selectionHelper" }] : /* istanbul ignore next */ []));
436
+ /** Caller columns + auto-injected selection column + layout filtering. */
437
+ _finalColumns = computed(() => {
438
+ const isGrid = this._effectiveLayout() === 'grid';
439
+ const base = isGrid ? (this.gridColumns() ?? this.columns()) : this.columns();
440
+ const visible = isGrid ? base : base.filter((column) => column.meta?.hideInTable !== true);
441
+ if (!this.enableSelection())
442
+ return [...visible];
443
+ const helper = this._selectionHelper();
444
+ const selectionColumn = helper.display({
445
+ id: 'select',
446
+ header: () => EgTableHeadSelection,
447
+ cell: () => EgTableRowSelection,
448
+ enableSorting: false,
449
+ enableHiding: false,
450
+ });
451
+ return [selectionColumn, ...visible];
452
+ }, /* @ts-ignore */
453
+ ...(ngDevMode ? [{ debugName: "_finalColumns" }] : /* istanbul ignore next */ []));
454
+ _table = injectTable(() => {
455
+ const server = this._isServer();
456
+ return {
457
+ features: this.features(),
458
+ columns: this._finalColumns(),
459
+ data: this._tableItems(),
460
+ getRowId: this.getRowId(),
461
+ manualPagination: server,
462
+ manualSorting: server,
463
+ manualFiltering: server,
464
+ ...(server ? { pageCount: this._serverPageCount() } : {}),
465
+ state: {
466
+ sorting: this._sorting(),
467
+ columnFilters: this._columnFilters(),
468
+ columnVisibility: this._columnVisibility(),
469
+ rowSelection: this._rowSelection(),
470
+ pagination: this._paginationState(),
471
+ },
472
+ onSortingChange: (updater) => {
473
+ const next = typeof updater === 'function' ? updater(this._sorting()) : updater;
474
+ this._sorting.set(next);
475
+ this.sortingChange.emit(next);
476
+ },
477
+ onColumnFiltersChange: (updater) => {
478
+ const next = typeof updater === 'function' ? updater(this._columnFilters()) : updater;
479
+ this._columnFilters.set(next);
480
+ this.columnFiltersChange.emit(next);
481
+ const filterId = this.filterColumnId();
482
+ if (filterId) {
483
+ const value = next.find((filter) => filter.id === filterId)?.value;
484
+ this.filterChange.emit(typeof value === 'string' ? value : '');
485
+ }
486
+ },
487
+ onColumnVisibilityChange: (updater) => {
488
+ const next = typeof updater === 'function' ? updater(this._columnVisibility()) : updater;
489
+ this._columnVisibility.set(next);
490
+ this.columnVisibilityChange.emit(next);
491
+ },
492
+ onRowSelectionChange: (updater) => {
493
+ const next = typeof updater === 'function' ? updater(this._rowSelection()) : updater;
494
+ this._rowSelection.set(next);
495
+ },
496
+ onPaginationChange: (updater) => {
497
+ const current = this._paginationState();
498
+ const next = typeof updater === 'function' ? updater(current) : updater;
499
+ if (next.pageIndex !== current.pageIndex)
500
+ this.pageChange.emit(next.pageIndex);
501
+ if (next.pageSize !== current.pageSize)
502
+ this.pageSizeChange.emit(next.pageSize);
503
+ if (!this._isServer()) {
504
+ this._clientPageIndex.set(next.pageIndex);
505
+ this._clientPageSize.set(next.pageSize);
506
+ }
507
+ },
508
+ };
509
+ });
510
+ _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]) });
511
+ _emitSelection = effect(() => {
512
+ const selected = this._selectedRows();
513
+ // Consumer handlers may read signals; those reads must not retrigger us.
514
+ untracked(() => this.selectionChange.emit(selected));
515
+ }, /* @ts-ignore */
516
+ ...(ngDevMode ? [{ debugName: "_emitSelection" }] : /* istanbul ignore next */ []));
517
+ /**
518
+ * Seeds internal state from the `initial*` inputs. Runs in `ngOnInit` (after
519
+ * first bindings, before first render) exactly once, so inline-literal
520
+ * bindings (new references every change detection) cannot clobber user
521
+ * interaction afterwards. Values are copied to avoid aliasing caller data.
522
+ */
523
+ ngOnInit() {
524
+ this._sorting.set([...this.initialSorting()]);
525
+ this._columnFilters.set([...this.initialColumnFilters()]);
526
+ this._columnVisibility.set({ ...this.initialColumnVisibility() });
527
+ this._rowSelection.set(this._keepCurrentSelection(this.initialRowSelection()));
528
+ }
529
+ _hasGrid = computed(() => this.gridColumns() !== undefined, /* @ts-ignore */
530
+ ...(ngDevMode ? [{ debugName: "_hasGrid" }] : /* istanbul ignore next */ []));
531
+ _effectiveLayout = computed(() => this.layout() === 'grid' && this._hasGrid() ? 'grid' : 'table', /* @ts-ignore */
532
+ ...(ngDevMode ? [{ debugName: "_effectiveLayout" }] : /* istanbul ignore next */ []));
533
+ _showLayoutToggle = computed(() => this.showLayoutToggle() && this._hasGrid(), /* @ts-ignore */
534
+ ...(ngDevMode ? [{ debugName: "_showLayoutToggle" }] : /* istanbul ignore next */ []));
535
+ _visibleColumnCount = computed(() => {
536
+ const count = this._table.getVisibleLeafColumns().length;
537
+ return count > 0 ? count : 1;
538
+ }, /* @ts-ignore */
539
+ ...(ngDevMode ? [{ debugName: "_visibleColumnCount" }] : /* istanbul ignore next */ []));
540
+ _statusText = computed(() => {
541
+ const paginated = this._page();
542
+ const table = this._table;
543
+ const selected = table.getFilteredSelectedRowModel().rows.length;
544
+ if (this.enableSelection() && selected > 0) {
545
+ const total = paginated ? paginated.total : table.getFilteredRowModel().rows.length;
546
+ return `${selected} of ${total} row(s) selected`;
547
+ }
548
+ if (paginated) {
549
+ const from = paginated.items.length === 0 ? 0 : paginated.offset + 1;
550
+ const to = paginated.offset + paginated.items.length;
551
+ return `Showing ${from} to ${to} of ${paginated.total} records`;
552
+ }
553
+ const total = table.getFilteredRowModel().rows.length;
554
+ return `${total} row(s).`;
555
+ }, /* @ts-ignore */
556
+ ...(ngDevMode ? [{ debugName: "_statusText" }] : /* istanbul ignore next */ []));
557
+ _onLayoutToggle(value) {
558
+ if (value === 'table' || value === 'grid')
559
+ this.layout.set(value);
560
+ }
561
+ _onFilterInput(event) {
562
+ const value = event.target.value;
563
+ const id = this.filterColumnId();
564
+ if (!id) {
565
+ this.filterChange.emit(value);
566
+ return;
567
+ }
568
+ this._table.getColumn(id)?.setFilterValue(value);
569
+ }
570
+ /**
571
+ * Row/card click handler. Ignores clicks originating from nested interactive
572
+ * elements (selection checkboxes, action buttons, links, inputs) so those
573
+ * controls keep working without also firing `rowClick`.
574
+ */
575
+ _onRowClick(event, row) {
576
+ const target = event.target;
577
+ if (target instanceof Element && target.closest('button, a, input, select, textarea, [role="checkbox"]')) {
578
+ return;
579
+ }
580
+ this.rowClick.emit(row.original);
581
+ }
582
+ /** Show the inline TH sort button only for sortable plain-string headers (component headers own their UI). */
583
+ _showHeaderSortButton(header) {
584
+ return header.column.getCanSort() && typeof header.column.columnDef.header === 'string';
585
+ }
586
+ _toggleHeaderSorting(header) {
587
+ header.column.toggleSorting(header.column.getIsSorted() === 'asc');
588
+ }
589
+ _selectionCell(row) {
590
+ return row.getVisibleCells().find((cell) => cell.column.id === 'select');
591
+ }
592
+ _thumbnailCell(row) {
593
+ return row.getVisibleCells().find((cell) => cell.column.columnDef.meta?.thumbnail === true);
594
+ }
595
+ _contentCells(row) {
596
+ return row
597
+ .getVisibleCells()
598
+ .filter((cell) => cell.column.id !== 'select' && cell.column.columnDef.meta?.thumbnail !== true);
599
+ }
600
+ _cellLabel(cell) {
601
+ const header = cell.column.columnDef.header;
602
+ if (typeof header === 'string')
603
+ return header;
604
+ return cell.column.id.replace(/_/g, ' ');
605
+ }
606
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: EgDataTable, deps: [], target: i0.ɵɵFactoryTarget.Component });
607
+ 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: [
608
+ provideIcons({ lucideArrowDown, lucideArrowUp, lucideChevronsUpDown, lucideLayoutGrid, lucideLayoutList }),
609
+ ], ngImport: i0, template: "\n <div [class]=\"_containerClass()\">\n @if (_showLayoutToggle()) {\n <div class=\"flex items-center justify-between\">\n <div hlmToggleGroup type=\"single\" [value]=\"_effectiveLayout()\" (valueChange)=\"_onLayoutToggle($event)\">\n <button hlmToggleGroupItem value=\"table\" aria-label=\"Table view\">\n <ng-icon hlm name=\"lucideLayoutList\" />\n </button>\n <button hlmToggleGroupItem value=\"grid\" aria-label=\"Grid view\">\n <ng-icon hlm name=\"lucideLayoutGrid\" />\n </button>\n </div>\n <div></div>\n </div>\n }\n\n @if (showToolbar() || toolbarActions()) {\n <div class=\"flex flex-wrap items-center justify-between gap-2 py-1\" [tanStackTable]=\"_table\">\n @if (showToolbar()) {\n <div class=\"flex flex-wrap items-center gap-2\">\n <input\n hlmInput\n class=\"w-full min-w-0 md:w-80\"\n [size]=\"size()\"\n [placeholder]=\"filterPlaceholder()\"\n (input)=\"_onFilterInput($event)\"\n />\n @if (showColumnToggle()) {\n <eg-data-table-view-options [size]=\"size()\" />\n }\n </div>\n }\n @if (toolbarActions()) {\n <div class=\"flex flex-wrap items-center gap-2\">\n <ng-container *ngTemplateOutlet=\"toolbarActions()\" />\n </div>\n }\n </div>\n }\n\n @if (_effectiveLayout() === 'grid') {\n <ng-container *ngTemplateOutlet=\"_gridView\" />\n } @else {\n <ng-container *ngTemplateOutlet=\"_tableView\" />\n }\n\n <ng-template #_tableView>\n <div class=\"overflow-hidden rounded-md border\">\n <div hlmTableContainer>\n <table hlmTable>\n <thead hlmTHead>\n @for (headerGroup of _table.getHeaderGroups(); track headerGroup.id) {\n <tr hlmTr>\n @for (header of headerGroup.headers; track header.id) {\n <th hlmTh [size]=\"size()\" [attr.colSpan]=\"header.colSpan\">\n @if (!header.isPlaceholder) {\n <div class=\"flex items-center gap-1\">\n <ng-container\n *flexRender=\"header.column.columnDef.header; props: header.getContext(); let headerText\"\n >\n <div [innerHTML]=\"headerText\"></div>\n </ng-container>\n @if (_showHeaderSortButton(header)) {\n <button\n hlmButton\n variant=\"ghost\"\n size=\"sm\"\n [class]=\"_sortButtonClass()\"\n type=\"button\"\n [attr.aria-label]=\"'Sort by ' + header.column.id\"\n (click)=\"_toggleHeaderSorting(header)\"\n >\n @switch (header.column.getIsSorted()) {\n @case ('asc') {\n <ng-icon hlm size=\"sm\" name=\"lucideArrowUp\" />\n }\n @case ('desc') {\n <ng-icon hlm size=\"sm\" name=\"lucideArrowDown\" />\n }\n @default {\n <ng-icon hlm size=\"sm\" name=\"lucideChevronsUpDown\" />\n }\n }\n </button>\n }\n </div>\n }\n </th>\n }\n </tr>\n }\n </thead>\n <tbody hlmTBody>\n @if (isLoading()) {\n <tr hlmTr>\n <td hlmTd [attr.colspan]=\"_visibleColumnCount()\" class=\"h-24 text-center\">\n <hlm-spinner class=\"inline-flex\" />\n </td>\n </tr>\n } @else if (_table.getRowModel().rows.length === 0) {\n <tr hlmTr>\n <td hlmTd [attr.colspan]=\"_visibleColumnCount()\" class=\"h-24 text-center\">\n {{ emptyMessage() }}\n </td>\n </tr>\n } @else {\n @for (row of _table.getRowModel().rows; track row.id) {\n <tr\n hlmTr\n [attr.data-state]=\"row.getIsSelected() ? 'selected' : null\"\n (click)=\"_onRowClick($event, row)\"\n >\n @for (cell of row.getVisibleCells(); track cell.id) {\n <td hlmTd [size]=\"size()\">\n <ng-container\n *flexRender=\"cell.column.columnDef.cell; props: cell.getContext(); let cellText\"\n >\n <div [innerHTML]=\"cellText\"></div>\n </ng-container>\n </td>\n }\n </tr>\n }\n }\n </tbody>\n </table>\n </div>\n </div>\n </ng-template>\n\n <ng-template #_gridView>\n @if (isLoading()) {\n <div\n class=\"flex h-64 items-center justify-center rounded-lg border border-dashed\"\n role=\"status\"\n >\n <hlm-spinner />\n </div>\n } @else if (_table.getRowModel().rows.length === 0) {\n <div\n class=\"text-muted-foreground flex h-64 items-center justify-center rounded-lg border border-dashed\"\n >\n {{ emptyMessage() }}\n </div>\n } @else {\n <div class=\"grid grid-cols-1 gap-4 md:grid-cols-2 xl:grid-cols-3 2xl:grid-cols-4\">\n @for (row of _table.getRowModel().rows; track row.id) {\n <div\n hlmCard\n class=\"group relative transition-all hover:shadow-md data-[state=selected]:border-primary data-[state=selected]:ring-1 data-[state=selected]:ring-primary/20\"\n [attr.data-state]=\"row.getIsSelected() ? 'selected' : null\"\n (click)=\"_onRowClick($event, row)\"\n >\n @if (_thumbnailCell(row); as thumbnail) {\n <div class=\"border-b bg-muted/30\">\n <ng-container\n *flexRender=\"thumbnail.column.columnDef.cell; props: thumbnail.getContext(); let thumbHtml\"\n >\n <div [innerHTML]=\"thumbHtml\"></div>\n </ng-container>\n </div>\n }\n @if (_selectionCell(row); as selection) {\n <div class=\"absolute top-4 right-4\">\n <ng-container\n *flexRender=\"selection.column.columnDef.cell; props: selection.getContext(); let selectHtml\"\n >\n <div [innerHTML]=\"selectHtml\"></div>\n </ng-container>\n </div>\n }\n <div hlmCardContent class=\"space-y-3\">\n @for (cell of _contentCells(row); track cell.id) {\n <div class=\"flex flex-col\">\n <dt\n class=\"text-[10px] font-bold tracking-wider uppercase text-muted-foreground/80\"\n >\n {{ _cellLabel(cell) }}\n </dt>\n <dd class=\"mt-0.5 text-sm leading-none font-medium\">\n <ng-container *flexRender=\"cell.column.columnDef.cell; props: cell.getContext(); let valueHtml\">\n <div [innerHTML]=\"valueHtml\"></div>\n </ng-container>\n </dd>\n </div>\n }\n </div>\n </div>\n }\n </div>\n }\n </ng-template>\n\n @if (!hideFooter()) {\n <div\n class=\"flex flex-col gap-2 px-2 py-4 sm:flex-row sm:items-center sm:justify-between\"\n [tanStackTable]=\"_table\"\n >\n <div class=\"text-muted-foreground flex-1 text-sm\">{{ _statusText() }}</div>\n <eg-data-table-pagination\n [showStatus]=\"false\"\n [showPageSize]=\"showPageSize()\"\n [pageSizes]=\"pageSizes()\"\n [navMode]=\"navMode()\"\n [size]=\"size()\"\n />\n </div>\n }\n </div>\n ", 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 });
610
+ }
611
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: EgDataTable, decorators: [{
612
+ type: Component,
613
+ args: [{
614
+ selector: 'eg-data-table',
615
+ imports: [
616
+ FlexRender,
617
+ TanStackTable,
618
+ NgTemplateOutlet,
619
+ HlmTableImports,
620
+ HlmButton,
621
+ HlmCard,
622
+ HlmCardContent,
623
+ HlmIcon,
624
+ HlmInput,
625
+ HlmSpinner,
626
+ HlmToggleGroup,
627
+ HlmToggleGroupItem,
628
+ NgIcon,
629
+ EgDataTablePagination,
630
+ EgDataTableViewOptions,
631
+ ],
632
+ providers: [
633
+ provideIcons({ lucideArrowDown, lucideArrowUp, lucideChevronsUpDown, lucideLayoutGrid, lucideLayoutList }),
634
+ ],
635
+ template: "\n <div [class]=\"_containerClass()\">\n @if (_showLayoutToggle()) {\n <div class=\"flex items-center justify-between\">\n <div hlmToggleGroup type=\"single\" [value]=\"_effectiveLayout()\" (valueChange)=\"_onLayoutToggle($event)\">\n <button hlmToggleGroupItem value=\"table\" aria-label=\"Table view\">\n <ng-icon hlm name=\"lucideLayoutList\" />\n </button>\n <button hlmToggleGroupItem value=\"grid\" aria-label=\"Grid view\">\n <ng-icon hlm name=\"lucideLayoutGrid\" />\n </button>\n </div>\n <div></div>\n </div>\n }\n\n @if (showToolbar() || toolbarActions()) {\n <div class=\"flex flex-wrap items-center justify-between gap-2 py-1\" [tanStackTable]=\"_table\">\n @if (showToolbar()) {\n <div class=\"flex flex-wrap items-center gap-2\">\n <input\n hlmInput\n class=\"w-full min-w-0 md:w-80\"\n [size]=\"size()\"\n [placeholder]=\"filterPlaceholder()\"\n (input)=\"_onFilterInput($event)\"\n />\n @if (showColumnToggle()) {\n <eg-data-table-view-options [size]=\"size()\" />\n }\n </div>\n }\n @if (toolbarActions()) {\n <div class=\"flex flex-wrap items-center gap-2\">\n <ng-container *ngTemplateOutlet=\"toolbarActions()\" />\n </div>\n }\n </div>\n }\n\n @if (_effectiveLayout() === 'grid') {\n <ng-container *ngTemplateOutlet=\"_gridView\" />\n } @else {\n <ng-container *ngTemplateOutlet=\"_tableView\" />\n }\n\n <ng-template #_tableView>\n <div class=\"overflow-hidden rounded-md border\">\n <div hlmTableContainer>\n <table hlmTable>\n <thead hlmTHead>\n @for (headerGroup of _table.getHeaderGroups(); track headerGroup.id) {\n <tr hlmTr>\n @for (header of headerGroup.headers; track header.id) {\n <th hlmTh [size]=\"size()\" [attr.colSpan]=\"header.colSpan\">\n @if (!header.isPlaceholder) {\n <div class=\"flex items-center gap-1\">\n <ng-container\n *flexRender=\"header.column.columnDef.header; props: header.getContext(); let headerText\"\n >\n <div [innerHTML]=\"headerText\"></div>\n </ng-container>\n @if (_showHeaderSortButton(header)) {\n <button\n hlmButton\n variant=\"ghost\"\n size=\"sm\"\n [class]=\"_sortButtonClass()\"\n type=\"button\"\n [attr.aria-label]=\"'Sort by ' + header.column.id\"\n (click)=\"_toggleHeaderSorting(header)\"\n >\n @switch (header.column.getIsSorted()) {\n @case ('asc') {\n <ng-icon hlm size=\"sm\" name=\"lucideArrowUp\" />\n }\n @case ('desc') {\n <ng-icon hlm size=\"sm\" name=\"lucideArrowDown\" />\n }\n @default {\n <ng-icon hlm size=\"sm\" name=\"lucideChevronsUpDown\" />\n }\n }\n </button>\n }\n </div>\n }\n </th>\n }\n </tr>\n }\n </thead>\n <tbody hlmTBody>\n @if (isLoading()) {\n <tr hlmTr>\n <td hlmTd [attr.colspan]=\"_visibleColumnCount()\" class=\"h-24 text-center\">\n <hlm-spinner class=\"inline-flex\" />\n </td>\n </tr>\n } @else if (_table.getRowModel().rows.length === 0) {\n <tr hlmTr>\n <td hlmTd [attr.colspan]=\"_visibleColumnCount()\" class=\"h-24 text-center\">\n {{ emptyMessage() }}\n </td>\n </tr>\n } @else {\n @for (row of _table.getRowModel().rows; track row.id) {\n <tr\n hlmTr\n [attr.data-state]=\"row.getIsSelected() ? 'selected' : null\"\n (click)=\"_onRowClick($event, row)\"\n >\n @for (cell of row.getVisibleCells(); track cell.id) {\n <td hlmTd [size]=\"size()\">\n <ng-container\n *flexRender=\"cell.column.columnDef.cell; props: cell.getContext(); let cellText\"\n >\n <div [innerHTML]=\"cellText\"></div>\n </ng-container>\n </td>\n }\n </tr>\n }\n }\n </tbody>\n </table>\n </div>\n </div>\n </ng-template>\n\n <ng-template #_gridView>\n @if (isLoading()) {\n <div\n class=\"flex h-64 items-center justify-center rounded-lg border border-dashed\"\n role=\"status\"\n >\n <hlm-spinner />\n </div>\n } @else if (_table.getRowModel().rows.length === 0) {\n <div\n class=\"text-muted-foreground flex h-64 items-center justify-center rounded-lg border border-dashed\"\n >\n {{ emptyMessage() }}\n </div>\n } @else {\n <div class=\"grid grid-cols-1 gap-4 md:grid-cols-2 xl:grid-cols-3 2xl:grid-cols-4\">\n @for (row of _table.getRowModel().rows; track row.id) {\n <div\n hlmCard\n class=\"group relative transition-all hover:shadow-md data-[state=selected]:border-primary data-[state=selected]:ring-1 data-[state=selected]:ring-primary/20\"\n [attr.data-state]=\"row.getIsSelected() ? 'selected' : null\"\n (click)=\"_onRowClick($event, row)\"\n >\n @if (_thumbnailCell(row); as thumbnail) {\n <div class=\"border-b bg-muted/30\">\n <ng-container\n *flexRender=\"thumbnail.column.columnDef.cell; props: thumbnail.getContext(); let thumbHtml\"\n >\n <div [innerHTML]=\"thumbHtml\"></div>\n </ng-container>\n </div>\n }\n @if (_selectionCell(row); as selection) {\n <div class=\"absolute top-4 right-4\">\n <ng-container\n *flexRender=\"selection.column.columnDef.cell; props: selection.getContext(); let selectHtml\"\n >\n <div [innerHTML]=\"selectHtml\"></div>\n </ng-container>\n </div>\n }\n <div hlmCardContent class=\"space-y-3\">\n @for (cell of _contentCells(row); track cell.id) {\n <div class=\"flex flex-col\">\n <dt\n class=\"text-[10px] font-bold tracking-wider uppercase text-muted-foreground/80\"\n >\n {{ _cellLabel(cell) }}\n </dt>\n <dd class=\"mt-0.5 text-sm leading-none font-medium\">\n <ng-container *flexRender=\"cell.column.columnDef.cell; props: cell.getContext(); let valueHtml\">\n <div [innerHTML]=\"valueHtml\"></div>\n </ng-container>\n </dd>\n </div>\n }\n </div>\n </div>\n }\n </div>\n }\n </ng-template>\n\n @if (!hideFooter()) {\n <div\n class=\"flex flex-col gap-2 px-2 py-4 sm:flex-row sm:items-center sm:justify-between\"\n [tanStackTable]=\"_table\"\n >\n <div class=\"text-muted-foreground flex-1 text-sm\">{{ _statusText() }}</div>\n <eg-data-table-pagination\n [showStatus]=\"false\"\n [showPageSize]=\"showPageSize()\"\n [pageSizes]=\"pageSizes()\"\n [navMode]=\"navMode()\"\n [size]=\"size()\"\n />\n </div>\n }\n </div>\n ",
636
+ changeDetection: ChangeDetectionStrategy.OnPush,
637
+ }]
638
+ }], 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"] }] } });
639
+
640
+ /**
641
+ * Sortable + hideable column header.
642
+ *
643
+ * Render via `flexRenderComponent(EgDataTableColumnHeader, { inputs: { column, title } })`
644
+ * so the extra `title` input flows alongside the flex-render `column` context.
645
+ * Non-sortable columns render a plain label.
646
+ */
647
+ class EgDataTableColumnHeader {
648
+ column = input.required(/* @ts-ignore */
649
+ ...(ngDevMode ? [{ debugName: "column" }] : /* istanbul ignore next */ []));
650
+ title = input.required(/* @ts-ignore */
651
+ ...(ngDevMode ? [{ debugName: "title" }] : /* istanbul ignore next */ []));
652
+ /** Density of the trigger button. */
653
+ size = input('default', /* @ts-ignore */
654
+ ...(ngDevMode ? [{ debugName: "size" }] : /* istanbul ignore next */ []));
655
+ _sorted = computed(() => this.column().getIsSorted(), /* @ts-ignore */
656
+ ...(ngDevMode ? [{ debugName: "_sorted" }] : /* istanbul ignore next */ []));
657
+ /** Height per density. Merged by `hlmButton`. */
658
+ _buttonClass = computed(() => hlm("-ml-3", this.size() === 'sm' ? "h-7" : this.size() === 'lg' ? "h-9" : "h-8"), /* @ts-ignore */
659
+ ...(ngDevMode ? [{ debugName: "_buttonClass" }] : /* istanbul ignore next */ []));
660
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: EgDataTableColumnHeader, deps: [], target: i0.ɵɵFactoryTarget.Component });
661
+ 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: "\n @if (column().getCanSort()) {\n <div class=\"flex items-center gap-2\">\n <button\n hlmButton\n variant=\"ghost\"\n size=\"sm\"\n [class]=\"_buttonClass()\"\n type=\"button\"\n [hlmDropdownMenuTrigger]=\"_menu\"\n >\n <span>{{ title() }}</span>\n @switch (_sorted()) {\n @case ('desc') {\n <ng-icon hlm size=\"sm\" name=\"lucideArrowDown\" />\n }\n @case ('asc') {\n <ng-icon hlm size=\"sm\" name=\"lucideArrowUp\" />\n }\n @default {\n <ng-icon hlm size=\"sm\" name=\"lucideChevronsUpDown\" />\n }\n }\n </button>\n <ng-template #_menu>\n <div hlmDropdownMenu>\n <button hlmDropdownMenuItem type=\"button\" (click)=\"column().toggleSorting(false)\">\n <ng-icon hlm size=\"sm\" name=\"lucideArrowUp\" />\n Asc\n </button>\n <button hlmDropdownMenuItem type=\"button\" (click)=\"column().toggleSorting(true)\">\n <ng-icon hlm size=\"sm\" name=\"lucideArrowDown\" />\n Desc\n </button>\n <div hlmDropdownMenuSeparator></div>\n <button hlmDropdownMenuItem type=\"button\" (click)=\"column().toggleVisibility(false)\">\n <ng-icon hlm size=\"sm\" name=\"lucideEyeOff\" />\n Hide\n </button>\n </div>\n </ng-template>\n </div>\n } @else {\n <div>{{ title() }}</div>\n }\n ", 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 });
662
+ }
663
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: EgDataTableColumnHeader, decorators: [{
664
+ type: Component,
665
+ args: [{
666
+ selector: 'eg-data-table-column-header',
667
+ imports: [HlmButton, HlmDropdownMenuImports, NgIcon, HlmIcon],
668
+ providers: [provideIcons({ lucideArrowDown, lucideArrowUp, lucideChevronsUpDown, lucideEyeOff })],
669
+ template: "\n @if (column().getCanSort()) {\n <div class=\"flex items-center gap-2\">\n <button\n hlmButton\n variant=\"ghost\"\n size=\"sm\"\n [class]=\"_buttonClass()\"\n type=\"button\"\n [hlmDropdownMenuTrigger]=\"_menu\"\n >\n <span>{{ title() }}</span>\n @switch (_sorted()) {\n @case ('desc') {\n <ng-icon hlm size=\"sm\" name=\"lucideArrowDown\" />\n }\n @case ('asc') {\n <ng-icon hlm size=\"sm\" name=\"lucideArrowUp\" />\n }\n @default {\n <ng-icon hlm size=\"sm\" name=\"lucideChevronsUpDown\" />\n }\n }\n </button>\n <ng-template #_menu>\n <div hlmDropdownMenu>\n <button hlmDropdownMenuItem type=\"button\" (click)=\"column().toggleSorting(false)\">\n <ng-icon hlm size=\"sm\" name=\"lucideArrowUp\" />\n Asc\n </button>\n <button hlmDropdownMenuItem type=\"button\" (click)=\"column().toggleSorting(true)\">\n <ng-icon hlm size=\"sm\" name=\"lucideArrowDown\" />\n Desc\n </button>\n <div hlmDropdownMenuSeparator></div>\n <button hlmDropdownMenuItem type=\"button\" (click)=\"column().toggleVisibility(false)\">\n <ng-icon hlm size=\"sm\" name=\"lucideEyeOff\" />\n Hide\n </button>\n </div>\n </ng-template>\n </div>\n } @else {\n <div>{{ title() }}</div>\n }\n ",
670
+ changeDetection: ChangeDetectionStrategy.OnPush,
671
+ }]
672
+ }], 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 }] }] } });
673
+
674
+ /*
675
+ * Public API Surface of data-table
676
+ */
677
+ const EgDataTableImports = [
678
+ EgDataTable,
679
+ EgDataTableColumnHeader,
680
+ EgDataTablePagination,
681
+ EgDataTableViewOptions,
682
+ EgTableHeadSelection,
683
+ EgTableRowSelection,
684
+ ];
685
+ class EgDataTableModule {
686
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: EgDataTableModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
687
+ static ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "22.1.3", ngImport: i0, type: EgDataTableModule, imports: [EgDataTable,
688
+ EgDataTableColumnHeader,
689
+ EgDataTablePagination,
690
+ EgDataTableViewOptions,
691
+ EgTableHeadSelection,
692
+ EgTableRowSelection], exports: [EgDataTable,
693
+ EgDataTableColumnHeader,
694
+ EgDataTablePagination,
695
+ EgDataTableViewOptions,
696
+ EgTableHeadSelection,
697
+ EgTableRowSelection] });
698
+ static ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: EgDataTableModule, imports: [EgDataTableImports] });
699
+ }
700
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: EgDataTableModule, decorators: [{
701
+ type: NgModule,
702
+ args: [{
703
+ imports: [...EgDataTableImports],
704
+ exports: [...EgDataTableImports],
705
+ }]
706
+ }] });
707
+
708
+ /**
709
+ * Generated bundle index. Do not edit.
710
+ */
711
+
712
+ export { EgDataTable, EgDataTableColumnHeader, EgDataTableImports, EgDataTableModule, EgDataTablePagination, EgDataTableViewOptions, EgTableHeadSelection, EgTableRowSelection, defaultEgDataTableFeatures };
713
+