@appius-fr/apx 2.7.0 → 2.8.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.
@@ -194,67 +194,74 @@ __webpack_require__.r(__webpack_exports__);
194
194
 
195
195
  var ___CSS_LOADER_EXPORT___ = _node_modules_css_loader_dist_runtime_api_js__WEBPACK_IMPORTED_MODULE_1___default()((_node_modules_css_loader_dist_runtime_sourceMaps_js__WEBPACK_IMPORTED_MODULE_0___default()));
196
196
  // Module
197
- ___CSS_LOADER_EXPORT___.push([module.id, `/* APX Scrollable Table: scrollable tbody with fixed thead/tfoot and aligned columns (CSS Grid + subgrid) */
198
-
199
- .apx-scrollable-table {
200
- display: grid;
201
- grid-template-columns: repeat(var(--apx-scrollable-cols, 3), minmax(0, 1fr));
202
- grid-template-rows: auto fit-content(var(--apx-scrollable-body-max-height, 200px)) auto;
203
- width: 100%;
204
- }
205
-
206
- /* Table with no tfoot: thead + tbody only */
207
- .apx-scrollable-table:not(.apx-scrollable-table--has-tfoot) {
208
- grid-template-rows: auto fit-content(var(--apx-scrollable-body-max-height, 200px));
209
- }
210
-
211
- /* Table with no thead: tbody + tfoot only */
212
- .apx-scrollable-table.apx-scrollable-table--no-thead {
213
- grid-template-rows: fit-content(var(--apx-scrollable-body-max-height, 200px)) auto;
214
- }
215
-
216
- /* Table with neither thead nor tfoot: tbody only */
217
- .apx-scrollable-table.apx-scrollable-table--no-thead:not(.apx-scrollable-table--has-tfoot) {
218
- grid-template-rows: fit-content(var(--apx-scrollable-body-max-height, 200px));
219
- }
220
-
221
- .apx-scrollable-table > thead,
222
- .apx-scrollable-table > tbody,
223
- .apx-scrollable-table > tfoot {
224
- display: grid;
225
- grid-template-columns: subgrid;
226
- grid-column: 1 / -1;
227
- grid-template-rows: repeat(var(--apx-scrollable-thead-rows, 1), auto);
228
- min-height: 0;
229
- }
230
-
231
- .apx-scrollable-table > thead {
232
- grid-template-rows: repeat(var(--apx-scrollable-thead-rows, 1), auto);
233
- }
234
-
235
- .apx-scrollable-table > tbody {
236
- grid-template-rows: repeat(var(--apx-scrollable-tbody-rows, 1), auto);
237
- overflow: auto;
238
- /* Reserve space for the vertical scrollbar so it doesn't shrink content width and trigger a horizontal scrollbar */
239
- scrollbar-gutter: stable;
240
- }
241
-
242
- .apx-scrollable-table > tfoot {
243
- grid-template-rows: repeat(var(--apx-scrollable-tfoot-rows, 1), auto);
244
- }
245
-
246
- .apx-scrollable-table > thead > tr,
247
- .apx-scrollable-table > tbody > tr,
248
- .apx-scrollable-table > tfoot > tr {
249
- display: contents;
250
- }
251
-
252
- .apx-scrollable-table th,
253
- .apx-scrollable-table td {
254
- /* Grid placement set by JS (grid-row, grid-column) for colspan/rowspan */
255
- min-width: 0;
256
- }
257
- `, "",{"version":3,"sources":["webpack://./modules/scrollableTable/css/scrollableTable.css"],"names":[],"mappings":"AAAA,2GAA2G;;AAE3G;IACI,aAAa;IACb,4EAA4E;IAC5E,uFAAuF;IACvF,WAAW;AACf;;AAEA,4CAA4C;AAC5C;IACI,kFAAkF;AACtF;;AAEA,4CAA4C;AAC5C;IACI,kFAAkF;AACtF;;AAEA,mDAAmD;AACnD;IACI,6EAA6E;AACjF;;AAEA;;;IAGI,aAAa;IACb,8BAA8B;IAC9B,mBAAmB;IACnB,qEAAqE;IACrE,aAAa;AACjB;;AAEA;IACI,qEAAqE;AACzE;;AAEA;IACI,qEAAqE;IACrE,cAAc;IACd,mHAAmH;IACnH,wBAAwB;AAC5B;;AAEA;IACI,qEAAqE;AACzE;;AAEA;;;IAGI,iBAAiB;AACrB;;AAEA;;IAEI,yEAAyE;IACzE,YAAY;AAChB","sourcesContent":["/* APX Scrollable Table: scrollable tbody with fixed thead/tfoot and aligned columns (CSS Grid + subgrid) */\r\n\r\n.apx-scrollable-table {\r\n display: grid;\r\n grid-template-columns: repeat(var(--apx-scrollable-cols, 3), minmax(0, 1fr));\r\n grid-template-rows: auto fit-content(var(--apx-scrollable-body-max-height, 200px)) auto;\r\n width: 100%;\r\n}\r\n\r\n/* Table with no tfoot: thead + tbody only */\r\n.apx-scrollable-table:not(.apx-scrollable-table--has-tfoot) {\r\n grid-template-rows: auto fit-content(var(--apx-scrollable-body-max-height, 200px));\r\n}\r\n\r\n/* Table with no thead: tbody + tfoot only */\r\n.apx-scrollable-table.apx-scrollable-table--no-thead {\r\n grid-template-rows: fit-content(var(--apx-scrollable-body-max-height, 200px)) auto;\r\n}\r\n\r\n/* Table with neither thead nor tfoot: tbody only */\r\n.apx-scrollable-table.apx-scrollable-table--no-thead:not(.apx-scrollable-table--has-tfoot) {\r\n grid-template-rows: fit-content(var(--apx-scrollable-body-max-height, 200px));\r\n}\r\n\r\n.apx-scrollable-table > thead,\r\n.apx-scrollable-table > tbody,\r\n.apx-scrollable-table > tfoot {\r\n display: grid;\r\n grid-template-columns: subgrid;\r\n grid-column: 1 / -1;\r\n grid-template-rows: repeat(var(--apx-scrollable-thead-rows, 1), auto);\r\n min-height: 0;\r\n}\r\n\r\n.apx-scrollable-table > thead {\r\n grid-template-rows: repeat(var(--apx-scrollable-thead-rows, 1), auto);\r\n}\r\n\r\n.apx-scrollable-table > tbody {\r\n grid-template-rows: repeat(var(--apx-scrollable-tbody-rows, 1), auto);\r\n overflow: auto;\r\n /* Reserve space for the vertical scrollbar so it doesn't shrink content width and trigger a horizontal scrollbar */\r\n scrollbar-gutter: stable;\r\n}\r\n\r\n.apx-scrollable-table > tfoot {\r\n grid-template-rows: repeat(var(--apx-scrollable-tfoot-rows, 1), auto);\r\n}\r\n\r\n.apx-scrollable-table > thead > tr,\r\n.apx-scrollable-table > tbody > tr,\r\n.apx-scrollable-table > tfoot > tr {\r\n display: contents;\r\n}\r\n\r\n.apx-scrollable-table th,\r\n.apx-scrollable-table td {\r\n /* Grid placement set by JS (grid-row, grid-column) for colspan/rowspan */\r\n min-width: 0;\r\n}\r\n"],"sourceRoot":""}]);
197
+ ___CSS_LOADER_EXPORT___.push([module.id, `/* APX Scrollable Table: scrollable tbody with fixed thead/tfoot and aligned columns (CSS Grid + subgrid)
198
+ Use !important so page styles (e.g. display: table) do not override the grid layout. */
199
+
200
+ /* --apx-scrollable-template-columns: set by JS (measured widths + gutter); fallback = equal columns + gutter */
201
+ /* --apx-scrollable-gutter-width: space for vertical scrollbar so it does not overlap the last column (set to 0 to allow overlap) */
202
+ /* --apx-scrollable-body-height: when class apx-scrollable-table--body-height is set, tbody row uses fixed height instead of max-height */
203
+ .apx-scrollable-table {
204
+ display: grid !important;
205
+ grid-template-columns: var(--apx-scrollable-template-columns, repeat(var(--apx-scrollable-cols, 3), minmax(0, 1fr)) minmax(var(--apx-scrollable-gutter-width, 17px), var(--apx-scrollable-gutter-width, 17px)));
206
+ grid-template-rows: auto var(--apx-scrollable-body-row-size, fit-content(var(--apx-scrollable-body-max-height, 200px))) auto;
207
+ width: 100%;
208
+ table-layout: unset !important;
209
+ }
210
+
211
+ .apx-scrollable-table--body-height {
212
+ --apx-scrollable-body-row-size: var(--apx-scrollable-body-max-height, 200px);
213
+ }
214
+
215
+ /* Table with no tfoot: thead + tbody only */
216
+ .apx-scrollable-table:not(.apx-scrollable-table--has-tfoot) {
217
+ grid-template-rows: auto var(--apx-scrollable-body-row-size, fit-content(var(--apx-scrollable-body-max-height, 200px)));
218
+ }
219
+
220
+ /* Table with no thead: tbody + tfoot only */
221
+ .apx-scrollable-table.apx-scrollable-table--no-thead {
222
+ grid-template-rows: var(--apx-scrollable-body-row-size, fit-content(var(--apx-scrollable-body-max-height, 200px))) auto;
223
+ }
224
+
225
+ /* Table with neither thead nor tfoot: tbody only */
226
+ .apx-scrollable-table.apx-scrollable-table--no-thead:not(.apx-scrollable-table--has-tfoot) {
227
+ grid-template-rows: var(--apx-scrollable-body-row-size, fit-content(var(--apx-scrollable-body-max-height, 200px)));
228
+ }
229
+
230
+ /* --apx-scrollable-*-template-rows: set by JS (measured heights) or override in CSS / via options */
231
+ .apx-scrollable-table > thead,
232
+ .apx-scrollable-table > tbody,
233
+ .apx-scrollable-table > tfoot {
234
+ display: grid !important;
235
+ grid-template-columns: subgrid;
236
+ grid-column: 1 / -1;
237
+ min-height: 0;
238
+ }
239
+
240
+ .apx-scrollable-table > thead {
241
+ grid-template-rows: var(--apx-scrollable-thead-template-rows, repeat(var(--apx-scrollable-thead-rows, 1), auto));
242
+ }
243
+
244
+ .apx-scrollable-table > tbody {
245
+ grid-template-rows: var(--apx-scrollable-tbody-template-rows, repeat(var(--apx-scrollable-tbody-rows, 1), auto));
246
+ overflow: auto;
247
+ }
248
+
249
+ .apx-scrollable-table > tfoot {
250
+ grid-template-rows: var(--apx-scrollable-tfoot-template-rows, repeat(var(--apx-scrollable-tfoot-rows, 1), auto));
251
+ }
252
+
253
+ .apx-scrollable-table > thead > tr,
254
+ .apx-scrollable-table > tbody > tr,
255
+ .apx-scrollable-table > tfoot > tr {
256
+ display: contents !important;
257
+ }
258
+
259
+ .apx-scrollable-table th,
260
+ .apx-scrollable-table td {
261
+ min-width: 0;
262
+ box-sizing: border-box;
263
+ }
264
+ `, "",{"version":3,"sources":["webpack://./modules/scrollableTable/css/scrollableTable.css"],"names":[],"mappings":"AAAA;yFACyF;;AAEzF,+GAA+G;AAC/G,mIAAmI;AACnI,yIAAyI;AACzI;IACI,wBAAwB;IACxB,+MAA+M;IAC/M,4HAA4H;IAC5H,WAAW;IACX,8BAA8B;AAClC;;AAEA;IACI,4EAA4E;AAChF;;AAEA,4CAA4C;AAC5C;IACI,uHAAuH;AAC3H;;AAEA,4CAA4C;AAC5C;IACI,uHAAuH;AAC3H;;AAEA,mDAAmD;AACnD;IACI,kHAAkH;AACtH;;AAEA,oGAAoG;AACpG;;;IAGI,wBAAwB;IACxB,8BAA8B;IAC9B,mBAAmB;IACnB,aAAa;AACjB;;AAEA;IACI,gHAAgH;AACpH;;AAEA;IACI,gHAAgH;IAChH,cAAc;AAClB;;AAEA;IACI,gHAAgH;AACpH;;AAEA;;;IAGI,4BAA4B;AAChC;;AAEA;;IAEI,YAAY;IACZ,sBAAsB;AAC1B","sourcesContent":["/* APX Scrollable Table: scrollable tbody with fixed thead/tfoot and aligned columns (CSS Grid + subgrid)\n Use !important so page styles (e.g. display: table) do not override the grid layout. */\n\n/* --apx-scrollable-template-columns: set by JS (measured widths + gutter); fallback = equal columns + gutter */\n/* --apx-scrollable-gutter-width: space for vertical scrollbar so it does not overlap the last column (set to 0 to allow overlap) */\n/* --apx-scrollable-body-height: when class apx-scrollable-table--body-height is set, tbody row uses fixed height instead of max-height */\n.apx-scrollable-table {\n display: grid !important;\n grid-template-columns: var(--apx-scrollable-template-columns, repeat(var(--apx-scrollable-cols, 3), minmax(0, 1fr)) minmax(var(--apx-scrollable-gutter-width, 17px), var(--apx-scrollable-gutter-width, 17px)));\n grid-template-rows: auto var(--apx-scrollable-body-row-size, fit-content(var(--apx-scrollable-body-max-height, 200px))) auto;\n width: 100%;\n table-layout: unset !important;\n}\n\n.apx-scrollable-table--body-height {\n --apx-scrollable-body-row-size: var(--apx-scrollable-body-max-height, 200px);\n}\n\n/* Table with no tfoot: thead + tbody only */\n.apx-scrollable-table:not(.apx-scrollable-table--has-tfoot) {\n grid-template-rows: auto var(--apx-scrollable-body-row-size, fit-content(var(--apx-scrollable-body-max-height, 200px)));\n}\n\n/* Table with no thead: tbody + tfoot only */\n.apx-scrollable-table.apx-scrollable-table--no-thead {\n grid-template-rows: var(--apx-scrollable-body-row-size, fit-content(var(--apx-scrollable-body-max-height, 200px))) auto;\n}\n\n/* Table with neither thead nor tfoot: tbody only */\n.apx-scrollable-table.apx-scrollable-table--no-thead:not(.apx-scrollable-table--has-tfoot) {\n grid-template-rows: var(--apx-scrollable-body-row-size, fit-content(var(--apx-scrollable-body-max-height, 200px)));\n}\n\n/* --apx-scrollable-*-template-rows: set by JS (measured heights) or override in CSS / via options */\n.apx-scrollable-table > thead,\n.apx-scrollable-table > tbody,\n.apx-scrollable-table > tfoot {\n display: grid !important;\n grid-template-columns: subgrid;\n grid-column: 1 / -1;\n min-height: 0;\n}\n\n.apx-scrollable-table > thead {\n grid-template-rows: var(--apx-scrollable-thead-template-rows, repeat(var(--apx-scrollable-thead-rows, 1), auto));\n}\n\n.apx-scrollable-table > tbody {\n grid-template-rows: var(--apx-scrollable-tbody-template-rows, repeat(var(--apx-scrollable-tbody-rows, 1), auto));\n overflow: auto;\n}\n\n.apx-scrollable-table > tfoot {\n grid-template-rows: var(--apx-scrollable-tfoot-template-rows, repeat(var(--apx-scrollable-tfoot-rows, 1), auto));\n}\n\n.apx-scrollable-table > thead > tr,\n.apx-scrollable-table > tbody > tr,\n.apx-scrollable-table > tfoot > tr {\n display: contents !important;\n}\n\n.apx-scrollable-table th,\n.apx-scrollable-table td {\n min-width: 0;\n box-sizing: border-box;\n}\n"],"sourceRoot":""}]);
258
265
  // Exports
