@appius-fr/apx 2.7.0 → 2.7.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -5,32 +5,112 @@ const CLASS_TABLE = 'apx-scrollable-table';
5
5
 
6
6
  const DEFAULT_MAX_HEIGHT = '200px';
7
7
 
8
+ const THROTTLE_MS = 16;
9
+
10
+ /** @type {Set<HTMLTableElement>} */
11
+ const dynamicTables = new Set();
12
+ /** @type {Map<Element, Set<HTMLTableElement>>} */
13
+ const scrollSourceToTables = new Map();
14
+ /** @type {Map<Element, Set<HTMLTableElement>>} */
15
+ const resizeSourceToTables = new Map();
16
+ /** @type {boolean} */
17
+ let resizeWindowAttached = false;
18
+ /** @type {ResizeObserver|null} */
19
+ let resizeObserver = null;
20
+ /** @type {number} */
21
+ let throttleLast = 0;
22
+ /** @type {number|null} */
23
+ let throttleRaf = null;
24
+
8
25
  /**
9
- * Get number of columns from the first row that has cells (sum of colspan).
10
- * @param {HTMLTableSectionElement} section - thead, tbody, or tfoot
26
+ * Sum of colspans for one row (direct th/td children of tr).
27
+ * @param {HTMLTableRowElement} tr
11
28
  * @returns {number}
12
29
  */
