ngx-kit 4.0.0 → 5.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,17 +1,61 @@
1
1
  import * as i0 from '@angular/core';
2
- import { InjectionToken, inject, input, model, output, computed, effect, Component, TemplateRef, Directive, signal, viewChild, EventEmitter, ContentChildren, Output, makeEnvironmentProviders } from '@angular/core';
3
- import * as i1 from '@angular/forms';
4
- import { FormsModule } from '@angular/forms';
2
+ import { InjectionToken, makeEnvironmentProviders, input, inject, TemplateRef, Directive, output, HostListener, model, computed, effect, ChangeDetectionStrategy, Component, signal, ContentChildren } from '@angular/core';
5
3
  import * as i1$1 from '@angular/common';
6
4
  import { CommonModule } from '@angular/common';
7
- import { mergeConfig } from 'ngx-kit/shared';
5
+ import * as i1 from '@angular/forms';
6
+ import { FormsModule } from '@angular/forms';
7
+ import { DirectionService } from 'ngx-kit/shared';
8
8
 
9
- const NGX_PAGINATION_CONFIG = new InjectionToken('ngx-pagination-config', {
10
- factory: () => NGX_PAGINATION_CONFIG_DEFAULT,
9
+ /**
10
+ * Identity helper: یک رجیستری رندرر را با inference کامل تعریف می‌کند.
11
+ * همین آبجکت باید هم در provideTable({ renderers }) و هم در defineFields(renderers, ...)
12
+ * استفاده شود تا کلیدها (و ورودی‌های اضافه‌ی هر رندرر) در کل پروژه type-check شوند.
13
+ */
14
+ function defineRenderers(registry) {
15
+ return registry;
16
+ }
17
+ /**
18
+ * Identity helper برای تعریف ستون‌های یک جدول با inference و type-check کامل
19
+ * نسبت به هم مدل داده (T) و هم رجیستری رندررها (R).
20
+ *
21
+ * @example
22
+ * const renderers = defineRenderers({ avatar: AvatarCellRenderer, boolean: BooleanCellRenderer });
23
+ *
24
+ * const fields = defineFields<Tenant, typeof renderers>(renderers, [
25
+ * { column: 'avatarUrl', title: 'کاربر', renderer: 'avatar', rendererInputs: { showName: true } }, // ✅
26
+ * { column: 'avatarUrl', title: 'کاربر', renderer: 'avatar', rendererInputs: { showName: 'x' } }, // ❌ باید boolean باشد
27
+ * { column: 'isActive', title: 'فعال', renderer: 'bool' }, // ❌ کلید رجیستری نیست
28
+ * { column: 'ageXYZ', title: '...' }, // ❌ فیلد Tenant نیست
29
+ * ]);
30
+ */
31
+ function defineFields(_renderers, fields) {
32
+ return fields;
33
+ }
34
+
35
+ const NGX_TABLE_CONFIG_DEFAULT = {
36
+ showRecordNumber: true,
37
+ hoverable: true,
38
+ multiSort: true,
39
+ resizable: true,
40
+ stickyHeader: true,
41
+ stripedRows: true,
42
+ column: { minWidth: 60, maxWidth: 600, defaultWidth: 150 },
43
+ labels: {
44
+ noData: 'There is no data to display!',
45
+ loading: 'Loading...',
46
+ operation: 'Operation',
47
+ },
48
+ renderers: {},
49
+ formatters: {},
50
+ };
51
+ /** به هر نمونه‌ی ngx-table تزریق می‌شود. با provideTable() مقداردهی کنید. */
52
+ const NGX_TABLE_CONFIG = new InjectionToken('ngx-table-config', {
53
+ factory: () => NGX_TABLE_CONFIG_DEFAULT,
11
54
  });
55
+
12
56
  const NGX_PAGINATION_CONFIG_DEFAULT = {
13
57
  defaultPageSize: 10,
14
- pageSizeOptions: [5, 10, 20, 30, 50, 100, 500, 1000],
58
+ pageSizeOptions: [5, 10, 20, 30, 50, 100],
15
59
  labels: {
16
60
  first: 'First',
17
61
  last: 'Last',
@@ -21,10 +65,164 @@ const NGX_PAGINATION_CONFIG_DEFAULT = {
21
65
  to: 'to',
22
66
  of: 'of',
23
67
  results: 'results',
24
- perPage: 'Per Page',
25
68
  pageSize: 'Page Size',
26
69
  },
27
70
  };
71
+ const NGX_PAGINATION_CONFIG = new InjectionToken('ngx-pagination-config', {
72
+ factory: () => NGX_PAGINATION_CONFIG_DEFAULT,
73
+ });
74
+
75
+ function mergeTableConfig(base, override) {
76
+ if (!override)
77
+ return base;
78
+ return {
79
+ ...base,
80
+ ...override,
81
+ column: { ...base.column, ...override.column },
82
+ labels: { ...base.labels, ...override.labels },
83
+ renderers: { ...base.renderers, ...override.renderers },
84
+ formatters: { ...base.formatters, ...override.formatters },
85
+ };
86
+ }
87
+ /**
88
+ * کانفیگ سراسری <ngx-table>: جهت پیش‌فرض، حداقل/حداکثر عرض ستون، فعال بودن
89
+ * پیش‌فرض سورت چندستونه، و از همه مهم‌تر رجیستری رندررها.
90
+ *
91
+ * @example
92
+ * provideTable({
93
+ * renderers: defineRenderers({ avatar: AvatarCellRenderer, boolean: BooleanCellRenderer }),
94
+ * column: { minWidth: 80, maxWidth: 480, defaultWidth: 160 },
95
+ * })
96
+ */
97
+ function provideTable(options) {
98
+ return makeEnvironmentProviders([
99
+ { provide: NGX_TABLE_CONFIG, useValue: mergeTableConfig(NGX_TABLE_CONFIG_DEFAULT, options) },
100
+ ]);
101
+ }
102
+
103
+ function mergePaginationConfig(base, override) {
104
+ if (!override)
105
+ return base;
106
+ return {
107
+ ...base,
108
+ ...override,
109
+ labels: { ...base.labels, ...override.labels },
110
+ };
111
+ }
112
+ function providePagination(options) {
113
+ return makeEnvironmentProviders([
114
+ {
115
+ provide: NGX_PAGINATION_CONFIG,
116
+ useValue: mergePaginationConfig(NGX_PAGINATION_CONFIG_DEFAULT, options),
117
+ },
118
+ ]);
119
+ }
120
+
121
+ /**
122
+ * برای projection قالب سفارشی یک ستون بدون این‌که مجبور باشید cellTemplate را
123
+ * از طریق ViewChild به آبجکت ستون وصل کنید:
124
+ *
125
+ * <ngx-table [fields]="fields" [data]="rows()">
126
+ * <ng-template ngxTableCell="userName" let-row let-value="value">
127
+ * <strong>{{ value }}</strong>
128
+ * </ng-template>
129
+ * </ngx-table>
130
+ *
131
+ * مهم: چون این دایرکتیو در تمپلیت *کامپوننت مصرف‌کننده* (نه ngx-table) استفاده
132
+ * می‌شود، باید آن را در آرایه‌ی imports همان کامپوننت (standalone) وارد کنید:
133
+ * imports: [NgxTable, TableCell]
134
+ *
135
+ * محدودیت شناخته‌شده: context این تمپلیت (row/value) از نوع T دقیق نیست
136
+ * (چون TemplateRef اینجا به‌صورت پویا از ContentChildren جمع‌آوری می‌شود و
137
+ * اطلاعات جنریک T در آن نقطه از بین می‌رود). برای type-safety کامل روی
138
+ * row/value، از field.cellTemplate به همراه @ViewChild استفاده کنید (به README
139
+ * بخش «Cell Template کاملاً Type-Safe» مراجعه کنید).
140
+ */
141
+ class TableCell {
142
+ column = input.required({ ...(ngDevMode ? { debugName: "column" } : /* istanbul ignore next */ {}), alias: 'ngxTableCell' });
143
+ templateRef = inject((TemplateRef));
144
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.4", ngImport: i0, type: TableCell, deps: [], target: i0.ɵɵFactoryTarget.Directive });
145
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "22.0.4", type: TableCell, isStandalone: true, selector: "ng-template[ngxTableCell]", inputs: { column: { classPropertyName: "column", publicName: "ngxTableCell", isSignal: true, isRequired: true, transformFunction: null } }, ngImport: i0 });
146
+ }
147
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.4", ngImport: i0, type: TableCell, decorators: [{
148
+ type: Directive,
149
+ args: [{
150
+ selector: 'ng-template[ngxTableCell]',
151
+ standalone: true,
152
+ }]
153
+ }], propDecorators: { column: [{ type: i0.Input, args: [{ isSignal: true, alias: "ngxTableCell", required: true }] }] } });
154
+
155
+ /**
156
+ * دستگیره‌ی درگ برای ریسایز ستون. روی لبه‌ی «انتهای منطقی» (inline-end) قرار
157
+ * می‌گیرد، یعنی خودش زیر [dir="rtl"] جابه‌جا می‌شود؛ فقط جهت محاسبه‌ی دلتا هم
158
+ * برعکس می‌شود تا حس درگ همیشه طبیعی باشد.
159
+ *
160
+ * مقدار نهایی توسط جدول در یک Map از عرض‌ها ذخیره می‌شود (نه در استایل مستقیم
161
+ * ستون)، به همراه علامت‌گذاری «دستی ریسایز شده» — یعنی بعد از این، هیچ
162
+ * re-render یا تغییر داده‌ای این عرض را از بین نمی‌برد.
163
+ */
164
+ class ColumnResize {
165
+ startWidth = input.required({ ...(ngDevMode ? { debugName: "startWidth" } : /* istanbul ignore next */ {}), alias: 'ngxColumnResizeWidth' });
166
+ minWidth = input(40, { ...(ngDevMode ? { debugName: "minWidth" } : /* istanbul ignore next */ {}), alias: 'ngxColumnResizeMin' });
167
+ maxWidth = input(1000, { ...(ngDevMode ? { debugName: "maxWidth" } : /* istanbul ignore next */ {}), alias: 'ngxColumnResizeMax' });
168
+ direction = input('ltr', { ...(ngDevMode ? { debugName: "direction" } : /* istanbul ignore next */ {}), alias: 'ngxColumnResizeDir' });
169
+ resizing = output();
170
+ resizeEnd = output();
171
+ dragging = false;
172
+ startX = 0;
173
+ baseWidth = 0;
174
+ onPointerDown(event) {
175
+ event.preventDefault();
176
+ event.stopPropagation();
177
+ this.dragging = true;
178
+ this.startX = event.clientX;
179
+ this.baseWidth = this.startWidth();
180
+ event.target.setPointerCapture(event.pointerId);
181
+ }
182
+ onPointerMove(event) {
183
+ if (!this.dragging)
184
+ return;
185
+ this.resizing.emit(this.computeWidth(event.clientX));
186
+ }
187
+ onPointerUp(event) {
188
+ if (!this.dragging)
189
+ return;
190
+ this.dragging = false;
191
+ this.resizeEnd.emit(this.computeWidth(event.clientX));
192
+ }
193
+ computeWidth(clientX) {
194
+ const delta = clientX - this.startX;
195
+ const signedDelta = this.direction() === 'rtl' ? -delta : delta;
196
+ const raw = this.baseWidth + signedDelta;
197
+ return Math.min(this.maxWidth(), Math.max(this.minWidth(), raw));
198
+ }
199
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.4", ngImport: i0, type: ColumnResize, deps: [], target: i0.ɵɵFactoryTarget.Directive });
200
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "22.0.4", type: ColumnResize, isStandalone: true, selector: "[ngxColumnResize]", inputs: { startWidth: { classPropertyName: "startWidth", publicName: "ngxColumnResizeWidth", isSignal: true, isRequired: true, transformFunction: null }, minWidth: { classPropertyName: "minWidth", publicName: "ngxColumnResizeMin", isSignal: true, isRequired: false, transformFunction: null }, maxWidth: { classPropertyName: "maxWidth", publicName: "ngxColumnResizeMax", isSignal: true, isRequired: false, transformFunction: null }, direction: { classPropertyName: "direction", publicName: "ngxColumnResizeDir", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { resizing: "resizing", resizeEnd: "resizeEnd" }, host: { attributes: { "role": "separator", "aria-orientation": "vertical" }, listeners: { "pointerdown": "onPointerDown($event)", "pointermove": "onPointerMove($event)", "pointerup": "onPointerUp($event)", "pointercancel": "onPointerUp($event)" }, classAttribute: "ngx-table__resize-handle" }, ngImport: i0 });
201
+ }
202
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.4", ngImport: i0, type: ColumnResize, decorators: [{
203
+ type: Directive,
204
+ args: [{
205
+ selector: '[ngxColumnResize]',
206
+ standalone: true,
207
+ host: {
208
+ class: 'ngx-table__resize-handle',
209
+ role: 'separator',
210
+ 'aria-orientation': 'vertical',
211
+ },
212
+ }]
213
+ }], propDecorators: { startWidth: [{ type: i0.Input, args: [{ isSignal: true, alias: "ngxColumnResizeWidth", required: true }] }], minWidth: [{ type: i0.Input, args: [{ isSignal: true, alias: "ngxColumnResizeMin", required: false }] }], maxWidth: [{ type: i0.Input, args: [{ isSignal: true, alias: "ngxColumnResizeMax", required: false }] }], direction: [{ type: i0.Input, args: [{ isSignal: true, alias: "ngxColumnResizeDir", required: false }] }], resizing: [{ type: i0.Output, args: ["resizing"] }], resizeEnd: [{ type: i0.Output, args: ["resizeEnd"] }], onPointerDown: [{
214
+ type: HostListener,
215
+ args: ['pointerdown', ['$event']]
216
+ }], onPointerMove: [{
217
+ type: HostListener,
218
+ args: ['pointermove', ['$event']]
219
+ }], onPointerUp: [{
220
+ type: HostListener,
221
+ args: ['pointerup', ['$event']]
222
+ }, {
223
+ type: HostListener,
224
+ args: ['pointercancel', ['$event']]
225
+ }] } });
28
226
 