259
266
  /* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (___CSS_LOADER_EXPORT___);
260
267
 
@@ -1267,34 +1274,6 @@ module.exports = "data:image/svg+xml,%3Csvg xmlns=%27http://www.w3.org/2000/svg%
1267
1274
  "use strict";
1268
1275
  module.exports = "data:image/svg+xml,%3Csvg xmlns=%27http://www.w3.org/2000/svg%27 width=%2732%27 height=%2732%27 viewBox=%270 0 32 32%27%3E%3Cpath d=%27M8 8L24 24M24 8L8 24%27 fill=%27none%27 stroke=%27%23fff%27 stroke-width=%273%27 stroke-linecap=%27round%27 stroke-linejoin=%27round%27/%3E%3C/svg%3E";
1269
1276
 
1270
- /***/ }),
1271
-
1272
- /***/ "./modules/common.mjs":
1273
- /*!****************************!*\
1274
- !*** ./modules/common.mjs ***!
1275
- \****************************/
1276
- /***/ ((__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) => {
1277
-
1278
- "use strict";
1279
- __webpack_require__.r(__webpack_exports__);
1280
- /* harmony export */ __webpack_require__.d(__webpack_exports__, {
1281
- /* harmony export */ loadCss: () => (/* binding */ loadCss)
1282
- /* harmony export */ });
1283
- // Function to load the CSS from a given URL
1284
- function loadCss(url) {
1285
- return fetch(url).then(function (response) {
1286
- return response.text();
1287
- }).then(function (css) {
1288
- var styleSheet = document.createElement("style");
1289
- styleSheet.type = "text/css";
1290
- styleSheet.textContent = css; // Use textContent instead of innerText
1291
- document.head.appendChild(styleSheet);
1292
- })["catch"](function (error) {
1293
- console.error("Failed to load CSS:", error);
1294
- });
1295
- }
1296
-
1297
-
1298
1277
  /***/ }),
