@mmlogic/components 0.1.10 → 0.1.12
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +196 -61
- package/dist/cjs/format-DBr-GTvS.js +308 -0
- package/dist/cjs/loader.cjs.js +1 -1
- package/dist/cjs/mosterdcomponents.cjs.js +1 -1
- package/dist/cjs/mrd-boolean-field_16.cjs.entry.js +29 -110
- package/dist/cjs/mrd-table.cjs.entry.js +323 -62
- package/dist/collection/components/mrd-table/mrd-table.js +391 -62
- package/dist/collection/components/mrd-table/mrd-table.scss +388 -0
- package/dist/collection/dev/app.js +48 -4
- package/dist/collection/dev/sprites.svg +55 -0
- package/dist/collection/utils/i18n.js +144 -0
- package/dist/components/i18n.js +1 -1
- package/dist/components/mrd-table.js +1 -1
- package/dist/esm/format-EzhfM0uw.js +299 -0
- package/dist/esm/loader.js +1 -1
- package/dist/esm/mosterdcomponents.js +1 -1
- package/dist/esm/mrd-boolean-field_16.entry.js +1 -82
- package/dist/esm/mrd-table.entry.js +323 -62
- package/dist/mosterdcomponents/mosterdcomponents.esm.js +1 -1
- package/dist/mosterdcomponents/p-6832ea50.entry.js +1 -0
- package/dist/mosterdcomponents/p-EzhfM0uw.js +1 -0
- package/dist/mosterdcomponents/p-ca5f9919.entry.js +1 -0
- package/dist/types/components/mrd-table/mrd-table.d.ts +52 -18
- package/dist/types/components.d.ts +23 -3
- package/dist/types/utils/cell-renderer.d.ts +27 -0
- package/package.json +1 -1
- package/dist/cjs/format-CDw-zie_.js +0 -82
- package/dist/esm/format-Dt-aHxkM.js +0 -74
- package/dist/mosterdcomponents/p-Dt-aHxkM.js +0 -1
- package/dist/mosterdcomponents/p-baf08615.entry.js +0 -1
- package/dist/mosterdcomponents/p-bb567c32.entry.js +0 -1
|
@@ -1,16 +1,22 @@
|
|
|
1
1
|
import { h, Host } from "@stencil/core";
|
|
2
2
|
import { CellRenderer } from "../../utils/cell-renderer";
|
|
3
|
+
import { t } from "../../utils/i18n";
|
|
3
4
|
const BUFFER = 10;
|
|
4
5
|
/** Wacht deze tijd (ms) na het laatste scroll-event voordat pagina's worden
|
|
5
6
|
* aangevraagd. Pagina's die de gebruiker snel voorbij scrollt worden zo geskipt. */
|
|
6
7
|
const REQUEST_DEBOUNCE_MS = 150;
|
|
8
|
+
/** Breedte van de filterpopup in px — voor overflow-correctie. */
|
|
9
|
+
const POPUP_WIDTH = 280;
|
|
10
|
+
const TEXT_TYPES = new Set(['TEXT', 'TEXTBLOCK', 'EMAIL', 'HYPERLINK']);
|
|
11
|
+
const NUMERIC_TYPES = new Set(['INTEGER', 'DECIMAL', 'PERCENTAGE', 'CURRENCY']);
|
|
12
|
+
const DATE_TYPES = new Set(['DATE', 'DATETIME', 'TIME']);
|
|
13
|
+
const NO_FILTER_TYPES = new Set(['FILE', 'IMAGE']);
|
|
7
14
|
export class MrdTable {
|
|
8
15
|
constructor() {
|
|
9
|
-
// ──
|
|
10
|
-
/** Pagina's die wachten op debounce-flush. */
|
|
16
|
+
// ── Non-state internals ────────────────────────────────────────────────────
|
|
11
17
|
this.pendingPages = new Set();
|
|
12
|
-
/** Handle van de actieve debounce-timer. */
|
|
13
18
|
this.debounceTimer = null;
|
|
19
|
+
this.outsideClickHandler = null;
|
|
14
20
|
// ── Props ──────────────────────────────────────────────────────────────────
|
|
15
21
|
this.columns = [];
|
|
16
22
|
/** Direct rows (non-paginated mode, used when totalElements === 0). */
|
|
@@ -27,32 +33,45 @@ export class MrdTable {
|
|
|
27
33
|
/** Initial sort applied on load, e.g. "timestamp,desc" or "name".
|
|
28
34
|
* Parsed by init() into sortField + sortDir. */
|
|
29
35
|
this.defaultSort = '';
|
|
36
|
+
/** Toolbar action buttons rendered above the table. */
|
|
37
|
+
this.actions = [];
|
|
30
38
|
// ── Internal state ─────────────────────────────────────────────────────────
|
|
31
|
-
/** Pages injected via setPage(). Always replaced by a new Map to trigger re-render. */
|
|
32
39
|
this.loadedPages = new Map();
|
|
33
|
-
/** Pages already requested via mrdLoadPage (to avoid duplicate events). */
|
|
34
40
|
this.requestedPages = new Set();
|
|
35
|
-
/** Absolute index of the first row currently in the render window. */
|
|
36
41
|
this.renderStart = 0;
|
|
37
|
-
/** Absolute index of the last row currently in the render window. */
|
|
38
42
|
this.renderEnd = 0;
|
|
39
|
-
/** Locked column widths (px) — measured after first page renders, then fixed. */
|
|
40
43
|
this.colWidths = [];
|
|
41
|
-
/** Column currently used for sorting (empty = no sort). */
|
|
42
44
|
this.sortField = '';
|
|
43
|
-
/** Sort direction for sortField. */
|
|
44
45
|
this.sortDir = 'asc';
|
|
46
|
+
/** Whether the filter UI is visible on column headers. */
|
|
47
|
+
this.filterMode = false;
|
|
48
|
+
/** Active filters keyed by field name. */
|
|
49
|
+
this.activeFilters = new Map();
|
|
50
|
+
/** Field name of the currently open filter popup (null = closed). */
|
|
51
|
+
this.openFilterCol = null;
|
|
52
|
+
/** Filter state being edited in the open popup. */
|
|
53
|
+
this.pendingFilter = null;
|
|
54
|
+
/** Viewport-relative position for the filter popup. */
|
|
55
|
+
this.popupPos = { top: 0, left: 0 };
|
|
56
|
+
/** Current scroll offset of the scroll container — drives pagination footer. */
|
|
57
|
+
this.scrollTop = 0;
|
|
45
58
|
this.handleScroll = (e) => {
|
|
46
59
|
const scroller = e.currentTarget;
|
|
47
60
|
const scrollTop = scroller.scrollTop;
|
|
48
61
|
const total = this.totalElements;
|
|
49
62
|
const visStart = Math.floor(scrollTop / this.rowHeight);
|
|
50
63
|
const visEnd = Math.min(visStart + this.visibleCount(), total - 1);
|
|
64
|
+
this.scrollTop = scrollTop;
|
|
51
65
|
this.renderStart = Math.max(0, visStart - BUFFER);
|
|
52
66
|
this.renderEnd = Math.min(total - 1, visEnd + BUFFER);
|
|
53
67
|
this.requestPagesForWindow(this.renderStart, this.renderEnd);
|
|
54
68
|
};
|
|
55
69
|
}
|
|
70
|
+
// ── Prop watchers ─────────────────────────────────────────────────────────
|
|
71
|
+
/** Clamp renderEnd when totalElements shrinks (e.g. after a filter is applied). */
|
|
72
|
+
totalElementsChanged(newVal) {
|
|
73
|
+
this.renderEnd = Math.min(this.renderEnd, Math.max(0, newVal - 1));
|
|
74
|
+
}
|
|
56
75
|
// ── Public API ─────────────────────────────────────────────────────────────
|
|
57
76
|
/**
|
|
58
77
|
* Initialise (or reset) the virtual scroll.
|
|
@@ -69,7 +88,6 @@ export class MrdTable {
|
|
|
69
88
|
this.loadedPages = new Map();
|
|
70
89
|
this.requestedPages = new Set();
|
|
71
90
|
this.colWidths = [];
|
|
72
|
-
// Apply defaultSort prop as the initial sort state.
|
|
73
91
|
if (this.defaultSort) {
|
|
74
92
|
const parts = this.defaultSort.split(',');
|
|
75
93
|
this.sortField = parts[0].trim();
|
|
@@ -79,66 +97,105 @@ export class MrdTable {
|
|
|
79
97
|
this.sortField = '';
|
|
80
98
|
this.sortDir = 'asc';
|
|
81
99
|
}
|
|
100
|
+
this.scrollTop = 0;
|
|
82
101
|
this.renderStart = 0;
|
|
83
|
-
|
|
84
|
-
//
|
|
102
|
+
// No BUFFER on init — only request what fits the visible area (page 0).
|
|
103
|
+
// BUFFER is applied during scroll to pre-fetch the next page proactively.
|
|
104
|
+
this.renderEnd = Math.max(0, Math.min(this.visibleCount() - 1, this.totalElements - 1));
|
|
85
105
|
const scroller = this.el.querySelector('.mrd-table__scroll');
|
|
86
106
|
if (scroller)
|
|
87
107
|
scroller.scrollTop = 0;
|
|
88
|
-
// Do NOT emit mrdLoadPage here — the host injects page 0 via setPage().
|
|
89
108
|
}
|
|
90
109
|
/**
|
|
91
110
|
* Inject the rows for a given page (0-based).
|
|
92
111
|
* Creates a new Map reference so Stencil detects the state change.
|
|
112
|
+
*
|
|
113
|
+
* When the page contains fewer rows than pageSize it is the last page.
|
|
114
|
+
* renderEnd is clamped immediately so no loading-placeholder rows appear
|
|
115
|
+
* beyond the actual data — without requiring the host to update totalElements.
|
|
93
116
|
*/
|
|
94
117
|
async setPage(pageNumber, rows) {
|
|
118
|
+
if (rows.length < this.pageSize) {
|
|
119
|
+
// lastRowIdx is -1 when the page is empty; clamp renderEnd to -1 so the
|
|
120
|
+
// render loop does not execute and no shimmer rows appear.
|
|
121
|
+
const lastRowIdx = pageNumber * this.pageSize + rows.length - 1;
|
|
122
|
+
this.renderEnd = Math.min(this.renderEnd, lastRowIdx);
|
|
123
|
+
}
|
|
95
124
|
const next = new Map(this.loadedPages);
|
|
96
125
|
next.set(pageNumber, rows);
|
|
97
126
|
this.loadedPages = next;
|
|
98
127
|
}
|
|
99
|
-
// ──
|
|
128
|
+
// ── Lifecycle ──────────────────────────────────────────────────────────────
|
|
129
|
+
disconnectedCallback() {
|
|
130
|
+
if (this.outsideClickHandler) {
|
|
131
|
+
document.removeEventListener('click', this.outsideClickHandler);
|
|
132
|
+
this.outsideClickHandler = null;
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
componentDidRender() {
|
|
136
|
+
if (this.colWidths.length === 0 && this.loadedPages.size > 0 && this.totalElements > 0) {
|
|
137
|
+
const ths = this.el.querySelectorAll('.mrd-table__header');
|
|
138
|
+
if (ths.length > 0) {
|
|
139
|
+
this.colWidths = Array.from(ths).map(th => th.offsetWidth);
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
// ── Paging / scroll helpers ────────────────────────────────────────────────
|
|
100
144
|
visibleCount() {
|
|
101
145
|
return Math.ceil(this.tableHeight / this.rowHeight);
|
|
102
146
|
}
|
|
103
|
-
/** Returns the current sort value for use in ?sort= query params. */
|
|
104
147
|
sortParam() {
|
|
105
148
|
if (!this.sortField)
|
|
106
149
|
return '';
|
|
107
150
|
return this.sortDir === 'desc' ? `${this.sortField},desc` : this.sortField;
|
|
108
151
|
}
|
|
109
|
-
/** Called when a header cell is clicked. Toggles direction or sets a new column. */
|
|
110
152
|
colName(col) {
|
|
111
153
|
var _a, _b, _c, _d;
|
|
112
154
|
return (_d = (_b = (_a = col.field) === null || _a === void 0 ? void 0 : _a.name) !== null && _b !== void 0 ? _b : (_c = col.relation) === null || _c === void 0 ? void 0 : _c.name) !== null && _d !== void 0 ? _d : '';
|
|
113
155
|
}
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
if (
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
}
|
|
123
|
-
// Cancel any pending scroll debounce.
|
|
156
|
+
colDataType(col) {
|
|
157
|
+
var _a, _b;
|
|
158
|
+
if (col.type === 'RELATION')
|
|
159
|
+
return 'RELATION';
|
|
160
|
+
return (_b = (_a = col.field) === null || _a === void 0 ? void 0 : _a.dataType) !== null && _b !== void 0 ? _b : 'TEXT';
|
|
161
|
+
}
|
|
162
|
+
/** Reset pagination state and scroll to top (used after sort or filter change). */
|
|
163
|
+
resetPages() {
|
|
124
164
|
if (this.debounceTimer !== null) {
|
|
125
165
|
clearTimeout(this.debounceTimer);
|
|
126
166
|
this.debounceTimer = null;
|
|
127
167
|
}
|
|
128
168
|
this.pendingPages.clear();
|
|
129
|
-
// Wipe all loaded data so the new sort order is fetched fresh.
|
|
130
169
|
this.loadedPages = new Map();
|
|
131
170
|
this.requestedPages = new Set();
|
|
132
171
|
this.colWidths = [];
|
|
172
|
+
this.scrollTop = 0;
|
|
133
173
|
this.renderStart = 0;
|
|
134
|
-
|
|
174
|
+
// No BUFFER here — totalElements may be stale after a filter change.
|
|
175
|
+
// Only request what is visible; BUFFER kicks in during scroll as usual.
|
|
176
|
+
this.renderEnd = Math.max(0, Math.min(this.visibleCount() - 1, this.totalElements - 1));
|
|
135
177
|
const scroller = this.el.querySelector('.mrd-table__scroll');
|
|
136
178
|
if (scroller)
|
|
137
179
|
scroller.scrollTop = 0;
|
|
138
|
-
|
|
180
|
+
}
|
|
181
|
+
handleSortClick(col) {
|
|
182
|
+
const name = this.colName(col);
|
|
183
|
+
if (this.sortField === name) {
|
|
184
|
+
this.sortDir = this.sortDir === 'asc' ? 'desc' : 'asc';
|
|
185
|
+
}
|
|
186
|
+
else {
|
|
187
|
+
this.sortField = name;
|
|
188
|
+
this.sortDir = 'asc';
|
|
189
|
+
}
|
|
190
|
+
this.resetPages();
|
|
191
|
+
this.emitPagesForWindow(this.renderStart, this.renderEnd);
|
|
192
|
+
}
|
|
193
|
+
applySort(col, dir) {
|
|
194
|
+
this.sortField = this.colName(col);
|
|
195
|
+
this.sortDir = dir;
|
|
196
|
+
this.resetPages();
|
|
139
197
|
this.emitPagesForWindow(this.renderStart, this.renderEnd);
|
|
140
198
|
}
|
|
141
|
-
/** Emits mrdLoadPage immediately for all missing pages in [start, end]. */
|
|
142
199
|
emitPagesForWindow(start, end) {
|
|
143
200
|
const firstPage = Math.floor(start / this.pageSize);
|
|
144
201
|
const lastPage = Math.floor(end / this.pageSize);
|
|
@@ -171,13 +228,10 @@ export class MrdTable {
|
|
|
171
228
|
}
|
|
172
229
|
if (!anyNew)
|
|
173
230
|
return;
|
|
174
|
-
// Reset de timer: wacht tot het scrollen even stopt.
|
|
175
231
|
if (this.debounceTimer !== null)
|
|
176
232
|
clearTimeout(this.debounceTimer);
|
|
177
233
|
this.debounceTimer = setTimeout(() => this.flushPendingPages(), REQUEST_DEBOUNCE_MS);
|
|
178
234
|
}
|
|
179
|
-
/** Emitteert mrdLoadPage alleen voor pagina's die na de debounce-wachttijd
|
|
180
|
-
* nog steeds binnen het huidige render-venster vallen. */
|
|
181
235
|
flushPendingPages() {
|
|
182
236
|
this.debounceTimer = null;
|
|
183
237
|
if (this.pendingPages.size === 0)
|
|
@@ -185,10 +239,8 @@ export class MrdTable {
|
|
|
185
239
|
const next = new Set(this.requestedPages);
|
|
186
240
|
let changed = false;
|
|
187
241
|
for (const page of this.pendingPages) {
|
|
188
|
-
// Sla over als pagina inmiddels geladen of al aangevraagd is.
|
|
189
242
|
if (this.loadedPages.has(page) || next.has(page))
|
|
190
243
|
continue;
|
|
191
|
-
// Sla over als de pagina buiten het huidige venster is geraakt.
|
|
192
244
|
const pageStart = page * this.pageSize;
|
|
193
245
|
const pageEnd = pageStart + this.pageSize - 1;
|
|
194
246
|
if (pageEnd < this.renderStart || pageStart > this.renderEnd)
|
|
@@ -201,42 +253,241 @@ export class MrdTable {
|
|
|
201
253
|
if (changed)
|
|
202
254
|
this.requestedPages = next;
|
|
203
255
|
}
|
|
204
|
-
// ──
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
256
|
+
// ── Filter helpers ─────────────────────────────────────────────────────────
|
|
257
|
+
handleFilterToggle() {
|
|
258
|
+
this.filterMode = !this.filterMode;
|
|
259
|
+
if (!this.filterMode)
|
|
260
|
+
this.closeFilterPopup();
|
|
261
|
+
}
|
|
262
|
+
handleFilterOpen(col, e) {
|
|
263
|
+
e.stopPropagation();
|
|
264
|
+
const btn = e.currentTarget;
|
|
265
|
+
const rect = btn.getBoundingClientRect();
|
|
266
|
+
let left = rect.left;
|
|
267
|
+
if (left + POPUP_WIDTH > window.innerWidth - 8)
|
|
268
|
+
left = rect.right - POPUP_WIDTH;
|
|
269
|
+
this.popupPos = { top: rect.bottom + 4, left: Math.max(8, left) };
|
|
270
|
+
const name = this.colName(col);
|
|
271
|
+
const dataType = this.colDataType(col);
|
|
272
|
+
const existing = this.activeFilters.get(name);
|
|
273
|
+
// Set the default operator explicitly so it is present in the ColumnFilter
|
|
274
|
+
// even when the user never touches the operator dropdown.
|
|
275
|
+
const defaultOperator = (TEXT_TYPES.has(dataType) || dataType === 'RELATION')
|
|
276
|
+
? 'startsWith'
|
|
277
|
+
: undefined;
|
|
278
|
+
this.pendingFilter = existing ? Object.assign({}, existing) : { field: name, dataType, operator: defaultOperator };
|
|
279
|
+
this.openFilterCol = name;
|
|
280
|
+
// Close on outside click — re-register to replace any stale handler
|
|
281
|
+
if (this.outsideClickHandler)
|
|
282
|
+
document.removeEventListener('click', this.outsideClickHandler);
|
|
283
|
+
this.outsideClickHandler = (ev) => {
|
|
284
|
+
const popup = this.el.querySelector('.mrd-table__filter-popup');
|
|
285
|
+
if (popup && !popup.contains(ev.target))
|
|
286
|
+
this.closeFilterPopup();
|
|
287
|
+
};
|
|
288
|
+
document.addEventListener('click', this.outsideClickHandler);
|
|
289
|
+
}
|
|
290
|
+
closeFilterPopup() {
|
|
291
|
+
this.openFilterCol = null;
|
|
292
|
+
this.pendingFilter = null;
|
|
293
|
+
if (this.outsideClickHandler) {
|
|
294
|
+
document.removeEventListener('click', this.outsideClickHandler);
|
|
295
|
+
this.outsideClickHandler = null;
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
setPending(key, val) {
|
|
299
|
+
this.pendingFilter = Object.assign(Object.assign({}, this.pendingFilter), { [key]: val });
|
|
300
|
+
}
|
|
301
|
+
togglePendingValue(key, checked) {
|
|
302
|
+
var _a, _b;
|
|
303
|
+
const current = (_b = (_a = this.pendingFilter) === null || _a === void 0 ? void 0 : _a.values) !== null && _b !== void 0 ? _b : [];
|
|
304
|
+
this.pendingFilter = Object.assign(Object.assign({}, this.pendingFilter), { values: checked ? [...current, key] : current.filter(k => k !== key) });
|
|
305
|
+
}
|
|
306
|
+
filterHasValue(f) {
|
|
307
|
+
if (f.operator === 'isEmpty' || f.operator === 'isNotEmpty')
|
|
308
|
+
return true;
|
|
309
|
+
if (f.values !== undefined && f.values.length > 0)
|
|
310
|
+
return true;
|
|
311
|
+
if (f.value != null && f.value !== '')
|
|
312
|
+
return true;
|
|
313
|
+
if (typeof f.value === 'boolean')
|
|
314
|
+
return true;
|
|
315
|
+
if (f.from != null && f.from !== '')
|
|
316
|
+
return true;
|
|
317
|
+
if (f.to != null && f.to !== '')
|
|
318
|
+
return true;
|
|
319
|
+
return false;
|
|
320
|
+
}
|
|
321
|
+
applyFilter() {
|
|
322
|
+
const f = this.pendingFilter;
|
|
323
|
+
if (!(f === null || f === void 0 ? void 0 : f.field)) {
|
|
324
|
+
this.closeFilterPopup();
|
|
325
|
+
return;
|
|
326
|
+
}
|
|
327
|
+
const next = new Map(this.activeFilters);
|
|
328
|
+
if (this.filterHasValue(f)) {
|
|
329
|
+
next.set(f.field, f);
|
|
330
|
+
}
|
|
331
|
+
else {
|
|
332
|
+
next.delete(f.field);
|
|
333
|
+
}
|
|
334
|
+
this.activeFilters = next;
|
|
335
|
+
this.closeFilterPopup();
|
|
336
|
+
this.mrdFilter.emit({ filters: Array.from(this.activeFilters.values()) });
|
|
337
|
+
if (this.totalElements > 0) {
|
|
338
|
+
this.resetPages();
|
|
339
|
+
this.emitPagesForWindow(this.renderStart, this.renderEnd);
|
|
213
340
|
}
|
|
214
341
|
}
|
|
342
|
+
clearFilter() {
|
|
343
|
+
const name = this.openFilterCol;
|
|
344
|
+
const next = new Map(this.activeFilters);
|
|
345
|
+
if (name)
|
|
346
|
+
next.delete(name);
|
|
347
|
+
this.activeFilters = next;
|
|
348
|
+
this.closeFilterPopup();
|
|
349
|
+
this.mrdFilter.emit({ filters: Array.from(this.activeFilters.values()) });
|
|
350
|
+
if (this.totalElements > 0) {
|
|
351
|
+
this.resetPages();
|
|
352
|
+
this.emitPagesForWindow(this.renderStart, this.renderEnd);
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
clearAllFilters() {
|
|
356
|
+
this.activeFilters = new Map();
|
|
357
|
+
this.mrdFilter.emit({ filters: [] });
|
|
358
|
+
if (this.totalElements > 0) {
|
|
359
|
+
this.resetPages();
|
|
360
|
+
this.emitPagesForWindow(this.renderStart, this.renderEnd);
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
// ── Render: toolbar ────────────────────────────────────────────────────────
|
|
364
|
+
renderToolbar() {
|
|
365
|
+
var _a;
|
|
366
|
+
const filterCount = this.activeFilters.size;
|
|
367
|
+
const hasActions = ((_a = this.actions) === null || _a === void 0 ? void 0 : _a.length) > 0;
|
|
368
|
+
return (h("div", { class: "mrd-table__toolbar" }, h("div", { class: "mrd-table__toolbar-left" }, h("button", { class: `mrd-table__action mrd-table__action--secondary mrd-table__filter-toggle${this.filterMode ? ' mrd-table__filter-toggle--active' : ''}`, onClick: () => this.handleFilterToggle() }, h("svg", { class: "mrd-table__action-icon", viewBox: "0 0 24 24", "aria-hidden": "true" }, h("path", { fill: "currentColor", d: "M10 18h4v-2h-4v2zM3 6v2h18V6H3zm3 7h12v-2H6v2z" })), filterCount > 0 && h("span", { class: "mrd-table__filter-badge" }, filterCount), h("span", { class: "mrd-table__action-tooltip" }, this.filterMode ? t('table_filter_hide', this.locale) : t('table_filter', this.locale), filterCount > 0 ? ` (${filterCount} ${t('table_filter_active', this.locale)})` : '')), filterCount > 0 && (h("button", { class: "mrd-table__action mrd-table__action--secondary", onClick: () => this.clearAllFilters() }, h("svg", { class: "mrd-table__action-icon", viewBox: "0 0 24 24", "aria-hidden": "true" }, h("path", { fill: "currentColor", d: "M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z" })), h("span", { class: "mrd-table__action-tooltip" }, t('table_filter_clear_all', this.locale))))), hasActions && (h("div", { class: "mrd-table__toolbar-right" }, this.actions.map(a => {
|
|
369
|
+
var _a;
|
|
370
|
+
return (h("button", { class: `mrd-table__action mrd-table__action--${(_a = a.variant) !== null && _a !== void 0 ? _a : 'secondary'}`, disabled: a.disabled, onClick: () => this.mrdAction.emit({ action: a.action }) }, a.icon
|
|
371
|
+
? h("svg", { class: "mrd-table__action-icon", "aria-hidden": "true" }, h("use", { href: a.icon }))
|
|
372
|
+
: a.label, h("span", { class: "mrd-table__action-tooltip" }, a.label)));
|
|
373
|
+
})))));
|
|
374
|
+
}
|
|
375
|
+
// ── Render: filter popup ───────────────────────────────────────────────────
|
|
376
|
+
renderFilterEditor(col) {
|
|
377
|
+
var _a, _b, _c, _d, _e, _f, _g;
|
|
378
|
+
const pf = (_a = this.pendingFilter) !== null && _a !== void 0 ? _a : {};
|
|
379
|
+
const dataType = this.colDataType(col);
|
|
380
|
+
if (NO_FILTER_TYPES.has(dataType)) {
|
|
381
|
+
return h("p", { class: "mrd-table__filter-no-support" }, t('filter_no_support', this.locale));
|
|
382
|
+
}
|
|
383
|
+
if (dataType === 'BOOLEAN') {
|
|
384
|
+
return (h("div", { class: "mrd-table__filter-radio-group" }, [
|
|
385
|
+
{ labelKey: 'filter_all', value: null },
|
|
386
|
+
{ labelKey: 'yes', value: true },
|
|
387
|
+
{ labelKey: 'no', value: false },
|
|
388
|
+
].map(opt => (h("label", { class: "mrd-table__filter-radio-label" }, h("input", { type: "radio", name: `bf-${this.openFilterCol}`, checked: pf.value === opt.value, onChange: () => this.setPending('value', opt.value) }), t(opt.labelKey, this.locale))))));
|
|
389
|
+
}
|
|
390
|
+
if (dataType === 'LIST') {
|
|
391
|
+
const items = (_c = (_b = col.field) === null || _b === void 0 ? void 0 : _b.listItems) !== null && _c !== void 0 ? _c : [];
|
|
392
|
+
const selected = (_d = pf.values) !== null && _d !== void 0 ? _d : [];
|
|
393
|
+
return (h("div", { class: "mrd-table__filter-list" }, h("div", { class: "mrd-table__filter-list-controls" }, h("button", { class: "mrd-table__filter-list-btn", onClick: () => { this.pendingFilter = Object.assign(Object.assign({}, pf), { values: items.map(i => i.key) }); } }, t('filter_select_all', this.locale)), h("button", { class: "mrd-table__filter-list-btn", onClick: () => { this.pendingFilter = Object.assign(Object.assign({}, pf), { values: [] }); } }, t('filter_select_none', this.locale))), items.map(item => (h("label", { class: "mrd-table__filter-checkbox-label" }, h("input", { type: "checkbox", checked: selected.includes(item.key), onChange: (e) => this.togglePendingValue(item.key, e.target.checked) }), item.label)))));
|
|
394
|
+
}
|
|
395
|
+
if (TEXT_TYPES.has(dataType) || dataType === 'RELATION') {
|
|
396
|
+
const op = (_e = pf.operator) !== null && _e !== void 0 ? _e : 'startsWith';
|
|
397
|
+
const noInput = op === 'isEmpty' || op === 'isNotEmpty';
|
|
398
|
+
return (h("div", { class: "mrd-table__filter-editor" }, h("select", { class: "mrd-table__filter-select", onChange: (e) => this.setPending('operator', e.target.value) }, [
|
|
399
|
+
{ val: 'startsWith', labelKey: 'filter_starts_with' },
|
|
400
|
+
{ val: 'equals', labelKey: 'filter_equals' },
|
|
401
|
+
{ val: 'isEmpty', labelKey: 'filter_is_empty' },
|
|
402
|
+
{ val: 'isNotEmpty', labelKey: 'filter_is_not_empty' },
|
|
403
|
+
].map(o => h("option", { value: o.val, selected: op === o.val }, t(o.labelKey, this.locale)))), !noInput && (h("input", { type: "text", class: "mrd-table__filter-input", value: String((_f = pf.value) !== null && _f !== void 0 ? _f : ''), placeholder: t('filter_search_value', this.locale), onInput: (e) => this.setPending('value', e.target.value) }))));
|
|
404
|
+
}
|
|
405
|
+
if (NUMERIC_TYPES.has(dataType)) {
|
|
406
|
+
const rangeMode = pf.from !== undefined || pf.to !== undefined;
|
|
407
|
+
return (h("div", { class: "mrd-table__filter-editor" }, h("div", { class: "mrd-table__filter-radio-group mrd-table__filter-radio-group--inline" }, h("label", { class: "mrd-table__filter-radio-label" }, h("input", { type: "radio", name: `nm-${this.openFilterCol}`, checked: !rangeMode, onChange: () => { this.pendingFilter = Object.assign(Object.assign({}, pf), { from: undefined, to: undefined }); } }), t('filter_exact', this.locale)), h("label", { class: "mrd-table__filter-radio-label" }, h("input", { type: "radio", name: `nm-${this.openFilterCol}`, checked: rangeMode, onChange: () => { this.pendingFilter = Object.assign(Object.assign({}, pf), { value: undefined, from: null, to: null }); } }), t('filter_range', this.locale))), !rangeMode ? (h("input", { type: "number", class: "mrd-table__filter-input", value: pf.value != null ? String(pf.value) : '', onInput: (e) => this.setPending('value', e.target.value) })) : (h("div", { class: "mrd-table__filter-range" }, h("input", { type: "number", class: "mrd-table__filter-input", placeholder: t('filter_from', this.locale), value: pf.from != null ? String(pf.from) : '', onInput: (e) => this.setPending('from', e.target.value) }), h("span", { class: "mrd-table__filter-range-sep" }, "\u2013"), h("input", { type: "number", class: "mrd-table__filter-input", placeholder: t('filter_to', this.locale), value: pf.to != null ? String(pf.to) : '', onInput: (e) => this.setPending('to', e.target.value) })))));
|
|
408
|
+
}
|
|
409
|
+
if (DATE_TYPES.has(dataType)) {
|
|
410
|
+
const inputType = dataType === 'DATE' ? 'date'
|
|
411
|
+
: dataType === 'DATETIME' ? 'datetime-local'
|
|
412
|
+
: 'time';
|
|
413
|
+
const rangeMode = pf.from !== undefined || pf.to !== undefined;
|
|
414
|
+
return (h("div", { class: "mrd-table__filter-editor" }, h("div", { class: "mrd-table__filter-radio-group mrd-table__filter-radio-group--inline" }, h("label", { class: "mrd-table__filter-radio-label" }, h("input", { type: "radio", name: `dt-${this.openFilterCol}`, checked: !rangeMode, onChange: () => { this.pendingFilter = Object.assign(Object.assign({}, pf), { from: undefined, to: undefined }); } }), t('filter_exact', this.locale)), h("label", { class: "mrd-table__filter-radio-label" }, h("input", { type: "radio", name: `dt-${this.openFilterCol}`, checked: rangeMode, onChange: () => { this.pendingFilter = Object.assign(Object.assign({}, pf), { value: undefined, from: null, to: null }); } }), t('filter_range', this.locale))), !rangeMode ? (h("input", { type: inputType, class: "mrd-table__filter-input", value: String((_g = pf.value) !== null && _g !== void 0 ? _g : ''), onInput: (e) => this.setPending('value', e.target.value) })) : (h("div", { class: "mrd-table__filter-range" }, h("input", { type: inputType, class: "mrd-table__filter-input", placeholder: t('filter_from', this.locale), value: pf.from != null ? String(pf.from) : '', onInput: (e) => this.setPending('from', e.target.value) }), h("input", { type: inputType, class: "mrd-table__filter-input", placeholder: t('filter_to', this.locale), value: pf.to != null ? String(pf.to) : '', onInput: (e) => this.setPending('to', e.target.value) })))));
|
|
415
|
+
}
|
|
416
|
+
return null;
|
|
417
|
+
}
|
|
418
|
+
renderFilterPopup() {
|
|
419
|
+
var _a, _b, _c, _d;
|
|
420
|
+
if (!this.openFilterCol || !this.pendingFilter)
|
|
421
|
+
return null;
|
|
422
|
+
const col = this.columns.find(c => this.colName(c) === this.openFilterCol);
|
|
423
|
+
if (!col)
|
|
424
|
+
return null;
|
|
425
|
+
const label = (_d = (_b = (_a = col.field) === null || _a === void 0 ? void 0 : _a.label) !== null && _b !== void 0 ? _b : (_c = col.relation) === null || _c === void 0 ? void 0 : _c.label) !== null && _d !== void 0 ? _d : this.openFilterCol;
|
|
426
|
+
const sortActive = this.sortField === this.openFilterCol;
|
|
427
|
+
return (h("div", { class: "mrd-table__filter-popup", style: { top: `${this.popupPos.top}px`, left: `${this.popupPos.left}px` }, onClick: (e) => e.stopPropagation() }, h("div", { class: "mrd-table__filter-popup-header" }, h("span", { class: "mrd-table__filter-popup-title" }, label), h("button", { class: "mrd-table__filter-close", onClick: () => this.closeFilterPopup() }, "\u2715")), h("div", { class: "mrd-table__filter-section" }, h("div", { class: "mrd-table__filter-section-label" }, t('filter_sorting', this.locale)), h("div", { class: "mrd-table__filter-sort-buttons" }, h("button", { class: `mrd-table__filter-sort-btn${sortActive && this.sortDir === 'asc' ? ' mrd-table__filter-sort-btn--active' : ''}`, onClick: () => this.applySort(col, 'asc') }, "\u25B2 ", t('filter_ascending', this.locale)), h("button", { class: `mrd-table__filter-sort-btn${sortActive && this.sortDir === 'desc' ? ' mrd-table__filter-sort-btn--active' : ''}`, onClick: () => this.applySort(col, 'desc') }, "\u25BC ", t('filter_descending', this.locale)))), h("div", { class: "mrd-table__filter-divider" }), h("div", { class: "mrd-table__filter-section" }, h("div", { class: "mrd-table__filter-section-label" }, t('filter_section', this.locale)), this.renderFilterEditor(col)), h("div", { class: "mrd-table__filter-popup-footer" }, h("button", { class: "mrd-table__filter-btn mrd-table__filter-btn--clear", onClick: () => this.clearFilter() }, t('filter_clear', this.locale)), h("button", { class: "mrd-table__filter-btn mrd-table__filter-btn--apply", onClick: () => this.applyFilter() }, t('filter_apply', this.locale)))));
|
|
428
|
+
}
|
|
429
|
+
// ── Render: footer ────────────────────────────────────────────────────────
|
|
430
|
+
renderFooter(rowCount, effectiveTotal) {
|
|
431
|
+
const total = this.totalElements;
|
|
432
|
+
// Non-paginated mode: show plain row count
|
|
433
|
+
if (total === 0) {
|
|
434
|
+
const count = rowCount !== null && rowCount !== void 0 ? rowCount : 0;
|
|
435
|
+
if (count === 0)
|
|
436
|
+
return null;
|
|
437
|
+
return (h("div", { class: "mrd-table__footer" }, count, " ", t('table_of', this.locale), " ", count));
|
|
438
|
+
}
|
|
439
|
+
// Paginated mode: only show once page 0 has loaded (avoids stale total during filter reset)
|
|
440
|
+
if (!this.loadedPages.has(0))
|
|
441
|
+
return null;
|
|
442
|
+
// Use effectiveTotal (derived from actual page lengths) so the counter
|
|
443
|
+
// is correct even when the host has not yet updated totalElements.
|
|
444
|
+
const displayTotal = effectiveTotal !== null && effectiveTotal !== void 0 ? effectiveTotal : total;
|
|
445
|
+
// Compute from/to independently so partial rows at top/bottom are included.
|
|
446
|
+
const from = Math.min(Math.floor(this.scrollTop / this.rowHeight) + 1, displayTotal);
|
|
447
|
+
const to = Math.min(Math.ceil((this.scrollTop + this.tableHeight) / this.rowHeight), displayTotal);
|
|
448
|
+
return (h("div", { class: "mrd-table__footer" }, from, "\u2013", to, " ", t('table_of', this.locale), " ", displayTotal));
|
|
449
|
+
}
|
|
215
450
|
// ── Render ─────────────────────────────────────────────────────────────────
|
|
216
451
|
render() {
|
|
217
|
-
var _a, _b;
|
|
452
|
+
var _a, _b, _c;
|
|
218
453
|
if (!((_a = this.columns) === null || _a === void 0 ? void 0 : _a.length))
|
|
219
454
|
return null;
|
|
220
455
|
const numericTypes = new Set(['INTEGER', 'DECIMAL', 'PERCENTAGE', 'CURRENCY']);
|
|
221
456
|
// ── Non-paginated mode ──────────────────────────────────────────────────
|
|
222
457
|
if (this.totalElements === 0) {
|
|
223
|
-
return (h(Host, null, h("div", { class: "mrd-table" }, h("table", { class: "mrd-table__table" }, h("thead", null, h("tr", null, this.columns.map(col => {
|
|
458
|
+
return (h(Host, null, this.renderToolbar(), h("div", { class: "mrd-table" }, h("table", { class: "mrd-table__table" }, h("thead", null, h("tr", null, this.columns.map(col => {
|
|
224
459
|
var _a, _b, _c, _d;
|
|
225
|
-
|
|
460
|
+
const name = this.colName(col);
|
|
461
|
+
const isFiltered = this.activeFilters.has(name);
|
|
462
|
+
return (h("th", { class: `mrd-table__header${isFiltered ? ' mrd-table__header--filtered' : ''}` }, h("span", { class: "mrd-table__header-label" }, (_d = (_b = (_a = col.field) === null || _a === void 0 ? void 0 : _a.label) !== null && _b !== void 0 ? _b : (_c = col.relation) === null || _c === void 0 ? void 0 : _c.label) !== null && _d !== void 0 ? _d : ''), this.filterMode && (h("button", { class: `mrd-table__header-filter-btn${isFiltered ? ' mrd-table__header-filter-btn--active' : ''}`, onClick: (e) => this.handleFilterOpen(col, e) }, "\u25BE"))));
|
|
226
463
|
}))), h("tbody", null, (_b = this.rows) === null || _b === void 0 ? void 0 : _b.map((row, i) => (h("tr", { class: "mrd-table__row mrd-table__row--clickable", style: { background: i % 2 === 0 ? '' : 'var(--mrd-color-neutral-100)' }, onClick: () => this.mrdRowClick.emit(row) }, this.columns.map(col => {
|
|
227
464
|
var _a, _b;
|
|
228
465
|
const value = CellRenderer.render(col, row, this.locale);
|
|
229
466
|
const isNumeric = col.type === 'FIELD' && numericTypes.has((_b = (_a = col.field) === null || _a === void 0 ? void 0 : _a.dataType) !== null && _b !== void 0 ? _b : '');
|
|
230
467
|
return (h("td", { class: `mrd-table__cell${isNumeric ? ' mrd-table__cell--numeric' : ''}` }, value));
|
|
231
|
-
})))))), (!this.rows || this.rows.length === 0) && (h("p", { class: "mrd-table__empty" },
|
|
468
|
+
})))))), (!this.rows || this.rows.length === 0) && (h("p", { class: "mrd-table__empty" }, t('no_results', this.locale)))), this.renderFooter((_c = this.rows) === null || _c === void 0 ? void 0 : _c.length), this.renderFilterPopup()));
|
|
232
469
|
}
|
|
233
470
|
// ── Paginated / virtual-scroll mode ────────────────────────────────────
|
|
234
|
-
|
|
471
|
+
// Derive the authoritative row count from loaded pages:
|
|
472
|
+
// if any loaded page is shorter than pageSize it is the last page,
|
|
473
|
+
// so the true total cannot exceed (pageNum * pageSize + pageRows.length).
|
|
474
|
+
// This self-corrects without requiring the host to update totalElements.
|
|
475
|
+
let effectiveTotal = this.totalElements;
|
|
476
|
+
for (const [pageNum, pageRows] of this.loadedPages) {
|
|
477
|
+
if (pageRows.length < this.pageSize) {
|
|
478
|
+
effectiveTotal = Math.min(effectiveTotal, pageNum * this.pageSize + pageRows.length);
|
|
479
|
+
}
|
|
480
|
+
}
|
|
481
|
+
// Clamp renderEnd to what we actually know exists (-1 when empty)
|
|
482
|
+
const clampedEnd = Math.min(this.renderEnd, effectiveTotal - 1);
|
|
235
483
|
const colCount = this.columns.length;
|
|
236
484
|
const topSpacerHeight = this.renderStart * this.rowHeight;
|
|
237
|
-
const bottomSpacerHeight = Math.max(0, (
|
|
485
|
+
const bottomSpacerHeight = Math.max(0, (effectiveTotal - 1 - clampedEnd) * this.rowHeight);
|
|
486
|
+
const tableStyle = this.colWidths.length > 0
|
|
487
|
+
? { tableLayout: 'fixed' }
|
|
488
|
+
: undefined;
|
|
238
489
|
const renderedRows = [];
|
|
239
|
-
for (let i = this.renderStart; i <=
|
|
490
|
+
for (let i = this.renderStart; i <= clampedEnd; i++) {
|
|
240
491
|
const row = this.getRow(i);
|
|
241
492
|
if (row === null) {
|
|
242
493
|
renderedRows.push(h("tr", { class: "mrd-table__row mrd-table__row--loading" }, h("td", { class: "mrd-table__cell--placeholder", colSpan: colCount }, h("span", { class: "mrd-table__placeholder-bar" }))));
|
|
@@ -250,15 +501,19 @@ export class MrdTable {
|
|
|
250
501
|
})));
|
|
251
502
|
}
|
|
252
503
|
}
|
|
253
|
-
|
|
254
|
-
? { tableLayout: 'fixed' }
|
|
255
|
-
: undefined;
|
|
256
|
-
return (h(Host, null, h("div", { class: "mrd-table__scroll", style: { height: `${this.tableHeight}px` }, onScroll: this.handleScroll }, h("table", { class: "mrd-table__table", style: tableStyle }, h("thead", null, h("tr", null, this.columns.map((col, idx) => {
|
|
504
|
+
return (h(Host, null, this.renderToolbar(), h("div", { class: "mrd-table__scroll", style: { height: `${this.tableHeight}px` }, onScroll: this.handleScroll }, h("table", { class: "mrd-table__table", style: tableStyle }, h("thead", null, h("tr", null, this.columns.map((col, idx) => {
|
|
257
505
|
var _a, _b, _c, _d;
|
|
258
|
-
const
|
|
259
|
-
const
|
|
260
|
-
|
|
261
|
-
|
|
506
|
+
const name = this.colName(col);
|
|
507
|
+
const isActive = this.sortField === name;
|
|
508
|
+
const isFiltered = this.activeFilters.has(name);
|
|
509
|
+
const cls = [
|
|
510
|
+
'mrd-table__header',
|
|
511
|
+
'mrd-table__header--sortable',
|
|
512
|
+
isActive ? `mrd-table__header--sorted-${this.sortDir}` : '',
|
|
513
|
+
isFiltered ? 'mrd-table__header--filtered' : '',
|
|
514
|
+
].filter(Boolean).join(' ');
|
|
515
|
+
return (h("th", { class: cls, style: this.colWidths[idx] ? { width: `${this.colWidths[idx]}px` } : undefined, onClick: () => this.handleSortClick(col) }, h("span", { class: "mrd-table__header-label" }, (_d = (_b = (_a = col.field) === null || _a === void 0 ? void 0 : _a.label) !== null && _b !== void 0 ? _b : (_c = col.relation) === null || _c === void 0 ? void 0 : _c.label) !== null && _d !== void 0 ? _d : ''), h("span", { class: "mrd-table__sort-icon", "aria-hidden": "true" }, isActive ? (this.sortDir === 'asc' ? '▲' : '▼') : '⇅'), this.filterMode && (h("button", { class: `mrd-table__header-filter-btn${isFiltered ? ' mrd-table__header-filter-btn--active' : ''}`, onClick: (e) => { e.stopPropagation(); this.handleFilterOpen(col, e); } }, "\u25BE"))));
|
|
516
|
+
}))), h("tbody", null, topSpacerHeight > 0 && (h("tr", { class: "mrd-table__spacer", style: { height: `${topSpacerHeight}px` } }, h("td", { colSpan: colCount }))), renderedRows, bottomSpacerHeight > 0 && (h("tr", { class: "mrd-table__spacer", style: { height: `${bottomSpacerHeight}px` } }, h("td", { colSpan: colCount })))))), effectiveTotal === 0 && this.loadedPages.has(0) && (h("p", { class: "mrd-table__empty" }, t('no_results', this.locale))), effectiveTotal > 0 && this.renderFooter(undefined, effectiveTotal), this.renderFilterPopup()));
|
|
262
517
|
}
|
|
263
518
|
static get is() { return "mrd-table"; }
|
|
264
519
|
static get encapsulation() { return "scoped"; }
|
|
@@ -441,6 +696,31 @@ export class MrdTable {
|
|
|
441
696
|
"reflect": false,
|
|
442
697
|
"attribute": "default-sort",
|
|
443
698
|
"defaultValue": "''"
|
|
699
|
+
},
|
|
700
|
+
"actions": {
|
|
701
|
+
"type": "unknown",
|
|
702
|
+
"mutable": false,
|
|
703
|
+
"complexType": {
|
|
704
|
+
"original": "TableAction[]",
|
|
705
|
+
"resolved": "TableAction[]",
|
|
706
|
+
"references": {
|
|
707
|
+
"TableAction": {
|
|
708
|
+
"location": "import",
|
|
709
|
+
"path": "../../utils/cell-renderer",
|
|
710
|
+
"id": "src/utils/cell-renderer.ts::TableAction",
|
|
711
|
+
"referenceLocation": "TableAction"
|
|
712
|
+
}
|
|
713
|
+
}
|
|
714
|
+
},
|
|
715
|
+
"required": false,
|
|
716
|
+
"optional": false,
|
|
717
|
+
"docs": {
|
|
718
|
+
"tags": [],
|
|
719
|
+
"text": "Toolbar action buttons rendered above the table."
|
|
720
|
+
},
|
|
721
|
+
"getter": false,
|
|
722
|
+
"setter": false,
|
|
723
|
+
"defaultValue": "[]"
|
|
444
724
|
}
|
|
445
725
|
};
|
|
446
726
|
}
|
|
@@ -452,7 +732,13 @@ export class MrdTable {
|
|
|
452
732
|
"renderEnd": {},
|
|
453
733
|
"colWidths": {},
|
|
454
734
|
"sortField": {},
|
|
455
|
-
"sortDir": {}
|
|
735
|
+
"sortDir": {},
|
|
736
|
+
"filterMode": {},
|
|
737
|
+
"activeFilters": {},
|
|
738
|
+
"openFilterCol": {},
|
|
739
|
+
"pendingFilter": {},
|
|
740
|
+
"popupPos": {},
|
|
741
|
+
"scrollTop": {}
|
|
456
742
|
};
|
|
457
743
|
}
|
|
458
744
|
static get events() {
|
|
@@ -491,6 +777,43 @@ export class MrdTable {
|
|
|
491
777
|
}
|
|
492
778
|
}
|
|
493
779
|
}
|
|
780
|
+
}, {
|
|
781
|
+
"method": "mrdAction",
|
|
782
|
+
"name": "mrdAction",
|
|
783
|
+
"bubbles": true,
|
|
784
|
+
"cancelable": true,
|
|
785
|
+
"composed": true,
|
|
786
|
+
"docs": {
|
|
787
|
+
"tags": [],
|
|
788
|
+
"text": "Fired when a toolbar action button is clicked. Detail contains the action identifier."
|
|
789
|
+
},
|
|
790
|
+
"complexType": {
|
|
791
|
+
"original": "{ action: string }",
|
|
792
|
+
"resolved": "{ action: string; }",
|
|
793
|
+
"references": {}
|
|
794
|
+
}
|
|
795
|
+
}, {
|
|
796
|
+
"method": "mrdFilter",
|
|
797
|
+
"name": "mrdFilter",
|
|
798
|
+
"bubbles": true,
|
|
799
|
+
"cancelable": true,
|
|
800
|
+
"composed": true,
|
|
801
|
+
"docs": {
|
|
802
|
+
"tags": [],
|
|
803
|
+
"text": "Fired when active filters change. Host translates filters to API query params."
|
|
804
|
+
},
|
|
805
|
+
"complexType": {
|
|
806
|
+
"original": "{ filters: ColumnFilter[] }",
|
|
807
|
+
"resolved": "{ filters: ColumnFilter[]; }",
|
|
808
|
+
"references": {
|
|
809
|
+
"ColumnFilter": {
|
|
810
|
+
"location": "import",
|
|
811
|
+
"path": "../../utils/cell-renderer",
|
|
812
|
+
"id": "src/utils/cell-renderer.ts::ColumnFilter",
|
|
813
|
+
"referenceLocation": "ColumnFilter"
|
|
814
|
+
}
|
|
815
|
+
}
|
|
816
|
+
}
|
|
494
817
|
}];
|
|
495
818
|
}
|
|
496
819
|
static get methods() {
|
|
@@ -541,11 +864,17 @@ export class MrdTable {
|
|
|
541
864
|
"return": "Promise<void>"
|
|
542
865
|
},
|
|
543
866
|
"docs": {
|
|
544
|
-
"text": "Inject the rows for a given page (0-based).\nCreates a new Map reference so Stencil detects the state change.",
|
|
867
|
+
"text": "Inject the rows for a given page (0-based).\nCreates a new Map reference so Stencil detects the state change.\n\nWhen the page contains fewer rows than pageSize it is the last page.\nrenderEnd is clamped immediately so no loading-placeholder rows appear\nbeyond the actual data \u2014 without requiring the host to update totalElements.",
|
|
545
868
|
"tags": []
|
|
546
869
|
}
|
|
547
870
|
}
|
|
548
871
|
};
|
|
549
872
|
}
|
|
550
873
|
static get elementRef() { return "el"; }
|
|
874
|
+
static get watchers() {
|
|
875
|
+
return [{
|
|
876
|
+
"propName": "totalElements",
|
|
877
|
+
"methodName": "totalElementsChanged"
|
|
878
|
+
}];
|
|
879
|
+
}
|
|
551
880
|
}
|