29
227
  class NgxPagination {
30
228
  config = inject(NGX_PAGINATION_CONFIG);
@@ -43,33 +241,20 @@ class NgxPagination {
43
241
  boundaryCount = input(1, /* @ts-ignore */
44
242
  ...(ngDevMode ? [{ debugName: "boundaryCount" }] : /* istanbul ignore next */ []));
45
243
  paginate = output();
46
- totalPages = computed(() => {
47
- return Math.max(1, Math.ceil(this.total() / this.pageSize()));
48
- }, /* @ts-ignore */
244
+ totalPages = computed(() => Math.max(1, Math.ceil(this.total() / this.pageSize())), /* @ts-ignore */
49
245
  ...(ngDevMode ? [{ debugName: "totalPages" }] : /* istanbul ignore next */ []));
50
- firstItem = computed(() => {
51
- if (this.total() === 0)
52
- return 0;
53
- return (this.page() - 1) * this.pageSize() + 1;
54
- }, /* @ts-ignore */
246
+ firstItem = computed(() => this.total() === 0 ? 0 : (this.page() - 1) * this.pageSize() + 1, /* @ts-ignore */
55
247
  ...(ngDevMode ? [{ debugName: "firstItem" }] : /* istanbul ignore next */ []));
56
- lastItem = computed(() => {
57
- return Math.min(this.firstItem() + this.pageSize() - 1, this.total());
58
- }, /* @ts-ignore */
248
+ lastItem = computed(() => Math.min(this.firstItem() + this.pageSize() - 1, this.total()), /* @ts-ignore */
59
249
  ...(ngDevMode ? [{ debugName: "lastItem" }] : /* istanbul ignore next */ []));
60
250
  pages = computed(() => this.buildPages(this.page(), this.totalPages(), this.siblingCount(), this.boundaryCount()), /* @ts-ignore */
61
251
  ...(ngDevMode ? [{ debugName: "pages" }] : /* istanbul ignore next */ []));
62
252
  constructor() {
253
+ // هر تغییری در page/pageSize را برای مصرف‌کننده امیت کن.
63
254
  effect(() => {
64
- const page = this.page();
65
- const pageSize = +this.pageSize();
66
- // this.pageChange.emit(page);
67
- debugger;
68
- this.paginate.emit({
69
- page,
70
- pageSize,
71
- });
255
+ this.paginate.emit({ page: this.page(), pageSize: this.pageSize() });
72
256
  });
257
+ // اگر بعد از کوچک‌شدن total، صفحه‌ی جاری خارج از بازه افتاد، اصلاحش کن.
73
258
  effect(() => {
74
259
  const max = this.totalPages();
75
260
  if (this.page() > max)
@@ -112,54 +297,40 @@ class NgxPagination {
112
297
  this.page.set(this.totalPages());
113
298
  }
114
299
  goto(page) {
115
- if (typeof page !== 'number')
300
+ if (typeof page !== 'number' || Number.isNaN(page))
116
301
  return;
117
302
  this.page.set(page);
118
303
  }
304
+ onPageSizeChange(value) {
305
+ this.pageSize.set(Number(value));
306
+ this.page.set(1);
307
+ }
119
308
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.4", ngImport: i0, type: NgxPagination, deps: [], target: i0.ɵɵFactoryTarget.Component });
120
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.4", type: NgxPagination, isStandalone: true, selector: "ngx-pagination", inputs: { total: { classPropertyName: "total", publicName: "total", isSignal: true, isRequired: true, transformFunction: null }, page: { classPropertyName: "page", publicName: "page", isSignal: true, isRequired: false, transformFunction: null }, pageSize: { classPropertyName: "pageSize", publicName: "pageSize", isSignal: true, isRequired: false, transformFunction: null }, pageSizeOptions: { classPropertyName: "pageSizeOptions", publicName: "pageSizeOptions", isSignal: true, isRequired: false, transformFunction: null }, labels: { classPropertyName: "labels", publicName: "labels", isSignal: true, isRequired: false, transformFunction: null }, siblingCount: { classPropertyName: "siblingCount", publicName: "siblingCount", isSignal: true, isRequired: false, transformFunction: null }, boundaryCount: { classPropertyName: "boundaryCount", publicName: "boundaryCount", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { page: "pageChange", pageSize: "pageSizeChange", paginate: "paginate" }, ngImport: i0, template: "<nav class=\"ngx-pagination\">\r\n <div class=\"\">\r\n {{ labels().showing }}\r\n <span class=\"fw-semibold\">{{ firstItem() }}</span>\r\n {{ labels().to }}\r\n <span class=\"fw-semibold\">{{ lastItem() }}</span>\r\n {{ labels().of }}\r\n <span class=\"fw-semibold\">{{ total() }}</span>\r\n {{ labels().results }}\r\n </div>\r\n\r\n <div class=\"ngx-paination_page-numbers\">\r\n <ul>\r\n <!-- Previous Page Link -->\r\n <li [class.disabled]=\"page() === 1\" [title]=\"labels().first\">\r\n <a (click)=\"first()\">\r\n <svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 448 512\">\r\n <path\r\n fill=\"currentColor\"\r\n d=\"M235.8 453.1L53.8 256l181.1-197.1c2.844-3.078 4.25-6.969 4.25-10.86c0-4.312-1.719-8.609-5.156-11.75c-6.5-6-16.59-5.594-22.59 .8906l-192 208c-5.688 6.156-5.688 15.56 0 21.72l192 208c6 6.484 16.09 6.891 22.59 .8906C241.4 469.8 241.8 459.6 235.8 453.1zM212.2 245.1c-5.688 6.156-5.688 15.56 0 21.72l192 208c6 6.484 16.09 6.891 22.59 .8906c6.531-5.969 6.906-16.11 .9062-22.61l-181.1-197.1l181.1-197.1c2.844-3.078 4.25-6.969 4.25-10.86c0-4.312-1.719-8.609-5.156-11.75c-6.5-6-16.59-5.594-22.59 .8906L212.2 245.1z\" />\r\n </svg>\r\n </a>\r\n </li>\r\n <li [class.disabled]=\"page() === 1\" [title]=\"labels().previous\">\r\n <a (click)=\"previous()\">\r\n <svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 320 512\">\r\n <path\r\n fill=\"currentColor\"\r\n d=\"M234.8 36.25c3.438 3.141 5.156 7.438 5.156 11.75c0 3.891-1.406 7.781-4.25 10.86L53.77 256l181.1 197.1c6 6.5 5.625 16.64-.9062 22.61c-6.5 6-16.59 5.594-22.59-.8906l-192-208c-5.688-6.156-5.688-15.56 0-21.72l192-208C218.2 30.66 228.3 30.25 234.8 36.25z\" />\r\n </svg>\r\n </a>\r\n </li>\r\n\r\n <!-- Pagination Elements -->\r\n @for (item of pages(); track $index) {\r\n <li class=\"page-num\" [class.active]=\"+item === page()\">\r\n @if (item !== page() && item != '...') {\r\n <a (click)=\"goto(+item)\">{{ item }}</a>\r\n }\r\n @if (item === page() || item == '...') {\r\n <span>{{ item }}</span>\r\n }\r\n </li>\r\n }\r\n\r\n <!-- Next Page Link -->\r\n <li [class.disabled]=\"page() === totalPages()\" [title]=\"labels().next\">\r\n <a (click)=\"next()\">\r\n <svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 320 512\">\r\n <path\r\n fill=\"currentColor\"\r\n d=\"M85.14 475.8c-3.438-3.141-5.156-7.438-5.156-11.75c0-3.891 1.406-7.781 4.25-10.86l181.1-197.1L84.23 58.86c-6-6.5-5.625-16.64 .9062-22.61c6.5-6 16.59-5.594 22.59 .8906l192 208c5.688 6.156 5.688 15.56 0 21.72l-192 208C101.7 481.3 91.64 481.8 85.14 475.8z\" />\r\n </svg>\r\n </a>\r\n </li>\r\n <li [class.disabled]=\"page() === totalPages()\" [title]=\"labels().last\">\r\n <a (click)=\"last()\">\r\n <svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 448 512\">\r\n <path\r\n fill=\"currentColor\"\r\n d=\"M212.2 58.86l181.1 197.1L212.2 453.1c-2.844 3.078-4.25 6.969-4.25 10.86c0 4.312 1.719 8.609 5.156 11.75c6.5 6 16.59 5.594 22.59-.8906l192-208c5.688-6.156 5.688-15.56 0-21.72l-192-208c-6-6.484-16.09-6.891-22.59-.8906C206.6 42.22 206.2 52.36 212.2 58.86zM235.8 266.9c5.688-6.156 5.688-15.56 0-21.72l-192-208c-6-6.484-16.09-6.891-22.59-.8906c-6.531 5.969-6.906 16.11-.9062 22.61l181.1 197.1L20.26 453.1c-2.844 3.078-4.25 6.969-4.25 10.86c0 4.312 1.719 8.609 5.156 11.75c6.5 6 16.59 5.594 22.59-.8906L235.8 266.9z\" />\r\n </svg>\r\n </a>\r\n </li>\r\n </ul>\r\n\r\n <div class=\"ngx-paination_page-size\">\r\n <span>{{ labels().pageSize }}:</span>\r\n <select\r\n name=\"pageSize\"\r\n [ngModel]=\"pageSize()\"\r\n (ngModelChange)=\"pageSize.update((u) => (u = $event))\">\r\n @for (opt of pageSizeOptions(); track $index) {\r\n <option [value]=\"opt\" [selected]=\"opt === pageSize()\">\r\n {{ opt }}\r\n </option>\r\n }\r\n </select>\r\n </div>\r\n </div>\r\n</nav>\r\n", styles: [":host{--ngx-pagination-border: light-dark(#dbdbdb, #373737);--ngx-pagination-border-radius: 4px;--bs-pagination-active-bg: light-dark(#6485fa, #6485fa)}.ngx-pagination{display:flex;align-items:center;justify-content:space-between;padding:15px 0;-webkit-user-select:none;user-select:none}.ngx-paination_page-numbers{display:flex;gap:5px}.ngx-paination_page-numbers ul{display:flex;padding:0;margin:0;gap:2px;list-style:none}.ngx-paination_page-numbers ul li{padding:5px 10px;border:1px var(--ngx-pagination-border) solid;border-radius:var(--ngx-pagination-border-radius);cursor:pointer}.ngx-paination_page-numbers ul li.disabled{cursor:not-allowed;opacity:.4}.ngx-paination_page-numbers ul li.active:not(:disabled){background-color:var(--bs-pagination-active-bg)}.ngx-paination_page-numbers ul li a{display:block;color:inherit;text-decoration:none;width:100%;height:100%}.ngx-paination_page-numbers ul li a svg{width:100%;height:12px}.ngx-paination_page-size{display:flex;align-items:center;gap:5px}.ngx-paination_page-size span{white-space:nowrap}.ngx-paination_page-size select{border-radius:var(--ngx-pagination-border-radius);height:100%}::ng-deep [dir=rtl] .ngx-paination_page-numbers li svg{transform:rotate(180deg)}\n"], dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.NgSelectOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i1.ɵNgSelectMultipleOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i1.SelectControlValueAccessor, selector: "select:not([multiple]):not([ngNoCva])[formControlName],select:not([multiple]):not([ngNoCva])[formControl],select:not([multiple]):not([ngNoCva])[ngModel]", inputs: ["compareWith"] }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }] });
309
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.4", type: NgxPagination, isStandalone: true, selector: "ngx-pagination", inputs: { total: { classPropertyName: "total", publicName: "total", isSignal: true, isRequired: true, transformFunction: null }, page: { classPropertyName: "page", publicName: "page", isSignal: true, isRequired: false, transformFunction: null }, pageSize: { classPropertyName: "pageSize", publicName: "pageSize", isSignal: true, isRequired: false, transformFunction: null }, pageSizeOptions: { classPropertyName: "pageSizeOptions", publicName: "pageSizeOptions", isSignal: true, isRequired: false, transformFunction: null }, labels: { classPropertyName: "labels", publicName: "labels", isSignal: true, isRequired: false, transformFunction: null }, siblingCount: { classPropertyName: "siblingCount", publicName: "siblingCount", isSignal: true, isRequired: false, transformFunction: null }, boundaryCount: { classPropertyName: "boundaryCount", publicName: "boundaryCount", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { page: "pageChange", pageSize: "pageSizeChange", paginate: "paginate" }, ngImport: i0, template: "<nav class=\"ngx-pagination\">\n <div class=\"ngx-pagination__summary\">\n {{ labels().showing }}\n <span class=\"fw-semibold\">{{ firstItem() }}</span>\n {{ labels().to }}\n <span class=\"fw-semibold\">{{ lastItem() }}</span>\n {{ labels().of }}\n <span class=\"fw-semibold\">{{ total() }}</span>\n {{ labels().results }}\n </div>\n\n <div class=\"ngx-pagination__controls\">\n <ul class=\"ngx-pagination__list\">\n <li [class.disabled]=\"page() === 1\" [title]=\"labels().first\">\n <a (click)=\"first()\" class=\"icon\">\u00AB</a>\n </li>\n <li [class.disabled]=\"page() === 1\" [title]=\"labels().previous\">\n <a (click)=\"previous()\" class=\"icon\">\u2039</a>\n </li>\n\n @for (item of pages(); track $index) {\n <li class=\"ngx-pagination__page-num\" [class.active]=\"item === page()\">\n @if (item !== page() && item !== '...') {\n <a (click)=\"goto(+item)\">{{ item }}</a>\n }\n @if (item === page() || item === '...') {\n <span>{{ item }}</span>\n }\n </li>\n }\n\n <li [class.disabled]=\"page() === totalPages()\" [title]=\"labels().next\">\n <a (click)=\"next()\" class=\"icon\">\u203A</a>\n </li>\n <li [class.disabled]=\"page() === totalPages()\" [title]=\"labels().last\">\n <a (click)=\"last()\" class=\"icon\">\u00BB</a>\n </li>\n </ul>\n\n <div class=\"ngx-pagination__page-size\">\n <span>{{ labels().pageSize }}:</span>\n <select [ngModel]=\"pageSize()\" (ngModelChange)=\"onPageSizeChange($event)\">\n @for (opt of pageSizeOptions(); track opt) {\n <option [value]=\"opt\" [selected]=\"opt === pageSize()\">{{ opt }}</option>\n }\n </select>\n </div>\n </div>\n</nav>\n", styles: [".ngx-pagination{display:flex;align-items:center;justify-content:space-between;flex-wrap:wrap;gap:.75rem;padding:.625rem 1rem;font-size:.8125rem}.ngx-pagination__controls{display:flex;align-items:center;gap:1rem;flex-wrap:wrap}.ngx-pagination__list{display:flex;align-items:center;gap:.25rem;list-style:none;margin:0;padding:0}.ngx-pagination__list li{min-width:1.75rem;height:1.75rem;display:inline-flex;align-items:center;justify-content:center;border-radius:6px}.ngx-pagination__list li a,.ngx-pagination__list li span{display:inline-flex;align-items:center;justify-content:center;width:100%;height:100%;cursor:pointer;border-radius:6px;-webkit-user-select:none;user-select:none}.ngx-pagination__list li a.icon,.ngx-pagination__list li span.icon{font-size:20px;font-family:Courier New,Courier,monospace}.ngx-pagination__list li.active a,.ngx-pagination__list li.active span{background:var(--ngx-table-accent, #4f46e5);color:#fff;cursor:default}.ngx-pagination__list li.disabled{opacity:.4;pointer-events:none}.ngx-pagination__list li:hover:not(.active):not(.disabled) a{background:color-mix(in srgb,var(--ngx-table-accent, #4f46e5) 12%,transparent)}.ngx-pagination__page-size{display:flex;align-items:center;gap:.5rem}.ngx-pagination__page-size select{border-radius:6px;padding:.25rem .5rem;font-size:.8125rem}\n"], dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.NgSelectOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i1.ɵNgSelectMultipleOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i1.SelectControlValueAccessor, selector: "select:not([multiple]):not([ngNoCva])[formControlName],select:not([multiple]):not([ngNoCva])[formControl],select:not([multiple]):not([ngNoCva])[ngModel]", inputs: ["compareWith"] }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
121
310
  }
122
311
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.4", ngImport: i0, type: NgxPagination, decorators: [{
123
312
  type: Component,
124
- args: [{ selector: 'ngx-pagination', imports: [FormsModule], template: "<nav class=\"ngx-pagination\">\r\n <div class=\"\">\r\n {{ labels().showing }}\r\n <span class=\"fw-semibold\">{{ firstItem() }}</span>\r\n {{ labels().to }}\r\n <span class=\"fw-semibold\">{{ lastItem() }}</span>\r\n {{ labels().of }}\r\n <span class=\"fw-semibold\">{{ total() }}</span>\r\n {{ labels().results }}\r\n </div>\r\n\r\n <div class=\"ngx-paination_page-numbers\">\r\n <ul>\r\n <!-- Previous Page Link -->\r\n <li [class.disabled]=\"page() === 1\" [title]=\"labels().first\">\r\n <a (click)=\"first()\">\r\n <svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 448 512\">\r\n <path\r\n fill=\"currentColor\"\r\n d=\"M235.8 453.1L53.8 256l181.1-197.1c2.844-3.078 4.25-6.969 4.25-10.86c0-4.312-1.719-8.609-5.156-11.75c-6.5-6-16.59-5.594-22.59 .8906l-192 208c-5.688 6.156-5.688 15.56 0 21.72l192 208c6 6.484 16.09 6.891 22.59 .8906C241.4 469.8 241.8 459.6 235.8 453.1zM212.2 245.1c-5.688 6.156-5.688 15.56 0 21.72l192 208c6 6.484 16.09 6.891 22.59 .8906c6.531-5.969 6.906-16.11 .9062-22.61l-181.1-197.1l181.1-197.1c2.844-3.078 4.25-6.969 4.25-10.86c0-4.312-1.719-8.609-5.156-11.75c-6.5-6-16.59-5.594-22.59 .8906L212.2 245.1z\" />\r\n </svg>\r\n </a>\r\n </li>\r\n <li [class.disabled]=\"page() === 1\" [title]=\"labels().previous\">\r\n <a (click)=\"previous()\">\r\n <svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 320 512\">\r\n <path\r\n fill=\"currentColor\"\r\n d=\"M234.8 36.25c3.438 3.141 5.156 7.438 5.156 11.75c0 3.891-1.406 7.781-4.25 10.86L53.77 256l181.1 197.1c6 6.5 5.625 16.64-.9062 22.61c-6.5 6-16.59 5.594-22.59-.8906l-192-208c-5.688-6.156-5.688-15.56 0-21.72l192-208C218.2 30.66 228.3 30.25 234.8 36.25z\" />\r\n </svg>\r\n </a>\r\n </li>\r\n\r\n <!-- Pagination Elements -->\r\n @for (item of pages(); track $index) {\r\n <li class=\"page-num\" [class.active]=\"+item === page()\">\r\n @if (item !== page() && item != '...') {\r\n <a (click)=\"goto(+item)\">{{ item }}</a>\r\n }\r\n @if (item === page() || item == '...') {\r\n <span>{{ item }}</span>\r\n }\r\n </li>\r\n }\r\n\r\n <!-- Next Page Link -->\r\n <li [class.disabled]=\"page() === totalPages()\" [title]=\"labels().next\">\r\n <a (click)=\"next()\">\r\n <svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 320 512\">\r\n <path\r\n fill=\"currentColor\"\r\n d=\"M85.14 475.8c-3.438-3.141-5.156-7.438-5.156-11.75c0-3.891 1.406-7.781 4.25-10.86l181.1-197.1L84.23 58.86c-6-6.5-5.625-16.64 .9062-22.61c6.5-6 16.59-5.594 22.59 .8906l192 208c5.688 6.156 5.688 15.56 0 21.72l-192 208C101.7 481.3 91.64 481.8 85.14 475.8z\" />\r\n </svg>\r\n </a>\r\n </li>\r\n <li [class.disabled]=\"page() === totalPages()\" [title]=\"labels().last\">\r\n <a (click)=\"last()\">\r\n <svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 448 512\">\r\n <path\r\n fill=\"currentColor\"\r\n d=\"M212.2 58.86l181.1 197.1L212.2 453.1c-2.844 3.078-4.25 6.969-4.25 10.86c0 4.312 1.719 8.609 5.156 11.75c6.5 6 16.59 5.594 22.59-.8906l192-208c5.688-6.156 5.688-15.56 0-21.72l-192-208c-6-6.484-16.09-6.891-22.59-.8906C206.6 42.22 206.2 52.36 212.2 58.86zM235.8 266.9c5.688-6.156 5.688-15.56 0-21.72l-192-208c-6-6.484-16.09-6.891-22.59-.8906c-6.531 5.969-6.906 16.11-.9062 22.61l181.1 197.1L20.26 453.1c-2.844 3.078-4.25 6.969-4.25 10.86c0 4.312 1.719 8.609 5.156 11.75c6.5 6 16.59 5.594 22.59-.8906L235.8 266.9z\" />\r\n </svg>\r\n </a>\r\n </li>\r\n </ul>\r\n\r\n <div class=\"ngx-paination_page-size\">\r\n <span>{{ labels().pageSize }}:</span>\r\n <select\r\n name=\"pageSize\"\r\n [ngModel]=\"pageSize()\"\r\n (ngModelChange)=\"pageSize.update((u) => (u = $event))\">\r\n @for (opt of pageSizeOptions(); track $index) {\r\n <option [value]=\"opt\" [selected]=\"opt === pageSize()\">\r\n {{ opt }}\r\n </option>\r\n }\r\n </select>\r\n </div>\r\n </div>\r\n</nav>\r\n", styles: [":host{--ngx-pagination-border: light-dark(#dbdbdb, #373737);--ngx-pagination-border-radius: 4px;--bs-pagination-active-bg: light-dark(#6485fa, #6485fa)}.ngx-pagination{display:flex;align-items:center;justify-content:space-between;padding:15px 0;-webkit-user-select:none;user-select:none}.ngx-paination_page-numbers{display:flex;gap:5px}.ngx-paination_page-numbers ul{display:flex;padding:0;margin:0;gap:2px;list-style:none}.ngx-paination_page-numbers ul li{padding:5px 10px;border:1px var(--ngx-pagination-border) solid;border-radius:var(--ngx-pagination-border-radius);cursor:pointer}.ngx-paination_page-numbers ul li.disabled{cursor:not-allowed;opacity:.4}.ngx-paination_page-numbers ul li.active:not(:disabled){background-color:var(--bs-pagination-active-bg)}.ngx-paination_page-numbers ul li a{display:block;color:inherit;text-decoration:none;width:100%;height:100%}.ngx-paination_page-numbers ul li a svg{width:100%;height:12px}.ngx-paination_page-size{display:flex;align-items:center;gap:5px}.ngx-paination_page-size span{white-space:nowrap}.ngx-paination_page-size select{border-radius:var(--ngx-pagination-border-radius);height:100%}::ng-deep [dir=rtl] .ngx-paination_page-numbers li svg{transform:rotate(180deg)}\n"] }]
313
+ args: [{ selector: 'ngx-pagination', standalone: true, imports: [FormsModule], changeDetection: ChangeDetectionStrategy.OnPush, template: "<nav class=\"ngx-pagination\">\n <div class=\"ngx-pagination__summary\">\n {{ labels().showing }}\n <span class=\"fw-semibold\">{{ firstItem() }}</span>\n {{ labels().to }}\n <span class=\"fw-semibold\">{{ lastItem() }}</span>\n {{ labels().of }}\n <span class=\"fw-semibold\">{{ total() }}</span>\n {{ labels().results }}\n </div>\n\n <div class=\"ngx-pagination__controls\">\n <ul class=\"ngx-pagination__list\">\n <li [class.disabled]=\"page() === 1\" [title]=\"labels().first\">\n <a (click)=\"first()\" class=\"icon\">\u00AB</a>\n </li>\n <li [class.disabled]=\"page() === 1\" [title]=\"labels().previous\">\n <a (click)=\"previous()\" class=\"icon\">\u2039</a>\n </li>\n\n @for (item of pages(); track $index) {\n <li class=\"ngx-pagination__page-num\" [class.active]=\"item === page()\">\n @if (item !== page() && item !== '...') {\n <a (click)=\"goto(+item)\">{{ item }}</a>\n }\n @if (item === page() || item === '...') {\n <span>{{ item }}</span>\n }\n </li>\n }\n\n <li [class.disabled]=\"page() === totalPages()\" [title]=\"labels().next\">\n <a (click)=\"next()\" class=\"icon\">\u203A</a>\n </li>\n <li [class.disabled]=\"page() === totalPages()\" [title]=\"labels().last\">\n <a (click)=\"last()\" class=\"icon\">\u00BB</a>\n </li>\n </ul>\n\n <div class=\"ngx-pagination__page-size\">\n <span>{{ labels().pageSize }}:</span>\n <select [ngModel]=\"pageSize()\" (ngModelChange)=\"onPageSizeChange($event)\">\n @for (opt of pageSizeOptions(); track opt) {\n <option [value]=\"opt\" [selected]=\"opt === pageSize()\">{{ opt }}</option>\n }\n </select>\n </div>\n </div>\n</nav>\n", styles: [".ngx-pagination{display:flex;align-items:center;justify-content:space-between;flex-wrap:wrap;gap:.75rem;padding:.625rem 1rem;font-size:.8125rem}.ngx-pagination__controls{display:flex;align-items:center;gap:1rem;flex-wrap:wrap}.ngx-pagination__list{display:flex;align-items:center;gap:.25rem;list-style:none;margin:0;padding:0}.ngx-pagination__list li{min-width:1.75rem;height:1.75rem;display:inline-flex;align-items:center;justify-content:center;border-radius:6px}.ngx-pagination__list li a,.ngx-pagination__list li span{display:inline-flex;align-items:center;justify-content:center;width:100%;height:100%;cursor:pointer;border-radius:6px;-webkit-user-select:none;user-select:none}.ngx-pagination__list li a.icon,.ngx-pagination__list li span.icon{font-size:20px;font-family:Courier New,Courier,monospace}.ngx-pagination__list li.active a,.ngx-pagination__list li.active span{background:var(--ngx-table-accent, #4f46e5);color:#fff;cursor:default}.ngx-pagination__list li.disabled{opacity:.4;pointer-events:none}.ngx-pagination__list li:hover:not(.active):not(.disabled) a{background:color-mix(in srgb,var(--ngx-table-accent, #4f46e5) 12%,transparent)}.ngx-pagination__page-size{display:flex;align-items:center;gap:.5rem}.ngx-pagination__page-size select{border-radius:6px;padding:.25rem .5rem;font-size:.8125rem}\n"] }]
125
314
  }], ctorParameters: () => [], propDecorators: { total: [{ type: i0.Input, args: [{ isSignal: true, alias: "total", required: true }] }], page: [{ type: i0.Input, args: [{ isSignal: true, alias: "page", required: false }] }, { type: i0.Output, args: ["pageChange"] }], pageSize: [{ type: i0.Input, args: [{ isSignal: true, alias: "pageSize", required: false }] }, { type: i0.Output, args: ["pageSizeChange"] }], pageSizeOptions: [{ type: i0.Input, args: [{ isSignal: true, alias: "pageSizeOptions", required: false }] }], labels: [{ type: i0.Input, args: [{ isSignal: true, alias: "labels", required: false }] }], siblingCount: [{ type: i0.Input, args: [{ isSignal: true, alias: "siblingCount", required: false }] }], boundaryCount: [{ type: i0.Input, args: [{ isSignal: true, alias: "boundaryCount", required: false }] }], paginate: [{ type: i0.Output, args: ["paginate"] }] } });