1299
1278
 
1300
1279
  /***/ "./modules/dialog/dialog.mjs":
@@ -1914,65 +1893,184 @@ __webpack_require__.r(__webpack_exports__);
1914
1893
  /* harmony export */ "default": () => (/* binding */ augmentWithScrollableTable)
1915
1894
  /* harmony export */ });
1916
1895
  /* harmony import */ var _css_scrollableTable_css__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./css/scrollableTable.css */ "./modules/scrollableTable/css/scrollableTable.css");
1896
+ /* harmony import */ var _tools_getScrollbarSize_mjs__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../tools/getScrollbarSize.mjs */ "./modules/tools/getScrollbarSize.mjs");
1917
1897
  function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
1918
1898
  function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
1919
1899
  function _defineProperty(obj, key, value) { key = _toPropertyKey(key); if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
1920
1900
  function _toPropertyKey(arg) { var key = _toPrimitive(arg, "string"); return _typeof(key) === "symbol" ? key : String(key); }
1921
1901
  function _toPrimitive(input, hint) { if (_typeof(input) !== "object" || input === null) return input; var prim = input[Symbol.toPrimitive]; if (prim !== undefined) { var res = prim.call(input, hint || "default"); if (_typeof(res) !== "object") return res; throw new TypeError("@@toPrimitive must return a primitive value."); } return (hint === "string" ? String : Number)(input); }
1922
1902
  function _typeof(o) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, _typeof(o); }
1903
+ function _toConsumableArray(arr) { return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _unsupportedIterableToArray(arr) || _nonIterableSpread(); }
1904
+ function _nonIterableSpread() { throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); }
1905
+ function _iterableToArray(iter) { if (typeof Symbol !== "undefined" && iter[Symbol.iterator] != null || iter["@@iterator"] != null) return Array.from(iter); }
1906
+ function _arrayWithoutHoles(arr) { if (Array.isArray(arr)) return _arrayLikeToArray(arr); }
1923
1907
  function _createForOfIteratorHelper(o, allowArrayLike) { var it = typeof Symbol !== "undefined" && o[Symbol.iterator] || o["@@iterator"]; if (!it) { if (Array.isArray(o) || (it = _unsupportedIterableToArray(o)) || allowArrayLike && o && typeof o.length === "number") { if (it) o = it; var i = 0; var F = function F() {}; return { s: F, n: function n() { if (i >= o.length) return { done: true }; return { done: false, value: o[i++] }; }, e: function e(_e) { throw _e; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var normalCompletion = true, didErr = false, err; return { s: function s() { it = it.call(o); }, n: function n() { var step = it.next(); normalCompletion = step.done; return step; }, e: function e(_e2) { didErr = true; err = _e2; }, f: function f() { try { if (!normalCompletion && it["return"] != null) it["return"](); } finally { if (didErr) throw err; } } }; }
1924
1908
  function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); }
1925
1909
  function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] = arr[i]; return arr2; }
1926
1910
 
1911
+
1927
1912
  var DATA_KEY = '_apxScrollableTable';
1928
1913
  var CLASS_TABLE = 'apx-scrollable-table';
1929
1914
  var DEFAULT_MAX_HEIGHT = '200px';
1915
+ var DEFAULT_GUTTER_PX = 17;
1916
+ var THROTTLE_MS = 16;
1917
+
1918
+ /** @type {Set<HTMLTableElement>} */
1919
+ var dynamicTables = new Set();
1920
+ /** @type {Map<Element, Set<HTMLTableElement>>} */
1921
+ var scrollSourceToTables = new Map();
1922
+ /** @type {Map<Element, Set<HTMLTableElement>>} */
1923
+ var resizeSourceToTables = new Map();
1924
+ /** @type {boolean} */
1925
+ var resizeWindowAttached = false;
1926
+ /** @type {ResizeObserver|null} */
1927
+ var resizeObserver = null;
1928
+ /** @type {number} */
1929
+ var throttleLast = 0;
1930
+ /** @type {number|null} */
1931
+ var throttleRaf = null;
1930
1932
 
1931
- /**
1932
- * Get number of columns from the first row that has cells (sum of colspan).
1933
- * @param {HTMLTableSectionElement} section - thead, tbody, or tfoot
1934
- * @returns {number}
1933
+ /**
1934
+ * Sum of colspans for one row (direct th/td children of tr).
1935
+ * @param {HTMLTableRowElement} tr
1936
+ * @returns {number}
1935
1937
  */