13
- function getColumnCountFromSection(section) {
14
- const firstRow = section?.querySelector(':scope > tr');
15
- if (!firstRow) return 0;
30
+ function getRowColumnCount(tr) {
16
31
  let cols = 0;
17
- firstRow.querySelectorAll(':scope > th, :scope > td').forEach((cell) => {
32
+ tr.querySelectorAll(':scope > th, :scope > td').forEach((cell) => {
18
33
  cols += parseInt(cell.getAttribute('colspan'), 10) || 1;
19
34
  });
20
35
  return cols;
21
36
  }
22
37
 
23
38
  /**
24
- * Get total column count for the table (from thead or tbody first row).
39
+ * Get maximum column count in a section (max sum of colspans across all rows).
40
+ * @param {HTMLTableSectionElement} section - thead, tbody, or tfoot
41
+ * @returns {number}
42
+ */
43
+ function getColumnCountFromSection(section) {
44
+ if (!section) return 0;
45
+ const rows = section.querySelectorAll(':scope > tr');
46
+ let maxCols = 0;
47
+ rows.forEach((tr) => {
48
+ const sum = getRowColumnCount(tr);
49
+ if (sum > maxCols) maxCols = sum;
50
+ });
51
+ return maxCols;
52
+ }
53
+
54
+ /**
55
+ * Get total column count for the table (max across thead, tbody, tfoot).
25
56
  * @param {HTMLTableElement} table
26
57
  * @returns {number}
27
58
  */
28
59
  function getTableColumnCount(table) {
29
60
  const thead = table.querySelector('thead');
30
61
  const tbody = table.querySelector('tbody');
31
- const countFromThead = thead ? getColumnCountFromSection(thead) : 0;
32
- const countFromTbody = tbody ? getColumnCountFromSection(tbody) : 0;
33
- return countFromThead || countFromTbody || 1;
62
+ const tfoot = table.querySelector('tfoot');
63
+ const countThead = thead ? getColumnCountFromSection(thead) : 0;
64
+ const countTbody = tbody ? getColumnCountFromSection(tbody) : 0;
65
+ const countTfoot = tfoot ? getColumnCountFromSection(tfoot) : 0;
66
+ return Math.max(countThead, countTbody, countTfoot, 1);
67
+ }
68
+
69
+ /**
70
+ * Measure current column widths from the table in its natural layout (before applying scrollable class).
71
+ * Prefers a row where each cell has colspan 1 so we get one width per column; otherwise splits cell widths by colspan.
72
+ * @param {HTMLTableElement} table - table not yet with scrollable class
73
+ * @param {number} numCols
74
+ * @returns {number[]} pixel widths per column
75
+ */
76
+ function measureColumnWidths(table, numCols) {
77
+ const thead = table.querySelector('thead');
78
+ const tbody = table.querySelector('tbody');
79
+ const sections = [thead, tbody].filter(Boolean);
80
+ /** @type {HTMLTableRowElement|null} */
81
+ let bestRow = null;
82
+ for (const section of sections) {
83
+ const rows = section.querySelectorAll(':scope > tr');
84
+ for (const tr of rows) {
85
+ const cells = tr.querySelectorAll(':scope > th, :scope > td');
86
+ if (getRowColumnCount(tr) !== numCols) continue;
87
+ const allSingle = Array.from(cells).every((c) => (parseInt(c.getAttribute('colspan'), 10) || 1) === 1);
88
+ if (allSingle && cells.length === numCols) {
89
+ bestRow = tr;
90
+ break;
91
+ }
92
+ if (!bestRow) bestRow = tr;
93
+ }
94
+ if (bestRow && Array.from(bestRow.querySelectorAll(':scope > th, :scope > td')).every((c) => (parseInt(c.getAttribute('colspan'), 10) || 1) === 1))
95
+ break;
96
+ }
97
+ if (!bestRow) return [];
98
+
99
+ const widths = new Array(numCols).fill(0);
100
+ const cells = bestRow.querySelectorAll(':scope > th, :scope > td');
101
+ let col = 0;
102
+ for (const cell of cells) {
103
+ const span = Math.min(parseInt(cell.getAttribute('colspan'), 10) || 1, numCols - col);
104
+ if (span <= 0) break;
105
+ const w = cell.getBoundingClientRect().width;
106
+ const perCol = w / span;
107
+ for (let i = 0; i < span; i++) widths[col + i] = perCol;
108
+ col += span;
109
+ }
110
+ if (col === 0) return [];
111
+ const fallback = widths.some((w) => w > 0) ? Math.max(80, ...widths.filter((w) => w > 0)) / 2 : 80;
112
+ for (let i = 0; i < numCols; i++) if (widths[i] <= 0) widths[i] = fallback;
113
+ return widths.slice(0, numCols);
34
114
  }
35
115
 
36
116
  /**
@@ -108,22 +188,254 @@ function clearPlacements(table) {
108
188
  }
109
189
 
110
190
  /**
111
- * Normalize maxHeight option to a CSS length string.
191
+ * Normalize height/maxHeight option to a CSS length string.
112
192
  * @param {number|string} value
113
193
  * @returns {string}
114
194
  */
115
- function normalizeMaxHeight(value) {
195
+ function normalizeHeight(value) {
116
196
  if (value == null) return DEFAULT_MAX_HEIGHT;
117
197
  if (typeof value === 'number') return `${value}px`;
118
198
  return String(value);
119
199
  }
120
200
 
201
+ /**
202
+ * Resolve current body height from options: either bodyHeightDynamic.get(table) or static height/maxHeight.
203
+ * @param {Object} options - scrollableTable options (may include bodyHeightDynamic, height, maxHeight)
204
+ * @param {HTMLTableElement} table
205
+ * @returns {{ bodySize: string, useFixedHeight: boolean }}
206
+ */
207
+ function resolveBodyHeight(options, table) {
208
+ const dyn = options.bodyHeightDynamic;
209
+ if (dyn && typeof dyn.get === 'function') {
210
+ const value = dyn.get(table);
211
+ const bodySize = normalizeHeight(value);
212
+ const useFixedHeight = dyn.useAs === 'height';
213
+ return { bodySize, useFixedHeight };
214
+ }
215
+ const useFixedHeight = options.height != null;
216
+ const raw = useFixedHeight ? options.height : options.maxHeight;
217
+ const bodySize = normalizeHeight(raw);
218
+ return { bodySize, useFixedHeight };
219
+ }
220
+
221
+ /**
222
+ * Update only the tbody height CSS variable and class (used on scroll/resize for dynamic height).
223
+ * @param {HTMLTableElement} table
224
+ * @param {Object} options - full scrollableTable options (with ref.options when called from throttle)
225
+ */
226
+ function updateTableBodyHeight(table, options) {
227
+ const { bodySize, useFixedHeight } = resolveBodyHeight(options, table);
228
+ table.style.setProperty('--apx-scrollable-body-max-height', bodySize);
229
+ table.classList.toggle('apx-scrollable-table--body-height', useFixedHeight);
230
+ }
231
+
232
+ /**
233
+ * Run lazy cleanup then updateTableBodyHeight for all tables still in dynamicTables. (Called by throttled entry point or RAF.)
234
+ */
235
+ function flushDynamicHeightUpdate() {
236
+ const toRemove = [];
237
+ dynamicTables.forEach((table) => {
238
+ if (!table.isConnected) toRemove.push(table);
239
+ });
240
+ toRemove.forEach((table) => removeTableFromDynamicSources(table));
241
+ dynamicTables.forEach((table) => {
242
+ const ref = table[DATA_KEY];
243
+ if (ref?.options) updateTableBodyHeight(table, ref.options);
244
+ });
245
+ }
246
+
247
+ /**
248
+ * Throttled entry: run flushDynamicHeightUpdate now or schedule with RAF.
249
+ */
250
+ function runDynamicHeightUpdate() {
251
+ const now = Date.now();
252
+ if (now - throttleLast < THROTTLE_MS) {
253
+ if (!throttleRaf) {
254
+ throttleRaf = requestAnimationFrame(() => {
255
+ throttleRaf = null;
256
+ throttleLast = Date.now();
257
+ flushDynamicHeightUpdate();
258
+ });
259
+ }
260
+ return;
261
+ }
262
+ throttleLast = now;
263
+ flushDynamicHeightUpdate();
264
+ }
265
+
266
+ /**
267
+ * Resolve updateOn into scroll targets (Element[]) and resize: { window: boolean, elements: Element[] }.
268
+ * @param {Object} options - options.bodyHeightDynamic.updateOn
269
+ * @returns {{ scrollTargets: Element[], resizeWindow: boolean, resizeElements: Element[] }}
270
+ */
271
+ function resolveUpdateOn(options) {
272
+ const u = options?.bodyHeightDynamic?.updateOn;
273
+ const scrollOn = u?.scrollOn;
274
+ const resizeOn = u?.resizeOn;
275
+ const scrollTargets = [];
276
+ if (scrollOn != null && Array.isArray(scrollOn) && scrollOn.length > 0) {
277
+ scrollOn.forEach((x) => {
278
+ if (x === 'document') scrollTargets.push(document.documentElement);
279
+ else if (x && typeof x.addEventListener === 'function') scrollTargets.push(x);
280
+ });
281
+ } else if (u?.scroll === true) {
282
+ scrollTargets.push(document.documentElement);
283
+ scrollTargets.push(typeof window !== 'undefined' ? window : document.documentElement);
284
+ }
285
+ let resizeWindow = false;
286
+ const resizeElements = [];
287
+ if (resizeOn != null && Array.isArray(resizeOn) && resizeOn.length > 0) {
288
+ resizeOn.forEach((x) => {
289
+ if (x === 'window') resizeWindow = true;
290
+ else if (x && typeof x.addEventListener === 'function') resizeElements.push(x);
291
+ });
292
+ } else if (u?.resize !== false) {
293
+ resizeWindow = true;
294
+ resizeElements.push(document.documentElement);
295
+ }
296
+ return { scrollTargets, resizeWindow, resizeElements };
297
+ }
298
+
299
+ /**
300
+ * Remove table from dynamicTables and from all scroll/resize Maps; detach listeners if Set becomes empty.
301
+ * @param {HTMLTableElement} table
302
+ */
303
+ function removeTableFromDynamicSources(table) {
304
+ dynamicTables.delete(table);
305
+ scrollSourceToTables.forEach((set, el) => {
306
+ set.delete(table);
307
+ if (set.size === 0) {
308
+ scrollSourceToTables.delete(el);
309
+ el.removeEventListener('scroll', onScrollThrottled);
310
+ }
311
+ });
312
+ resizeSourceToTables.forEach((set, el) => {
313
+ set.delete(table);
314
+ if (set.size === 0) {
315
+ resizeSourceToTables.delete(el);
316
+ if (resizeObserver) resizeObserver.unobserve(el);
317
+ }
318
+ });
319
+ if (resizeWindowAttached && dynamicTables.size === 0) {
320
+ window.removeEventListener('resize', onResizeThrottled);
321
+ resizeWindowAttached = false;
322
+ }
323
+ }
324
+
325
+ function onScrollThrottled() {
326
+ runDynamicHeightUpdate();
327
+ }
328
+
329
+ function onResizeThrottled() {
330
+ runDynamicHeightUpdate();
331
+ }
332
+
333
+ /**
334
+ * Register a table with bodyHeightDynamic: add to Set and attach scroll/resize listeners per updateOn.
335
+ * @param {HTMLTableElement} table
336
+ * @param {Object} options - full options (ref.options)
337
+ */
338
+ function registerDynamicTable(table, options) {
339
+ const { scrollTargets, resizeWindow, resizeElements } = resolveUpdateOn(options);
340
+ dynamicTables.add(table);
341
+ scrollTargets.forEach((el) => {
342
+ let set = scrollSourceToTables.get(el);
343
+ if (!set) {
344
+ set = new Set();
345
+ scrollSourceToTables.set(el, set);
346
+ el.addEventListener('scroll', onScrollThrottled, { passive: true });
347
+ }
348
+ set.add(table);
349
+ });
350
+ if (resizeWindow) {
351
+ if (!resizeWindowAttached) {
352
+ resizeWindowAttached = true;
353
+ window.addEventListener('resize', onResizeThrottled, { passive: true });
354
+ }
355
+ }
356
+ resizeElements.forEach((el) => {
357
+ let set = resizeSourceToTables.get(el);
358
+ if (!set) {
359
+ set = new Set();
360
+ resizeSourceToTables.set(el, set);
361
+ if (!resizeObserver) resizeObserver = new ResizeObserver(onResizeThrottled);
362
+ resizeObserver.observe(el);
363
+ }
364
+ set.add(table);
365
+ });
366
+ }
367
+
368
+ /**
369
+ * Build grid-template-columns from measured widths and optional overrides per column.
370
+ * @param {number} numCols
371
+ * @param {number[]} columnWidths
372
+ * @param {Object<number, string>|(string|null)[]} columnOverrides - map column index → CSS value (e.g. '2fr'), or array; null/empty = use measured
373
+ * @returns {string}
374
+ */
375
+ function buildTemplateColumns(numCols, columnWidths, columnOverrides) {
376
+ if (!columnWidths || columnWidths.length !== numCols) return '';
377
+ const get = (i) =>
378
+ Array.isArray(columnOverrides) ? columnOverrides[i] : columnOverrides[i];
379
+ const parts = [];
380
+ for (let i = 0; i < numCols; i++) {
381
+ const ov = get(i);
382
+ if (ov != null && typeof ov === 'string' && ov.trim() !== '') {
383
+ parts.push(ov.trim());
384
+ } else {
385
+ parts.push(`${Math.round(columnWidths[i])}fr`);
386
+ }
387
+ }
388
+ return parts.join(' ');
389
+ }
390
+
391
+ /**
392
+ * Build grid-template-rows from measured heights and optional overrides per row.
393
+ * @param {number} numRows
394
+ * @param {number[]} rowHeights
395
+ * @param {Object<number, string>|(string|null)[]} rowOverrides - map row index → CSS value (e.g. '48px', '2fr'), or array; null/empty = use measured
396
+ * @returns {string}
397
+ */
398
+ function buildTemplateRows(numRows, rowHeights, rowOverrides) {
399
+ if (!rowHeights || rowHeights.length < numRows) return '';
400
+ const get = (i) =>
401
+ Array.isArray(rowOverrides) ? rowOverrides[i] : rowOverrides?.[i];
402
+ const parts = [];
403
+ for (let i = 0; i < numRows; i++) {
404
+ const ov = get(i);
405
+ if (ov != null && typeof ov === 'string' && ov.trim() !== '') {
406
+ parts.push(ov.trim());
407
+ } else {
408
+ parts.push(`${Math.round(rowHeights[i] ?? 0)}px`);
409
+ }
410
+ }
411
+ return parts.join(' ');
412
+ }
413
+
414
+ /**
415
+ * Measure each tr height in a section (table must not yet have scrollable class).
416
+ * @param {HTMLTableSectionElement|null} section
417
+ * @returns {number[]}
418
+ */
419
+ function measureRowHeights(section) {
420
+ if (!section) return [];
421
+ const rows = section.querySelectorAll(':scope > tr');
422
+ return Array.from(rows).map((tr) => tr.getBoundingClientRect().height);
423
+ }
424
+
121
425
  /**
122
426
  * Apply scrollable table layout to a single table.
123
427
  * @param {HTMLTableElement} table
124
- * @param {{ maxHeight?: number|string }} options
428
+ * @param {Object} options - scrollableTable options
429
+ * @param {number|string} [options.maxHeight] - Max height of tbody (default '200px'). Ignored when height or bodyHeightDynamic is set.
430
+ * @param {number|string} [options.height] - Fixed height of tbody. Ignored when bodyHeightDynamic is set.
431
+ * @param {{ get: (function(HTMLTableElement): number|string), useAs: 'height'|'maxHeight', updateOn?: { scroll?: boolean, resize?: boolean, scrollOn?: ('document'|Element)[], resizeOn?: ('window'|Element)[] } }} [options.bodyHeightDynamic] - When set, body size is computed by get(table) and re-applied when scroll/resize sources fire. updateOn: scrollOn/resizeOn list elements (sentinels 'document'/'window'); or use scroll (default false) / resize (default true) booleans.
432
+ * @param {string} [options.gridTemplateColumns]
433
+ * @param {{ thead?: string, tbody?: string, tfoot?: string }} [options.gridTemplateRows]
434
+ * @param {{ thead?: Object<number, string>|(string|null)[], tbody?: Object<number, string>|(string|null)[], tfoot?: Object<number, string>|(string|null)[] }} [options.rowOverrides]
435
+ * @param {Object<number, string>|(string|null)[]} [options.columnOverrides]
436
+ * @param {{ columnWidths?: number[], rowHeights?: { thead?: number[], tbody?: number[], tfoot?: number[] } } | undefined} ref - existing ref when refreshing
125
437
  */
126
- function applyScrollableTable(table, options) {
438
+ function applyScrollableTable(table, options, ref) {
127
439
  const thead = table.querySelector('thead');
128
440
  const tbody = table.querySelector('tbody');
129
441
  const tfoot = table.querySelector('tfoot');
@@ -131,32 +443,88 @@ function applyScrollableTable(table, options) {
131
443
  const numCols = getTableColumnCount(table);
132
444
  if (numCols === 0) return;
133
445
 
446
+ const alreadyScrollable = table.classList.contains(CLASS_TABLE);
447
+ const customTemplate = typeof options.gridTemplateColumns === 'string' && options.gridTemplateColumns.trim().length > 0;
448
+ const columnWidths = customTemplate
449
+ ? null
450
+ : (ref?.columnWidths ?? (alreadyScrollable ? null : measureColumnWidths(table, numCols)));
451
+
134
452
  const theadRows = getRowCount(thead);
135
453
  const tbodyRows = getRowCount(tbody);
136
454
  const tfootRows = getRowCount(tfoot);
137
455
 
456
+ const rowHeights =
457
+ ref?.rowHeights ??
458
+ (alreadyScrollable
459
+ ? null
460
+ : {
461
+ thead: measureRowHeights(thead),
462
+ tbody: measureRowHeights(tbody),
463
+ tfoot: measureRowHeights(tfoot)
464
+ });
465
+
138
466
  table.style.setProperty('--apx-scrollable-cols', String(numCols));
139
467
  table.style.setProperty('--apx-scrollable-thead-rows', String(Math.max(1, theadRows)));
140
468
  table.style.setProperty('--apx-scrollable-tbody-rows', String(Math.max(1, tbodyRows)));
141
469
  table.style.setProperty('--apx-scrollable-tfoot-rows', String(Math.max(1, tfootRows)));
142
- table.style.setProperty('--apx-scrollable-body-max-height', normalizeMaxHeight(options.maxHeight));
470
+ const { bodySize, useFixedHeight } = resolveBodyHeight(options, table);
471
+ table.style.setProperty('--apx-scrollable-body-max-height', bodySize);
472
+ table.classList.toggle('apx-scrollable-table--body-height', useFixedHeight);
143
473
 
144
474
  table.classList.add(CLASS_TABLE);
145
475
  table.classList.toggle('apx-scrollable-table--has-tfoot', !!(tfoot && tfootRows > 0));
146
476
  table.classList.toggle('apx-scrollable-table--no-thead', !(thead && theadRows > 0));
147
477
 
478
+ // Force reflow so the grid layout is established before setting measured template-columns.
479
+ // Without this, the browser batches class + template into one pass and the tbody overflows horizontally.
480
+ table.offsetHeight; // eslint-disable-line no-unused-expressions
481
+
482
+ const gutterSuffix = ' minmax(var(--apx-scrollable-gutter-width, 17px), var(--apx-scrollable-gutter-width, 17px))';
483
+ if (customTemplate) {
484
+ table.style.setProperty('--apx-scrollable-template-columns', options.gridTemplateColumns.trim() + gutterSuffix);
485
+ } else if (columnWidths && columnWidths.length === numCols) {
486
+ const template =
487
+ options.columnOverrides != null
488
+ ? buildTemplateColumns(numCols, columnWidths, options.columnOverrides)
489
+ : columnWidths.map((w) => `${Math.round(w)}fr`).join(' ');
490
+ table.style.setProperty('--apx-scrollable-template-columns', template + gutterSuffix);
491
+ } else {
492
+ table.style.removeProperty('--apx-scrollable-template-columns');
493
+ }
494
+
148
495
  clearPlacements(table);
149
496
 
150
497
  const sections = [
151
- { section: thead, rows: Math.max(1, theadRows) },
152
- { section: tbody, rows: Math.max(1, tbodyRows) },
153
- { section: tfoot, rows: Math.max(1, tfootRows) }
498
+ { section: thead, rows: Math.max(1, theadRows), heights: rowHeights?.thead, key: 'thead' },
499
+ { section: tbody, rows: Math.max(1, tbodyRows), heights: rowHeights?.tbody, key: 'tbody' },
500
+ { section: tfoot, rows: Math.max(1, tfootRows), heights: rowHeights?.tfoot, key: 'tfoot' }
154
501
  ];
155
- sections.forEach(({ section, rows }) => {
502
+ const customRows = options.gridTemplateRows && typeof options.gridTemplateRows === 'object' ? options.gridTemplateRows : null;
503
+ const rowOverrides = options.rowOverrides && typeof options.rowOverrides === 'object' ? options.rowOverrides : null;
504
+ sections.forEach(({ section, rows, heights, key }) => {
156
505
  if (!section) return;
506
+ const varName = `--apx-scrollable-${key}-template-rows`;
507
+ const custom = customRows?.[key];
508
+ const overrides = rowOverrides?.[key];
509
+ if (typeof custom === 'string' && custom.trim().length > 0) {
510
+ section.style.setProperty(varName, custom.trim());
511
+ } else if (heights && heights.length >= rows) {
512
+ const template =
513
+ overrides != null
514
+ ? buildTemplateRows(rows, heights.slice(0, rows), overrides)
515
+ : heights
516
+ .slice(0, rows)
517
+ .map((h) => `${Math.round(h)}px`)
518
+ .join(' ');
519
+ section.style.setProperty(varName, template);
520
+ } else {
521
+ section.style.removeProperty(varName);
522
+ }
157
523
  const placements = computeCellPlacements(section, rows, numCols);
158
524
  applyPlacements(placements);
159
525
  });
526
+
527
+ return { columnWidths, rowHeights };
160
528
  }
161
529
 
162
530
  /**
@@ -180,17 +548,28 @@ export default function augmentWithScrollableTable(apx) {
180
548
  const ref = table[DATA_KEY];
181
549
  if (ref) {
182
550
  if (isRefresh) {
183
- applyScrollableTable(table, ref.options);
551
+ applyScrollableTable(table, ref.options, ref);
184
552
  } else if (options && Object.keys(options).length > 0) {
185
553
  ref.options = { ...ref.options, ...options };
186
- applyScrollableTable(table, ref.options);
554
+ const result = applyScrollableTable(table, ref.options, ref);
555
+ if (result?.columnWidths) ref.columnWidths = result.columnWidths;
556
+ if (result?.rowHeights) ref.rowHeights = result.rowHeights;
187
557
  }
558
+ const currentOptions = ref.options;
559
+ if (currentOptions?.bodyHeightDynamic) registerDynamicTable(table, currentOptions);
560
+ else removeTableFromDynamicSources(table);
188
561
  return;
189
562
  }
190
563
  if (isRefresh) return;
191
564
 
192
- applyScrollableTable(table, options);
193
- table[DATA_KEY] = { options: { ...options } };
565
+ console.log('[APX scrollableTable] create', table);
566
+ const result = applyScrollableTable(table, options, undefined);
567
+ table[DATA_KEY] = {
568
+ options: { ...options },
569
+ columnWidths: result?.columnWidths || undefined,
570
+ rowHeights: result?.rowHeights || undefined
571
+ };
572
+ if (options?.bodyHeightDynamic) registerDynamicTable(table, options);
194
573
  });
195
574
 
196
575
  return apx;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@appius-fr/apx",
3
- "version": "2.7.0",
3
+ "version": "2.7.1",
4
4
  "description": "Appius Extended JS - A powerful JavaScript extension library",
5
5
  "main": "dist/APX.prod.mjs",
6
6
  "module": "dist/APX.prod.mjs",