@pagamio/frontend-commons-lib 0.8.319 → 0.8.320

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.
@@ -1,7 +1,7 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { MantineReactTable, useMantineReactTable } from 'mantine-react-table';
3
3
  import { HiPlusSm } from 'react-icons/hi';
4
- import { useMemo, useRef, useState } from 'react';
4
+ import { useEffect, useLayoutEffect, useMemo, useRef, useState } from 'react';
5
5
  import { FilterComponent, IconButton } from '../../components';
6
6
  import { cn } from '../../helpers';
7
7
  import { useMediaQueries } from '../../shared';
@@ -104,18 +104,81 @@ function CustomToolbar({ filters, appliedFilters, onFilterChange, onApply, onCle
104
104
  const PagamioTable = ({ columns, data, isLoading = false, rowCount, sorting, pagination, filtering, search, onRowClick, rowClassName, expandable = false, renderDetailPanel, toolbar, toolbarMode = 'custom', enableColumnResizing, enableColumnPinning, enableColumnOrdering, enableColumnFilters, enableHiding, enableRowSelection, enableRowActions, enableRowVirtualization, enableGrouping, enableEditing, enableDensityToggle, enableFullScreenToggle, enableClickToCopy, enableRowNumbers, enableMultiSort, enableStickyHeader, enableStickyFooter, editDisplayMode, onEditingRowSave, onEditingRowCancel, renderRowActions, renderRowActionMenuItems, positionActionsColumn, renderTopToolbarCustomActions, renderBottomToolbarCustomActions, layoutMode, defaultColumn, mantineTableOptions, }) => {
105
105
  const [expanded, setExpanded] = useState({});
106
106
  const tableRef = useRef(null);
107
- // Note: previously this component force-applied
108
- // max-height: calc(100vh - {tableTop + 68}px)
109
- // to the inner mantine table container. That produced a "squeezed" table
110
- // whenever the table sat below other content (e.g. nested in tabs on the
111
- // event details page) — the table's own top was already far down the
112
- // viewport, so the leftover max-height was tiny and only ~3 rows showed
113
- // before an internal scroll kicked in.
107
+ // ── Internal max-height ─────────────────────────────────────────────
108
+ // The mantine table container is height-capped to `viewportHeight - tableTop`
109
+ // so that the table is the only scrolling element when its parent layout
110
+ // is fixed (page header + sidebar stay put). Without this, large datasets
111
+ // would push the page itself into a scroll, breaking the toolbar/header
112
+ // sticky behaviour that the rest of the app relies on.
114
113
  //
115
- // We now let the table render its natural height. Pagination caps the row
116
- // count, and the parent route layout already scrolls when the page is
117
- // taller than the viewport, so the user gets one continuous scroll instead
118
- // of a nested mini-scroll.
114
+ // Bottom margin reserves space for the bottom toolbar (pagination, ~52px)
115
+ // plus a small gap so the table doesn't sit flush against page edges.
116
+ const TABLE_BOTTOM_MARGIN = 68;
117
+ /**
118
+ * Walk up the DOM looking for the closest scrollable ancestor (i.e. an
119
+ * element with overflow-y: auto/scroll AND scrollHeight > clientHeight).
120
+ * If we find one, the *page* is what's scrolling — we should NOT cap the
121
+ * table's height because that would create a confusing nested scroll
122
+ * (page scroll + table scroll). Returns true when the table itself
123
+ * should manage its own scroll.
124
+ */
125
+ const tableShouldOwnScroll = (el) => {
126
+ let node = el.parentElement;
127
+ while (node && node !== document.body) {
128
+ const style = window.getComputedStyle(node);
129
+ const overflowY = style.overflowY;
130
+ const isScrollable = (overflowY === 'auto' || overflowY === 'scroll') && node.scrollHeight > node.clientHeight + 1;
131
+ if (isScrollable)
132
+ return false;
133
+ node = node.parentElement;
134
+ }
135
+ return true;
136
+ };
137
+ const applyTableHeight = (el) => {
138
+ const mrtContainer = el.querySelector('.mrt-table-container');
139
+ if (!mrtContainer)
140
+ return;
141
+ // If a parent is already handling the scroll, let the table render at
142
+ // its natural height — the user gets one continuous page scroll.
143
+ if (!tableShouldOwnScroll(el)) {
144
+ mrtContainer.style.removeProperty('max-height');
145
+ return;
146
+ }
147
+ const containerTop = mrtContainer.getBoundingClientRect().top;
148
+ const newMax = Math.round(Math.max(240, window.innerHeight - containerTop - TABLE_BOTTOM_MARGIN));
149
+ const newMaxStr = `${newMax}px`;
150
+ // Skip the write if the value hasn't changed — avoids re-layout loops
151
+ // with ResizeObserver where mutating the cell's max-height would refire
152
+ // the observer on the next frame.
153
+ if (mrtContainer.style.maxHeight === newMaxStr)
154
+ return;
155
+ mrtContainer.style.setProperty('max-height', newMaxStr, 'important');
156
+ };
157
+ // Runs once on mount + whenever the *window* resizes. We deliberately do
158
+ // NOT run on every render or use a ResizeObserver on the document — both
159
+ // produce loop conditions: applyTableHeight mutates layout, which fires
160
+ // the observer, which calls applyTableHeight again. The window-resize
161
+ // signal is sufficient because tableTop changes during a render get
162
+ // re-applied by useLayoutEffect-on-mount when the table remounts.
163
+ useLayoutEffect(() => {
164
+ if (tableRef.current)
165
+ applyTableHeight(tableRef.current);
166
+ }, []);
167
+ useEffect(() => {
168
+ const el = tableRef.current;
169
+ if (!el)
170
+ return;
171
+ let frame = 0;
172
+ const handler = () => {
173
+ cancelAnimationFrame(frame);
174
+ frame = requestAnimationFrame(() => applyTableHeight(el));
175
+ };
176
+ window.addEventListener('resize', handler);
177
+ return () => {
178
+ cancelAnimationFrame(frame);
179
+ window.removeEventListener('resize', handler);
180
+ };
181
+ }, []);
119
182
  // Process columns (handle showHeader: false)
120
183
  const processedColumns = useMemo(() => processColumns(columns), [columns]);
121
184
  // Convert our SortConfig to MRT's SortingState
package/lib/styles.css CHANGED
@@ -3889,14 +3889,25 @@ video {
3889
3889
  text-overflow: clip !important;
3890
3890
  }
3891
3891
 
3892
- /* MRT semantic mode: the explicit `width: <n>px` on each cell prevents the
3893
- table from filling its container — leftover space becomes dead gap on the
3894
- right. Treat the inline width as a minimum hint instead by overriding it
3895
- to `auto`; the browser's table-layout: auto then distributes width based
3896
- on content + min-width while filling 100% of the table width. */
3892
+ /* MRT semantic mode column sizing.
3893
+ *
3894
+ * MRT inlines `width: calc(--col-X-size * 1px)` and
3895
+ * `min-width: max(calc(--col-X-size * 1px), 50px)` on every cell. With
3896
+ * `table-layout: auto`, those fixed values cause two problems:
3897
+ * 1. Cells can't shrink below their min-width, leaving dead gaps when
3898
+ * content is short.
3899
+ * 2. The combined widths can exceed the container, leaving a horizontal
3900
+ * gap on the right.
3901
+ *
3902
+ * We override both: cells get `width: auto` and `min-width: 0` so the
3903
+ * browser sizes columns by content, then distributes remaining row space
3904
+ * proportionally. `whiteSpace: normal` (set above) lets long content wrap
3905
+ * instead of being crushed.
3906
+ */
3897
3907
  .mantine-Table-table > thead > tr > .mantine-Table-th,
3898
3908
  .mantine-Table-table > tbody > tr > .mantine-Table-td {
3899
3909
  width: auto !important;
3910
+ min-width: 0 !important;
3900
3911
  }
3901
3912
  .file\:-ms-4::file-selector-button {
3902
3913
  margin-inline-start: -1rem;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@pagamio/frontend-commons-lib",
3
3
  "description": "Pagamio library for Frontend reusable components like the form engine and table container",
4
- "version": "0.8.319",
4
+ "version": "0.8.320",
5
5
  "publishConfig": {
6
6
  "access": "public",
7
7
  "provenance": false