126
315
 
127
- class TableCellDirective {
128
- column = input.required({ ...(ngDevMode ? { debugName: "column" } : /* istanbul ignore next */ {}), alias: 'ngxTableCell' });
129
- template = inject(TemplateRef);
130
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.4", ngImport: i0, type: TableCellDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
131
- static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "22.0.4", type: TableCellDirective, isStandalone: true, selector: "ng-template[ngxTableCell]", inputs: { column: { classPropertyName: "column", publicName: "ngxTableCell", isSignal: true, isRequired: true, transformFunction: null } }, ngImport: i0 });
132
- }
133
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.4", ngImport: i0, type: TableCellDirective, decorators: [{
134
- type: Directive,
135
- args: [{
136
- selector: 'ng-template[ngxTableCell]',
137
- }]
138
- }], propDecorators: { column: [{ type: i0.Input, args: [{ isSignal: true, alias: "ngxTableCell", required: true }] }] } });
139
-
140
- /** Injected into every ngx-table instance. Populate via provideTable(). */
141
- const NGX_TABLE_CONFIG = new InjectionToken('NGX_TABLE_CONFIG', {
142
- factory: () => NGX_TABLE_CONFIG_DEFAULT,
143
- });
144
- const NGX_TABLE_CONFIG_DEFAULT = {
145
- showRecordNumber: true,
146
- hoverable: true,
147
- multiSort: true,
148
- resizable: false,
149
- stickyHeader: true,
150
- stripedRows: true,
151
- labels: {
152
- noData: 'There is no data to display!',
153
- loading: 'Loading...',
154
- operation: 'Operation',
155
- },
156
- renderers: {},
157
- formatters: {},
158
- };
159
-
316
+ /**
317
+ * جدول داده‌ی جنریک و Type-Safe.
318
+ *
319
+ * `T` از روی چیزی که به [data] بایند می‌کنید استنتاج می‌شود؛ `field.column` در
320
+ * `TableField<T, R>` محدود به `keyof T` است، و اگر از defineFields(renderers, ...)
321
+ * استفاده کنید، `field.renderer` محدود به کلیدهای رجیستری و `rendererInputs`
322
+ * دقیقاً همان ورودی‌های اضافه‌ی همان renderer است.
323
+ *
324
+ * دو حالت:
325
+ * - کلاینت‌ساید (پیش‌فرض): [data] کل آرایه است؛ سورت/صفحه‌بندی داخلی و روی
326
+ * یک computed خالص انجام می‌شود (بدون mutation روی آبجکت‌های شما).
327
+ * - lazy: [lazy]="true" + [totalRecords]؛ [data] فقط صفحه‌ی جاری است؛ به
328
+ * (lazyLoad) گوش بدهید.
329
+ */
160
330
  class NgxTable {
161
331
  config = inject(NGX_TABLE_CONFIG);
162
332
  paginationConfig = inject(NGX_PAGINATION_CONFIG);
333
+ // ---------------------------------------------------------------- inputs
163
334
  fields = input.required(/* @ts-ignore */
164
335
  ...(ngDevMode ? [{ debugName: "fields" }] : /* istanbul ignore next */ []));
165
336
  data = input.required(/* @ts-ignore */
@@ -168,8 +339,6 @@ class NgxTable {
168
339
  ...(ngDevMode ? [{ debugName: "totalRecords" }] : /* istanbul ignore next */ []));
169
340
  showRecordNumber = input(this.config.showRecordNumber, /* @ts-ignore */
170
341
  ...(ngDevMode ? [{ debugName: "showRecordNumber" }] : /* istanbul ignore next */ []));
171
- list = signal([], /* @ts-ignore */
172
- ...(ngDevMode ? [{ debugName: "list" }] : /* istanbul ignore next */ []));
173
342
  operations = input(/* @ts-ignore */
174
343
  ...(ngDevMode ? [undefined, { debugName: "operations" }] : /* istanbul ignore next */ []));
175
344
  operationWidth = input(60, /* @ts-ignore */
@@ -180,105 +349,213 @@ class NgxTable {
180
349
  ...(ngDevMode ? [{ debugName: "pageSize" }] : /* istanbul ignore next */ []));
181
350
  loading = input(false, /* @ts-ignore */
182
351
  ...(ngDevMode ? [{ debugName: "loading" }] : /* istanbul ignore next */ []));
183
- multiSort = input(this.config.multiSort, /* @ts-ignore */
352
+ multiSort = input(undefined, /* @ts-ignore */
184
353
  ...(ngDevMode ? [{ debugName: "multiSort" }] : /* istanbul ignore next */ []));
185
354
  lazy = input(false, /* @ts-ignore */
186
355
  ...(ngDevMode ? [{ debugName: "lazy" }] : /* istanbul ignore next */ []));
356
+ /** پیش‌فرض بر اساس ایندکس؛ برای جلوگیری از گم‌شدن state سطرها هنگام سورت،
357
+ * یک شناسه‌ی یکتا بدهید: [trackBy]="(i, row) => row.id" */
358
+ trackBy = input((index) => index, /* @ts-ignore */
359
+ ...(ngDevMode ? [{ debugName: "trackBy" }] : /* istanbul ignore next */ []));
360
+ // --------------------------------------------------------------- outputs
187
361
  lazyLoad = output();
188
- sortField = '';
189
- sortDirection = 'asc';
190
- tableContainer = viewChild('tableContainer', /* @ts-ignore */
191
- ...(ngDevMode ? [{ debugName: "tableContainer" }] : /* istanbul ignore next */ []));
192
- sortChange = new EventEmitter();
362
+ sortChange = output();
363
+ columnResize = output();
364
+ // ------------------------------------------------------------ int. state
365
+ page = signal(1, /* @ts-ignore */
366
+ ...(ngDevMode ? [{ debugName: "page" }] : /* istanbul ignore next */ []));
367
+ pageSizeS = signal(this.paginationConfig.defaultPageSize, /* @ts-ignore */
368
+ ...(ngDevMode ? [{ debugName: "pageSizeS" }] : /* istanbul ignore next */ []));
369
+ sorts = signal([], /* @ts-ignore */
370
+ ...(ngDevMode ? [{ debugName: "sorts" }] : /* istanbul ignore next */ []));
371
+ widths = signal({}, /* @ts-ignore */
372
+ ...(ngDevMode ? [{ debugName: "widths" }] : /* istanbul ignore next */ []));
373
+ manuallyResized = new Set();
374
+ rendererInputsCache = new Map();
193
375
  cellTemplates;
194
376
  templateMap = new Map();
195
- page = 1;
377
+ resolvedMultiSort = computed(() => this.multiSort() ?? this.config.multiSort, /* @ts-ignore */
378
+ ...(ngDevMode ? [{ debugName: "resolvedMultiSort" }] : /* istanbul ignore next */ []));
379
+ directionService = inject(DirectionService);
380
+ resolvedDirection = computed(() => this.directionService.direction(), /* @ts-ignore */
381
+ ...(ngDevMode ? [{ debugName: "resolvedDirection" }] : /* istanbul ignore next */ []));
196
382
  constructor() {
197
383
  effect(() => {
198
- const data = this.data();
199
- data.map((r, index) => (r.ngxRecordNumber = this.pageSize() * (this.page - 1) + index + 1));
200
- if (this.lazy()) {
201
- this.list.set(data);
202
- return;
384
+ const ps = this.pageSize();
385
+ if (ps)
386
+ this.pageSizeS.set(ps);
387
+ });
388
+ // برای هر ستونِ تازه‌دیده‌شده یک عرض seed کن؛ ستون‌هایی که کاربر دستی
389
+ // ریسایز کرده دیگر هیچ‌وقت دوباره نوشته نمی‌شوند.
390
+ effect(() => {
391
+ const cols = this.fields();
392
+ const current = this.widths();
393
+ let changed = false;
394
+ const next = { ...current };
395
+ for (const f of cols) {
396
+ if (!(f.column in next) && !this.manuallyResized.has(f.column)) {
397
+ next[f.column] = f.width ?? this.config.column.defaultWidth;
398
+ changed = true;
399
+ }
203
400
  }
204
- this.loadClientPage(data);
401
+ if (changed)
402
+ this.widths.set(next);
205
403
  });
206
404
  }
207
405
  ngOnInit() {
208
406
  if (this.lazy()) {
209
- this.lazyLoad.emit({
210
- first: 0,
211
- pageIndex: 1,
212
- pageSize: this.pageSize(),
213
- sorts: [],
214
- });
407
+ this.lazyLoad.emit({ first: 0, pageIndex: 1, pageSize: this.pageSizeS(), sorts: [] });
215
408
  }
216
409
  }
217
410
  ngAfterContentInit() {
411
+ this.syncTemplateMap();
412
+ this.cellTemplates.changes.subscribe(() => this.syncTemplateMap());
413
+ }
414
+ syncTemplateMap() {
218
415
  this.templateMap.clear();
219
416
  this.cellTemplates.forEach((cell) => {
220
- // console.log(cell.columnName, cell.template);
221
- this.templateMap.set(cell.column.name, cell.template);
417
+ // نکته‌ی مهم: cell.column() باید فراخوانی شود (سیگنال است)، نه cell.column.name.
418
+ this.templateMap.set(cell.column(), cell.templateRef);
222
419
  });
223
- this.adjustScroll(this.tableContainer()?.nativeElement);
224
- }
225
- loadClientPage(data) {
226
- const from = (this.page - 1) * this.pageSize();
227
- const to = from + this.pageSize();
228
- this.list.set(data.slice(from, to));
229
420
  }
230
- onSortChange(item) { }
231
- getTemplate(column) {
232
- return this.templateMap.get(column) ?? null;
421
+ // ------------------------------------------------------------- داده‌ها
422
+ sortedData = computed(() => {
423
+ if (this.lazy())
424
+ return this.data();
425
+ const sorts = this.sorts();
426
+ if (sorts.length === 0)
427
+ return this.data();
428
+ const copy = [...this.data()];
429
+ copy.sort((a, b) => {
430
+ for (const s of sorts) {
431
+ const cmp = this.compare(a[s.field], b[s.field]);
432
+ if (cmp !== 0)
433
+ return s.direction === 'asc' ? cmp : -cmp;
434
+ }
435
+ return 0;
436
+ });
437
+ return copy;
438
+ }, /* @ts-ignore */
439
+ ...(ngDevMode ? [{ debugName: "sortedData" }] : /* istanbul ignore next */ []));
440
+ totalCount = computed(() => this.lazy() ? this.totalRecords() : this.data().length, /* @ts-ignore */
441
+ ...(ngDevMode ? [{ debugName: "totalCount" }] : /* istanbul ignore next */ []));
442
+ pagedData = computed(() => {
443
+ if (this.lazy())
444
+ return this.sortedData();
445
+ const start = (this.page() - 1) * this.pageSizeS();
446
+ return this.sortedData().slice(start, start + this.pageSizeS());
447
+ }, /* @ts-ignore */
448
+ ...(ngDevMode ? [{ debugName: "pagedData" }] : /* istanbul ignore next */ []));
449
+ compare(a, b) {
450
+ if (a == null && b == null)
451
+ return 0;
452
+ if (a == null)
453
+ return -1;
454
+ if (b == null)
455
+ return 1;
456
+ if (typeof a === 'number' && typeof b === 'number')
457
+ return a - b;
458
+ if (typeof a === 'boolean' && typeof b === 'boolean')
459
+ return a === b ? 0 : a ? 1 : -1;
460
+ if (a instanceof Date && b instanceof Date)
461
+ return a.getTime() - b.getTime();
462
+ return String(a).localeCompare(String(b));
233
463
  }
234
- sortList() {
235
- // this._list = orderBy(this._list, [this.sortField], [this.sortDirection]);
464
+ /** بدون mutation روی داده‌ی ورودی: شماره‌ی ردیف صرفاً از روی page/pageSize/rowIndex محاسبه می‌شود. */
465
+ recordNumber(rowIndex) {
466
+ return (this.page() - 1) * this.pageSizeS() + rowIndex + 1;
236
467
  }
237
- getRecordNumber(item) {
238
- debugger;
239
- return item.ngxRecordNumber;
468
+ // -------------------------------------------------------------- سورت
469
+ sortDirectionFor(column) {
470
+ return this.sorts().find((s) => s.field === column)?.direction ?? null;
240
471
  }
241
- onPageChange(event) {
242
- console.log('p', event);
243
- this.page = event.page;
244
- if (this.lazy()) {
245
- this.lazyLoad.emit({
246
- first: (event.page - 1) * event.pageSize,
247
- pageIndex: event.page,
248
- pageSize: event.pageSize,
249
- sorts: this.sortField
250
- ? [
251
- {
252
- field: this.sortField,
253
- direction: this.sortDirection,
254
- },
255
- ]
256
- : [],
257
- });
472
+ onHeaderClick(field, event) {
473
+ if (!field.sortable)
258
474
  return;
475
+ const column = field.column;
476
+ const current = this.sorts();
477
+ const existingIndex = current.findIndex((s) => s.field === column);
478
+ const isMultiGesture = this.resolvedMultiSort() && (event.shiftKey || event.ctrlKey || event.metaKey);
479
+ let next;
480
+ if (isMultiGesture) {
481
+ next = [...current];
482
+ if (existingIndex === -1) {
483
+ next.push({ field: column, direction: 'asc' });
484
+ }
485
+ else if (next[existingIndex].direction === 'asc') {
486
+ next[existingIndex] = { field: column, direction: 'desc' };
487
+ }
488
+ else {
489
+ next.splice(existingIndex, 1);
490
+ }
491
+ }
492
+ else if (existingIndex === -1 || current.length > 1) {
493
+ next = [{ field: column, direction: 'asc' }];
259
494
  }
260
- this.loadClientPage(this.data());
495
+ else if (current[0].direction === 'asc') {
496
+ next = [{ field: column, direction: 'desc' }];
497
+ }
498
+ else {
499
+ next = [];
500
+ }
501
+ this.sorts.set(next);
502
+ this.page.set(1);
503
+ this.sortChange.emit(next);
504
+ this.emitLazyIfNeeded();
261
505
  }
262
- /**
263
- * اگر بدنه جدول اسکرول شد هدر جدول نیز منطبق شود
264
- */
265
- adjustScroll(table) {
266
- if (!table)
267
- return;
268
- const body = table.querySelector('.tbody-mrs');
269
- const header = table.querySelector('.thead-mrs');
270
- if (!body || !header)
506
+ // ------------------------------------------------------------ صفحه‌بندی
507
+ onPaginate(event) {
508
+ this.page.set(event.page);
509
+ this.pageSizeS.set(event.pageSize);
510
+ this.emitLazyIfNeeded();
511
+ }
512
+ emitLazyIfNeeded() {
513
+ if (!this.lazy())
271
514
  return;
272
- body.addEventListener('scroll', () => {
273
- header.scrollLeft = body.scrollLeft;
515
+ const pageIndex = this.page();
516
+ const pageSize = this.pageSizeS();
517
+ this.lazyLoad.emit({
518
+ pageIndex,
519
+ pageSize,
520
+ first: (pageIndex - 1) * pageSize,
521
+ sorts: this.sorts(),
274
522
  });
275
523
  }
524
+ // -------------------------------------------------------------- ریسایز
525
+ columnWidth(column) {
526
+ return this.widths()[column] ?? this.config.column.defaultWidth;
527
+ }
528
+ columnMin(field) {
529
+ return field.minWidth ?? this.config.column.minWidth;
530
+ }
531
+ columnMax(field) {
532
+ return field.maxWidth ?? this.config.column.maxWidth;
533
+ }
534
+ isResizable(field) {
535
+ return (field.resizable ?? this.config.resizable) !== false;
536
+ }
537
+ onColumnResizing(column, width) {
538
+ this.widths.update((w) => ({ ...w, [column]: width }));
539
+ }
540
+ onColumnResizeEnd(column, width) {
541
+ this.manuallyResized.add(column);
542
+ this.widths.update((w) => ({ ...w, [column]: width }));
543
+ this.columnResize.emit({ field: column, width });
544
+ }
545
+ // --------------------------------------------------------------- سلول‌ها
546
+ getTemplate(column) {
547
+ const fromDirective = this.templateMap.get(column);
548
+ if (fromDirective)
549
+ return fromDirective;
550
+ const fromFieldConfig = this.fields().find((f) => f.column === column)?.cellTemplate;
551
+ return fromFieldConfig ?? null;
552
+ }
276
553
  getRenderer(field) {
277
- const key = field.renderer ?? field.dataType;
278
- if (!key) {
554
+ if (!field.renderer)
279
555
  return null;
280
- }
281
- return this.config.renderers?.[key] ?? null;
556
+ // نکته: نوع دقیق field.renderer (که به کلیدهای رجیستری محدود است) در
557
+ // defineFields() چک می‌شود؛ اینجا فقط یک lookup رانتایم ساده لازم است.
558
+ return this.config.renderers[field.renderer] ?? null;
282
559
  }
283
560
  getCellValue(row, field) {
284
561
  return row[field.column];
@@ -289,83 +566,54 @@ class NgxTable {
289
566
  return this.stringify(field.formatter(value, row, field));
290
567
  }
291
568
  if (typeof field.formatter === 'string') {
292
- const formatter = this.config.formatters?.[field.formatter];
293
- if (formatter) {
569
+ const formatter = this.config.formatters[field.formatter];
570
+ if (formatter)
294
571
  return this.stringify(formatter(value, row, field));
295
- }
296
572
  }
297
573
  return this.stringify(value);
298
574
  }
299
575
  stringify(value) {
300
576
  return value == null ? '' : String(value);
301
577
  }
578
+ /** ورودی‌های renderer را به‌ازای هر (field, row) کش می‌کند تا هر Change
579
+ * Detection یک آبجکت جدید ساخته نشود؛ با WeakMap، وقتی row از حافظه خارج
580
+ * شود (مثلاً بعد از عوض‌شدن صفحه)، entry آن هم خودکار پاک می‌شود. */
302
581
  getRendererInputs(row, field) {
303
- return {
304
- value: this.getCellValue(row, field),
305
- row,
306
- field,
307
- ...field.rendererInputs,
308
- };
582
+ let fieldCache = this.rendererInputsCache.get(field);
583
+ if (!fieldCache) {
584
+ fieldCache = new WeakMap();
585
+ this.rendererInputsCache.set(field, fieldCache);
586
+ }
587
+ let inputs = fieldCache.get(row);
588
+ if (!inputs) {
589
+ inputs = {
590
+ value: this.getCellValue(row, field),
591
+ row,
592
+ field,
593
+ ...(field.renderer ? field.rendererInputs : undefined),
594
+ };
595
+ fieldCache.set(row, inputs);
596
+ }
597
+ return inputs;
309
598
  }
310
599
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.4", ngImport: i0, type: NgxTable, deps: [], target: i0.ɵɵFactoryTarget.Component });
311
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.4", type: NgxTable, isStandalone: true, selector: "ngx-table", inputs: { fields: { classPropertyName: "fields", publicName: "fields", isSignal: true, isRequired: true, transformFunction: null }, data: { classPropertyName: "data", publicName: "data", isSignal: true, isRequired: true, transformFunction: null }, totalRecords: { classPropertyName: "totalRecords", publicName: "totalRecords", isSignal: true, isRequired: true, transformFunction: null }, showRecordNumber: { classPropertyName: "showRecordNumber", publicName: "showRecordNumber", isSignal: true, isRequired: false, transformFunction: null }, operations: { classPropertyName: "operations", publicName: "operations", isSignal: true, isRequired: false, transformFunction: null }, operationWidth: { classPropertyName: "operationWidth", publicName: "operationWidth", isSignal: true, isRequired: false, transformFunction: null }, numWidth: { classPropertyName: "numWidth", publicName: "numWidth", isSignal: true, isRequired: false, transformFunction: null }, pageSize: { classPropertyName: "pageSize", publicName: "pageSize", isSignal: true, isRequired: false, transformFunction: null }, loading: { classPropertyName: "loading", publicName: "loading", isSignal: true, isRequired: false, transformFunction: null }, multiSort: { classPropertyName: "multiSort", publicName: "multiSort", isSignal: true, isRequired: false, transformFunction: null }, lazy: { classPropertyName: "lazy", publicName: "lazy", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { lazyLoad: "lazyLoad", sortChange: "sortChange" }, providers: [], queries: [{ propertyName: "cellTemplates", predicate: TableCellDirective }], viewQueries: [{ propertyName: "tableContainer", first: true, predicate: ["tableContainer"], descendants: true, isSignal: true }], ngImport: i0, template: "<div class=\"table-responsive\" #tableContainer>\r\n <div class=\"table-mrs\">\r\n <div class=\"thead-mrs\">\r\n <div class=\"tr-mrs\">\r\n @if (operations()) {\r\n <div\r\n class=\"th-mrs operations\"\r\n [style.max-width.px]=\"operationWidth()\"\r\n [style.min-width.px]=\"operationWidth()\">\r\n {{ config.labels.operation }}\r\n </div>\r\n }\r\n @if (showRecordNumber()) {\r\n <div\r\n class=\"th-mrs operations\"\r\n [style.max-width.px]=\"numWidth()\"\r\n [style.min-width.px]=\"numWidth()\">\r\n #\r\n </div>\r\n }\r\n @for (item of fields(); track $index) {\r\n <div class=\"th-mrs\" [style.max-width.px]=\"item.width\" [style.min-width.px]=\"item.width\">\r\n {{ item.title }}\r\n <span\r\n class=\"sort-icon\"\r\n [class.active]=\"sortField == item.column\"\r\n (click)=\"onSortChange(item)\">\r\n @if (sortField == item.column && sortDirection == 'asc') {\r\n <svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 576 512\">\r\n <path\r\n fill=\"currentColor\"\r\n d=\"M368 432h-64c-8.844 0-15.1 7.156-15.1 16S295.2 464 304 464h64c8.844 0 16-7.156 16-16S376.8 432 368 432zM432 304h-128c-8.844 0-15.1 7.156-15.1 16S295.2 336 304 336h128c8.844 0 16-7.156 16-16S440.8 304 432 304zM496 176h-192c-8.844 0-15.1 7.156-15.1 16S295.2 208 304 208h192C504.8 208 512 200.8 512 192S504.8 176 496 176zM560 48h-256c-8.844 0-15.1 7.156-15.1 16S295.2 80 304 80h256C568.8 80 576 72.84 576 64S568.8 48 560 48zM224 352c-4.094 0-8.188 1.562-11.31 4.688L144 425.4V48C144 39.16 136.8 32 128 32S112 39.16 112 48v377.4l-68.69-68.69c-6.25-6.25-16.38-6.25-22.62 0s-6.25 16.38 0 22.62l96 96c6.25 6.25 16.38 6.25 22.62 0l96-96c6.25-6.25 6.25-16.38 0-22.62C232.2 353.6 228.1 352 224 352z\" />\r\n </svg>\r\n } @else if (sortField == item.column && sortDirection == 'desc') {\r\n <svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 576 512\">\r\n <path\r\n fill=\"currentColor\"\r\n d=\"M304 208h128C440.8 208 448 200.8 448 192s-7.156-16-16-16h-128c-8.844 0-15.1 7.156-15.1 16S295.2 208 304 208zM304 336h192c8.844 0 16-7.156 16-16s-7.156-16-16-16h-192c-8.844 0-15.1 7.156-15.1 16S295.2 336 304 336zM304 80h64c8.844 0 16-7.156 16-16S376.8 48 368 48h-64c-8.844 0-15.1 7.156-15.1 16S295.2 80 304 80zM560 432h-256c-8.844 0-15.1 7.156-15.1 16S295.2 464 304 464h256c8.844 0 16-7.156 16-16S568.8 432 560 432zM224 352c-4.094 0-8.188 1.562-11.31 4.688L144 425.4V48C144 39.16 136.8 32 128 32S112 39.16 112 48v377.4l-68.69-68.69c-6.25-6.25-16.38-6.25-22.62 0s-6.25 16.38 0 22.62l96 96c6.25 6.25 16.38 6.25 22.62 0l96-96c6.25-6.25 6.25-16.38 0-22.62C232.2 353.6 228.1 352 224 352z\" />\r\n </svg>\r\n } @else {\r\n <svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 448 512\">\r\n <path\r\n fill=\"currentColor\"\r\n d=\"M224 352c-4.094 0-8.188 1.562-11.31 4.688L144 425.4V48C144 39.16 136.8 32 128 32S112 39.16 112 48v377.4l-68.69-68.69c-6.25-6.25-16.38-6.25-22.62 0s-6.25 16.38 0 22.62l96 96c6.25 6.25 16.38 6.25 22.62 0l96-96c6.25-6.25 6.25-16.38 0-22.62C232.2 353.6 228.1 352 224 352zM427.3 132.7l-96-96c-6.25-6.25-16.38-6.25-22.62 0l-96 96c-6.25 6.25-6.25 16.38 0 22.62s16.38 6.25 22.62 0L304 86.63V464c0 8.844 7.156 16 16 16s16-7.156 16-16V86.63l68.69 68.69C407.8 158.4 411.9 160 416 160s8.188-1.562 11.31-4.688C433.6 149.1 433.6 138.9 427.3 132.7z\" />\r\n </svg>\r\n }\r\n </span>\r\n </div>\r\n }\r\n </div>\r\n </div>\r\n <div class=\"tbody-mrs\">\r\n @if (!loading() && list().length === 0) {\r\n <div class=\"no-data\">{{ config.labels.noData }}</div>\r\n }\r\n @for (item of list(); track $index) {\r\n @let num = getRecordNumber(item);\r\n <div class=\"tr-mrs\">\r\n @if (operations()) {\r\n <div\r\n class=\"td-mrs operations\"\r\n vAlign=\"middle\"\r\n [style.max-width.px]=\"operationWidth()\"\r\n [style.min-width.px]=\"operationWidth()\">\r\n <div class=\"cel\">\r\n <span class=\"cell-title\">{{ config.labels.operation }}:</span>\r\n <ng-container\r\n [ngTemplateOutlet]=\"operations()\"\r\n [ngTemplateOutletContext]=\"{ $implicit: item }\"></ng-container>\r\n </div>\r\n </div>\r\n }\r\n\r\n @if (showRecordNumber()) {\r\n <div\r\n class=\"td-mrs operations\"\r\n vAlign=\"middle\"\r\n [style.max-width.px]=\"numWidth()\"\r\n [style.min-width.px]=\"numWidth()\">\r\n <div class=\"cel\">\r\n <span class=\"cell-title\"></span>\r\n {{ num }}\r\n </div>\r\n </div>\r\n }\r\n\r\n @for (f of fields(); track f.column) {\r\n @let template = getTemplate(f.column);\r\n @let renderer = getRenderer(f);\r\n\r\n <div\r\n class=\"td-mrs\"\r\n vAlign=\"middle\"\r\n [style.max-width.px]=\"f.width\"\r\n [style.min-width.px]=\"f.width\">\r\n <div class=\"cel\" [class.wrap]=\"f.wrap\">\r\n <span class=\"cell-title\">{{ f.title }}</span>\r\n @if (template) {\r\n <ng-container\r\n [ngTemplateOutlet]=\"template\"\r\n [ngTemplateOutletContext]=\"{\r\n $implicit: item,\r\n row: item,\r\n value: getCellValue(item, f),\r\n field: f,\r\n }\"></ng-container>\r\n } @else if (renderer) {\r\n <ng-container\r\n *ngComponentOutlet=\"\r\n renderer;\r\n inputs: getRendererInputs(item, f)\r\n \"></ng-container>\r\n } @else {\r\n {{ formatCellValue(item, f) }}\r\n }\r\n @if (f.prefix) {\r\n <span>{{ f.prefix }}</span>\r\n }\r\n </div>\r\n </div>\r\n }\r\n </div>\r\n }\r\n </div>\r\n </div>\r\n\r\n @if (loading()) {\r\n <div class=\"loading-container\">\r\n <div class=\"loading\">{{ config.labels.loading }}</div>\r\n </div>\r\n }\r\n</div>\r\n\r\n<ngx-pagination\r\n [(page)]=\"page\"\r\n [pageSize]=\"pageSize()\"\r\n [total]=\"totalRecords()\"\r\n (paginate)=\"onPageChange($event)\"></ngx-pagination>\r\n", styles: [":host{--border-color: light-dark(#70707030, #2a2a3e);--header-height: 50px;--header-padding-y: 8px;--bg-color: light-dark(#eeeeee, #111118);--fg-color: light-dark(#000000, #ffffff);--header-shadow-color: light-dark(#00000024, #00000066);--header-bg: light-dark(#e5e5e5, #1a1a26)}*{box-sizing:border-box}.table-responsive{position:relative}.table-mrs{border:1px var(--border-color) solid;border-radius:32px;corner-shape:squircle;overflow:hidden;background-color:var(--bg-color);color:var(--fg-color)}.thead-mrs{background:var(--header-bg);height:var(--header-height);padding:var(--header-padding-y) 0px;box-shadow:0 0 10px 5px var(--header-shadow-color);overflow:hidden}.tbody-mrs{border-top:1px var(--border-color) solid;overflow:auto;height:calc(var(--available-content-height, 100vh) - (var(--header-height) + var(--header-padding-y) * 2));min-height:200px}.tr-mrs{display:flex;border-bottom:1px var(--border-color) solid}.tbody-mrs .tr-mrs{animation:showrow .35s cubic-bezier(.4,-.32,.4,1.24)}.tbody-mrs .tr-mrs:hover{background:#6c63ff0a}.tr-mrs:last-child{border-bottom:none}.thead-mrs .th-mrs{padding:5px 10px;flex:1;border-right:1px var(--border-color) solid;align-items:center;justify-content:space-between;display:flex;gap:5px;overflow:hidden}.thead-mrs .th-mrs:hover .sort-icon{opacity:1}.th-mrs:last-child{border:none}.td-mrs{padding:8px 10px;flex:100;overflow:hidden;margin:auto 0}.td-mrs .cel{overflow:hidden;max-width:100%}.td-mrs .cel :not(.wrap){white-space:nowrap;text-overflow:ellipsis}.cel .cell-title{display:none}.text-wrap{white-space:normal}@media(max-width:768px){.thead-mrs{display:none}.tr-mrs{flex-direction:column}.tr-mrs .td-mrs{max-width:unset!important;width:unset!important}.tr-mrs .td-mrs .cel{display:flex;align-items:center;gap:10px}.cel .cell-title{color:#6bb6f3;display:inline-block;font-weight:600}}@keyframes showrow{0%{margin-top:-100px;opacity:0}to{margin-top:0;opacity:1}}.loading-container{position:absolute;inset:0;display:flex;align-items:center;justify-content:center}.loading-container .loading{background:#3b3b3ba3;color:#fff;border:10px rgba(57,57,57,.1803921569) solid;border-radius:10px;padding:18px 25px}.no-data{display:flex;align-items:center;justify-content:center;height:100%;font-size:2rem;opacity:.5}.sort-icon{cursor:pointer;opacity:0;transition:opacity .5s;width:16px;height:16px}.sort-icon svg{width:100%;height:100%}.sort-icon.active{opacity:1}.tag{color:#fff;padding:0 10px;border-radius:5px}.tag.tag-success{background:#008e44}.tag.tag-danger{background:#bb001b}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$1.NgComponentOutlet, selector: "[ngComponentOutlet]", inputs: ["ngComponentOutlet", "ngComponentOutletInputs", "ngComponentOutletInjector", "ngComponentOutletEnvironmentInjector", "ngComponentOutletContent", "ngComponentOutletNgModule"], exportAs: ["ngComponentOutlet"] }, { kind: "directive", type: i1$1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "component", type: NgxPagination, selector: "ngx-pagination", inputs: ["total", "page", "pageSize", "pageSizeOptions", "labels", "siblingCount", "boundaryCount"], outputs: ["pageChange", "pageSizeChange", "paginate"] }] });
600
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.4", type: NgxTable, isStandalone: true, selector: "ngx-table", inputs: { fields: { classPropertyName: "fields", publicName: "fields", isSignal: true, isRequired: true, transformFunction: null }, data: { classPropertyName: "data", publicName: "data", isSignal: true, isRequired: true, transformFunction: null }, totalRecords: { classPropertyName: "totalRecords", publicName: "totalRecords", isSignal: true, isRequired: true, transformFunction: null }, showRecordNumber: { classPropertyName: "showRecordNumber", publicName: "showRecordNumber", isSignal: true, isRequired: false, transformFunction: null }, operations: { classPropertyName: "operations", publicName: "operations", isSignal: true, isRequired: false, transformFunction: null }, operationWidth: { classPropertyName: "operationWidth", publicName: "operationWidth", isSignal: true, isRequired: false, transformFunction: null }, numWidth: { classPropertyName: "numWidth", publicName: "numWidth", isSignal: true, isRequired: false, transformFunction: null }, pageSize: { classPropertyName: "pageSize", publicName: "pageSize", isSignal: true, isRequired: false, transformFunction: null }, loading: { classPropertyName: "loading", publicName: "loading", isSignal: true, isRequired: false, transformFunction: null }, multiSort: { classPropertyName: "multiSort", publicName: "multiSort", isSignal: true, isRequired: false, transformFunction: null }, lazy: { classPropertyName: "lazy", publicName: "lazy", isSignal: true, isRequired: false, transformFunction: null }, trackBy: { classPropertyName: "trackBy", publicName: "trackBy", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { lazyLoad: "lazyLoad", sortChange: "sortChange", columnResize: "columnResize" }, host: { classAttribute: "ngx-table-host" }, queries: [{ propertyName: "cellTemplates", predicate: TableCell }], ngImport: i0, template: "<div class=\"ngx-table-wrapper\" [class.ngx-table--loading]=\"loading()\">\n <div class=\"ngx-table-scroll\">\n <div\n class=\"ngx-table\"\n [class.ngx-table--striped]=\"config.stripedRows\"\n [class.ngx-table--hover]=\"config.hoverable\"\n role=\"table\">\n <div class=\"thead-mrs\" [class.thead-mrs--sticky]=\"config.stickyHeader\" role=\"rowgroup\">\n <div class=\"tr-mrs\" role=\"row\">\n @if (operations()) {\n <div\n class=\"th-mrs operations\"\n role=\"columnheader\"\n [style.flex]=\"'0 0 ' + operationWidth() + 'px'\">\n {{ config.labels.operation }}\n </div>\n }\n @if (showRecordNumber()) {\n <div\n class=\"th-mrs operations\"\n role=\"columnheader\"\n [style.flex]=\"'0 0 ' + numWidth() + 'px'\">\n #\n </div>\n }\n\n @for (f of fields(); track f.column) {\n <div\n class=\"th-mrs\"\n role=\"columnheader\"\n [class.th-mrs--sortable]=\"f.sortable\"\n [style.flex]=\"'0 0 ' + columnWidth(f.column) + 'px'\"\n [attr.aria-sort]=\"\n sortDirectionFor(f.column) === 'asc'\n ? 'ascending'\n : sortDirectionFor(f.column) === 'desc'\n ? 'descending'\n : null\n \"\n (click)=\"onHeaderClick(f, $event)\">\n <span class=\"th-mrs__title\">{{ f.title }}</span>\n\n @if (f.sortable) {\n <span class=\"sort-icon\" [class.active]=\"sortDirectionFor(f.column) !== null\">\n @if (sortDirectionFor(f.column) === 'asc') {\n <svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 320 512\">\n <path\n fill=\"currentColor\"\n d=\"M182.6 41.4c-12.5-12.5-32.8-12.5-45.3 0l-128 128c-9.2 9.2-11.9 22.9-6.9 34.9s16.6 19.8 29.6 19.8H96V448c0 17.7 14.3 32 32 32s32-14.3 32-32V224h64c12.9 0 24.6-7.8 29.6-19.8s2.2-25.7-6.9-34.9l-128-128z\" />\n </svg>\n } @else if (sortDirectionFor(f.column) === 'desc') {\n <svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 320 512\">\n <path\n fill=\"currentColor\"\n d=\"M137.4 470.6c12.5 12.5 32.8 12.5 45.3 0l128-128c9.2-9.2 11.9-22.9 6.9-34.9s-16.6-19.8-29.6-19.8H224V64c0-17.7-14.3-32-32-32s-32 14.3-32 32V288H96c-12.9 0-24.6 7.8-29.6 19.8s-2.2 25.7 6.9 34.9l128 128z\" />\n </svg>\n } @else {\n <svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 320 512\">\n <path\n fill=\"currentColor\"\n d=\"M137.4 41.4c12.5-12.5 32.8-12.5 45.3 0l96 96c9.2 9.2 11.9 22.9 6.9 34.9s-16.6 19.8-29.6 19.8H224v96c0 17.7-14.3 32-32 32s-32-14.3-32-32V192H96c-12.9 0-24.6-7.8-29.6-19.8s-2.3-25.7 6.9-34.9l96-96zM32 400c0-17.7 14.3-32 32-32H256c17.7 0 32 14.3 32 32s-14.3 32-32 32H64c-17.7 0-32-14.3-32-32z\"\n opacity=\".35\" />\n </svg>\n }\n </span>\n }\n\n @if (isResizable(f)) {\n <span\n ngxColumnResize\n [ngxColumnResizeWidth]=\"columnWidth(f.column)\"\n [ngxColumnResizeMin]=\"columnMin(f)\"\n [ngxColumnResizeMax]=\"columnMax(f)\"\n [ngxColumnResizeDir]=\"resolvedDirection()\"\n (resizing)=\"onColumnResizing(f.column, $event)\"\n (resizeEnd)=\"onColumnResizeEnd(f.column, $event)\"\n (click)=\"$event.stopPropagation()\"></span>\n }\n </div>\n }\n </div>\n </div>\n\n <div class=\"tbody-mrs\" role=\"rowgroup\">\n @if (!loading() && pagedData().length === 0) {\n <div class=\"no-data\">{{ config.labels.noData }}</div>\n }\n\n @for (row of pagedData(); track trackBy()($index, row); let rowIndex = $index) {\n <div class=\"tr-mrs\" role=\"row\">\n @if (operations()) {\n <div\n class=\"td-mrs operations\"\n role=\"cell\"\n [style.flex]=\"'0 0 ' + operationWidth() + 'px'\">\n <div class=\"cel\">\n <span class=\"cell-title\">{{ config.labels.operation }}:</span>\n <ng-container\n [ngTemplateOutlet]=\"operations()!\"\n [ngTemplateOutletContext]=\"{ $implicit: row }\"></ng-container>\n </div>\n </div>\n }\n\n @if (showRecordNumber()) {\n <div class=\"td-mrs operations\" role=\"cell\" [style.flex]=\"'0 0 ' + numWidth() + 'px'\">\n <div class=\"cel\">{{ recordNumber(rowIndex) }}</div>\n </div>\n }\n\n @for (f of fields(); track f.column) {\n @let template = getTemplate(f.column);\n @let renderer = getRenderer(f);\n\n <div class=\"td-mrs\" role=\"cell\" [style.flex]=\"'0 0 ' + columnWidth(f.column) + 'px'\">\n <div class=\"cel\" [class.wrap]=\"f.wrap\">\n <span class=\"cell-title\">{{ f.title }}</span>\n\n @if (template) {\n <ng-container\n [ngTemplateOutlet]=\"template\"\n [ngTemplateOutletContext]=\"{\n $implicit: row,\n row: row,\n value: getCellValue(row, f),\n rowIndex: rowIndex,\n field: f,\n }\"></ng-container>\n } @else if (renderer) {\n <ng-container\n *ngComponentOutlet=\"\n renderer;\n inputs: getRendererInputs(row, f)\n \"></ng-container>\n } @else {\n {{ formatCellValue(row, f) }}\n }\n\n @if (f.prefix) {\n <span>{{ f.prefix }}</span>\n }\n </div>\n </div>\n }\n </div>\n }\n </div>\n </div>\n\n @if (loading()) {\n <div class=\"loading-container\">\n <div class=\"loading\">{{ config.labels.loading }}</div>\n </div>\n }\n </div>\n</div>\n\n<ngx-pagination\n [page]=\"page()\"\n [pageSize]=\"pageSizeS()\"\n [total]=\"totalCount()\"\n (paginate)=\"onPaginate($event)\"></ngx-pagination>\n", styles: [":host{--ngx-table-accent: light-dark(#4f46e5, #818cf8);--ngx-table-border: light-dark(#e5e7eb, #27272a);--ngx-table-header-bg: light-dark(#f8fafc, #18181b);--ngx-table-header-fg: light-dark(#334155, #d4d4d8);--ngx-table-row-bg: light-dark(#ffffff, #111114);--ngx-table-row-alt-bg: light-dark(#f9fafb, #17171b);--ngx-table-row-hover-bg: light-dark(#eef2ff, #1e1b4b);--ngx-table-text: light-dark(#1e293b, #e4e4e7);--ngx-table-radius: 12px;display:block;color:var(--ngx-table-text)}.ngx-table-wrapper{position:relative;border:1px solid var(--ngx-table-border);border-radius:var(--ngx-table-radius);overflow:hidden;background:var(--ngx-table-row-bg)}.ngx-table-scroll{overflow:auto;max-height:75vh}.ngx-table-scroll::-webkit-scrollbar{height:10px;width:10px}.ngx-table-scroll::-webkit-scrollbar-thumb{background:color-mix(in srgb,var(--ngx-table-border) 60%,gray);border-radius:8px}.ngx-table{display:flex;flex-direction:column;min-width:100%;width:max-content}.thead-mrs{display:flex;flex-direction:column;z-index:2}.thead-mrs--sticky{position:sticky;top:0}.tr-mrs{display:flex;align-items:stretch}.th-mrs,.td-mrs{position:relative;box-sizing:border-box;overflow:hidden;border-bottom:1px solid var(--ngx-table-border);border-inline-end:1px solid var(--ngx-table-border)}.th-mrs:last-child,.td-mrs:last-child{border-inline-end:none}.th-mrs{display:flex;align-items:center;gap:.375rem;background:var(--ngx-table-header-bg);color:var(--ngx-table-header-fg);font-weight:600;font-size:.8125rem;letter-spacing:.02em;padding:.75rem 1rem;-webkit-user-select:none;user-select:none;white-space:nowrap;text-overflow:ellipsis}.th-mrs--sortable{cursor:pointer}.th-mrs--sortable:hover{color:var(--ngx-table-accent)}.th-mrs.operations{justify-content:center}.th-mrs__title{overflow:hidden;text-overflow:ellipsis}.sort-icon{width:.75rem;height:.75rem;flex:none;opacity:.4;display:inline-flex}.sort-icon svg{width:100%;height:100%}.sort-icon.active{opacity:1}.ngx-table__resize-handle,[ngxColumnResize]{position:absolute;top:0;bottom:0;inset-inline-end:-3px;width:6px;cursor:col-resize;touch-action:none;z-index:3}.ngx-table__resize-handle:hover,.ngx-table__resize-handle:active,[ngxColumnResize]:hover,[ngxColumnResize]:active{background:var(--ngx-table-accent);opacity:.5}.td-mrs{display:flex;align-items:center;padding:.75rem 1rem;font-size:.875rem}.td-mrs.operations{justify-content:center}.cel{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;display:flex;align-items:center;gap:.25rem}.cel.wrap{white-space:normal}.cell-title{display:none;font-weight:600;color:var(--ngx-table-header-fg)}.ngx-table--striped .tbody-mrs .tr-mrs:nth-child(2n){background:var(--ngx-table-row-alt-bg)}.ngx-table--hover .tbody-mrs .tr-mrs:hover{background:var(--ngx-table-row-hover-bg)}.tr-mrs{transition:background-color .15s ease}.no-data{padding:2.5rem 1rem;text-align:center;color:#94a3b8;font-size:.875rem}.loading-container{position:absolute;inset:0;display:flex;align-items:center;justify-content:center;background:color-mix(in srgb,var(--ngx-table-row-bg) 75%,transparent);-webkit-backdrop-filter:blur(1px);backdrop-filter:blur(1px)}.loading{font-size:.875rem;color:var(--ngx-table-accent)}@media(max-width:768px){.ngx-table-scroll{overflow:visible;max-height:none}.ngx-table{width:100%}.thead-mrs{display:none}.tbody-mrs{display:flex;flex-direction:column;gap:.75rem;padding:.75rem}.tr-mrs{flex-direction:column;border:1px solid var(--ngx-table-border);border-radius:10px;overflow:hidden}.td-mrs{flex:1 1 auto!important;width:100%;border-inline-end:none;justify-content:space-between}.cel{justify-content:flex-end;white-space:normal;text-align:end}.cell-title{display:inline}}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$1.NgComponentOutlet, selector: "[ngComponentOutlet]", inputs: ["ngComponentOutlet", "ngComponentOutletInputs", "ngComponentOutletInjector", "ngComponentOutletEnvironmentInjector", "ngComponentOutletContent", "ngComponentOutletNgModule"], exportAs: ["ngComponentOutlet"] }, { kind: "directive", type: i1$1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "component", type: NgxPagination, selector: "ngx-pagination", inputs: ["total", "page", "pageSize", "pageSizeOptions", "labels", "siblingCount", "boundaryCount"], outputs: ["pageChange", "pageSizeChange", "paginate"] }, { kind: "directive", type: ColumnResize, selector: "[ngxColumnResize]", inputs: ["ngxColumnResizeWidth", "ngxColumnResizeMin", "ngxColumnResizeMax", "ngxColumnResizeDir"], outputs: ["resizing", "resizeEnd"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
312
601
  }
313
602
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.4", ngImport: i0, type: NgxTable, decorators: [{
314
603
  type: Component,
315
- args: [{ selector: 'ngx-table', imports: [CommonModule, NgxPagination], providers: [], template: "<div class=\"table-responsive\" #tableContainer>\r\n <div class=\"table-mrs\">\r\n <div class=\"thead-mrs\">\r\n <div class=\"tr-mrs\">\r\n @if (operations()) {\r\n <div\r\n class=\"th-mrs operations\"\r\n [style.max-width.px]=\"operationWidth()\"\r\n [style.min-width.px]=\"operationWidth()\">\r\n {{ config.labels.operation }}\r\n </div>\r\n }\r\n @if (showRecordNumber()) {\r\n <div\r\n class=\"th-mrs operations\"\r\n [style.max-width.px]=\"numWidth()\"\r\n [style.min-width.px]=\"numWidth()\">\r\n #\r\n </div>\r\n }\r\n @for (item of fields(); track $index) {\r\n <div class=\"th-mrs\" [style.max-width.px]=\"item.width\" [style.min-width.px]=\"item.width\">\r\n {{ item.title }}\r\n <span\r\n class=\"sort-icon\"\r\n [class.active]=\"sortField == item.column\"\r\n (click)=\"onSortChange(item)\">\r\n @if (sortField == item.column && sortDirection == 'asc') {\r\n <svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 576 512\">\r\n <path\r\n fill=\"currentColor\"\r\n d=\"M368 432h-64c-8.844 0-15.1 7.156-15.1 16S295.2 464 304 464h64c8.844 0 16-7.156 16-16S376.8 432 368 432zM432 304h-128c-8.844 0-15.1 7.156-15.1 16S295.2 336 304 336h128c8.844 0 16-7.156 16-16S440.8 304 432 304zM496 176h-192c-8.844 0-15.1 7.156-15.1 16S295.2 208 304 208h192C504.8 208 512 200.8 512 192S504.8 176 496 176zM560 48h-256c-8.844 0-15.1 7.156-15.1 16S295.2 80 304 80h256C568.8 80 576 72.84 576 64S568.8 48 560 48zM224 352c-4.094 0-8.188 1.562-11.31 4.688L144 425.4V48C144 39.16 136.8 32 128 32S112 39.16 112 48v377.4l-68.69-68.69c-6.25-6.25-16.38-6.25-22.62 0s-6.25 16.38 0 22.62l96 96c6.25 6.25 16.38 6.25 22.62 0l96-96c6.25-6.25 6.25-16.38 0-22.62C232.2 353.6 228.1 352 224 352z\" />\r\n </svg>\r\n } @else if (sortField == item.column && sortDirection == 'desc') {\r\n <svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 576 512\">\r\n <path\r\n fill=\"currentColor\"\r\n d=\"M304 208h128C440.8 208 448 200.8 448 192s-7.156-16-16-16h-128c-8.844 0-15.1 7.156-15.1 16S295.2 208 304 208zM304 336h192c8.844 0 16-7.156 16-16s-7.156-16-16-16h-192c-8.844 0-15.1 7.156-15.1 16S295.2 336 304 336zM304 80h64c8.844 0 16-7.156 16-16S376.8 48 368 48h-64c-8.844 0-15.1 7.156-15.1 16S295.2 80 304 80zM560 432h-256c-8.844 0-15.1 7.156-15.1 16S295.2 464 304 464h256c8.844 0 16-7.156 16-16S568.8 432 560 432zM224 352c-4.094 0-8.188 1.562-11.31 4.688L144 425.4V48C144 39.16 136.8 32 128 32S112 39.16 112 48v377.4l-68.69-68.69c-6.25-6.25-16.38-6.25-22.62 0s-6.25 16.38 0 22.62l96 96c6.25 6.25 16.38 6.25 22.62 0l96-96c6.25-6.25 6.25-16.38 0-22.62C232.2 353.6 228.1 352 224 352z\" />\r\n </svg>\r\n } @else {\r\n <svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 448 512\">\r\n <path\r\n fill=\"currentColor\"\r\n d=\"M224 352c-4.094 0-8.188 1.562-11.31 4.688L144 425.4V48C144 39.16 136.8 32 128 32S112 39.16 112 48v377.4l-68.69-68.69c-6.25-6.25-16.38-6.25-22.62 0s-6.25 16.38 0 22.62l96 96c6.25 6.25 16.38 6.25 22.62 0l96-96c6.25-6.25 6.25-16.38 0-22.62C232.2 353.6 228.1 352 224 352zM427.3 132.7l-96-96c-6.25-6.25-16.38-6.25-22.62 0l-96 96c-6.25 6.25-6.25 16.38 0 22.62s16.38 6.25 22.62 0L304 86.63V464c0 8.844 7.156 16 16 16s16-7.156 16-16V86.63l68.69 68.69C407.8 158.4 411.9 160 416 160s8.188-1.562 11.31-4.688C433.6 149.1 433.6 138.9 427.3 132.7z\" />\r\n </svg>\r\n }\r\n </span>\r\n </div>\r\n }\r\n </div>\r\n </div>\r\n <div class=\"tbody-mrs\">\r\n @if (!loading() && list().length === 0) {\r\n <div class=\"no-data\">{{ config.labels.noData }}</div>\r\n }\r\n @for (item of list(); track $index) {\r\n @let num = getRecordNumber(item);\r\n <div class=\"tr-mrs\">\r\n @if (operations()) {\r\n <div\r\n class=\"td-mrs operations\"\r\n vAlign=\"middle\"\r\n [style.max-width.px]=\"operationWidth()\"\r\n [style.min-width.px]=\"operationWidth()\">\r\n <div class=\"cel\">\r\n <span class=\"cell-title\">{{ config.labels.operation }}:</span>\r\n <ng-container\r\n [ngTemplateOutlet]=\"operations()\"\r\n [ngTemplateOutletContext]=\"{ $implicit: item }\"></ng-container>\r\n </div>\r\n </div>\r\n }\r\n\r\n @if (showRecordNumber()) {\r\n <div\r\n class=\"td-mrs operations\"\r\n vAlign=\"middle\"\r\n [style.max-width.px]=\"numWidth()\"\r\n [style.min-width.px]=\"numWidth()\">\r\n <div class=\"cel\">\r\n <span class=\"cell-title\"></span>\r\n {{ num }}\r\n </div>\r\n </div>\r\n }\r\n\r\n @for (f of fields(); track f.column) {\r\n @let template = getTemplate(f.column);\r\n @let renderer = getRenderer(f);\r\n\r\n <div\r\n class=\"td-mrs\"\r\n vAlign=\"middle\"\r\n [style.max-width.px]=\"f.width\"\r\n [style.min-width.px]=\"f.width\">\r\n <div class=\"cel\" [class.wrap]=\"f.wrap\">\r\n <span class=\"cell-title\">{{ f.title }}</span>\r\n @if (template) {\r\n <ng-container\r\n [ngTemplateOutlet]=\"template\"\r\n [ngTemplateOutletContext]=\"{\r\n $implicit: item,\r\n row: item,\r\n value: getCellValue(item, f),\r\n field: f,\r\n }\"></ng-container>\r\n } @else if (renderer) {\r\n <ng-container\r\n *ngComponentOutlet=\"\r\n renderer;\r\n inputs: getRendererInputs(item, f)\r\n \"></ng-container>\r\n } @else {\r\n {{ formatCellValue(item, f) }}\r\n }\r\n @if (f.prefix) {\r\n <span>{{ f.prefix }}</span>\r\n }\r\n </div>\r\n </div>\r\n }\r\n </div>\r\n }\r\n </div>\r\n </div>\r\n\r\n @if (loading()) {\r\n <div class=\"loading-container\">\r\n <div class=\"loading\">{{ config.labels.loading }}</div>\r\n </div>\r\n }\r\n</div>\r\n\r\n<ngx-pagination\r\n [(page)]=\"page\"\r\n [pageSize]=\"pageSize()\"\r\n [total]=\"totalRecords()\"\r\n (paginate)=\"onPageChange($event)\"></ngx-pagination>\r\n", styles: [":host{--border-color: light-dark(#70707030, #2a2a3e);--header-height: 50px;--header-padding-y: 8px;--bg-color: light-dark(#eeeeee, #111118);--fg-color: light-dark(#000000, #ffffff);--header-shadow-color: light-dark(#00000024, #00000066);--header-bg: light-dark(#e5e5e5, #1a1a26)}*{box-sizing:border-box}.table-responsive{position:relative}.table-mrs{border:1px var(--border-color) solid;border-radius:32px;corner-shape:squircle;overflow:hidden;background-color:var(--bg-color);color:var(--fg-color)}.thead-mrs{background:var(--header-bg);height:var(--header-height);padding:var(--header-padding-y) 0px;box-shadow:0 0 10px 5px var(--header-shadow-color);overflow:hidden}.tbody-mrs{border-top:1px var(--border-color) solid;overflow:auto;height:calc(var(--available-content-height, 100vh) - (var(--header-height) + var(--header-padding-y) * 2));min-height:200px}.tr-mrs{display:flex;border-bottom:1px var(--border-color) solid}.tbody-mrs .tr-mrs{animation:showrow .35s cubic-bezier(.4,-.32,.4,1.24)}.tbody-mrs .tr-mrs:hover{background:#6c63ff0a}.tr-mrs:last-child{border-bottom:none}.thead-mrs .th-mrs{padding:5px 10px;flex:1;border-right:1px var(--border-color) solid;align-items:center;justify-content:space-between;display:flex;gap:5px;overflow:hidden}.thead-mrs .th-mrs:hover .sort-icon{opacity:1}.th-mrs:last-child{border:none}.td-mrs{padding:8px 10px;flex:100;overflow:hidden;margin:auto 0}.td-mrs .cel{overflow:hidden;max-width:100%}.td-mrs .cel :not(.wrap){white-space:nowrap;text-overflow:ellipsis}.cel .cell-title{display:none}.text-wrap{white-space:normal}@media(max-width:768px){.thead-mrs{display:none}.tr-mrs{flex-direction:column}.tr-mrs .td-mrs{max-width:unset!important;width:unset!important}.tr-mrs .td-mrs .cel{display:flex;align-items:center;gap:10px}.cel .cell-title{color:#6bb6f3;display:inline-block;font-weight:600}}@keyframes showrow{0%{margin-top:-100px;opacity:0}to{margin-top:0;opacity:1}}.loading-container{position:absolute;inset:0;display:flex;align-items:center;justify-content:center}.loading-container .loading{background:#3b3b3ba3;color:#fff;border:10px rgba(57,57,57,.1803921569) solid;border-radius:10px;padding:18px 25px}.no-data{display:flex;align-items:center;justify-content:center;height:100%;font-size:2rem;opacity:.5}.sort-icon{cursor:pointer;opacity:0;transition:opacity .5s;width:16px;height:16px}.sort-icon svg{width:100%;height:100%}.sort-icon.active{opacity:1}.tag{color:#fff;padding:0 10px;border-radius:5px}.tag.tag-success{background:#008e44}.tag.tag-danger{background:#bb001b}\n"] }]
316
- }], ctorParameters: () => [], propDecorators: { fields: [{ type: i0.Input, args: [{ isSignal: true, alias: "fields", required: true }] }], data: [{ type: i0.Input, args: [{ isSignal: true, alias: "data", required: true }] }], totalRecords: [{ type: i0.Input, args: [{ isSignal: true, alias: "totalRecords", required: true }] }], showRecordNumber: [{ type: i0.Input, args: [{ isSignal: true, alias: "showRecordNumber", required: false }] }], operations: [{ type: i0.Input, args: [{ isSignal: true, alias: "operations", required: false }] }], operationWidth: [{ type: i0.Input, args: [{ isSignal: true, alias: "operationWidth", required: false }] }], numWidth: [{ type: i0.Input, args: [{ isSignal: true, alias: "numWidth", required: false }] }], pageSize: [{ type: i0.Input, args: [{ isSignal: true, alias: "pageSize", required: false }] }], loading: [{ type: i0.Input, args: [{ isSignal: true, alias: "loading", required: false }] }], multiSort: [{ type: i0.Input, args: [{ isSignal: true, alias: "multiSort", required: false }] }], lazy: [{ type: i0.Input, args: [{ isSignal: true, alias: "lazy", required: false }] }], lazyLoad: [{ type: i0.Output, args: ["lazyLoad"] }], tableContainer: [{ type: i0.ViewChild, args: ['tableContainer', { isSignal: true }] }], sortChange: [{
317
- type: Output
318
- }], cellTemplates: [{
604
+ args: [{ selector: 'ngx-table', standalone: true, imports: [CommonModule, NgxPagination, ColumnResize], changeDetection: ChangeDetectionStrategy.OnPush, host: {
605
+ class: 'ngx-table-host',
606
+ }, template: "<div class=\"ngx-table-wrapper\" [class.ngx-table--loading]=\"loading()\">\n <div class=\"ngx-table-scroll\">\n <div\n class=\"ngx-table\"\n [class.ngx-table--striped]=\"config.stripedRows\"\n [class.ngx-table--hover]=\"config.hoverable\"\n role=\"table\">\n <div class=\"thead-mrs\" [class.thead-mrs--sticky]=\"config.stickyHeader\" role=\"rowgroup\">\n <div class=\"tr-mrs\" role=\"row\">\n @if (operations()) {\n <div\n class=\"th-mrs operations\"\n role=\"columnheader\"\n [style.flex]=\"'0 0 ' + operationWidth() + 'px'\">\n {{ config.labels.operation }}\n </div>\n }\n @if (showRecordNumber()) {\n <div\n class=\"th-mrs operations\"\n role=\"columnheader\"\n [style.flex]=\"'0 0 ' + numWidth() + 'px'\">\n #\n </div>\n }\n\n @for (f of fields(); track f.column) {\n <div\n class=\"th-mrs\"\n role=\"columnheader\"\n [class.th-mrs--sortable]=\"f.sortable\"\n [style.flex]=\"'0 0 ' + columnWidth(f.column) + 'px'\"\n [attr.aria-sort]=\"\n sortDirectionFor(f.column) === 'asc'\n ? 'ascending'\n : sortDirectionFor(f.column) === 'desc'\n ? 'descending'\n : null\n \"\n (click)=\"onHeaderClick(f, $event)\">\n <span class=\"th-mrs__title\">{{ f.title }}</span>\n\n @if (f.sortable) {\n <span class=\"sort-icon\" [class.active]=\"sortDirectionFor(f.column) !== null\">\n @if (sortDirectionFor(f.column) === 'asc') {\n <svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 320 512\">\n <path\n fill=\"currentColor\"\n d=\"M182.6 41.4c-12.5-12.5-32.8-12.5-45.3 0l-128 128c-9.2 9.2-11.9 22.9-6.9 34.9s16.6 19.8 29.6 19.8H96V448c0 17.7 14.3 32 32 32s32-14.3 32-32V224h64c12.9 0 24.6-7.8 29.6-19.8s2.2-25.7-6.9-34.9l-128-128z\" />\n </svg>\n } @else if (sortDirectionFor(f.column) === 'desc') {\n <svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 320 512\">\n <path\n fill=\"currentColor\"\n d=\"M137.4 470.6c12.5 12.5 32.8 12.5 45.3 0l128-128c9.2-9.2 11.9-22.9 6.9-34.9s-16.6-19.8-29.6-19.8H224V64c0-17.7-14.3-32-32-32s-32 14.3-32 32V288H96c-12.9 0-24.6 7.8-29.6 19.8s-2.2 25.7 6.9 34.9l128 128z\" />\n </svg>\n } @else {\n <svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 320 512\">\n <path\n fill=\"currentColor\"\n d=\"M137.4 41.4c12.5-12.5 32.8-12.5 45.3 0l96 96c9.2 9.2 11.9 22.9 6.9 34.9s-16.6 19.8-29.6 19.8H224v96c0 17.7-14.3 32-32 32s-32-14.3-32-32V192H96c-12.9 0-24.6-7.8-29.6-19.8s-2.3-25.7 6.9-34.9l96-96zM32 400c0-17.7 14.3-32 32-32H256c17.7 0 32 14.3 32 32s-14.3 32-32 32H64c-17.7 0-32-14.3-32-32z\"\n opacity=\".35\" />\n </svg>\n }\n </span>\n }\n\n @if (isResizable(f)) {\n <span\n ngxColumnResize\n [ngxColumnResizeWidth]=\"columnWidth(f.column)\"\n [ngxColumnResizeMin]=\"columnMin(f)\"\n [ngxColumnResizeMax]=\"columnMax(f)\"\n [ngxColumnResizeDir]=\"resolvedDirection()\"\n (resizing)=\"onColumnResizing(f.column, $event)\"\n (resizeEnd)=\"onColumnResizeEnd(f.column, $event)\"\n (click)=\"$event.stopPropagation()\"></span>\n }\n </div>\n }\n </div>\n </div>\n\n <div class=\"tbody-mrs\" role=\"rowgroup\">\n @if (!loading() && pagedData().length === 0) {\n <div class=\"no-data\">{{ config.labels.noData }}</div>\n }\n\n @for (row of pagedData(); track trackBy()($index, row); let rowIndex = $index) {\n <div class=\"tr-mrs\" role=\"row\">\n @if (operations()) {\n <div\n class=\"td-mrs operations\"\n role=\"cell\"\n [style.flex]=\"'0 0 ' + operationWidth() + 'px'\">\n <div class=\"cel\">\n <span class=\"cell-title\">{{ config.labels.operation }}:</span>\n <ng-container\n [ngTemplateOutlet]=\"operations()!\"\n [ngTemplateOutletContext]=\"{ $implicit: row }\"></ng-container>\n </div>\n </div>\n }\n\n @if (showRecordNumber()) {\n <div class=\"td-mrs operations\" role=\"cell\" [style.flex]=\"'0 0 ' + numWidth() + 'px'\">\n <div class=\"cel\">{{ recordNumber(rowIndex) }}</div>\n </div>\n }\n\n @for (f of fields(); track f.column) {\n @let template = getTemplate(f.column);\n @let renderer = getRenderer(f);\n\n <div class=\"td-mrs\" role=\"cell\" [style.flex]=\"'0 0 ' + columnWidth(f.column) + 'px'\">\n <div class=\"cel\" [class.wrap]=\"f.wrap\">\n <span class=\"cell-title\">{{ f.title }}</span>\n\n @if (template) {\n <ng-container\n [ngTemplateOutlet]=\"template\"\n [ngTemplateOutletContext]=\"{\n $implicit: row,\n row: row,\n value: getCellValue(row, f),\n rowIndex: rowIndex,\n field: f,\n }\"></ng-container>\n } @else if (renderer) {\n <ng-container\n *ngComponentOutlet=\"\n renderer;\n inputs: getRendererInputs(row, f)\n \"></ng-container>\n } @else {\n {{ formatCellValue(row, f) }}\n }\n\n @if (f.prefix) {\n <span>{{ f.prefix }}</span>\n }\n </div>\n </div>\n }\n </div>\n }\n </div>\n </div>\n\n @if (loading()) {\n <div class=\"loading-container\">\n <div class=\"loading\">{{ config.labels.loading }}</div>\n </div>\n }\n </div>\n</div>\n\n<ngx-pagination\n [page]=\"page()\"\n [pageSize]=\"pageSizeS()\"\n [total]=\"totalCount()\"\n (paginate)=\"onPaginate($event)\"></ngx-pagination>\n", styles: [":host{--ngx-table-accent: light-dark(#4f46e5, #818cf8);--ngx-table-border: light-dark(#e5e7eb, #27272a);--ngx-table-header-bg: light-dark(#f8fafc, #18181b);--ngx-table-header-fg: light-dark(#334155, #d4d4d8);--ngx-table-row-bg: light-dark(#ffffff, #111114);--ngx-table-row-alt-bg: light-dark(#f9fafb, #17171b);--ngx-table-row-hover-bg: light-dark(#eef2ff, #1e1b4b);--ngx-table-text: light-dark(#1e293b, #e4e4e7);--ngx-table-radius: 12px;display:block;color:var(--ngx-table-text)}.ngx-table-wrapper{position:relative;border:1px solid var(--ngx-table-border);border-radius:var(--ngx-table-radius);overflow:hidden;background:var(--ngx-table-row-bg)}.ngx-table-scroll{overflow:auto;max-height:75vh}.ngx-table-scroll::-webkit-scrollbar{height:10px;width:10px}.ngx-table-scroll::-webkit-scrollbar-thumb{background:color-mix(in srgb,var(--ngx-table-border) 60%,gray);border-radius:8px}.ngx-table{display:flex;flex-direction:column;min-width:100%;width:max-content}.thead-mrs{display:flex;flex-direction:column;z-index:2}.thead-mrs--sticky{position:sticky;top:0}.tr-mrs{display:flex;align-items:stretch}.th-mrs,.td-mrs{position:relative;box-sizing:border-box;overflow:hidden;border-bottom:1px solid var(--ngx-table-border);border-inline-end:1px solid var(--ngx-table-border)}.th-mrs:last-child,.td-mrs:last-child{border-inline-end:none}.th-mrs{display:flex;align-items:center;gap:.375rem;background:var(--ngx-table-header-bg);color:var(--ngx-table-header-fg);font-weight:600;font-size:.8125rem;letter-spacing:.02em;padding:.75rem 1rem;-webkit-user-select:none;user-select:none;white-space:nowrap;text-overflow:ellipsis}.th-mrs--sortable{cursor:pointer}.th-mrs--sortable:hover{color:var(--ngx-table-accent)}.th-mrs.operations{justify-content:center}.th-mrs__title{overflow:hidden;text-overflow:ellipsis}.sort-icon{width:.75rem;height:.75rem;flex:none;opacity:.4;display:inline-flex}.sort-icon svg{width:100%;height:100%}.sort-icon.active{opacity:1}.ngx-table__resize-handle,[ngxColumnResize]{position:absolute;top:0;bottom:0;inset-inline-end:-3px;width:6px;cursor:col-resize;touch-action:none;z-index:3}.ngx-table__resize-handle:hover,.ngx-table__resize-handle:active,[ngxColumnResize]:hover,[ngxColumnResize]:active{background:var(--ngx-table-accent);opacity:.5}.td-mrs{display:flex;align-items:center;padding:.75rem 1rem;font-size:.875rem}.td-mrs.operations{justify-content:center}.cel{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;display:flex;align-items:center;gap:.25rem}.cel.wrap{white-space:normal}.cell-title{display:none;font-weight:600;color:var(--ngx-table-header-fg)}.ngx-table--striped .tbody-mrs .tr-mrs:nth-child(2n){background:var(--ngx-table-row-alt-bg)}.ngx-table--hover .tbody-mrs .tr-mrs:hover{background:var(--ngx-table-row-hover-bg)}.tr-mrs{transition:background-color .15s ease}.no-data{padding:2.5rem 1rem;text-align:center;color:#94a3b8;font-size:.875rem}.loading-container{position:absolute;inset:0;display:flex;align-items:center;justify-content:center;background:color-mix(in srgb,var(--ngx-table-row-bg) 75%,transparent);-webkit-backdrop-filter:blur(1px);backdrop-filter:blur(1px)}.loading{font-size:.875rem;color:var(--ngx-table-accent)}@media(max-width:768px){.ngx-table-scroll{overflow:visible;max-height:none}.ngx-table{width:100%}.thead-mrs{display:none}.tbody-mrs{display:flex;flex-direction:column;gap:.75rem;padding:.75rem}.tr-mrs{flex-direction:column;border:1px solid var(--ngx-table-border);border-radius:10px;overflow:hidden}.td-mrs{flex:1 1 auto!important;width:100%;border-inline-end:none;justify-content:space-between}.cel{justify-content:flex-end;white-space:normal;text-align:end}.cell-title{display:inline}}\n"] }]
607
+ }], ctorParameters: () => [], propDecorators: { fields: [{ type: i0.Input, args: [{ isSignal: true, alias: "fields", required: true }] }], data: [{ type: i0.Input, args: [{ isSignal: true, alias: "data", required: true }] }], totalRecords: [{ type: i0.Input, args: [{ isSignal: true, alias: "totalRecords", required: true }] }], showRecordNumber: [{ type: i0.Input, args: [{ isSignal: true, alias: "showRecordNumber", required: false }] }], operations: [{ type: i0.Input, args: [{ isSignal: true, alias: "operations", required: false }] }], operationWidth: [{ type: i0.Input, args: [{ isSignal: true, alias: "operationWidth", required: false }] }], numWidth: [{ type: i0.Input, args: [{ isSignal: true, alias: "numWidth", required: false }] }], pageSize: [{ type: i0.Input, args: [{ isSignal: true, alias: "pageSize", required: false }] }], loading: [{ type: i0.Input, args: [{ isSignal: true, alias: "loading", required: false }] }], multiSort: [{ type: i0.Input, args: [{ isSignal: true, alias: "multiSort", required: false }] }], lazy: [{ type: i0.Input, args: [{ isSignal: true, alias: "lazy", required: false }] }], trackBy: [{ type: i0.Input, args: [{ isSignal: true, alias: "trackBy", required: false }] }], lazyLoad: [{ type: i0.Output, args: ["lazyLoad"] }], sortChange: [{ type: i0.Output, args: ["sortChange"] }], columnResize: [{ type: i0.Output, args: ["columnResize"] }], cellTemplates: [{
319
608
  type: ContentChildren,
320
- args: [TableCellDirective]
609
+ args: [TableCell]
321
610
  }] } });
322
611
 
323
- function providePagination(options) {
324
- return makeEnvironmentProviders([
325
- {
326
- provide: NGX_PAGINATION_CONFIG,
327
- useValue: mergeConfig(NGX_PAGINATION_CONFIG_DEFAULT, options),
328
- },
329
- ]);
330
- }
331
-
332
- function provideTable(options) {
333
- return makeEnvironmentProviders([
334
- {
335
- provide: NGX_TABLE_CONFIG,
336
- useValue: mergeConfig(NGX_TABLE_CONFIG_DEFAULT, options),
337
- },
338
- ]);
339
- }
340
-
341
- class FieldsType {
342
- title;
343
- column;
344
- dataType;
345
- width;
346
- wrap;
347
- prefix;
348
- /**
349
- * نام renderer ثبت‌شده در provideTable
350
- */
351
- renderer;
352
- /**
353
- * ورودی‌های اضافه برای renderer
354
- */
355
- rendererInputs;
356
- /**
357
- * نام formatter سراسری یا تابع اختصاصی
358
- */
359
- formatter;
360
- }
361
- class SortEvent {
362
- field = '';
363
- direction = 'asc';
364
- }
612
+ // types
365
613
 
366
614
  /**
367
615
  * Generated bundle index. Do not edit.
368
616
  */
369
617
 
370
- export { FieldsType, NGX_PAGINATION_CONFIG, NGX_PAGINATION_CONFIG_DEFAULT, NGX_TABLE_CONFIG, NGX_TABLE_CONFIG_DEFAULT, NgxPagination, NgxTable, SortEvent, providePagination, provideTable };
618
+ export { ColumnResize, NGX_PAGINATION_CONFIG, NGX_PAGINATION_CONFIG_DEFAULT, NGX_TABLE_CONFIG, NGX_TABLE_CONFIG_DEFAULT, NgxPagination, NgxTable, TableCell, defineFields, defineRenderers, providePagination, provideTable };
371
619
  //# sourceMappingURL=ngx-kit-data-table.mjs.map