@toolbox-web/grid 1.1.1 → 1.1.2

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.
Files changed (50) hide show
  1. package/all.js +188 -112
  2. package/all.js.map +1 -1
  3. package/index.js +757 -716
  4. package/index.js.map +1 -1
  5. package/lib/core/grid.d.ts +7 -1
  6. package/lib/core/grid.d.ts.map +1 -1
  7. package/lib/core/internal/validate-config.d.ts +10 -0
  8. package/lib/core/internal/validate-config.d.ts.map +1 -1
  9. package/lib/core/plugin/base-plugin.d.ts +30 -0
  10. package/lib/core/plugin/base-plugin.d.ts.map +1 -1
  11. package/lib/core/plugin/index.d.ts +1 -1
  12. package/lib/core/plugin/index.d.ts.map +1 -1
  13. package/lib/core/plugin/plugin-manager.d.ts +6 -0
  14. package/lib/core/plugin/plugin-manager.d.ts.map +1 -1
  15. package/lib/core/types.d.ts +1 -1
  16. package/lib/core/types.d.ts.map +1 -1
  17. package/lib/plugins/clipboard/index.js.map +1 -1
  18. package/lib/plugins/column-virtualization/index.js.map +1 -1
  19. package/lib/plugins/context-menu/index.js.map +1 -1
  20. package/lib/plugins/editing/index.js.map +1 -1
  21. package/lib/plugins/export/index.js.map +1 -1
  22. package/lib/plugins/filtering/index.js.map +1 -1
  23. package/lib/plugins/grouping-columns/index.js.map +1 -1
  24. package/lib/plugins/grouping-rows/GroupingRowsPlugin.d.ts.map +1 -1
  25. package/lib/plugins/grouping-rows/index.js +5 -5
  26. package/lib/plugins/grouping-rows/index.js.map +1 -1
  27. package/lib/plugins/master-detail/index.js.map +1 -1
  28. package/lib/plugins/multi-sort/index.js.map +1 -1
  29. package/lib/plugins/pinned-columns/index.js.map +1 -1
  30. package/lib/plugins/pinned-rows/index.js.map +1 -1
  31. package/lib/plugins/pivot/index.js.map +1 -1
  32. package/lib/plugins/reorder/index.js.map +1 -1
  33. package/lib/plugins/responsive/ResponsivePlugin.d.ts +24 -1
  34. package/lib/plugins/responsive/ResponsivePlugin.d.ts.map +1 -1
  35. package/lib/plugins/responsive/index.js +224 -87
  36. package/lib/plugins/responsive/index.js.map +1 -1
  37. package/lib/plugins/selection/index.js.map +1 -1
  38. package/lib/plugins/server-side/index.js.map +1 -1
  39. package/lib/plugins/tree/index.js.map +1 -1
  40. package/lib/plugins/undo-redo/index.js.map +1 -1
  41. package/lib/plugins/visibility/index.js.map +1 -1
  42. package/package.json +1 -1
  43. package/umd/grid.all.umd.js +25 -19
  44. package/umd/grid.all.umd.js.map +1 -1
  45. package/umd/grid.umd.js +18 -12
  46. package/umd/grid.umd.js.map +1 -1
  47. package/umd/plugins/grouping-rows.umd.js +1 -1
  48. package/umd/plugins/grouping-rows.umd.js.map +1 -1
  49. package/umd/plugins/responsive.umd.js +1 -1
  50. package/umd/plugins/responsive.umd.js.map +1 -1
@@ -1,4 +1,4 @@
1
- import { BaseGridPlugin, GridElement } from '../../core/plugin/base-plugin';
1
+ import { BaseGridPlugin, GridElement, PluginManifest } from '../../core/plugin/base-plugin';
2
2
  import { BreakpointConfig, ResponsivePluginConfig } from './types';
3
3
  /**
4
4
  * Responsive Plugin for tbw-grid
@@ -52,6 +52,10 @@ export declare class ResponsivePlugin<T = unknown> extends BaseGridPlugin<Respon
52
52
  readonly name = "responsive";
53
53
  readonly version = "1.0.0";
54
54
  readonly styles: string;
55
+ /**
56
+ * Plugin manifest declaring incompatibilities with other plugins.
57
+ */
58
+ static readonly manifest: PluginManifest;
55
59
  /**
56
60
  * Check if currently in responsive mode.
57
61
  * @returns `true` if the grid is in card layout mode
@@ -119,5 +123,24 @@ export declare class ResponsivePlugin<T = unknown> extends BaseGridPlugin<Respon
119
123
  * @returns `true` if the event was handled and default behavior should be prevented
120
124
  */
121
125
  onKeyDown(e: KeyboardEvent): boolean;
126
+ /**
127
+ * Return total extra height contributed by mixed row heights.
128
+ * This is called by the grid's virtualization system to adjust scrollbar height.
129
+ *
130
+ * The grid calculates: totalRows * baseRowHeight + pluginExtraHeight
131
+ *
132
+ * For mixed layouts (groups + cards), we need to report the difference between
133
+ * actual heights and what the base calculation assumes:
134
+ * - Extra for groups: groupCount * (groupHeight - baseHeight)
135
+ * - Extra for cards: cardCount * (cardHeight - baseHeight)
136
+ */
137
+ getExtraHeight(): number;
138
+ /**
139
+ * Return extra height that appears before a given row index.
140
+ * Used by virtualization to correctly calculate scroll positions.
141
+ *
142
+ * Like getExtraHeight, this accounts for both group and card row heights.
143
+ */
144
+ getExtraHeightBefore(beforeRowIndex: number): number;
122
145
  }