1936
- function getColumnCountFromSection(section) {
1937
- var firstRow = section === null || section === void 0 ? void 0 : section.querySelector(':scope > tr');
1938
- if (!firstRow) return 0;
1938
+ function getRowColumnCount(tr) {
1939
1939
  var cols = 0;
1940
- firstRow.querySelectorAll(':scope > th, :scope > td').forEach(function (cell) {
1940
+ tr.querySelectorAll(':scope > th, :scope > td').forEach(function (cell) {
1941
1941
  cols += parseInt(cell.getAttribute('colspan'), 10) || 1;
1942
1942
  });
1943
1943
  return cols;
1944
1944
  }
1945
1945
 
1946
- /**
1947
- * Get total column count for the table (from thead or tbody first row).
1948
- * @param {HTMLTableElement} table
1949
- * @returns {number}
1946
+ /**
1947
+ * Get maximum column count in a section (max sum of colspans across all rows).
1948
+ * @param {HTMLTableSectionElement} section - thead, tbody, or tfoot
1949
+ * @returns {number}
1950
+ */
1951
+ function getColumnCountFromSection(section) {
1952
+ if (!section) return 0;
1953
+ var rows = section.querySelectorAll(':scope > tr');
1954
+ var maxCols = 0;
1955
+ rows.forEach(function (tr) {
1956
+ var sum = getRowColumnCount(tr);
1957
+ if (sum > maxCols) maxCols = sum;
1958
+ });
1959
+ return maxCols;
1960
+ }
1961
+
1962
+ /**
1963
+ * Get total column count for the table (max across thead, tbody, tfoot).
1964
+ * @param {HTMLTableElement} table
1965
+ * @returns {number}
1950
1966
  */
1951
1967
  function getTableColumnCount(table) {
1952
1968
  var thead = table.querySelector('thead');
1953
1969
  var tbody = table.querySelector('tbody');
1954
- var countFromThead = thead ? getColumnCountFromSection(thead) : 0;
1955
- var countFromTbody = tbody ? getColumnCountFromSection(tbody) : 0;
1956
- return countFromThead || countFromTbody || 1;
1970
+ var tfoot = table.querySelector('tfoot');
1971
+ var countThead = thead ? getColumnCountFromSection(thead) : 0;
1972
+ var countTbody = tbody ? getColumnCountFromSection(tbody) : 0;
1973
+ var countTfoot = tfoot ? getColumnCountFromSection(tfoot) : 0;
1974
+ return Math.max(countThead, countTbody, countTfoot, 1);
1957
1975
  }
1958
1976
 
1959
- /**
1960
- * Count direct tr children in a section.
1961
- * @param {HTMLTableSectionElement} section
1962
- * @returns {number}
1977
+ /**
1978
+ * Measure current column widths from the table in its natural layout (before applying scrollable class).
1979
+ * Prefers a row where each cell has colspan 1 so we get one width per column; otherwise splits cell widths by colspan.
1980
+ * @param {HTMLTableElement} table - table not yet with scrollable class
1981
+ * @param {number} numCols
1982
+ * @returns {number[]} pixel widths per column
1983
+ */
1984
+ function measureColumnWidths(table, numCols) {
1985
+ var thead = table.querySelector('thead');
1986
+ var tbody = table.querySelector('tbody');
1987
+ var sections = [thead, tbody].filter(Boolean);
1988
+ /** @type {HTMLTableRowElement|null} */
1989
+ var bestRow = null;
1990
+ var _iterator = _createForOfIteratorHelper(sections),
1991
+ _step;
1992
+ try {
1993
+ for (_iterator.s(); !(_step = _iterator.n()).done;) {
1994
+ var section = _step.value;
1995
+ var rows = section.querySelectorAll(':scope > tr');
1996
+ var _iterator3 = _createForOfIteratorHelper(rows),
1997
+ _step3;
1998
+ try {
1999
+ for (_iterator3.s(); !(_step3 = _iterator3.n()).done;) {
2000
+ var tr = _step3.value;
2001
+ var _cells = tr.querySelectorAll(':scope > th, :scope > td');
2002
+ if (getRowColumnCount(tr) !== numCols) continue;
2003
+ var allSingle = Array.from(_cells).every(function (c) {
2004
+ return (parseInt(c.getAttribute('colspan'), 10) || 1) === 1;
2005
+ });
2006
+ if (allSingle && _cells.length === numCols) {
2007
+ bestRow = tr;
2008
+ break;
2009
+ }
2010
+ if (!bestRow) bestRow = tr;
2011
+ }
2012
+ } catch (err) {
2013
+ _iterator3.e(err);
2014
+ } finally {
2015
+ _iterator3.f();
2016
+ }
2017
+ if (bestRow && Array.from(bestRow.querySelectorAll(':scope > th, :scope > td')).every(function (c) {
2018
+ return (parseInt(c.getAttribute('colspan'), 10) || 1) === 1;
2019
+ })) break;
2020
+ }
2021
+ } catch (err) {
2022
+ _iterator.e(err);
2023
+ } finally {
2024
+ _iterator.f();
2025
+ }
2026
+ if (!bestRow) return [];
2027
+ var widths = new Array(numCols).fill(0);
2028
+ var cells = bestRow.querySelectorAll(':scope > th, :scope > td');
2029
+ var col = 0;
2030
+ var _iterator2 = _createForOfIteratorHelper(cells),
2031
+ _step2;
2032
+ try {
2033
+ for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
2034
+ var cell = _step2.value;
2035
+ var span = Math.min(parseInt(cell.getAttribute('colspan'), 10) || 1, numCols - col);
2036
+ if (span <= 0) break;
2037
+ var w = cell.getBoundingClientRect().width;
2038
+ var perCol = w / span;
2039
+ for (var _i = 0; _i < span; _i++) widths[col + _i] = perCol;
2040
+ col += span;
2041
+ }
2042
+ } catch (err) {
2043
+ _iterator2.e(err);
2044
+ } finally {
2045
+ _iterator2.f();
2046
+ }
2047
+ if (col === 0) return [];
2048
+ var fallback = widths.some(function (w) {
2049
+ return w > 0;
2050
+ }) ? Math.max.apply(Math, [80].concat(_toConsumableArray(widths.filter(function (w) {
2051
+ return w > 0;
2052
+ })))) / 2 : 80;
2053
+ for (var i = 0; i < numCols; i++) if (widths[i] <= 0) widths[i] = fallback;
2054
+ return widths.slice(0, numCols);
2055
+ }
2056
+
2057
+ /**
2058
+ * Count direct tr children in a section.
2059
+ * @param {HTMLTableSectionElement} section
2060
+ * @returns {number}
1963
2061
  */
1964
2062
  function getRowCount(section) {
1965
2063
  if (!section) return 0;
1966
2064
  return section.querySelectorAll(':scope > tr').length;
1967
2065
  }
1968
2066
 
1969
- /**
1970
- * Build a 2D grid of occupied slots for a section (for rowspan/colspan placement).
1971
- * Place each cell in DOM order; return a list of { cell, row, col, colspan, rowspan }.
1972
- * @param {HTMLTableSectionElement} section
1973
- * @param {number} numRows
1974
- * @param {number} numCols
1975
- * @returns {{ cell: HTMLTableCellElement, row: number, col: number, colspan: number, rowspan: number }[]}
2067
+ /**
2068
+ * Build a 2D grid of occupied slots for a section (for rowspan/colspan placement).
2069
+ * Place each cell in DOM order; return a list of { cell, row, col, colspan, rowspan }.
2070
+ * @param {HTMLTableSectionElement} section
2071
+ * @param {number} numRows
2072
+ * @param {number} numCols
2073
+ * @returns {{ cell: HTMLTableCellElement, row: number, col: number, colspan: number, rowspan: number }[]}
1976
2074
  */
1977
2075
  function computeCellPlacements(section, numRows, numCols) {
1978
2076
  if (!section || numRows === 0 || numCols === 0) return [];
@@ -1986,11 +2084,11 @@ function computeCellPlacements(section, numRows, numCols) {
1986
2084
  for (var r = 0; r < rows.length; r++) {
1987
2085
  var tr = rows[r];
1988
2086
  var cells = tr.querySelectorAll(':scope > th, :scope > td');
1989
- var _iterator = _createForOfIteratorHelper(cells),
1990
- _step;
2087
+ var _iterator4 = _createForOfIteratorHelper(cells),
2088
+ _step4;
1991
2089
  try {
1992
- for (_iterator.s(); !(_step = _iterator.n()).done;) {
1993
- var cell = _step.value;
2090
+ for (_iterator4.s(); !(_step4 = _iterator4.n()).done;) {
2091
+ var cell = _step4.value;
1994
2092
  var colspan = Math.min(parseInt(cell.getAttribute('colspan'), 10) || 1, numCols);
1995
2093
  var rowspan = Math.min(parseInt(cell.getAttribute('rowspan'), 10) || 1, numRows - r);
1996
2094
  var col = 0;
@@ -2020,16 +2118,16 @@ function computeCellPlacements(section, numRows, numCols) {
2020
2118
  });
2021
2119
  }
2022
2120
  } catch (err) {
2023
- _iterator.e(err);
2121
+ _iterator4.e(err);
2024
2122
  } finally {
2025
- _iterator.f();
2123
+ _iterator4.f();
2026
2124
  }
2027
2125
  }
2028
2126
  return placements;
2029
2127
  }
2030
2128
 
2031
- /**
2032
- * Apply grid placement styles to a list of placements (1-based line numbers for CSS Grid).
2129
+ /**
2130
+ * Apply grid placement styles to a list of placements (1-based line numbers for CSS Grid).
2033
2131
  */
2034
2132
  function applyPlacements(placements) {
2035
2133
  placements.forEach(function (_ref) {
@@ -2043,9 +2141,9 @@ function applyPlacements(placements) {
2043
2141
  });
2044
2142
  }
2045
2143
 
2046
- /**
2047
- * Clear grid placement styles from all th/td in a table (for refresh).
2048
- * @param {HTMLTableElement} table
2144
+ /**
2145
+ * Clear grid placement styles from all th/td in a table (for refresh).
2146
+ * @param {HTMLTableElement} table
2049
2147
  */
2050
2148
  function clearPlacements(table) {
2051
2149
  table.querySelectorAll('th, td').forEach(function (cell) {
@@ -2054,67 +2152,394 @@ function clearPlacements(table) {
2054
2152
  });
2055
2153
  }
2056
2154
 
2057
- /**
2058
- * Normalize maxHeight option to a CSS length string.
2059
- * @param {number|string} value
2060
- * @returns {string}
2155
+ /**
2156
+ * Normalize height/maxHeight option to a CSS length string.
2157
+ * @param {number|string} value
2158
+ * @returns {string}
2061
2159
  */
2062
- function normalizeMaxHeight(value) {
2160
+ function normalizeHeight(value) {
2063
2161
  if (value == null) return DEFAULT_MAX_HEIGHT;
2064
2162
  if (typeof value === 'number') return "".concat(value, "px");
2065
2163
  return String(value);
2066
2164
  }
2067
2165
 
2068
- /**
2069
- * Apply scrollable table layout to a single table.
2070
- * @param {HTMLTableElement} table
2071
- * @param {{ maxHeight?: number|string }} options
2166
+ /**
2167
+ * Resolve current body height from options: either bodyHeightDynamic.get(table) or static height/maxHeight.
2168
+ * @param {Object} options - scrollableTable options (may include bodyHeightDynamic, height, maxHeight)
2169
+ * @param {HTMLTableElement} table
2170
+ * @returns {{ bodySize: string, useFixedHeight: boolean }}
2171
+ */
2172
+ function resolveBodyHeight(options, table) {
2173
+ var dyn = options.bodyHeightDynamic;
2174
+ if (dyn && typeof dyn.get === 'function') {
2175
+ var value = dyn.get(table);
2176
+ var _bodySize = normalizeHeight(value);
2177
+ var _useFixedHeight = dyn.useAs === 'height';
2178
+ return {
2179
+ bodySize: _bodySize,
2180
+ useFixedHeight: _useFixedHeight
2181
+ };
2182
+ }
2183
+ var useFixedHeight = options.height != null;
2184
+ var raw = useFixedHeight ? options.height : options.maxHeight;
2185
+ var bodySize = normalizeHeight(raw);
2186
+ return {
2187
+ bodySize: bodySize,
2188
+ useFixedHeight: useFixedHeight
2189
+ };
2190
+ }
2191
+
2192
+ /**
2193
+ * Update only the tbody height CSS variable and class (used on scroll/resize for dynamic height).
2194
+ * @param {HTMLTableElement} table
2195
+ * @param {Object} options - full scrollableTable options (with ref.options when called from throttle)
2196
+ */
2197
+ function updateTableBodyHeight(table, options) {
2198
+ var _resolveBodyHeight = resolveBodyHeight(options, table),
2199
+ bodySize = _resolveBodyHeight.bodySize,
2200
+ useFixedHeight = _resolveBodyHeight.useFixedHeight;
2201
+ table.style.setProperty('--apx-scrollable-body-max-height', bodySize);
2202
+ table.classList.toggle('apx-scrollable-table--body-height', useFixedHeight);
2203
+ }
2204
+
2205
+ /**
2206
+ * Run lazy cleanup then updateTableBodyHeight for all tables still in dynamicTables. (Called by throttled entry point or RAF.)
2072
2207
  */
2073
- function applyScrollableTable(table, options) {
2208
+ function flushDynamicHeightUpdate() {
2209
+ var toRemove = [];
2210
+ dynamicTables.forEach(function (table) {
2211
+ if (!table.isConnected) toRemove.push(table);
2212
+ });
2213
+ toRemove.forEach(function (table) {
2214
+ return removeTableFromDynamicSources(table);
2215
+ });
2216
+ dynamicTables.forEach(function (table) {
2217
+ var ref = table[DATA_KEY];
2218
+ if (ref !== null && ref !== void 0 && ref.options) updateTableBodyHeight(table, ref.options);
2219
+ });
2220
+ }
2221
+
2222
+ /**
2223
+ * Throttled entry: run flushDynamicHeightUpdate now or schedule with RAF.
2224
+ */
2225
+ function runDynamicHeightUpdate() {
2226
+ var now = Date.now();
2227
+ if (now - throttleLast < THROTTLE_MS) {
2228
+ if (!throttleRaf) {
2229
+ throttleRaf = requestAnimationFrame(function () {
2230
+ throttleRaf = null;
2231
+ throttleLast = Date.now();
2232
+ flushDynamicHeightUpdate();
2233
+ });
2234
+ }
2235
+ return;
2236
+ }
2237
+ throttleLast = now;
2238
+ flushDynamicHeightUpdate();
2239
+ }
2240
+
2241
+ /**
2242
+ * Resolve updateOn into scroll targets (Element[]) and resize: { window: boolean, elements: Element[] }.
2243
+ * @param {Object} options - options.bodyHeightDynamic.updateOn
2244
+ * @returns {{ scrollTargets: Element[], resizeWindow: boolean, resizeElements: Element[] }}
2245
+ */
2246
+ function resolveUpdateOn(options) {
2247
+ var _options$bodyHeightDy;
2248
+ var u = options === null || options === void 0 || (_options$bodyHeightDy = options.bodyHeightDynamic) === null || _options$bodyHeightDy === void 0 ? void 0 : _options$bodyHeightDy.updateOn;
2249
+ var scrollOn = u === null || u === void 0 ? void 0 : u.scrollOn;
2250
+ var resizeOn = u === null || u === void 0 ? void 0 : u.resizeOn;
2251
+ var scrollTargets = [];
2252
+ if (scrollOn != null && Array.isArray(scrollOn) && scrollOn.length > 0) {
2253
+ scrollOn.forEach(function (x) {
2254
+ if (x === 'document') scrollTargets.push(document.documentElement);else if (x && typeof x.addEventListener === 'function') scrollTargets.push(x);
2255
+ });
2256
+ } else if ((u === null || u === void 0 ? void 0 : u.scroll) === true) {
2257
+ scrollTargets.push(document.documentElement);
2258
+ scrollTargets.push(typeof window !== 'undefined' ? window : document.documentElement);
2259
+ }
2260
+ var resizeWindow = false;
2261
+ var resizeElements = [];
2262
+ if (resizeOn != null && Array.isArray(resizeOn) && resizeOn.length > 0) {
2263
+ resizeOn.forEach(function (x) {
2264
+ if (x === 'window') resizeWindow = true;else if (x && typeof x.addEventListener === 'function') resizeElements.push(x);
2265
+ });
2266
+ } else if ((u === null || u === void 0 ? void 0 : u.resize) !== false) {
2267
+ resizeWindow = true;
2268
+ resizeElements.push(document.documentElement);
2269
+ }
2270
+ return {
2271
+ scrollTargets: scrollTargets,
2272
+ resizeWindow: resizeWindow,
2273
+ resizeElements: resizeElements
2274
+ };
2275
+ }
2276
+
2277
+ /**
2278
+ * Remove table from dynamicTables and from all scroll/resize Maps; detach listeners if Set becomes empty.
2279
+ * @param {HTMLTableElement} table
2280
+ */
2281
+ function removeTableFromDynamicSources(table) {
2282
+ dynamicTables["delete"](table);
2283
+ scrollSourceToTables.forEach(function (set, el) {
2284
+ set["delete"](table);
2285
+ if (set.size === 0) {
2286
+ scrollSourceToTables["delete"](el);
2287
+ el.removeEventListener('scroll', onScrollThrottled);
2288
+ }
2289
+ });
2290
+ resizeSourceToTables.forEach(function (set, el) {
2291
+ set["delete"](table);
2292
+ if (set.size === 0) {
2293
+ resizeSourceToTables["delete"](el);
2294
+ if (resizeObserver) resizeObserver.unobserve(el);
2295
+ }
2296
+ });
2297
+ if (resizeWindowAttached && dynamicTables.size === 0) {
2298
+ window.removeEventListener('resize', onResizeThrottled);
2299
+ resizeWindowAttached = false;
2300
+ }
2301
+ }
2302
+ function onScrollThrottled() {
2303
+ runDynamicHeightUpdate();
2304
+ }
2305
+ function onResizeThrottled() {
2306
+ runDynamicHeightUpdate();
2307
+ }
2308
+
2309
+ /**
2310
+ * Register a table with bodyHeightDynamic: add to Set and attach scroll/resize listeners per updateOn.
2311
+ * @param {HTMLTableElement} table
2312
+ * @param {Object} options - full options (ref.options)
2313
+ */
2314
+ function registerDynamicTable(table, options) {
2315
+ var _resolveUpdateOn = resolveUpdateOn(options),
2316
+ scrollTargets = _resolveUpdateOn.scrollTargets,
2317
+ resizeWindow = _resolveUpdateOn.resizeWindow,
2318
+ resizeElements = _resolveUpdateOn.resizeElements;
2319
+ dynamicTables.add(table);
2320
+ scrollTargets.forEach(function (el) {
2321
+ var set = scrollSourceToTables.get(el);
2322
+ if (!set) {
2323
+ set = new Set();
2324
+ scrollSourceToTables.set(el, set);
2325
+ el.addEventListener('scroll', onScrollThrottled, {
2326
+ passive: true
2327
+ });
2328
+ }
2329
+ set.add(table);
2330
+ });
2331
+ if (resizeWindow) {
2332
+ if (!resizeWindowAttached) {
2333
+ resizeWindowAttached = true;
2334
+ window.addEventListener('resize', onResizeThrottled, {
2335
+ passive: true
2336
+ });
2337
+ }
2338
+ }
2339
+ resizeElements.forEach(function (el) {
2340
+ var set = resizeSourceToTables.get(el);
2341
+ if (!set) {
2342
+ set = new Set();
2343
+ resizeSourceToTables.set(el, set);
2344
+ if (!resizeObserver) resizeObserver = new ResizeObserver(onResizeThrottled);
2345
+ resizeObserver.observe(el);
2346
+ }
2347
+ set.add(table);
2348
+ });
2349
+ }
2350
+
2351
+ /**
2352
+ * Build grid-template-columns from measured widths and optional overrides per column.
2353
+ * @param {number} numCols
2354
+ * @param {number[]} columnWidths
2355
+ * @param {Object<number, string>|(string|null)[]} columnOverrides - map column index → CSS value (e.g. '2fr'), or array; null/empty = use measured
2356
+ * @param {string} [unit='fr'] - CSS unit for measured widths ('fr' or 'px')
2357
+ * @returns {string}
2358
+ */
2359
+ function buildTemplateColumns(numCols, columnWidths, columnOverrides) {
2360
+ var unit = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : 'fr';
2361
+ if (!columnWidths || columnWidths.length !== numCols) return '';
2362
+ var get = function get(i) {
2363
+ return Array.isArray(columnOverrides) ? columnOverrides[i] : columnOverrides[i];
2364
+ };
2365
+ var parts = [];
2366
+ for (var i = 0; i < numCols; i++) {
2367
+ var ov = get(i);
2368
+ if (ov != null && typeof ov === 'string' && ov.trim() !== '') {
2369
+ parts.push(ov.trim());
2370
+ } else {
2371
+ parts.push("".concat(Math.round(columnWidths[i])).concat(unit));
2372
+ }
2373
+ }
2374
+ return parts.join(' ');
2375
+ }
2376
+
2377
+ /**
2378
+ * Build grid-template-rows from measured heights and optional overrides per row.
2379
+ * @param {number} numRows
2380
+ * @param {number[]} rowHeights
2381
+ * @param {Object<number, string>|(string|null)[]} rowOverrides - map row index → CSS value (e.g. '48px', '2fr'), or array; null/empty = use measured
2382
+ * @param {string} [unit='px'] - CSS unit for measured heights ('px' or 'fr')
2383
+ * @returns {string}
2384
+ */
2385
+ function buildTemplateRows(numRows, rowHeights, rowOverrides) {
2386
+ var unit = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : 'px';
2387
+ if (!rowHeights || rowHeights.length < numRows) return '';
2388
+ var get = function get(i) {
2389
+ return Array.isArray(rowOverrides) ? rowOverrides[i] : rowOverrides === null || rowOverrides === void 0 ? void 0 : rowOverrides[i];
2390
+ };
2391
+ var parts = [];
2392
+ for (var i = 0; i < numRows; i++) {
2393
+ var ov = get(i);
2394
+ if (ov != null && typeof ov === 'string' && ov.trim() !== '') {
2395
+ parts.push(ov.trim());
2396
+ } else {
2397
+ var _rowHeights$i;
2398
+ parts.push("".concat(Math.round((_rowHeights$i = rowHeights[i]) !== null && _rowHeights$i !== void 0 ? _rowHeights$i : 0)).concat(unit));
2399
+ }
2400
+ }
2401
+ return parts.join(' ');
2402
+ }
2403
+
2404
+ /**
2405
+ * Measure each tr height in a section (table must not yet have scrollable class).
2406
+ * @param {HTMLTableSectionElement|null} section
2407
+ * @returns {number[]}
2408
+ */
2409
+ function measureRowHeights(section) {
2410
+ if (!section) return [];
2411
+ var rows = section.querySelectorAll(':scope > tr');
2412
+ return Array.from(rows).map(function (tr) {
2413
+ return tr.getBoundingClientRect().height;
2414
+ });
2415
+ }
2416
+
2417
+ /**
2418
+ * Apply scrollable table layout to a single table.
2419
+ * @param {HTMLTableElement} table
2420
+ * @param {Object} options - scrollableTable options
2421
+ * @param {number|string} [options.maxHeight] - Max height of tbody (default '200px'). Ignored when height or bodyHeightDynamic is set.
2422
+ * @param {number|string} [options.height] - Fixed height of tbody. Ignored when bodyHeightDynamic is set.
2423
+ * @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.
2424
+ * @param {string} [options.gridTemplateColumns]
2425
+ * @param {{ thead?: string, tbody?: string, tfoot?: string }} [options.gridTemplateRows]
2426
+ * @param {{ thead?: Object<number, string>|(string|null)[], tbody?: Object<number, string>|(string|null)[], tfoot?: Object<number, string>|(string|null)[] }} [options.rowOverrides]
2427
+ * @param {Object<number, string>|(string|null)[]} [options.columnOverrides]
2428
+ * @param {{ cols?: string, rows?: string }} [options.defaultSizingUnit] - CSS unit for measured widths/heights. cols defaults to 'fr', rows defaults to 'px'.
2429
+ * @param {{ columnWidths?: number[], rowHeights?: { thead?: number[], tbody?: number[], tfoot?: number[] } } | undefined} ref - existing ref when refreshing
2430
+ */
2431
+ function applyScrollableTable(table, options, ref) {
2432
+ var _ref$columnWidths, _ref$rowHeights, _options$defaultSizin, _options$defaultSizin2;
2074
2433
  var thead = table.querySelector('thead');
2075
2434
  var tbody = table.querySelector('tbody');
2076
2435
  var tfoot = table.querySelector('tfoot');
2077
2436
  var numCols = getTableColumnCount(table);
2078
2437
  if (numCols === 0) return;
2438
+ var alreadyScrollable = table.classList.contains(CLASS_TABLE);
2439
+ var customTemplate = typeof options.gridTemplateColumns === 'string' && options.gridTemplateColumns.trim().length > 0;
2440
+ var columnWidths = customTemplate ? null : (_ref$columnWidths = ref === null || ref === void 0 ? void 0 : ref.columnWidths) !== null && _ref$columnWidths !== void 0 ? _ref$columnWidths : alreadyScrollable ? null : measureColumnWidths(table, numCols);
2079
2441
  var theadRows = getRowCount(thead);
2080
2442
  var tbodyRows = getRowCount(tbody);
2081
2443
  var tfootRows = getRowCount(tfoot);
2444
+ var rowHeights = (_ref$rowHeights = ref === null || ref === void 0 ? void 0 : ref.rowHeights) !== null && _ref$rowHeights !== void 0 ? _ref$rowHeights : alreadyScrollable ? null : {
2445
+ thead: measureRowHeights(thead),
2446
+ tbody: measureRowHeights(tbody),
2447
+ tfoot: measureRowHeights(tfoot)
2448
+ };
2082
2449
  table.style.setProperty('--apx-scrollable-cols', String(numCols));
2083
2450
  table.style.setProperty('--apx-scrollable-thead-rows', String(Math.max(1, theadRows)));
2084
2451
  table.style.setProperty('--apx-scrollable-tbody-rows', String(Math.max(1, tbodyRows)));
2085
2452
  table.style.setProperty('--apx-scrollable-tfoot-rows', String(Math.max(1, tfootRows)));
2086
- table.style.setProperty('--apx-scrollable-body-max-height', normalizeMaxHeight(options.maxHeight));
2453
+ var _resolveBodyHeight2 = resolveBodyHeight(options, table),
2454
+ bodySize = _resolveBodyHeight2.bodySize,
2455
+ useFixedHeight = _resolveBodyHeight2.useFixedHeight;
2456
+ table.style.setProperty('--apx-scrollable-body-max-height', bodySize);
2457
+ table.classList.toggle('apx-scrollable-table--body-height', useFixedHeight);
2087
2458
  table.classList.add(CLASS_TABLE);
2088
2459
  table.classList.toggle('apx-scrollable-table--has-tfoot', !!(tfoot && tfootRows > 0));
2089
2460
  table.classList.toggle('apx-scrollable-table--no-thead', !(thead && theadRows > 0));
2461
+
2462
+ // Force reflow so the grid layout is established before setting measured template-columns.
2463
+ // Without this, the browser batches class + template into one pass and the tbody overflows horizontally.
2464
+ table.offsetHeight; // eslint-disable-line no-unused-expressions
2465
+
2466
+ var colUnit = ((_options$defaultSizin = options.defaultSizingUnit) === null || _options$defaultSizin === void 0 ? void 0 : _options$defaultSizin.cols) || 'fr';
2467
+ var rowUnit = ((_options$defaultSizin2 = options.defaultSizingUnit) === null || _options$defaultSizin2 === void 0 ? void 0 : _options$defaultSizin2.rows) || 'px';
2468
+ var gutterFallbackPx = DEFAULT_GUTTER_PX;
2469
+ try {
2470
+ var measured = (0,_tools_getScrollbarSize_mjs__WEBPACK_IMPORTED_MODULE_1__.getScrollbarSize)('vertical');
2471
+ if (typeof measured === 'number' && Number.isFinite(measured) && measured >= 0) {
2472
+ gutterFallbackPx = measured;
2473
+ }
2474
+ } catch (_) {
2475
+ /* use DEFAULT_GUTTER_PX */
2476
+ }
2477
+ var gutterSuffix = " minmax(var(--apx-scrollable-gutter-width, ".concat(gutterFallbackPx, "px), var(--apx-scrollable-gutter-width, ").concat(gutterFallbackPx, "px))");
2478
+ if (customTemplate) {
2479
+ table.style.setProperty('--apx-scrollable-template-columns', options.gridTemplateColumns.trim() + gutterSuffix);
2480
+ } else if (columnWidths && columnWidths.length === numCols) {
2481
+ var template = options.columnOverrides != null ? buildTemplateColumns(numCols, columnWidths, options.columnOverrides, colUnit) : columnWidths.map(function (w) {
2482
+ return "".concat(Math.round(w)).concat(colUnit);
2483
+ }).join(' ');
2484
+ table.style.setProperty('--apx-scrollable-template-columns', template + gutterSuffix);
2485
+ } else {
2486
+ table.style.removeProperty('--apx-scrollable-template-columns');
2487
+ }
2090
2488
  clearPlacements(table);
2091
2489
  var sections = [{
2092
2490
  section: thead,
2093
- rows: Math.max(1, theadRows)
2491
+ rows: Math.max(1, theadRows),
2492
+ heights: rowHeights === null || rowHeights === void 0 ? void 0 : rowHeights.thead,
2493
+ key: 'thead'
2094
2494
  }, {
2095
2495
  section: tbody,
2096
- rows: Math.max(1, tbodyRows)
2496
+ rows: Math.max(1, tbodyRows),
2497
+ heights: rowHeights === null || rowHeights === void 0 ? void 0 : rowHeights.tbody,
2498
+ key: 'tbody'
2097
2499
  }, {
2098
2500
  section: tfoot,
2099
- rows: Math.max(1, tfootRows)
2501
+ rows: Math.max(1, tfootRows),
2502
+ heights: rowHeights === null || rowHeights === void 0 ? void 0 : rowHeights.tfoot,
2503
+ key: 'tfoot'
2100
2504
  }];
2505
+ var customRows = options.gridTemplateRows && _typeof(options.gridTemplateRows) === 'object' ? options.gridTemplateRows : null;
2506
+ var rowOverrides = options.rowOverrides && _typeof(options.rowOverrides) === 'object' ? options.rowOverrides : null;
2101
2507
  sections.forEach(function (_ref2) {
2102
2508
  var section = _ref2.section,
2103
- rows = _ref2.rows;
2509
+ rows = _ref2.rows,
2510
+ heights = _ref2.heights,
2511
+ key = _ref2.key;
2104
2512
  if (!section) return;
2513
+ var varName = "--apx-scrollable-".concat(key, "-template-rows");
2514
+ var custom = customRows === null || customRows === void 0 ? void 0 : customRows[key];
2515
+ var overrides = rowOverrides === null || rowOverrides === void 0 ? void 0 : rowOverrides[key];
2516
+ if (typeof custom === 'string' && custom.trim().length > 0) {
2517
+ section.style.setProperty(varName, custom.trim());
2518
+ } else if (heights && heights.length >= rows) {
2519
+ var _template = overrides != null ? buildTemplateRows(rows, heights.slice(0, rows), overrides, rowUnit) : heights.slice(0, rows).map(function (h) {
2520
+ return "".concat(Math.round(h)).concat(rowUnit);
2521
+ }).join(' ');
2522
+ section.style.setProperty(varName, _template);
2523
+ } else {
2524
+ section.style.removeProperty(varName);
2525
+ }
2105
2526
  var placements = computeCellPlacements(section, rows, numCols);
2106
2527
  applyPlacements(placements);
2107
2528
  });
2529
+ return {
2530
+ columnWidths: columnWidths,
2531
+ rowHeights: rowHeights
2532
+ };
2108
2533
  }
2109
2534
 
2110
- /**
2111
- * Augments the APX object with scrollableTable(options | 'refresh').
2112
- * Makes the tbody of a table scrollable while keeping thead/tfoot fixed and columns aligned (CSS Grid + subgrid).
2113
- *
2114
- * @param {Object} apx - The APX object to augment.
2115
- * @example
2116
- * APX('table.data-grid').scrollableTable({ maxHeight: 300 });
2117
- * APX('table.data-grid').scrollableTable('refresh');
2535
+ /**
2536
+ * Augments the APX object with scrollableTable(options | 'refresh').
2537
+ * Makes the tbody of a table scrollable while keeping thead/tfoot fixed and columns aligned (CSS Grid + subgrid).
2538
+ *
2539
+ * @param {Object} apx - The APX object to augment.
2540
+ * @example
2541
+ * APX('table.data-grid').scrollableTable({ maxHeight: 300 });
2542
+ * APX('table.data-grid').scrollableTable('refresh');
2118
2543
  */
2119
2544
  function augmentWithScrollableTable(apx) {
2120
2545
  apx.scrollableTable = function (optionsOrAction) {
@@ -2126,18 +2551,26 @@ function augmentWithScrollableTable(apx) {
2126
2551
  var ref = table[DATA_KEY];
2127
2552
  if (ref) {
2128
2553
  if (isRefresh) {
2129
- applyScrollableTable(table, ref.options);
2554
+ applyScrollableTable(table, ref.options, ref);
2130
2555
  } else if (options && Object.keys(options).length > 0) {
2131
2556
  ref.options = _objectSpread(_objectSpread({}, ref.options), options);
2132
- applyScrollableTable(table, ref.options);
2557
+ var _result = applyScrollableTable(table, ref.options, ref);
2558
+ if (_result !== null && _result !== void 0 && _result.columnWidths) ref.columnWidths = _result.columnWidths;
2559
+ if (_result !== null && _result !== void 0 && _result.rowHeights) ref.rowHeights = _result.rowHeights;
2133
2560
  }
2561
+ var currentOptions = ref.options;
2562
+ if (currentOptions !== null && currentOptions !== void 0 && currentOptions.bodyHeightDynamic) registerDynamicTable(table, currentOptions);else removeTableFromDynamicSources(table);
2134
2563
  return;
2135
2564
  }
2136
2565
  if (isRefresh) return;
2137
- applyScrollableTable(table, options);
2566
+ console.log('[APX scrollableTable] create', table);
2567
+ var result = applyScrollableTable(table, options, undefined);
2138
2568
  table[DATA_KEY] = {
2139
- options: _objectSpread({}, options)
2569
+ options: _objectSpread({}, options),
2570
+ columnWidths: (result === null || result === void 0 ? void 0 : result.columnWidths) || undefined,
2571
+ rowHeights: (result === null || result === void 0 ? void 0 : result.rowHeights) || undefined
2140
2572
  };
2573
+ if (options !== null && options !== void 0 && options.bodyHeightDynamic) registerDynamicTable(table, options);
2141
2574
  });
2142
2575
  return apx;
2143
2576
  };
@@ -3475,24 +3908,34 @@ Object.assign(toast, {
3475
3908
  __webpack_require__.r(__webpack_exports__);
3476
3909
  /* harmony export */ __webpack_require__.d(__webpack_exports__, {
3477
3910
  /* harmony export */ augmentWithPack: () => (/* reexport safe */ _form_packer_augment_apx_mjs__WEBPACK_IMPORTED_MODULE_0__["default"]),
3911
+ /* harmony export */ getScrollbarSize: () => (/* reexport safe */ _getScrollbarSize_mjs__WEBPACK_IMPORTED_MODULE_2__.getScrollbarSize),
3912
+ /* harmony export */ loadCss: () => (/* reexport safe */ _loadCss_mjs__WEBPACK_IMPORTED_MODULE_3__.loadCss),
3478
3913
  /* harmony export */ packFormToJSON: () => (/* reexport safe */ _form_packer_packToJson_mjs__WEBPACK_IMPORTED_MODULE_1__.packFormToJSON),
3479
3914
  /* harmony export */ tools: () => (/* binding */ tools)
3480
3915
  /* harmony export */ });
3481
3916
  /* harmony import */ var _form_packer_augment_apx_mjs__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./form-packer/augment-apx.mjs */ "./modules/tools/form-packer/augment-apx.mjs");
3482
3917
  /* harmony import */ var _form_packer_packToJson_mjs__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./form-packer/packToJson.mjs */ "./modules/tools/form-packer/packToJson.mjs");
3918
+ /* harmony import */ var _getScrollbarSize_mjs__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./getScrollbarSize.mjs */ "./modules/tools/getScrollbarSize.mjs");
3919
+ /* harmony import */ var _loadCss_mjs__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./loadCss.mjs */ "./modules/tools/loadCss.mjs");
3483
3920
  // Import des fonctions et modules des sous-modules
3484
3921
 
3485
3922
 
3486
3923
 
3924
+
3925
+
3487
3926
  // Export de la fonction d'augmentation
3488
3927
 
3489
3928
 
3490
3929
  // Export des fonctions utilitaires
3491
3930
 
3492
3931
 
3932
+
3933
+
3493
3934
  // Export d'un objet tools pour faciliter l'utilisation
3494
3935
  var tools = {
3495
- packFormToJSON: _form_packer_packToJson_mjs__WEBPACK_IMPORTED_MODULE_1__.packFormToJSON
3936
+ packFormToJSON: _form_packer_packToJson_mjs__WEBPACK_IMPORTED_MODULE_1__.packFormToJSON,
3937
+ getScrollbarSize: _getScrollbarSize_mjs__WEBPACK_IMPORTED_MODULE_2__.getScrollbarSize,
3938
+ loadCss: _loadCss_mjs__WEBPACK_IMPORTED_MODULE_3__.loadCss
3496
3939
  };
3497
3940
 
3498
3941
  /***/ }),
@@ -4207,6 +4650,96 @@ var isPlainObject = function isPlainObject(obj) {
4207
4650
 
4208
4651
  /***/ }),
4209
4652
 
4653
+ /***/ "./modules/tools/getScrollbarSize.mjs":
4654
+ /*!********************************************!*\
4655
+ !*** ./modules/tools/getScrollbarSize.mjs ***!
4656
+ \********************************************/
4657
+ /***/ ((__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) => {
4658
+
4659
+ "use strict";
4660
+ __webpack_require__.r(__webpack_exports__);
4661
+ /* harmony export */ __webpack_require__.d(__webpack_exports__, {
4662
+ /* harmony export */ getScrollbarSize: () => (/* binding */ getScrollbarSize)
4663
+ /* harmony export */ });
4664
+ function getScrollbarSize() {
4665
+ var _getScrollbarSize$_ca;
4666
+ var orientation = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : "vertical";
4667
+ if (!getScrollbarSize._cache) {
4668
+ var outer = document.createElement("div");
4669
+ Object.assign(outer.style, {
4670
+ position: "absolute",
4671
+ top: "-9999px",
4672
+ left: "-9999px",
4673
+ width: "100px",
4674
+ height: "100px",
4675
+ overflow: "scroll"
4676
+ });
4677
+ document.body.appendChild(outer);
4678
+ getScrollbarSize._cache = {
4679
+ vertical: outer.offsetWidth - outer.clientWidth,
4680
+ horizontal: outer.offsetHeight - outer.clientHeight
4681
+ };
4682
+ outer.remove();
4683
+ }
4684
+ return (_getScrollbarSize$_ca = getScrollbarSize._cache[orientation]) !== null && _getScrollbarSize$_ca !== void 0 ? _getScrollbarSize$_ca : 0;
4685
+ }
4686
+
4687
+ /***/ }),
4688
+
4689
+ /***/ "./modules/tools/loadCss.mjs":
4690
+ /*!***********************************!*\
4691
+ !*** ./modules/tools/loadCss.mjs ***!
4692
+ \***********************************/
4693
+ /***/ ((__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) => {
4694
+
4695
+ "use strict";
4696
+ __webpack_require__.r(__webpack_exports__);
4697
+ /* harmony export */ __webpack_require__.d(__webpack_exports__, {
4698
+ /* harmony export */ loadCss: () => (/* binding */ loadCss)
4699
+ /* harmony export */ });
4700
+ var loadCssCache = new Map();
4701
+
4702
+ /**
4703
+ * Loads CSS from a URL and injects it into the document.
4704
+ * Idempotent: same URL returns the same Promise; duplicate loads are avoided.
4705
+ * @param {string} url - URL of the CSS file to load
4706
+ * @param {{ id?: string, media?: string, before?: Node }} [options] - Optional: id and media for the style element, before for insertion point
4707
+ * @returns {Promise<HTMLStyleElement>} Resolves with the injected style element; rejects on fetch failure or non-ok response
4708
+ */
4709
+ function loadCss(url) {
4710
+ var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
4711
+ var cached = loadCssCache.get(url);
4712
+ if (cached) {
4713
+ return cached;
4714
+ }
4715
+ var promise = fetch(url).then(function (response) {
4716
+ if (!response.ok) {
4717
+ throw new Error("Failed to load CSS: ".concat(response.status, " ").concat(response.statusText));
4718
+ }
4719
+ return response.text();
4720
+ }).then(function (css) {
4721
+ var styleSheet = document.createElement("style");
4722
+ if (options.id) styleSheet.id = options.id;
4723
+ if (options.media) styleSheet.media = options.media;
4724
+ styleSheet.textContent = css;
4725
+ var insertBefore = options.before;
4726
+ if (insertBefore && insertBefore.parentNode) {
4727
+ insertBefore.parentNode.insertBefore(styleSheet, insertBefore);
4728
+ } else {
4729
+ document.head.appendChild(styleSheet);
4730
+ }
4731
+ return styleSheet;
4732
+ })["catch"](function (error) {
4733
+ loadCssCache["delete"](url);
4734
+ console.error("Failed to load CSS:", error);
4735
+ throw error;
4736
+ });
4737
+ loadCssCache.set(url, promise);
4738
+ return promise;
4739
+ }
4740
+
4741
+ /***/ }),
4742
+
4210
4743
  /***/ "./modules/tristate/tristate.mjs":
4211
4744
  /*!***************************************!*\
4212
4745
  !*** ./modules/tristate/tristate.mjs ***!
@@ -4652,9 +5185,7 @@ __webpack_require__.r(__webpack_exports__);
4652
5185
  /* harmony import */ var _modules_scrollableTable_scrollableTable_mjs__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./modules/scrollableTable/scrollableTable.mjs */ "./modules/scrollableTable/scrollableTable.mjs");
4653
5186
  /* harmony import */ var _modules_dialog_dialog_mjs__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./modules/dialog/dialog.mjs */ "./modules/dialog/dialog.mjs");
