@mmlogic/components 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +221 -0
- package/dist/cjs/app-globals-V2Kpy_OQ.js +5 -0
- package/dist/cjs/format-CDw-zie_.js +82 -0
- package/dist/cjs/index-OvnIRO4Y.js +1523 -0
- package/dist/cjs/index.cjs.js +32 -0
- package/dist/cjs/loader.cjs.js +13 -0
- package/dist/cjs/mosterdcomponents.cjs.js +25 -0
- package/dist/cjs/mrd-boolean-field_16.cjs.entry.js +1185 -0
- package/dist/cjs/mrd-table.cjs.entry.js +322 -0
- package/dist/cjs/quill-DmFfnC1f.js +16272 -0
- package/dist/collection/collection-manifest.json +29 -0
- package/dist/collection/components/mrd-boolean-field/mrd-boolean-field.js +199 -0
- package/dist/collection/components/mrd-boolean-field/mrd-boolean-field.scss +77 -0
- package/dist/collection/components/mrd-currency-field/mrd-currency-field.js +248 -0
- package/dist/collection/components/mrd-currency-field/mrd-currency-field.scss +100 -0
- package/dist/collection/components/mrd-date-field/mrd-date-field.js +206 -0
- package/dist/collection/components/mrd-date-field/mrd-date-field.scss +66 -0
- package/dist/collection/components/mrd-datetime-field/mrd-datetime-field.js +206 -0
- package/dist/collection/components/mrd-datetime-field/mrd-datetime-field.scss +66 -0
- package/dist/collection/components/mrd-email-field/mrd-email-field.js +230 -0
- package/dist/collection/components/mrd-email-field/mrd-email-field.scss +69 -0
- package/dist/collection/components/mrd-field/mrd-field.js +187 -0
- package/dist/collection/components/mrd-file-field/mrd-file-field.js +273 -0
- package/dist/collection/components/mrd-file-field/mrd-file-field.scss +140 -0
- package/dist/collection/components/mrd-form/mrd-form.js +245 -0
- package/dist/collection/components/mrd-form/mrd-form.scss +116 -0
- package/dist/collection/components/mrd-hyperlink-field/mrd-hyperlink-field.js +230 -0
- package/dist/collection/components/mrd-hyperlink-field/mrd-hyperlink-field.scss +69 -0
- package/dist/collection/components/mrd-image-field/mrd-image-field.js +287 -0
- package/dist/collection/components/mrd-image-field/mrd-image-field.scss +166 -0
- package/dist/collection/components/mrd-list-field/mrd-list-field.js +311 -0
- package/dist/collection/components/mrd-list-field/mrd-list-field.scss +109 -0
- package/dist/collection/components/mrd-number-field/mrd-number-field.js +316 -0
- package/dist/collection/components/mrd-number-field/mrd-number-field.scss +77 -0
- package/dist/collection/components/mrd-relation-field/mrd-relation-field.js +490 -0
- package/dist/collection/components/mrd-relation-field/mrd-relation-field.scss +266 -0
- package/dist/collection/components/mrd-table/mrd-table.js +522 -0
- package/dist/collection/components/mrd-table/mrd-table.scss +158 -0
- package/dist/collection/components/mrd-text-field/mrd-text-field.js +227 -0
- package/dist/collection/components/mrd-text-field/mrd-text-field.scss +69 -0
- package/dist/collection/components/mrd-textarea-field/mrd-textarea-field.js +267 -0
- package/dist/collection/components/mrd-textarea-field/mrd-textarea-field.scss +79 -0
- package/dist/collection/components/mrd-time-field/mrd-time-field.js +206 -0
- package/dist/collection/components/mrd-time-field/mrd-time-field.scss +66 -0
- package/dist/collection/index.js +1 -0
- package/dist/collection/types/client-layout.js +30 -0
- package/dist/collection/types/index.js +1 -0
- package/dist/collection/utils/cell-renderer.js +57 -0
- package/dist/collection/utils/format.js +72 -0
- package/dist/collection/utils/i18n.js +80 -0
- package/dist/collection/utils/validation.js +46 -0
- package/dist/components/client-layout.js +1 -0
- package/dist/components/format.js +1 -0
- package/dist/components/i18n.js +1 -0
- package/dist/components/index.d.ts +35 -0
- package/dist/components/index.js +1 -0
- package/dist/components/mrd-boolean-field.d.ts +11 -0
- package/dist/components/mrd-boolean-field.js +1 -0
- package/dist/components/mrd-boolean-field2.js +1 -0
- package/dist/components/mrd-currency-field.d.ts +11 -0
- package/dist/components/mrd-currency-field.js +1 -0
- package/dist/components/mrd-currency-field2.js +1 -0
- package/dist/components/mrd-date-field.d.ts +11 -0
- package/dist/components/mrd-date-field.js +1 -0
- package/dist/components/mrd-date-field2.js +1 -0
- package/dist/components/mrd-datetime-field.d.ts +11 -0
- package/dist/components/mrd-datetime-field.js +1 -0
- package/dist/components/mrd-datetime-field2.js +1 -0
- package/dist/components/mrd-email-field.d.ts +11 -0
- package/dist/components/mrd-email-field.js +1 -0
- package/dist/components/mrd-email-field2.js +1 -0
- package/dist/components/mrd-field.d.ts +11 -0
- package/dist/components/mrd-field.js +1 -0
- package/dist/components/mrd-field2.js +1 -0
- package/dist/components/mrd-file-field.d.ts +11 -0
- package/dist/components/mrd-file-field.js +1 -0
- package/dist/components/mrd-file-field2.js +1 -0
- package/dist/components/mrd-form.d.ts +11 -0
- package/dist/components/mrd-form.js +1 -0
- package/dist/components/mrd-hyperlink-field.d.ts +11 -0
- package/dist/components/mrd-hyperlink-field.js +1 -0
- package/dist/components/mrd-hyperlink-field2.js +1 -0
- package/dist/components/mrd-image-field.d.ts +11 -0
- package/dist/components/mrd-image-field.js +1 -0
- package/dist/components/mrd-image-field2.js +1 -0
- package/dist/components/mrd-list-field.d.ts +11 -0
- package/dist/components/mrd-list-field.js +1 -0
- package/dist/components/mrd-list-field2.js +1 -0
- package/dist/components/mrd-number-field.d.ts +11 -0
- package/dist/components/mrd-number-field.js +1 -0
- package/dist/components/mrd-number-field2.js +1 -0
- package/dist/components/mrd-relation-field.d.ts +11 -0
- package/dist/components/mrd-relation-field.js +1 -0
- package/dist/components/mrd-relation-field2.js +1 -0
- package/dist/components/mrd-table.d.ts +11 -0
- package/dist/components/mrd-table.js +1 -0
- package/dist/components/mrd-text-field.d.ts +11 -0
- package/dist/components/mrd-text-field.js +1 -0
- package/dist/components/mrd-text-field2.js +1 -0
- package/dist/components/mrd-textarea-field.d.ts +11 -0
- package/dist/components/mrd-textarea-field.js +1 -0
- package/dist/components/mrd-textarea-field2.js +1 -0
- package/dist/components/mrd-time-field.d.ts +11 -0
- package/dist/components/mrd-time-field.js +1 -0
- package/dist/components/mrd-time-field2.js +1 -0
- package/dist/components/quill.js +1 -0
- package/dist/components/validation.js +1 -0
- package/dist/esm/app-globals-DQuL1Twl.js +3 -0
- package/dist/esm/format-Dt-aHxkM.js +74 -0
- package/dist/esm/index-DQ_he8te.js +1514 -0
- package/dist/esm/index.js +32 -0
- package/dist/esm/loader.js +11 -0
- package/dist/esm/mosterdcomponents.js +21 -0
- package/dist/esm/mrd-boolean-field_16.entry.js +1168 -0
- package/dist/esm/mrd-table.entry.js +320 -0
- package/dist/esm/quill-CiuCgGz_.js +16266 -0
- package/dist/index.cjs.js +1 -0
- package/dist/index.js +1 -0
- package/dist/mosterdcomponents/index.esm.js +1 -0
- package/dist/mosterdcomponents/mosterdcomponents.css +1 -0
- package/dist/mosterdcomponents/mosterdcomponents.esm.js +1 -0
- package/dist/mosterdcomponents/p-88cd0930.entry.js +1 -0
- package/dist/mosterdcomponents/p-926ed331.entry.js +1 -0
- package/dist/mosterdcomponents/p-CiuCgGz_.js +1 -0
- package/dist/mosterdcomponents/p-DQ_he8te.js +2 -0
- package/dist/mosterdcomponents/p-DQuL1Twl.js +1 -0
- package/dist/mosterdcomponents/p-Dt-aHxkM.js +1 -0
- package/dist/types/components/mrd-boolean-field/mrd-boolean-field.d.ts +22 -0
- package/dist/types/components/mrd-currency-field/mrd-currency-field.d.ts +26 -0
- package/dist/types/components/mrd-date-field/mrd-date-field.d.ts +21 -0
- package/dist/types/components/mrd-datetime-field/mrd-datetime-field.d.ts +21 -0
- package/dist/types/components/mrd-email-field/mrd-email-field.d.ts +22 -0
- package/dist/types/components/mrd-field/mrd-field.d.ts +23 -0
- package/dist/types/components/mrd-file-field/mrd-file-field.d.ts +30 -0
- package/dist/types/components/mrd-form/mrd-form.d.ts +24 -0
- package/dist/types/components/mrd-hyperlink-field/mrd-hyperlink-field.d.ts +22 -0
- package/dist/types/components/mrd-image-field/mrd-image-field.d.ts +31 -0
- package/dist/types/components/mrd-list-field/mrd-list-field.d.ts +28 -0
- package/dist/types/components/mrd-number-field/mrd-number-field.d.ts +29 -0
- package/dist/types/components/mrd-relation-field/mrd-relation-field.d.ts +44 -0
- package/dist/types/components/mrd-table/mrd-table.d.ts +72 -0
- package/dist/types/components/mrd-text-field/mrd-text-field.d.ts +22 -0
- package/dist/types/components/mrd-textarea-field/mrd-textarea-field.d.ts +25 -0
- package/dist/types/components/mrd-time-field/mrd-time-field.d.ts +21 -0
- package/dist/types/components.d.ts +1609 -0
- package/dist/types/index.d.ts +1 -0
- package/dist/types/stencil-public-runtime.d.ts +1860 -0
- package/dist/types/types/client-layout.d.ts +76 -0
- package/dist/types/types/index.d.ts +1 -0
- package/dist/types/utils/cell-renderer.d.ts +14 -0
- package/dist/types/utils/format.d.ts +7 -0
- package/dist/types/utils/i18n.d.ts +1 -0
- package/dist/types/utils/validation.d.ts +5 -0
- package/loader/cdn.js +1 -0
- package/loader/index.cjs.js +1 -0
- package/loader/index.d.ts +24 -0
- package/loader/index.es2017.js +1 -0
- package/loader/index.js +2 -0
- package/package.json +54 -0
|
@@ -0,0 +1,322 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var index = require('./index-OvnIRO4Y.js');
|
|
4
|
+
var format = require('./format-CDw-zie_.js');
|
|
5
|
+
|
|
6
|
+
class CellRenderer {
|
|
7
|
+
static render(column, row, locale) {
|
|
8
|
+
var _a, _b;
|
|
9
|
+
if (column.type === 'RELATION') {
|
|
10
|
+
const link = (_a = row === null || row === void 0 ? void 0 : row._links) === null || _a === void 0 ? void 0 : _a[column.name];
|
|
11
|
+
if (!link)
|
|
12
|
+
return '';
|
|
13
|
+
if (Array.isArray(link))
|
|
14
|
+
return link.map((l) => { var _a; return (_a = l.name) !== null && _a !== void 0 ? _a : ''; }).filter(Boolean).join(', ');
|
|
15
|
+
return (_b = link.name) !== null && _b !== void 0 ? _b : '';
|
|
16
|
+
}
|
|
17
|
+
const raw = row === null || row === void 0 ? void 0 : row[column.name];
|
|
18
|
+
if (raw == null || raw === '')
|
|
19
|
+
return '';
|
|
20
|
+
const values = Array.isArray(raw) ? raw : [raw];
|
|
21
|
+
return values
|
|
22
|
+
.map(v => { var _a; return CellRenderer.renderValue((_a = column.dataType) !== null && _a !== void 0 ? _a : 'TEXT', v, column, locale); })
|
|
23
|
+
.filter(s => s !== '')
|
|
24
|
+
.join(', ');
|
|
25
|
+
}
|
|
26
|
+
static renderValue(dataType, value, column, locale) {
|
|
27
|
+
var _a, _b;
|
|
28
|
+
switch (dataType) {
|
|
29
|
+
case 'INTEGER':
|
|
30
|
+
return format.formatNumber(Number(value), locale, { maximumFractionDigits: 0 });
|
|
31
|
+
case 'DECIMAL':
|
|
32
|
+
return format.formatNumber(Number(value), locale);
|
|
33
|
+
case 'PERCENTAGE':
|
|
34
|
+
return format.formatPercentage(Number(value), locale);
|
|
35
|
+
case 'CURRENCY': {
|
|
36
|
+
const { amount, currency } = typeof value === 'object' && value !== null
|
|
37
|
+
? value
|
|
38
|
+
: { amount: value, currency: '' };
|
|
39
|
+
return currency
|
|
40
|
+
? format.formatCurrency(Number(amount), currency, locale)
|
|
41
|
+
: format.formatNumber(Number(amount), locale);
|
|
42
|
+
}
|
|
43
|
+
case 'DATE':
|
|
44
|
+
return format.formatDate(value, locale);
|
|
45
|
+
case 'DATETIME':
|
|
46
|
+
return format.formatDateTime(value, locale);
|
|
47
|
+
case 'TIME':
|
|
48
|
+
return format.formatTime(value, locale);
|
|
49
|
+
case 'BOOLEAN':
|
|
50
|
+
return value ? '✓' : '';
|
|
51
|
+
case 'LIST': {
|
|
52
|
+
const item = (_a = column.listItems) === null || _a === void 0 ? void 0 : _a.find(li => li.key === String(value));
|
|
53
|
+
return (_b = item === null || item === void 0 ? void 0 : item.label) !== null && _b !== void 0 ? _b : String(value);
|
|
54
|
+
}
|
|
55
|
+
case 'TEXTBLOCK':
|
|
56
|
+
return String(value).replace(/<[^>]*>/g, '').trim();
|
|
57
|
+
default:
|
|
58
|
+
return String(value);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
const mrdTableScss = () => `.sc-mrd-table-h{display:block;width:100%}.mrd-table__scroll.sc-mrd-table{overflow-y:auto;overflow-x:auto;border:1px solid var(--mrd-border-color);border-radius:var(--mrd-border-radius);overflow-anchor:none}.mrd-table.sc-mrd-table{overflow-x:auto}.mrd-table__table.sc-mrd-table{width:auto;min-width:100%;border-collapse:collapse;font-size:var(--mrd-font-size-sm);color:var(--mrd-color-neutral-900)}.mrd-table__scroll.sc-mrd-table .mrd-table__table.sc-mrd-table{min-width:max-content}.mrd-table__header.sc-mrd-table{position:sticky;top:0;z-index:1;background:var(--mrd-color-white);text-align:left;padding:var(--mrd-space-2) var(--mrd-space-4);border-bottom:2px solid var(--mrd-border-color);color:var(--mrd-color-neutral-600);font-weight:var(--mrd-font-weight-medium);white-space:nowrap;font-size:var(--mrd-font-size-xs);text-transform:uppercase;letter-spacing:0.04em}.mrd-table__header--sortable.sc-mrd-table{cursor:pointer;user-select:none}.mrd-table__header--sortable.sc-mrd-table:hover{background:var(--mrd-color-neutral-50);color:var(--mrd-color-neutral-800)}.mrd-table__header--sorted-asc.sc-mrd-table,.mrd-table__header--sorted-desc.sc-mrd-table{color:var(--mrd-color-primary);border-bottom-color:var(--mrd-color-primary)}.mrd-table__header-label.sc-mrd-table{margin-right:var(--mrd-space-1)}.mrd-table__sort-icon.sc-mrd-table{font-size:0.65rem;opacity:0.4;vertical-align:middle}.mrd-table__header--sorted-asc.sc-mrd-table .mrd-table__sort-icon.sc-mrd-table,.mrd-table__header--sorted-desc.sc-mrd-table .mrd-table__sort-icon.sc-mrd-table{opacity:1;color:var(--mrd-color-primary)}.mrd-table__row.sc-mrd-table{border-bottom:1px solid var(--mrd-border-color)}.mrd-table__row.sc-mrd-table:hover{background:var(--mrd-color-neutral-200) !important}.mrd-table__spacer.sc-mrd-table{border:none}.mrd-table__spacer.sc-mrd-table td.sc-mrd-table{padding:0;border:none}.mrd-table__cell.sc-mrd-table{padding:var(--mrd-space-2) var(--mrd-space-4);vertical-align:top;white-space:nowrap}.mrd-table__cell--numeric.sc-mrd-table{text-align:right;font-variant-numeric:tabular-nums}.mrd-table__row--loading.sc-mrd-table{background:transparent}.mrd-table__cell--placeholder.sc-mrd-table{padding:var(--mrd-space-2) var(--mrd-space-4);border-bottom:1px solid var(--mrd-border-color)}.mrd-table__placeholder-bar.sc-mrd-table{display:block;height:0.75rem;width:55%;border-radius:var(--mrd-border-radius-sm);background:linear-gradient( 90deg, var(--mrd-color-neutral-200) 25%, var(--mrd-color-neutral-100) 50%, var(--mrd-color-neutral-200) 75% );background-size:200% 100%;animation:mrd-shimmer 1.4s ease infinite}@keyframes mrd-shimmer{0%{background-position:200% 0}100%{background-position:-200% 0}}.mrd-table__empty.sc-mrd-table{padding:var(--mrd-space-4) var(--mrd-space-3);color:var(--mrd-color-neutral-500);font-size:var(--mrd-font-size-sm);text-align:center;margin:0}`;
|
|
64
|
+
|
|
65
|
+
const BUFFER = 10;
|
|
66
|
+
/** Wacht deze tijd (ms) na het laatste scroll-event voordat pagina's worden
|
|
67
|
+
* aangevraagd. Pagina's die de gebruiker snel voorbij scrollt worden zo geskipt. */
|
|
68
|
+
const REQUEST_DEBOUNCE_MS = 150;
|
|
69
|
+
const MrdTable = class {
|
|
70
|
+
constructor(hostRef) {
|
|
71
|
+
index.registerInstance(this, hostRef);
|
|
72
|
+
this.mrdLoadPage = index.createEvent(this, "mrdLoadPage");
|
|
73
|
+
// ── Debounce internals (geen @State — triggert geen re-render) ─────────────
|
|
74
|
+
/** Pagina's die wachten op debounce-flush. */
|
|
75
|
+
this.pendingPages = new Set();
|
|
76
|
+
/** Handle van de actieve debounce-timer. */
|
|
77
|
+
this.debounceTimer = null;
|
|
78
|
+
// ── Props ──────────────────────────────────────────────────────────────────
|
|
79
|
+
this.columns = [];
|
|
80
|
+
/** Direct rows (non-paginated mode, used when totalElements === 0). */
|
|
81
|
+
this.rows = [];
|
|
82
|
+
this.locale = navigator.language;
|
|
83
|
+
/** Total number of records across all pages. 0 = non-paginated mode. */
|
|
84
|
+
this.totalElements = 0;
|
|
85
|
+
/** Records per page (must match the API page size). */
|
|
86
|
+
this.pageSize = 20;
|
|
87
|
+
/** Row height in px — used for spacer and scroll-position maths. */
|
|
88
|
+
this.rowHeight = 36;
|
|
89
|
+
/** Height of the scroll container in px. */
|
|
90
|
+
this.tableHeight = 500;
|
|
91
|
+
/** Initial sort applied on load, e.g. "timestamp,desc" or "name".
|
|
92
|
+
* Parsed by init() into sortField + sortDir. */
|
|
93
|
+
this.defaultSort = '';
|
|
94
|
+
// ── Internal state ─────────────────────────────────────────────────────────
|
|
95
|
+
/** Pages injected via setPage(). Always replaced by a new Map to trigger re-render. */
|
|
96
|
+
this.loadedPages = new Map();
|
|
97
|
+
/** Pages already requested via mrdLoadPage (to avoid duplicate events). */
|
|
98
|
+
this.requestedPages = new Set();
|
|
99
|
+
/** Absolute index of the first row currently in the render window. */
|
|
100
|
+
this.renderStart = 0;
|
|
101
|
+
/** Absolute index of the last row currently in the render window. */
|
|
102
|
+
this.renderEnd = 0;
|
|
103
|
+
/** Locked column widths (px) — measured after first page renders, then fixed. */
|
|
104
|
+
this.colWidths = [];
|
|
105
|
+
/** Column currently used for sorting (empty = no sort). */
|
|
106
|
+
this.sortField = '';
|
|
107
|
+
/** Sort direction for sortField. */
|
|
108
|
+
this.sortDir = 'asc';
|
|
109
|
+
this.handleScroll = (e) => {
|
|
110
|
+
const scroller = e.currentTarget;
|
|
111
|
+
const scrollTop = scroller.scrollTop;
|
|
112
|
+
const total = this.totalElements;
|
|
113
|
+
const visStart = Math.floor(scrollTop / this.rowHeight);
|
|
114
|
+
const visEnd = Math.min(visStart + this.visibleCount(), total - 1);
|
|
115
|
+
this.renderStart = Math.max(0, visStart - BUFFER);
|
|
116
|
+
this.renderEnd = Math.min(total - 1, visEnd + BUFFER);
|
|
117
|
+
this.requestPagesForWindow(this.renderStart, this.renderEnd);
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
// ── Public API ─────────────────────────────────────────────────────────────
|
|
121
|
+
/**
|
|
122
|
+
* Initialise (or reset) the virtual scroll.
|
|
123
|
+
* Call after setting all props and registering the mrdLoadPage listener,
|
|
124
|
+
* but before calling setPage(0, rows).
|
|
125
|
+
*/
|
|
126
|
+
async init() {
|
|
127
|
+
var _a;
|
|
128
|
+
if (this.debounceTimer !== null) {
|
|
129
|
+
clearTimeout(this.debounceTimer);
|
|
130
|
+
this.debounceTimer = null;
|
|
131
|
+
}
|
|
132
|
+
this.pendingPages.clear();
|
|
133
|
+
this.loadedPages = new Map();
|
|
134
|
+
this.requestedPages = new Set();
|
|
135
|
+
this.colWidths = [];
|
|
136
|
+
// Apply defaultSort prop as the initial sort state.
|
|
137
|
+
if (this.defaultSort) {
|
|
138
|
+
const parts = this.defaultSort.split(',');
|
|
139
|
+
this.sortField = parts[0].trim();
|
|
140
|
+
this.sortDir = ((_a = parts[1]) === null || _a === void 0 ? void 0 : _a.trim()) === 'desc' ? 'desc' : 'asc';
|
|
141
|
+
}
|
|
142
|
+
else {
|
|
143
|
+
this.sortField = '';
|
|
144
|
+
this.sortDir = 'asc';
|
|
145
|
+
}
|
|
146
|
+
this.renderStart = 0;
|
|
147
|
+
this.renderEnd = Math.max(0, Math.min(this.visibleCount() + BUFFER, this.totalElements - 1));
|
|
148
|
+
// Scroll the container back to the top when switching datasets.
|
|
149
|
+
const scroller = this.el.querySelector('.mrd-table__scroll');
|
|
150
|
+
if (scroller)
|
|
151
|
+
scroller.scrollTop = 0;
|
|
152
|
+
// Do NOT emit mrdLoadPage here — the host injects page 0 via setPage().
|
|
153
|
+
}
|
|
154
|
+
/**
|
|
155
|
+
* Inject the rows for a given page (0-based).
|
|
156
|
+
* Creates a new Map reference so Stencil detects the state change.
|
|
157
|
+
*/
|
|
158
|
+
async setPage(pageNumber, rows) {
|
|
159
|
+
const next = new Map(this.loadedPages);
|
|
160
|
+
next.set(pageNumber, rows);
|
|
161
|
+
this.loadedPages = next;
|
|
162
|
+
}
|
|
163
|
+
// ── Private helpers ────────────────────────────────────────────────────────
|
|
164
|
+
visibleCount() {
|
|
165
|
+
return Math.ceil(this.tableHeight / this.rowHeight);
|
|
166
|
+
}
|
|
167
|
+
/** Returns the current sort value for use in ?sort= query params. */
|
|
168
|
+
sortParam() {
|
|
169
|
+
if (!this.sortField)
|
|
170
|
+
return '';
|
|
171
|
+
return this.sortDir === 'desc' ? `${this.sortField},desc` : this.sortField;
|
|
172
|
+
}
|
|
173
|
+
/** Called when a header cell is clicked. Toggles direction or sets a new column. */
|
|
174
|
+
handleSortClick(col) {
|
|
175
|
+
if (this.sortField === col.name) {
|
|
176
|
+
this.sortDir = this.sortDir === 'asc' ? 'desc' : 'asc';
|
|
177
|
+
}
|
|
178
|
+
else {
|
|
179
|
+
this.sortField = col.name;
|
|
180
|
+
this.sortDir = 'asc';
|
|
181
|
+
}
|
|
182
|
+
// Cancel any pending scroll debounce.
|
|
183
|
+
if (this.debounceTimer !== null) {
|
|
184
|
+
clearTimeout(this.debounceTimer);
|
|
185
|
+
this.debounceTimer = null;
|
|
186
|
+
}
|
|
187
|
+
this.pendingPages.clear();
|
|
188
|
+
// Wipe all loaded data so the new sort order is fetched fresh.
|
|
189
|
+
this.loadedPages = new Map();
|
|
190
|
+
this.requestedPages = new Set();
|
|
191
|
+
this.colWidths = [];
|
|
192
|
+
this.renderStart = 0;
|
|
193
|
+
this.renderEnd = Math.max(0, Math.min(this.visibleCount() + BUFFER, this.totalElements - 1));
|
|
194
|
+
const scroller = this.el.querySelector('.mrd-table__scroll');
|
|
195
|
+
if (scroller)
|
|
196
|
+
scroller.scrollTop = 0;
|
|
197
|
+
// Emit immediately — no debounce for intentional sort clicks.
|
|
198
|
+
this.emitPagesForWindow(this.renderStart, this.renderEnd);
|
|
199
|
+
}
|
|
200
|
+
/** Emits mrdLoadPage immediately for all missing pages in [start, end]. */
|
|
201
|
+
emitPagesForWindow(start, end) {
|
|
202
|
+
const firstPage = Math.floor(start / this.pageSize);
|
|
203
|
+
const lastPage = Math.floor(end / this.pageSize);
|
|
204
|
+
const next = new Set(this.requestedPages);
|
|
205
|
+
let changed = false;
|
|
206
|
+
for (let p = firstPage; p <= lastPage; p++) {
|
|
207
|
+
if (!this.loadedPages.has(p) && !next.has(p)) {
|
|
208
|
+
next.add(p);
|
|
209
|
+
this.mrdLoadPage.emit({ page: p, sort: this.sortParam() });
|
|
210
|
+
changed = true;
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
if (changed)
|
|
214
|
+
this.requestedPages = next;
|
|
215
|
+
}
|
|
216
|
+
getRow(i) {
|
|
217
|
+
var _a;
|
|
218
|
+
const page = this.loadedPages.get(Math.floor(i / this.pageSize));
|
|
219
|
+
return (_a = page === null || page === void 0 ? void 0 : page[i % this.pageSize]) !== null && _a !== void 0 ? _a : null;
|
|
220
|
+
}
|
|
221
|
+
requestPagesForWindow(start, end) {
|
|
222
|
+
const firstPage = Math.floor(start / this.pageSize);
|
|
223
|
+
const lastPage = Math.floor(end / this.pageSize);
|
|
224
|
+
let anyNew = false;
|
|
225
|
+
for (let p = firstPage; p <= lastPage; p++) {
|
|
226
|
+
if (!this.loadedPages.has(p) && !this.requestedPages.has(p) && !this.pendingPages.has(p)) {
|
|
227
|
+
this.pendingPages.add(p);
|
|
228
|
+
anyNew = true;
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
if (!anyNew)
|
|
232
|
+
return;
|
|
233
|
+
// Reset de timer: wacht tot het scrollen even stopt.
|
|
234
|
+
if (this.debounceTimer !== null)
|
|
235
|
+
clearTimeout(this.debounceTimer);
|
|
236
|
+
this.debounceTimer = setTimeout(() => this.flushPendingPages(), REQUEST_DEBOUNCE_MS);
|
|
237
|
+
}
|
|
238
|
+
/** Emitteert mrdLoadPage alleen voor pagina's die na de debounce-wachttijd
|
|
239
|
+
* nog steeds binnen het huidige render-venster vallen. */
|
|
240
|
+
flushPendingPages() {
|
|
241
|
+
this.debounceTimer = null;
|
|
242
|
+
if (this.pendingPages.size === 0)
|
|
243
|
+
return;
|
|
244
|
+
const next = new Set(this.requestedPages);
|
|
245
|
+
let changed = false;
|
|
246
|
+
for (const page of this.pendingPages) {
|
|
247
|
+
// Sla over als pagina inmiddels geladen of al aangevraagd is.
|
|
248
|
+
if (this.loadedPages.has(page) || next.has(page))
|
|
249
|
+
continue;
|
|
250
|
+
// Sla over als de pagina buiten het huidige venster is geraakt.
|
|
251
|
+
const pageStart = page * this.pageSize;
|
|
252
|
+
const pageEnd = pageStart + this.pageSize - 1;
|
|
253
|
+
if (pageEnd < this.renderStart || pageStart > this.renderEnd)
|
|
254
|
+
continue;
|
|
255
|
+
next.add(page);
|
|
256
|
+
this.mrdLoadPage.emit({ page, sort: this.sortParam() });
|
|
257
|
+
changed = true;
|
|
258
|
+
}
|
|
259
|
+
this.pendingPages.clear();
|
|
260
|
+
if (changed)
|
|
261
|
+
this.requestedPages = next;
|
|
262
|
+
}
|
|
263
|
+
// ── Lifecycle ──────────────────────────────────────────────────────────────
|
|
264
|
+
/** After the first page of data renders, lock column widths so subsequent
|
|
265
|
+
* page loads don't cause layout shifts. */
|
|
266
|
+
componentDidRender() {
|
|
267
|
+
if (this.colWidths.length === 0 && this.loadedPages.size > 0 && this.totalElements > 0) {
|
|
268
|
+
const ths = this.el.querySelectorAll('.mrd-table__header');
|
|
269
|
+
if (ths.length > 0) {
|
|
270
|
+
this.colWidths = Array.from(ths).map(th => th.offsetWidth);
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
// ── Render ─────────────────────────────────────────────────────────────────
|
|
275
|
+
render() {
|
|
276
|
+
var _a, _b;
|
|
277
|
+
if (!((_a = this.columns) === null || _a === void 0 ? void 0 : _a.length))
|
|
278
|
+
return null;
|
|
279
|
+
const numericTypes = new Set(['INTEGER', 'DECIMAL', 'PERCENTAGE', 'CURRENCY']);
|
|
280
|
+
// ── Non-paginated mode ──────────────────────────────────────────────────
|
|
281
|
+
if (this.totalElements === 0) {
|
|
282
|
+
return (index.h(index.Host, null, index.h("div", { class: "mrd-table" }, index.h("table", { class: "mrd-table__table" }, index.h("thead", null, index.h("tr", null, this.columns.map(col => (index.h("th", { class: "mrd-table__header" }, col.label))))), index.h("tbody", null, (_b = this.rows) === null || _b === void 0 ? void 0 : _b.map((row, i) => (index.h("tr", { class: "mrd-table__row", style: { background: i % 2 === 0 ? '' : 'var(--mrd-color-neutral-100)' } }, this.columns.map(col => {
|
|
283
|
+
var _a;
|
|
284
|
+
const value = CellRenderer.render(col, row, this.locale);
|
|
285
|
+
const isNumeric = col.type === 'FIELD' && numericTypes.has((_a = col.dataType) !== null && _a !== void 0 ? _a : '');
|
|
286
|
+
return (index.h("td", { class: `mrd-table__cell${isNumeric ? ' mrd-table__cell--numeric' : ''}` }, value));
|
|
287
|
+
})))))), (!this.rows || this.rows.length === 0) && (index.h("p", { class: "mrd-table__empty" }, "Geen resultaten gevonden.")))));
|
|
288
|
+
}
|
|
289
|
+
// ── Paginated / virtual-scroll mode ────────────────────────────────────
|
|
290
|
+
const total = this.totalElements;
|
|
291
|
+
const colCount = this.columns.length;
|
|
292
|
+
const topSpacerHeight = this.renderStart * this.rowHeight;
|
|
293
|
+
const bottomSpacerHeight = Math.max(0, (total - 1 - this.renderEnd) * this.rowHeight);
|
|
294
|
+
const renderedRows = [];
|
|
295
|
+
for (let i = this.renderStart; i <= this.renderEnd; i++) {
|
|
296
|
+
const row = this.getRow(i);
|
|
297
|
+
if (row === null) {
|
|
298
|
+
renderedRows.push(index.h("tr", { class: "mrd-table__row mrd-table__row--loading" }, index.h("td", { class: "mrd-table__cell--placeholder", colSpan: colCount }, index.h("span", { class: "mrd-table__placeholder-bar" }))));
|
|
299
|
+
}
|
|
300
|
+
else {
|
|
301
|
+
renderedRows.push(index.h("tr", { class: "mrd-table__row", style: { background: i % 2 === 0 ? '' : 'var(--mrd-color-neutral-100)' } }, this.columns.map(col => {
|
|
302
|
+
var _a;
|
|
303
|
+
const value = CellRenderer.render(col, row, this.locale);
|
|
304
|
+
const isNumeric = col.type === 'FIELD' && numericTypes.has((_a = col.dataType) !== null && _a !== void 0 ? _a : '');
|
|
305
|
+
return (index.h("td", { class: `mrd-table__cell${isNumeric ? ' mrd-table__cell--numeric' : ''}` }, value));
|
|
306
|
+
})));
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
const tableStyle = this.colWidths.length > 0
|
|
310
|
+
? { tableLayout: 'fixed' }
|
|
311
|
+
: undefined;
|
|
312
|
+
return (index.h(index.Host, null, index.h("div", { class: "mrd-table__scroll", style: { height: `${this.tableHeight}px` }, onScroll: this.handleScroll }, index.h("table", { class: "mrd-table__table", style: tableStyle }, index.h("thead", null, index.h("tr", null, this.columns.map((col, idx) => {
|
|
313
|
+
const isActive = this.sortField === col.name;
|
|
314
|
+
const cls = `mrd-table__header mrd-table__header--sortable${isActive ? ` mrd-table__header--sorted-${this.sortDir}` : ''}`;
|
|
315
|
+
return (index.h("th", { class: cls, style: this.colWidths[idx] ? { width: `${this.colWidths[idx]}px` } : undefined, onClick: () => this.handleSortClick(col) }, index.h("span", { class: "mrd-table__header-label" }, col.label), index.h("span", { class: "mrd-table__sort-icon", "aria-hidden": "true" }, isActive ? (this.sortDir === 'asc' ? '▲' : '▼') : '⇅')));
|
|
316
|
+
}))), index.h("tbody", null, topSpacerHeight > 0 && (index.h("tr", { class: "mrd-table__spacer", style: { height: `${topSpacerHeight}px` } }, index.h("td", { colSpan: colCount }))), renderedRows, bottomSpacerHeight > 0 && (index.h("tr", { class: "mrd-table__spacer", style: { height: `${bottomSpacerHeight}px` } }, index.h("td", { colSpan: colCount })))))), total === 0 && (index.h("p", { class: "mrd-table__empty" }, "Geen resultaten gevonden."))));
|
|
317
|
+
}
|
|
318
|
+
get el() { return index.getElement(this); }
|
|
319
|
+
};
|
|
320
|
+
MrdTable.style = mrdTableScss();
|
|
321
|
+
|
|
322
|
+
exports.mrd_table = MrdTable;
|