123
146
  //# sourceMappingURL=ResponsivePlugin.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"ResponsivePlugin.d.ts","sourceRoot":"","sources":["../../../../../../libs/grid/src/lib/plugins/responsive/ResponsivePlugin.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AAGH,OAAO,EAAE,cAAc,EAAE,KAAK,WAAW,EAAE,MAAM,+BAA+B,CAAC;AAGjF,OAAO,KAAK,EAAE,gBAAgB,EAA8C,sBAAsB,EAAE,MAAM,SAAS,CAAC;AAEpH;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8CG;AACH,qBAAa,gBAAgB,CAAC,CAAC,GAAG,OAAO,CAAE,SAAQ,cAAc,CAAC,sBAAsB,CAAC,CAAC,CAAC,CAAC;;IAC1F,QAAQ,CAAC,IAAI,gBAAgB;IAC7B,SAAkB,OAAO,WAAW;IACpC,SAAkB,MAAM,SAAU;IAgBlC;;;OAGG;IACH,YAAY,IAAI,OAAO;IAIvB;;;;OAIG;IACH,aAAa,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI;IAYrC;;;OAGG;IACH,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI;IAKlC;;;;OAIG;IACH,eAAe,CAAC,QAAQ,EAAE,sBAAsB,CAAC,CAAC,CAAC,CAAC,cAAc,CAAC,GAAG,IAAI;IAQ1E;;;OAGG;IACH,QAAQ,IAAI,MAAM;IAIlB;;;OAGG;IACH,mBAAmB,IAAI,gBAAgB,GAAG,IAAI;IAIrC,MAAM,CAAC,IAAI,EAAE,WAAW,GAAG,IAAI;IA+C/B,MAAM,IAAI,IAAI;IAcvB;;;;OAIG;IACM,WAAW,IAAI,IAAI;IAgL5B;;;;;;;;;;OAUG;IACM,SAAS,CAAC,GAAG,EAAE,OAAO,EAAE,KAAK,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,GAAG,IAAI;IAoCtF;;;;;;;;;;;;;OAaG;IACM,SAAS,CAAC,CAAC,EAAE,aAAa,GAAG,OAAO;CAwF9C"}