4654
5187
  /* harmony import */ var _modules_toast_toast_mjs__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ./modules/toast/toast.mjs */ "./modules/toast/toast.mjs");
4655
- /* harmony import */ var _modules_common_mjs__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ./modules/common.mjs */ "./modules/common.mjs");
4656
- /* harmony import */ var _modules_tools_exports_mjs__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! ./modules/tools/exports.mjs */ "./modules/tools/exports.mjs");
4657
-
5188
+ /* harmony import */ var _modules_tools_exports_mjs__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ./modules/tools/exports.mjs */ "./modules/tools/exports.mjs");
4658
5189
 
4659
5190
 
4660
5191
 
@@ -4768,13 +5299,13 @@ var APX = function APX(input) {
4768
5299
  (0,_modules_listen_listen_mjs__WEBPACK_IMPORTED_MODULE_0__["default"])(apx);
4769
5300
  (0,_modules_tristate_tristate_mjs__WEBPACK_IMPORTED_MODULE_1__["default"])(apx);
4770
5301
  (0,_modules_scrollableTable_scrollableTable_mjs__WEBPACK_IMPORTED_MODULE_2__["default"])(apx);
4771
- (0,_modules_tools_exports_mjs__WEBPACK_IMPORTED_MODULE_6__.augmentWithPack)(apx);
5302
+ (0,_modules_tools_exports_mjs__WEBPACK_IMPORTED_MODULE_5__.augmentWithPack)(apx);
4772
5303
  return apx;
4773
5304
  };
4774
- APX.loadCss = _modules_common_mjs__WEBPACK_IMPORTED_MODULE_5__.loadCss;
5305
+ APX.loadCss = _modules_tools_exports_mjs__WEBPACK_IMPORTED_MODULE_5__.loadCss;
4775
5306
  APX.dialog = _modules_dialog_dialog_mjs__WEBPACK_IMPORTED_MODULE_3__["default"];
4776
5307
  APX.toast = _modules_toast_toast_mjs__WEBPACK_IMPORTED_MODULE_4__["default"];
4777
- APX.tools = _modules_tools_exports_mjs__WEBPACK_IMPORTED_MODULE_6__.tools;
5308
+ APX.tools = _modules_tools_exports_mjs__WEBPACK_IMPORTED_MODULE_5__.tools;
4778
5309
  APX.isAPXObject = function (obj) {
4779
5310
  return obj && obj._isAPXObject === true;
4780
5311
  };