1
+ {"version":3,"file":"ResponsivePlugin.d.ts","sourceRoot":"","sources":["../../../../../../libs/grid/src/lib/plugins/responsive/ResponsivePlugin.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AAGH,OAAO,EAAE,cAAc,EAAE,KAAK,WAAW,EAAE,KAAK,cAAc,EAAE,MAAM,+BAA+B,CAAC;AAGtG,OAAO,KAAK,EAAE,gBAAgB,EAA8C,sBAAsB,EAAE,MAAM,SAAS,CAAC;AAEpH;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8CG;AACH,qBAAa,gBAAgB,CAAC,CAAC,GAAG,OAAO,CAAE,SAAQ,cAAc,CAAC,sBAAsB,CAAC,CAAC,CAAC,CAAC;;IAC1F,QAAQ,CAAC,IAAI,gBAAgB;IAC7B,SAAkB,OAAO,WAAW;IACpC,SAAkB,MAAM,SAAU;IAElC;;OAEG;IACH,gBAAyB,QAAQ,EAAE,cAAc,CAS/C;IAgBF;;;OAGG;IACH,YAAY,IAAI,OAAO;IAIvB;;;;OAIG;IACH,aAAa,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI;IAYrC;;;OAGG;IACH,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI;IAKlC;;;;OAIG;IACH,eAAe,CAAC,QAAQ,EAAE,sBAAsB,CAAC,CAAC,CAAC,CAAC,cAAc,CAAC,GAAG,IAAI;IAQ1E;;;OAGG;IACH,QAAQ,IAAI,MAAM;IAIlB;;;OAGG;IACH,mBAAmB,IAAI,gBAAgB,GAAG,IAAI;IAIrC,MAAM,CAAC,IAAI,EAAE,WAAW,GAAG,IAAI;IA+C/B,MAAM,IAAI,IAAI;IAcvB;;;;OAIG;IACM,WAAW,IAAI,IAAI;IAyL5B;;;;;;;;;;OAUG;IACM,SAAS,CAAC,GAAG,EAAE,OAAO,EAAE,KAAK,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,GAAG,IAAI;IAqCtF;;;;;;;;;;;;;OAaG;IACM,SAAS,CAAC,CAAC,EAAE,aAAa,GAAG,OAAO;IAkK7C;;;;;;;;;;OAUG;IACM,cAAc,IAAI,MAAM;IAyBjC;;;;;OAKG;IACM,oBAAoB,CAAC,cAAc,EAAE,MAAM,GAAG,MAAM;CA8H9D"}
@@ -1,54 +1,54 @@
1
- function b(r) {
2
- r && r.querySelectorAll(".cell-focus").forEach((t) => t.classList.remove("cell-focus"));
1
+ function v(s) {
2
+ s && s.querySelectorAll(".cell-focus").forEach((t) => t.classList.remove("cell-focus"));
3
3
  }
4
- const w = 'input,select,textarea,[contenteditable="true"],[contenteditable=""],[tabindex]:not([tabindex="-1"])', m = document.createElement("template");
4
+ const b = 'input,select,textarea,[contenteditable="true"],[contenteditable=""],[tabindex]:not([tabindex="-1"])', m = document.createElement("template");
5
5
  m.innerHTML = '<div class="cell" role="gridcell" part="cell"></div>';
6
- const y = document.createElement("template");
7
- y.innerHTML = '<div class="data-grid-row" role="row" part="row"></div>';
8
- function u(r, t) {
9
- if (r._virtualization?.enabled) {
10
- const { rowHeight: a, container: s, viewportEl: d } = r._virtualization, n = s, c = d?.clientHeight ?? n?.clientHeight ?? 0;
11
- if (n && c > 0) {
12
- const h = r._focusRow * a;
13
- h < n.scrollTop ? n.scrollTop = h : h + a > n.scrollTop + c && (n.scrollTop = h - c + a);
6
+ const R = document.createElement("template");
7
+ R.innerHTML = '<div class="data-grid-row" role="row" part="row"></div>';
8
+ function u(s, t) {
9
+ if (s._virtualization?.enabled) {
10
+ const { rowHeight: r, container: o, viewportEl: l } = s._virtualization, d = o, h = l?.clientHeight ?? d?.clientHeight ?? 0;
11
+ if (d && h > 0) {
12
+ const c = s._focusRow * r;
13
+ c < d.scrollTop ? d.scrollTop = c : c + r > d.scrollTop + h && (d.scrollTop = c - h + r);
14
14
  }
15
15
  }
16
- const e = r._activeEditRows !== void 0 && r._activeEditRows !== -1;
17
- e || r.refreshVirtualWindow(!1), b(r._bodyEl), Array.from(r._bodyEl.querySelectorAll('[aria-selected="true"]')).forEach((a) => {
18
- a.setAttribute("aria-selected", "false");
16
+ const e = s._activeEditRows !== void 0 && s._activeEditRows !== -1;
17
+ e || s.refreshVirtualWindow(!1), v(s._bodyEl), Array.from(s._bodyEl.querySelectorAll('[aria-selected="true"]')).forEach((r) => {
18
+ r.setAttribute("aria-selected", "false");
19
19
  });
20
- const i = r._focusRow, o = r._virtualization.start ?? 0, l = r._virtualization.end ?? r._rows.length;
21
- if (i >= o && i < l) {
22
- const a = r._bodyEl.querySelectorAll(".data-grid-row")[i - o];
23
- let s = a?.children[r._focusCol];
24
- if ((!s || !s.classList?.contains("cell")) && (s = a?.querySelector(`.cell[data-col="${r._focusCol}"]`) ?? a?.querySelector(".cell[data-col]")), s) {
25
- s.classList.add("cell-focus"), s.setAttribute("aria-selected", "true");
26
- const d = r.querySelector(".tbw-scroll-area");
27
- if (d && s && !e) {
28
- const n = r._getHorizontalScrollOffsets?.(a ?? void 0, s) ?? { left: 0, right: 0 };
29
- if (!n.skipScroll) {
30
- const c = s.getBoundingClientRect(), h = d.getBoundingClientRect(), g = c.left - h.left + d.scrollLeft, p = g + c.width, f = d.scrollLeft + n.left, v = d.scrollLeft + d.clientWidth - n.right;
31
- g < f ? d.scrollLeft = g - n.left : p > v && (d.scrollLeft = p - d.clientWidth + n.right);
20
+ const i = s._focusRow, n = s._virtualization.start ?? 0, a = s._virtualization.end ?? s._rows.length;
21
+ if (i >= n && i < a) {
22
+ const r = s._bodyEl.querySelectorAll(".data-grid-row")[i - n];
23
+ let o = r?.children[s._focusCol];
24
+ if ((!o || !o.classList?.contains("cell")) && (o = r?.querySelector(`.cell[data-col="${s._focusCol}"]`) ?? r?.querySelector(".cell[data-col]")), o) {
25
+ o.classList.add("cell-focus"), o.setAttribute("aria-selected", "true");
26
+ const l = s.querySelector(".tbw-scroll-area");
27
+ if (l && o && !e) {
28
+ const d = s._getHorizontalScrollOffsets?.(r ?? void 0, o) ?? { left: 0, right: 0 };
29
+ if (!d.skipScroll) {
30
+ const h = o.getBoundingClientRect(), c = l.getBoundingClientRect(), g = h.left - c.left + l.scrollLeft, f = g + h.width, p = l.scrollLeft + d.left, w = l.scrollLeft + l.clientWidth - d.right;
31
+ g < p ? l.scrollLeft = g - d.left : f > w && (l.scrollLeft = f - l.clientWidth + d.right);
32
32
  }
33
33
  }
34
- if (r._activeEditRows !== void 0 && r._activeEditRows !== -1 && s.classList.contains("editing")) {
35
- const n = s.querySelector(w);
36
- if (n && document.activeElement !== n)
34
+ if (s._activeEditRows !== void 0 && s._activeEditRows !== -1 && o.classList.contains("editing")) {
35
+ const d = o.querySelector(b);
36
+ if (d && document.activeElement !== d)
37
37
  try {
38
- n.focus({ preventScroll: !0 });
38
+ d.focus({ preventScroll: !0 });
39
39
  } catch {
40
40
  }
41
- } else if (!s.contains(document.activeElement)) {
42
- s.hasAttribute("tabindex") || s.setAttribute("tabindex", "-1");
41
+ } else if (!o.contains(document.activeElement)) {
42
+ o.hasAttribute("tabindex") || o.setAttribute("tabindex", "-1");
43
43
  try {
44
- s.focus({ preventScroll: !0 });
44
+ o.focus({ preventScroll: !0 });
45
45
  } catch {
46
46
  }
47
47
  }
48
48
  }
49
49
  }
50
50
  }
51
- const R = {
51
+ const y = {
52
52
  expand: "▶",
53
53
  collapse: "▼",
54
54
  sortAsc: "▲",
@@ -58,7 +58,7 @@ const R = {
58
58
  dragHandle: "⋮⋮",
59
59
  toolPanel: "☰"
60
60
  };
61
- class _ {
61
+ class C {
62
62
  /**
63
63
  * Plugin dependencies - declare other plugins this one requires.
64
64
  *
@@ -282,7 +282,7 @@ class _ {
282
282
  */
283
283
  get gridIcons() {
284
284
  const t = this.grid?.gridConfig?.icons ?? {};
285
- return { ...R, ...t };
285
+ return { ...y, ...t };
286
286
  }
287
287
  // #region Animation Helpers
288
288
  /**
@@ -358,24 +358,35 @@ class _ {
358
358
  }
359
359
  // #endregion
360
360
  }
361
- const C = 'tbw-grid[data-responsive-animate] .data-grid-row,tbw-grid[data-responsive-animate] .data-grid-row>.cell{transition:opacity var(--tbw-responsive-duration, .2s) ease-out,transform var(--tbw-responsive-duration, .2s) ease-out}tbw-grid[data-responsive][data-responsive-animate] .data-grid-row{animation:responsive-card-enter var(--tbw-responsive-duration, .2s) ease-out}@keyframes responsive-card-enter{0%{opacity:0;transform:translateY(-10px)}to{opacity:1;transform:translateY(0)}}tbw-grid[data-responsive] .header{display:none!important}tbw-grid[data-responsive] .footer-row{display:none}tbw-grid[data-responsive] .tbw-scroll-area{overflow-x:hidden;min-width:0!important}tbw-grid[data-responsive] .rows-body-wrapper{min-width:0!important}tbw-grid[data-responsive] .data-grid-row{display:block!important;grid-template-columns:none!important;padding:var(--tbw-cell-padding);padding-left:var(--tbw-spacing-xl);border-bottom:1px solid var(--tbw-color-border);min-height:auto!important;height:auto!important;contain:none!important;content-visibility:visible!important;background:var(--tbw-color-bg);position:relative}tbw-grid[data-responsive] .data-grid-row:nth-child(2n){background:var(--tbw-color-row-alt)}tbw-grid[data-responsive] .data-grid-row:hover{background:var(--tbw-color-row-hover)}tbw-grid[data-responsive] .data-grid-row[aria-selected=true]{background:var(--tbw-color-selection)}tbw-grid[data-responsive] .data-grid-row[aria-selected=true]:before{content:"";position:absolute;left:0;top:0;bottom:0;width:4px;background:var(--tbw-color-accent)}tbw-grid[data-responsive] .data-grid-row>.cell{display:flex!important;justify-content:space-between;align-items:center;padding:var(--tbw-spacing-xs) var(--tbw-spacing-md);width:100%!important;min-width:0!important;min-height:auto!important;height:auto!important;line-height:1.5!important;position:static!important;left:auto!important;right:auto!important;border:none!important;border-bottom:none!important;border-right:none!important;background:transparent!important;white-space:normal!important;overflow:visible!important}tbw-grid[data-responsive] .data-grid-row>.cell:before{content:attr(data-header) ": ";font-weight:600;color:var(--tbw-color-header-fg);flex-shrink:0;margin-right:var(--tbw-spacing-md);min-width:100px}tbw-grid[data-responsive] .data-grid-row>.cell:after{content:none}tbw-grid[data-responsive] .cell[data-utility]{display:none!important}tbw-grid[data-responsive] .data-grid-row:not(:last-child){margin-bottom:var(--tbw-spacing-xs)}tbw-grid[data-responsive] .cell[data-responsive-hidden]{display:none!important}tbw-grid[data-responsive] .cell[data-responsive-value-only]{justify-content:flex-start!important;font-weight:500}tbw-grid[data-responsive] .cell[data-responsive-value-only]:before{display:none!important}tbw-grid:not([data-responsive]) .cell[data-responsive-hidden]{display:none!important}tbw-grid[data-responsive] .tbw-footer,tbw-grid[data-responsive] .tbw-pinned-rows,tbw-grid[data-responsive] .tbw-aggregation-rows{display:none!important}tbw-grid[data-responsive] .tbw-pinned-rows,tbw-grid[data-responsive] .tbw-aggregation-rows,tbw-grid[data-responsive] .tbw-aggregation-row{min-width:0!important}tbw-grid[data-responsive] .data-grid-row.responsive-card{display:block!important;padding:var(--tbw-cell-padding);border-bottom:1px solid var(--tbw-color-border)}tbw-grid[data-responsive] .data-grid-row.responsive-card>*{width:100%}tbw-grid[data-responsive] .data-grid-row.responsive-card .cell:before{display:none}';
362
- class A extends _ {
361
+ const _ = 'tbw-grid[data-responsive-animate] .data-grid-row,tbw-grid[data-responsive-animate] .data-grid-row>.cell{transition:opacity var(--tbw-responsive-duration, .2s) ease-out,transform var(--tbw-responsive-duration, .2s) ease-out}tbw-grid[data-responsive][data-responsive-animate] .data-grid-row{animation:responsive-card-enter var(--tbw-responsive-duration, .2s) ease-out}@keyframes responsive-card-enter{0%{opacity:0;transform:translateY(-10px)}to{opacity:1;transform:translateY(0)}}tbw-grid[data-responsive] .header{display:none!important}tbw-grid[data-responsive] .footer-row{display:none}tbw-grid[data-responsive] .tbw-scroll-area{overflow-x:hidden;min-width:0!important}tbw-grid[data-responsive] .rows-body-wrapper{min-width:0!important}tbw-grid[data-responsive] .data-grid-row:not(.group-row){display:block!important;grid-template-columns:none!important;padding:var(--tbw-cell-padding);padding-left:var(--tbw-spacing-xl);border-bottom:1px solid var(--tbw-color-border);min-height:auto!important;height:auto!important;contain:none!important;content-visibility:visible!important;background:var(--tbw-color-bg);position:relative}tbw-grid[data-responsive] .data-grid-row:not(.group-row):nth-child(2n){background:var(--tbw-color-row-alt)}tbw-grid[data-responsive] .data-grid-row:not(.group-row):hover{background:var(--tbw-color-row-hover)}tbw-grid[data-responsive] .data-grid-row:not(.group-row)[aria-selected=true]{background:var(--tbw-color-selection)}tbw-grid[data-responsive] .data-grid-row:not(.group-row)[aria-selected=true]:before{content:"";position:absolute;left:0;top:0;bottom:0;width:4px;background:var(--tbw-color-accent)}tbw-grid[data-responsive] .data-grid-row:not(.group-row)>.cell{display:flex!important;justify-content:space-between;align-items:center;padding:var(--tbw-spacing-xs) var(--tbw-spacing-md);width:100%!important;min-width:0!important;min-height:auto!important;height:auto!important;line-height:1.5!important;position:static!important;left:auto!important;right:auto!important;border:none!important;border-bottom:none!important;border-right:none!important;background:transparent!important;white-space:normal!important;overflow:visible!important}tbw-grid[data-responsive] .data-grid-row:not(.group-row)>.cell:before{content:attr(data-header) ": ";font-weight:600;color:var(--tbw-color-header-fg);flex-shrink:0;margin-right:var(--tbw-spacing-md);min-width:100px}tbw-grid[data-responsive] .data-grid-row:not(.group-row)>.cell:after{content:none}tbw-grid[data-responsive] .cell[data-utility]{display:none!important}tbw-grid[data-responsive] .cell[data-responsive-hidden]{display:none!important}tbw-grid[data-responsive] .cell[data-responsive-value-only]{justify-content:flex-start!important;font-weight:500}tbw-grid[data-responsive] .cell[data-responsive-value-only]:before{display:none!important}tbw-grid:not([data-responsive]) .cell[data-responsive-hidden]{display:none!important}tbw-grid[data-responsive] .tbw-footer,tbw-grid[data-responsive] .tbw-pinned-rows,tbw-grid[data-responsive] .tbw-aggregation-rows{display:none!important}tbw-grid[data-responsive] .tbw-pinned-rows,tbw-grid[data-responsive] .tbw-aggregation-rows,tbw-grid[data-responsive] .tbw-aggregation-row{min-width:0!important}tbw-grid[data-responsive] .data-grid-row.responsive-card{display:block!important;padding:var(--tbw-cell-padding);border-bottom:1px solid var(--tbw-color-border)}tbw-grid[data-responsive] .data-grid-row.responsive-card>*{width:100%}tbw-grid[data-responsive] .data-grid-row.responsive-card .cell:before{display:none}';
362
+ class E extends C {
363
363
  name = "responsive";
364
364
  version = "1.0.0";
365
- styles = C;
365
+ styles = _;
366
+ /**
367
+ * Plugin manifest declaring incompatibilities with other plugins.
368
+ */
369
+ static manifest = {
370
+ incompatibleWith: [
371
+ {
372
+ name: "groupingRows",
373
+ reason: "Responsive card layout does not yet support row grouping. The variable row heights (cards vs group headers) cause scroll calculation issues."
374
+ }
375
+ ]
376
+ };
366
377
  #e;
367
378
  #t = !1;
368
- #s;
369
- #h = !1;
370
- #o = 0;
379
+ #n;
380
+ #w = !1;
381
+ #a = 0;
371
382
  /** Set of column fields to completely hide */
372
- #i = /* @__PURE__ */ new Set();
383
+ #s = /* @__PURE__ */ new Set();
373
384
  /** Set of column fields to show value only (no header label) */
374
- #n = /* @__PURE__ */ new Set();
385
+ #d = /* @__PURE__ */ new Set();
375
386
  /** Currently active breakpoint, or null if none */
376
- #a = null;
387
+ #l = null;
377
388
  /** Sorted breakpoints from largest to smallest */
378
- #l = [];
389
+ #c = [];
379
390
  /**
380
391
  * Check if currently in responsive mode.
381
392
  * @returns `true` if the grid is in card layout mode
@@ -389,9 +400,9 @@ class A extends _ {
389
400
  * @param enabled - Whether to enable responsive mode
390
401
  */
391
402
  setResponsive(t) {
392
- t !== this.#t && (this.#t = t, this.#c(), this.emit("responsive-change", {
403
+ t !== this.#t && (this.#t = t, this.#u(), this.emit("responsive-change", {
393
404
  isResponsive: t,
394
- width: this.#o,
405
+ width: this.#a,
395
406
  breakpoint: this.config.breakpoint ?? 0
396
407
  }));
397
408
  }
@@ -400,7 +411,7 @@ class A extends _ {
400
411
  * @param width - New breakpoint width in pixels
401
412
  */
402
413
  setBreakpoint(t) {
403
- this.config.breakpoint = t, this.#u(this.#o);
414
+ this.config.breakpoint = t, this.#v(this.#a);
404
415
  }
405
416
  /**
406
417
  * Set a custom card renderer.
@@ -415,33 +426,33 @@ class A extends _ {
415
426
  * @returns Width of the grid element in pixels
416
427
  */
417
428
  getWidth() {
418
- return this.#o;
429
+ return this.#a;
419
430
  }
420
431
  /**
421
432
  * Get the currently active breakpoint config (multi-breakpoint mode only).
422
433
  * @returns The active BreakpointConfig, or null if no breakpoint is active
423
434
  */
424
435
  getActiveBreakpoint() {
425
- return this.#a;
436
+ return this.#l;
426
437
  }
427
438
  attach(t) {
428
- super.attach(t), this.#d(this.config.hiddenColumns), this.config.breakpoints?.length && (this.#l = [...this.config.breakpoints].sort((e, i) => i.maxWidth - e.maxWidth)), this.#e = new ResizeObserver((e) => {
439
+ super.attach(t), this.#h(this.config.hiddenColumns), this.config.breakpoints?.length && (this.#c = [...this.config.breakpoints].sort((e, i) => i.maxWidth - e.maxWidth)), this.#e = new ResizeObserver((e) => {
429
440
  const i = e[0]?.contentRect.width ?? 0;
430
- this.#o = i, clearTimeout(this.#s), this.#s = setTimeout(() => {
431
- this.#u(i);
441
+ this.#a = i, clearTimeout(this.#n), this.#n = setTimeout(() => {
442
+ this.#v(i);
432
443
  }, this.config.debounceMs ?? 100);
433
444
  }), this.#e.observe(this.gridElement);
434
445
  }
435
446
  /**
436
447
  * Build the hidden and value-only column sets from config.
437
448
  */
438
- #d(t) {
439
- if (this.#i.clear(), this.#n.clear(), !!t)
449
+ #h(t) {
450
+ if (this.#s.clear(), this.#d.clear(), !!t)
440
451
  for (const e of t)
441
- typeof e == "string" ? this.#i.add(e) : e.showValue ? this.#n.add(e.field) : this.#i.add(e.field);
452
+ typeof e == "string" ? this.#s.add(e) : e.showValue ? this.#d.add(e.field) : this.#s.add(e.field);
442
453
  }
443
454
  detach() {
444
- this.#e?.disconnect(), this.#e = void 0, clearTimeout(this.#s), this.#s = void 0, this.gridElement && this.gridElement.removeAttribute("data-responsive"), super.detach();
455
+ this.#e?.disconnect(), this.#e = void 0, clearTimeout(this.#n), this.#n = void 0, this.gridElement && this.gridElement.removeAttribute("data-responsive"), super.detach();
445
456
  }
446
457
  /**
447
458
  * Apply hidden and value-only columns.
@@ -449,32 +460,32 @@ class A extends _ {
449
460
  * In multi-breakpoint mode, applies whenever there's an active breakpoint.
450
461
  */
451
462
  afterRender() {
452
- if (!(this.#l.length > 0 ? this.#a !== null : this.#t))
463
+ if (this.#_(), !(this.#c.length > 0 ? this.#l !== null : this.#t))
453
464
  return;
454
- const e = this.#i.size > 0, i = this.#n.size > 0;
465
+ const e = this.#s.size > 0, i = this.#d.size > 0;
455
466
  if (!e && !i)
456
467
  return;
457
- const o = this.gridElement.querySelectorAll(".cell[data-field]");
458
- for (const l of o) {
459
- const a = l.getAttribute("data-field");
460
- a && (this.#i.has(a) ? (l.setAttribute("data-responsive-hidden", ""), l.removeAttribute("data-responsive-value-only")) : this.#n.has(a) ? (l.setAttribute("data-responsive-value-only", ""), l.removeAttribute("data-responsive-hidden")) : (l.removeAttribute("data-responsive-hidden"), l.removeAttribute("data-responsive-value-only")));
468
+ const n = this.gridElement.querySelectorAll(".cell[data-field]");
469
+ for (const a of n) {
470
+ const r = a.getAttribute("data-field");
471
+ r && (this.#s.has(r) ? (a.setAttribute("data-responsive-hidden", ""), a.removeAttribute("data-responsive-value-only")) : this.#d.has(r) ? (a.setAttribute("data-responsive-value-only", ""), a.removeAttribute("data-responsive-hidden")) : (a.removeAttribute("data-responsive-hidden"), a.removeAttribute("data-responsive-value-only")));
461
472
  }
462
473
  }
463
474
  /**
464
475
  * Check if width has crossed any breakpoint threshold.
465
476
  * Handles both single breakpoint (legacy) and multi-breakpoint modes.
466
477
  */
467
- #u(t) {
468
- if (this.#l.length > 0) {
469
- this.#g(t);
478
+ #v(t) {
479
+ if (this.#c.length > 0) {
480
+ this.#R(t);
470
481
  return;
471
482
  }
472
483
  const e = this.config.breakpoint ?? 0;
473
- e === 0 && !this.#h && (this.#h = !0, console.warn(
484
+ e === 0 && !this.#w && (this.#w = !0, console.warn(
474
485
  "[tbw-grid:ResponsivePlugin] No breakpoint configured. Responsive mode is disabled. Set a breakpoint based on your grid's column count."
475
486
  ));
476
487
  const i = e > 0 && t < e;
477
- i !== this.#t && (this.#t = i, this.#c(), this.emit("responsive-change", {
488
+ i !== this.#t && (this.#t = i, this.#u(), this.emit("responsive-change", {
478
489
  isResponsive: i,
479
490
  width: t,
480
491
  breakpoint: e
@@ -484,14 +495,14 @@ class A extends _ {
484
495
  * Check breakpoints in multi-breakpoint mode.
485
496
  * Evaluates breakpoints from largest to smallest, applying the first match.
486
497
  */
487
- #g(t) {
498
+ #R(t) {
488
499
  let e = null;
489
- for (const o of this.#l)
490
- t <= o.maxWidth && (e = o);
491
- if (e !== this.#a) {
492
- this.#a = e, e?.hiddenColumns ? this.#d(e.hiddenColumns) : this.#d(this.config.hiddenColumns);
493
- const o = e?.cardLayout === !0;
494
- o !== this.#t && (this.#t = o, this.#c()), this.emit("responsive-change", {
500
+ for (const n of this.#c)
501
+ t <= n.maxWidth && (e = n);
502
+ if (e !== this.#l) {
503
+ this.#l = e, e?.hiddenColumns ? this.#h(e.hiddenColumns) : this.#h(this.config.hiddenColumns);
504
+ const n = e?.cardLayout === !0;
505
+ n !== this.#t && (this.#t = n, this.#u()), this.emit("responsive-change", {
495
506
  isResponsive: this.#t,
496
507
  width: t,
497
508
  breakpoint: e?.maxWidth ?? 0
@@ -499,25 +510,25 @@ class A extends _ {
499
510
  }
500
511
  }
501
512
  /** Original row height before entering responsive mode, for restoration on exit */
502
- #r;
513
+ #i;
503
514
  /**
504
515
  * Apply the responsive state to the grid element.
505
516
  * Handles scroll reset when entering responsive mode and row height restoration on exit.
506
517
  */
507
- #c() {
518
+ #u() {
508
519
  this.gridElement.toggleAttribute("data-responsive", this.#t);
509
520
  const t = this.config.animate !== !1;
510
521
  this.gridElement.toggleAttribute("data-responsive-animate", t), this.config.animationDuration && this.gridElement.style.setProperty("--tbw-responsive-duration", `${this.config.animationDuration}ms`);
511
522
  const e = this.grid;
512
523
  if (this.#t) {
513
- e._virtualization && (this.#r = e._virtualization.rowHeight);
524
+ e._virtualization && (this.#i = e._virtualization.rowHeight);
514
525
  const i = this.gridElement.querySelector(".tbw-scroll-area");
515
526
  i && (i.scrollLeft = 0);
516
527
  } else {
517
528
  const i = this.gridElement.querySelectorAll(".data-grid-row");
518
- for (const o of i)
519
- o.style.height = "", o.classList.remove("responsive-card");
520
- this.#r && this.#r > 0 && e._virtualization && (e._virtualization.rowHeight = this.#r, this.#r = void 0);
529
+ for (const n of i)
530
+ n.style.height = "", n.classList.remove("responsive-card");
531
+ this.#i && this.#i > 0 && e._virtualization && (e._virtualization.rowHeight = this.#i, this.#i = void 0), this.#r = void 0, this.#o = void 0, this.#g = void 0;
521
532
  }
522
533
  }
523
534
  /**
@@ -535,10 +546,10 @@ class A extends _ {
535
546
  if (!this.#t || !this.config.cardRenderer || t.__isGroupRow)
536
547
  return;
537
548
  e.replaceChildren();
538
- const o = this.config.cardRenderer(t, i);
539
- e.classList.add("responsive-card");
540
- const l = this.config.cardRowHeight ?? "auto";
541
- return l !== "auto" ? e.style.height = `${l}px` : e.style.height = "auto", e.appendChild(o), !0;
549
+ const n = this.config.cardRenderer(t, i);
550
+ e.className = "data-grid-row responsive-card";
551
+ const a = this.config.cardRowHeight ?? "auto";
552
+ return a !== "auto" ? e.style.height = `${a}px` : e.style.height = "auto", e.appendChild(n), !0;
542
553
  }
543
554
  /**
544
555
  * Handle keyboard navigation in responsive mode.
@@ -582,8 +593,134 @@ class A extends _ {
582
593
  }
583
594
  return !1;
584
595
  }
596
+ // ============================================
597
+ // Variable Height Support for Mixed Row Types
598
+ // ============================================
599
+ /** Measured card height from DOM for virtualization calculations */
600
+ #r;
601
+ /** Measured group row height from DOM for virtualization calculations */
602
+ #o;
603
+ /** Last known card row count for detecting changes (e.g., group expand/collapse) */
604
+ #g;
605
+ /**
606
+ * Get the effective card height for virtualization calculations.
607
+ * Prioritizes DOM-measured height (actual rendered size) over config,
608
+ * since content can overflow the configured height.
609
+ */
610
+ #b() {
611
+ if (this.#r && this.#r > 0)
612
+ return this.#r;
613
+ const t = this.config.cardRowHeight;
614
+ return typeof t == "number" && t > 0 ? t : 80;
615
+ }
616
+ /**
617
+ * Get the effective group row height for virtualization calculations.
618
+ * Uses DOM-measured height, falling back to original row height.
619
+ */
620
+ #m() {
621
+ return this.#o && this.#o > 0 ? this.#o : this.#i ?? 28;
622
+ }
623
+ /**
624
+ * Check if there are any group rows in the current dataset.
625
+ * Used to determine if we have mixed row heights.
626
+ */
627
+ #f() {
628
+ for (const t of this.rows)
629
+ if (t.__isGroupRow)
630
+ return !0;
631
+ return !1;
632
+ }
633
+ /**
634
+ * Count group rows and card rows in the current dataset.
635
+ */
636
+ #y() {
637
+ let t = 0, e = 0;
638
+ for (const i of this.rows)
639
+ i.__isGroupRow ? t++ : e++;
640
+ return { groupCount: t, cardCount: e };
641
+ }
642
+ /**
643
+ * Return total extra height contributed by mixed row heights.
644
+ * This is called by the grid's virtualization system to adjust scrollbar height.
645
+ *
646
+ * The grid calculates: totalRows * baseRowHeight + pluginExtraHeight
647
+ *
648
+ * For mixed layouts (groups + cards), we need to report the difference between
649
+ * actual heights and what the base calculation assumes:
650
+ * - Extra for groups: groupCount * (groupHeight - baseHeight)
651
+ * - Extra for cards: cardCount * (cardHeight - baseHeight)
652
+ */
653
+ getExtraHeight() {
654
+ if (!this.#t || !this.config.cardRenderer || !this.#f())
655
+ return 0;
656
+ const t = this.#i ?? 28, e = this.#m(), i = this.#b(), { groupCount: n, cardCount: a } = this.#y(), r = n * Math.max(0, e - t), o = a * Math.max(0, i - t);
657
+ return r + o;
658
+ }
659
+ /**
660
+ * Return extra height that appears before a given row index.
661
+ * Used by virtualization to correctly calculate scroll positions.
662
+ *
663
+ * Like getExtraHeight, this accounts for both group and card row heights.
664
+ */
665
+ getExtraHeightBefore(t) {
666
+ if (!this.#t || !this.config.cardRenderer || !this.#f())
667
+ return 0;
668
+ const e = this.#i ?? 28, i = this.#m(), n = this.#b(), a = Math.max(0, i - e), r = Math.max(0, n - e);
669
+ let o = 0, l = 0;
670
+ const d = this.rows, h = Math.min(t, d.length);
671
+ for (let c = 0; c < h; c++)
672
+ d[c].__isGroupRow ? o++ : l++;
673
+ return o * a + l * r;
674
+ }
675
+ /**
676
+ * Count the number of card rows (non-group rows) in the current dataset.
677
+ */
678
+ #C() {
679
+ let t = 0;
680
+ for (const e of this.rows)
681
+ e.__isGroupRow || t++;
682
+ return t;
683
+ }
684
+ /** Pending refresh scheduled via microtask */
685
+ #p = !1;
686
+ /**
687
+ * Measure card height from DOM after render and detect row count changes.
688
+ * Called in afterRender to ensure scroll calculations are accurate.
689
+ *
690
+ * This handles two scenarios:
691
+ * 1. Card height changes (content overflow, dynamic sizing)
692
+ * 2. Card row count changes (group expand/collapse)
693
+ * 3. Group row height changes
694
+ *
695
+ * For uniform card layouts (no groups), we update the virtualization row height
696
+ * directly to the card height. For mixed layouts (groups + cards), we use the
697
+ * getExtraHeight mechanism to report height differences.
698
+ *
699
+ * The refresh is deferred via microtask to avoid nested render cycles.
700
+ */
701
+ #_() {
702
+ if (!this.#t || !this.config.cardRenderer)
703
+ return;
704
+ let t = !1;
705
+ const e = this.grid, i = this.#f(), n = this.#C();
706
+ if (n !== this.#g && (this.#g = n, t = !0), i) {
707
+ const r = this.gridElement.querySelector(".data-grid-row.group-row");
708
+ if (r) {
709
+ const o = r.getBoundingClientRect().height;
710
+ o > 0 && o !== this.#o && (this.#o = o, t = !0);
711
+ }
712
+ }
713
+ const a = this.gridElement.querySelector(".data-grid-row.responsive-card");
714
+ if (a) {
715
+ const r = a.getBoundingClientRect().height;
716
+ r > 0 && r !== this.#r && (this.#r = r, t = !0, !i && e._virtualization && (e._virtualization.rowHeight = r));
717
+ }
718
+ t && !this.#p && (this.#p = !0, queueMicrotask(() => {
719
+ this.#p = !1, this.grid && this.#t && this.grid.refreshVirtualWindow?.(!0, !0);
720
+ }));
721
+ }
585
722
  }
586
723
  export {
587
- A as ResponsivePlugin
724
+ E as ResponsivePlugin
588
725
  };
589
726
  //# sourceMappingURL=index.js.map