@spaced-out/ui-design-system 0.4.11 → 0.4.13

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.
@@ -82,6 +82,7 @@ noreferrer
82
82
  Noronha
83
83
  nsfmc
84
84
  OPACITYS
85
+ overscan
85
86
  Pago
86
87
  partialformat
87
88
  Paulo
package/CHANGELOG.md CHANGED
@@ -2,6 +2,20 @@
2
2
 
3
3
  All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
4
4
 
5
+ ### [0.4.13](https://github.com/spaced-out/ui-design-system/compare/v0.4.12...v0.4.13) (2025-08-04)
6
+
7
+
8
+ ### Features
9
+
10
+ * **table:** [GDS-529] table virtualisation and refactor ([#380](https://github.com/spaced-out/ui-design-system/issues/380)) ([32498d7](https://github.com/spaced-out/ui-design-system/commit/32498d7ccef6430d795781676027d342af664d6c))
11
+
12
+ ### [0.4.12](https://github.com/spaced-out/ui-design-system/compare/v0.4.11...v0.4.12) (2025-07-29)
13
+
14
+
15
+ ### Bug Fixes
16
+
17
+ * [filter-overlay] fluid class overrides small and medium class ([#383](https://github.com/spaced-out/ui-design-system/issues/383)) ([f94c132](https://github.com/spaced-out/ui-design-system/commit/f94c13297c25ff659b343587795919a9a264756c))
18
+
5
19
  ### [0.4.11](https://github.com/spaced-out/ui-design-system/compare/v0.4.10...v0.4.11) (2025-07-28)
6
20
 
7
21
 
@@ -96,8 +96,8 @@ const FilterButtonOverlay = exports.FilterButtonOverlay = /*#__PURE__*/React.for
96
96
  }, /*#__PURE__*/React.createElement("div", {
97
97
  className: (0, _classify.default)(_FilterButtonOverlayModule.default.overlayWrapper, {
98
98
  [_FilterButtonOverlayModule.default.fluid]: isFluid,
99
- [_FilterButtonOverlayModule.default.medium]: size === 'medium',
100
- [_FilterButtonOverlayModule.default.small]: size === 'small'
99
+ [_FilterButtonOverlayModule.default.small]: size === 'small',
100
+ [_FilterButtonOverlayModule.default.medium]: size === 'medium'
101
101
  }, classNames?.overlayContainer)
102
102
  }, children)))));
103
103
  });
@@ -146,8 +146,8 @@ export const FilterButtonOverlay: React$AbstractComponent<
146
146
  css.overlayWrapper,
147
147
  {
148
148
  [css.fluid]: isFluid,
149
- [css.medium]: size === 'medium',
150
149
  [css.small]: size === 'small',
150
+ [css.medium]: size === 'medium',
151
151
  },
152
152
  classNames?.overlayContainer,
153
153
  )}
@@ -19,11 +19,6 @@
19
19
  z-index: var(--menu-elevation);
20
20
  }
21
21
 
22
- .fluid {
23
- width: sizeFluid;
24
- min-width: size160;
25
- }
26
-
27
22
  .medium {
28
23
  width: size300;
29
24
  min-width: size300;
@@ -34,6 +29,11 @@
34
29
  min-width: size240;
35
30
  }
36
31
 
32
+ .fluid {
33
+ width: sizeFluid;
34
+ min-width: size160;
35
+ }
36
+
37
37
  .isFluid {
38
38
  width: sizeFluid;
39
39
  }
@@ -5,20 +5,137 @@ Object.defineProperty(exports, "__esModule", {
5
5
  });
6
6
  exports.BasicTableBody = exports.BasicTable = void 0;
7
7
  exports.StaticTable = StaticTable;
8
+ exports.StaticTableVirtualized = StaticTableVirtualized;
8
9
  var React = _interopRequireWildcard(require("react"));
10
+ var _reactVirtual = require("@tanstack/react-virtual");
9
11
  var _get = _interopRequireDefault(require("lodash/get"));
10
12
  var _xor = _interopRequireDefault(require("lodash/xor"));
11
13
  var _useWindowSize = require("../../hooks/useWindowSize");
12
14
  var _size = require("../../styles/variables/_size");
15
+ var _space = require("../../styles/variables/_space");
13
16
  var _classify = require("../../utils/classify");
14
17
  var _makeClassNameComponent = require("../../utils/makeClassNameComponent");
18
+ var _CircularLoader = require("../CircularLoader");
15
19
  var _DefaultRow = require("./DefaultRow");
16
20
  var _DefaultTableHeader = require("./DefaultTableHeader");
17
21
  var _TableModule = _interopRequireDefault(require("./Table.module.css"));
18
22
  function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
19
23
  function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function (e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != typeof e && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (const t in e) "default" !== t && {}.hasOwnProperty.call(e, t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, t)) && (i.get || i.set) ? o(f, t, i) : f[t] = e[t]); return f; })(e, t); }
24
+ // $FlowFixMe[untyped-import]
20
25
  const BasicTable = exports.BasicTable = (0, _makeClassNameComponent.makeClassNameComponent)(_TableModule.default.defaultTable, 'table');
21
26
  const BasicTableBody = exports.BasicTableBody = (0, _makeClassNameComponent.makeClassNameComponent)(_TableModule.default.defaultTableBody, 'tbody');
27
+ function useTableWidth(ref) {
28
+ const {
29
+ width
30
+ } = (0, _useWindowSize.useWindowSize)();
31
+ const [tableWidth, setTableWidth] = React.useState();
32
+ React.useEffect(() => {
33
+ if (ref.current) {
34
+ setTableWidth(ref.current.offsetWidth);
35
+ }
36
+ }, [width]);
37
+ return tableWidth;
38
+ }
39
+ function useMappedKeys(entries, rowKeys, idName) {
40
+ return React.useMemo(() => rowKeys ?? entries.map(e => (0, _get.default)(e, idName)), [entries, idName, rowKeys]);
41
+ }
42
+ function useHeaderCheckboxHandler(selectedKeys, entries, idName, onSelect) {
43
+ if (!selectedKeys) {
44
+ return undefined;
45
+ }
46
+ return _ref => {
47
+ let {
48
+ checked
49
+ } = _ref;
50
+ const allIds = entries.map(row => (0, _get.default)(row, idName));
51
+ const newSelection = checked ? allIds : [];
52
+ onSelect?.(newSelection);
53
+ };
54
+ }
55
+ function RowRenderer(_ref2) {
56
+ let {
57
+ TableRow,
58
+ data,
59
+ headers,
60
+ extras,
61
+ sortedKeys,
62
+ selected,
63
+ disabled,
64
+ classNames,
65
+ keyId,
66
+ onSelect
67
+ } = _ref2;
68
+ return TableRow ? /*#__PURE__*/React.createElement(TableRow, {
69
+ key: keyId,
70
+ data: data,
71
+ headers: headers
72
+ // extras and rowKeys are both 'optional'
73
+ ,
74
+ extras: extras,
75
+ sortedKeys: sortedKeys,
76
+ selected: selected,
77
+ disabled: disabled
78
+ }) : /*#__PURE__*/React.createElement(_DefaultRow.DefaultRow, {
79
+ key: keyId,
80
+ data: data,
81
+ extras: extras,
82
+ headers: headers,
83
+ selected: selected,
84
+ onSelect: onSelect,
85
+ disabled: disabled,
86
+ classNames: {
87
+ tableRow: classNames?.tableRow,
88
+ checkbox: classNames?.checkbox
89
+ }
90
+ });
91
+ }
92
+ function TableWrapper(_ref3) {
93
+ let {
94
+ tableRef,
95
+ classNames,
96
+ className,
97
+ tableHeaderClassName,
98
+ children,
99
+ wrapperStyle,
100
+ isLoading = false,
101
+ emptyText,
102
+ showHeader = true,
103
+ stickyHeader = false,
104
+ sortable,
105
+ disabled = false,
106
+ entriesLength = 0,
107
+ selectedKeys,
108
+ headers,
109
+ sortKey,
110
+ sortDirection,
111
+ handleSortClick,
112
+ handleHeaderCheckboxClick
113
+ } = _ref3;
114
+ return /*#__PURE__*/React.createElement("div", {
115
+ className: (0, _classify.classify)(_TableModule.default.tableContainer, classNames?.wrapper),
116
+ "data-id": 'table-wrap',
117
+ ref: tableRef,
118
+ style: wrapperStyle
119
+ }, /*#__PURE__*/React.createElement(BasicTable, {
120
+ "data-id": "basic-table",
121
+ className: (0, _classify.classify)(className, {
122
+ [_TableModule.default.fullHeightTable]: isLoading || !entriesLength && !!emptyText
123
+ }, classNames?.table)
124
+ }, showHeader && /*#__PURE__*/React.createElement(_DefaultTableHeader.DefaultTableHeader, {
125
+ className: (0, _classify.classify)(tableHeaderClassName, classNames?.tableHeader),
126
+ sortable: sortable,
127
+ columns: headers,
128
+ handleSortClick: handleSortClick,
129
+ sortKey: sortKey,
130
+ sortDirection: sortDirection,
131
+ disabled: disabled,
132
+ handleCheckboxClick: handleHeaderCheckboxClick,
133
+ stickyHeader: stickyHeader,
134
+ checked: selectedKeys == null || selectedKeys.length === 0 ? 'false' : selectedKeys.length < entriesLength ? 'mixed' : 'true'
135
+ }), /*#__PURE__*/React.createElement(BasicTableBody, {
136
+ className: classNames?.tableBody
137
+ }, children)));
138
+ }
22
139
 
23
140
  /**
24
141
  * A Static Default Table.
@@ -61,59 +178,37 @@ function StaticTable(props) {
61
178
 
62
179
  // this is a fallback and honestly probably doesn't need the
63
180
  // memo'ing
64
- const mappedKeys = React.useMemo(() => rowKeys ?? entries.map(e => (0, _get.default)(e, idName)), [entries, idName, rowKeys]);
65
181
  const tableRef = React.useRef(null);
66
- const {
67
- width
68
- } = (0, _useWindowSize.useWindowSize)();
69
- const [tableWidth, setTableWidth] = React.useState();
70
- React.useEffect(() => {
71
- if (tableRef.current) {
72
- setTableWidth(tableRef.current.offsetWidth);
73
- }
74
- }, [width]);
182
+ const mappedKeys = useMappedKeys(entries, rowKeys, idName);
183
+ const tableWidth = useTableWidth(tableRef);
75
184
 
76
185
  /**
77
186
  * this function is also used to decide weather to show checkbox in header or not. so it's value is undefined in case selectedKeys is not there.
78
187
  */
79
-
80
- const handleHeaderCheckboxClick = selectedKeys ? ({
81
- checked
82
- }) => {
83
- let selectedRowIds = [];
84
- if (selectedKeys) {
85
- if (checked === true) {
86
- selectedRowIds = entries.map(singleRowObj => (0, _get.default)(singleRowObj, idName));
87
- }
88
- onSelect?.(selectedRowIds);
89
- }
90
- } : undefined;
91
- return /*#__PURE__*/React.createElement("div", {
92
- className: (0, _classify.classify)(_TableModule.default.tableContainer, classNames?.wrapper),
93
- "data-id": "table-wrap",
94
- ref: tableRef,
95
- style: {
188
+ const handleHeaderCheckboxClick = useHeaderCheckboxHandler(selectedKeys, entries, idName, onSelect);
189
+ return /*#__PURE__*/React.createElement(TableWrapper, {
190
+ tableRef: tableRef,
191
+ wrapperStyle: {
96
192
  '--border-radius': borderRadius,
97
193
  '--table-width': tableWidth ? `${tableWidth}px` : _size.sizeFluid
98
- }
99
- }, /*#__PURE__*/React.createElement(BasicTable, {
100
- "data-id": "basic-table",
101
- className: (0, _classify.classify)(className, {
102
- [_TableModule.default.fullHeightTable]: isLoading || !entries.length && !!emptyText
103
- }, classNames?.table)
104
- }, showHeader && /*#__PURE__*/React.createElement(_DefaultTableHeader.DefaultTableHeader, {
105
- className: (0, _classify.classify)(tableHeaderClassName, classNames?.tableHeader),
194
+ },
195
+ classNames: classNames,
196
+ className: className,
197
+ tableHeaderClassName: tableHeaderClassName,
198
+ borderRadius: borderRadius,
199
+ isLoading: isLoading,
200
+ emptyText: emptyText,
201
+ showHeader: showHeader,
202
+ stickyHeader: stickyHeader,
106
203
  sortable: sortable,
107
- columns: headers,
108
- handleSortClick: handleSortClick,
204
+ disabled: false,
205
+ entriesLength: entries.length,
206
+ selectedKeys: selectedKeys,
207
+ headers: headers,
109
208
  sortKey: sortKey,
110
209
  sortDirection: sortDirection,
111
- disabled: disabled,
112
- handleCheckboxClick: handleHeaderCheckboxClick,
113
- stickyHeader: stickyHeader,
114
- checked: selectedKeys == null || selectedKeys.length === 0 ? 'false' : selectedKeys.length < entries.length ? 'mixed' : 'true'
115
- }), /*#__PURE__*/React.createElement(BasicTableBody, {
116
- className: classNames?.tableBody
210
+ handleSortClick: handleSortClick,
211
+ handleHeaderCheckboxClick: handleHeaderCheckboxClick
117
212
  }, isLoading || !entries.length ? /*#__PURE__*/React.createElement(_DefaultRow.EmptyRow, {
118
213
  isLoading: isLoading,
119
214
  emptyText: emptyText,
@@ -124,31 +219,189 @@ function StaticTable(props) {
124
219
  if (data == null) {
125
220
  return null;
126
221
  }
127
- data;
128
222
  const selected = selectedKeys && Array.isArray(selectedKeys) ? selectedKeys.includes((0, _get.default)(data, idName)) : undefined;
129
223
  const isRowDisabled = disabledKeys && Array.isArray(disabledKeys) ? disabledKeys.includes((0, _get.default)(data, idName)) : false;
130
- return TableRow ? /*#__PURE__*/React.createElement(TableRow, {
131
- key: key,
224
+ return /*#__PURE__*/React.createElement(RowRenderer, {
225
+ TableRow: TableRow,
226
+ keyId: key,
132
227
  data: data,
133
- headers: headers
134
- // extras and rowKeys are both 'optional'
135
- ,
228
+ headers: headers,
136
229
  extras: extras,
137
230
  sortedKeys: rowKeys ?? mappedKeys,
138
231
  selected: selected,
139
- disabled: disabled || isRowDisabled
140
- }) : /*#__PURE__*/React.createElement(_DefaultRow.DefaultRow, {
141
- key: key,
232
+ disabled: disabled || isRowDisabled,
233
+ classNames: classNames,
234
+ onSelect: selectedKeys != null ? _v => onSelect?.((0, _xor.default)(selectedKeys ?? [], [key])) : undefined
235
+ });
236
+ }));
237
+ }
238
+ function StaticTableVirtualized(props) {
239
+ const {
240
+ classNames,
241
+ className,
242
+ TableRow,
243
+ entries,
244
+ extras,
245
+ rowKeys,
246
+ headers,
247
+ showHeader = true,
248
+ tableHeaderClassName,
249
+ sortable,
250
+ // eslint-disable-next-line unused-imports/no-unused-vars
251
+ defaultSortKey,
252
+ // eslint-disable-next-line unused-imports/no-unused-vars
253
+ defaultSortDirection = 'original',
254
+ // eslint-disable-next-line unused-imports/no-unused-vars
255
+ onSort,
256
+ handleSortClick,
257
+ sortKey,
258
+ sortDirection,
259
+ selectedKeys,
260
+ disabledKeys = [],
261
+ onSelect,
262
+ isLoading,
263
+ idName = 'id',
264
+ emptyText,
265
+ disabled,
266
+ customLoader,
267
+ borderRadius,
268
+ stickyHeader,
269
+ virtualizationOptions
270
+ } = props;
271
+ const {
272
+ rowsCount,
273
+ rowHeight = _size.size48,
274
+ onEndReached,
275
+ isEndLoading = false,
276
+ isAllDataFetched = false
277
+ } = virtualizationOptions ?? {};
278
+ const tableRef = React.useRef(null);
279
+
280
+ // this is a fallback and honestly probably doesn't need the
281
+ // memo'ing
282
+ const mappedKeys = useMappedKeys(entries, rowKeys, idName);
283
+ const tableWidth = useTableWidth(tableRef);
284
+ const virtualizer = (0, _reactVirtual.useVirtualizer)({
285
+ count: entries.length,
286
+ getScrollElement: () => tableRef.current,
287
+ estimateSize: () => parseInt(rowHeight),
288
+ getItemKey: index => entries[index][idName],
289
+ overscan: 1
290
+ });
291
+ const currRows = virtualizer.getVirtualItems();
292
+ const hasTriggeredRef = React.useRef(false);
293
+ React.useEffect(() => {
294
+ if (!tableRef.current || !onEndReached || isAllDataFetched) {
295
+ return;
296
+ }
297
+ const scrollElement = tableRef.current;
298
+ const handleScroll = () => {
299
+ const {
300
+ scrollTop,
301
+ scrollHeight,
302
+ clientHeight
303
+ } = scrollElement;
304
+ const isAtEnd = scrollTop + clientHeight >= scrollHeight - 100; // buffer
305
+
306
+ if (isAtEnd) {
307
+ if (!hasTriggeredRef.current) {
308
+ hasTriggeredRef.current = true;
309
+ onEndReached();
310
+ }
311
+ } else {
312
+ hasTriggeredRef.current = false; // reset when scrolling up
313
+ }
314
+ };
315
+ scrollElement.addEventListener('scroll', handleScroll);
316
+ return () => {
317
+ scrollElement.removeEventListener('scroll', handleScroll);
318
+ };
319
+ }, [onEndReached, isAllDataFetched]);
320
+
321
+ /**
322
+ * this function is also used to decide weather to show checkbox in header or not. so it's value is undefined in case selectedKeys is not there.
323
+ */
324
+
325
+ const handleHeaderCheckboxClick = useHeaderCheckboxHandler(selectedKeys, entries, idName, onSelect);
326
+ const VirtualizedStartRow = () => /*#__PURE__*/React.createElement("tr", {
327
+ style: {
328
+ height: virtualizer.getVirtualItems()[0]?.start ?? _space.spaceNone,
329
+ width: _size.sizeFluid
330
+ }
331
+ }, /*#__PURE__*/React.createElement("td", {
332
+ colSpan: headers.length + (handleHeaderCheckboxClick ? 1 : 0),
333
+ style: {
334
+ padding: _space.spaceNone,
335
+ border: 'none',
336
+ height: '100%'
337
+ }
338
+ }));
339
+ const VirtualizedEndRow = () => /*#__PURE__*/React.createElement("tr", {
340
+ style: {
341
+ height: virtualizer.getTotalSize() - (virtualizer.getVirtualItems().at(-1)?.end ?? _space.spaceNone)
342
+ },
343
+ "aria-hidden": true
344
+ }, /*#__PURE__*/React.createElement("td", {
345
+ colSpan: headers.length + (handleHeaderCheckboxClick ? 1 : 0),
346
+ style: {
347
+ padding: _space.spaceNone,
348
+ border: 'none',
349
+ height: '100%'
350
+ }
351
+ }));
352
+ return /*#__PURE__*/React.createElement(TableWrapper, {
353
+ tableRef: tableRef,
354
+ wrapperStyle: {
355
+ '--border-radius': borderRadius,
356
+ '--table-width': tableWidth ? `${tableWidth}px` : _size.sizeFluid,
357
+ height: (rowsCount + 1) * parseInt(rowHeight),
358
+ overflowY: 'auto'
359
+ },
360
+ classNames: classNames,
361
+ className: className,
362
+ tableHeaderClassName: tableHeaderClassName,
363
+ borderRadius: borderRadius,
364
+ isLoading: isLoading,
365
+ emptyText: emptyText,
366
+ showHeader: showHeader,
367
+ stickyHeader: stickyHeader,
368
+ sortable: sortable,
369
+ disabled: false,
370
+ entriesLength: entries.length,
371
+ selectedKeys: selectedKeys,
372
+ headers: headers,
373
+ sortKey: sortKey,
374
+ sortDirection: sortDirection,
375
+ handleSortClick: handleSortClick,
376
+ handleHeaderCheckboxClick: handleHeaderCheckboxClick
377
+ }, /*#__PURE__*/React.createElement(VirtualizedStartRow, null), isLoading || !entries.length ? /*#__PURE__*/React.createElement(_DefaultRow.EmptyRow, {
378
+ isLoading: isLoading,
379
+ emptyText: emptyText,
380
+ headersLength: handleHeaderCheckboxClick ? headers.length + 1 : headers.length,
381
+ customLoader: customLoader
382
+ }) : currRows.map(virtualRow => {
383
+ const key = virtualRow.key;
384
+ const data = entries[virtualRow.index];
385
+ if (data == null) {
386
+ return null;
387
+ }
388
+ const selected = selectedKeys && Array.isArray(selectedKeys) ? selectedKeys.includes((0, _get.default)(data, idName)) : undefined;
389
+ const isRowDisabled = disabledKeys && Array.isArray(disabledKeys) ? disabledKeys.includes((0, _get.default)(data, idName)) : false;
390
+ return /*#__PURE__*/React.createElement(RowRenderer, {
391
+ TableRow: TableRow,
392
+ keyId: key,
142
393
  data: data,
143
- extras: extras,
144
394
  headers: headers,
395
+ extras: extras,
396
+ sortedKeys: rowKeys ?? mappedKeys,
145
397
  selected: selected,
146
- onSelect: selectedKeys != null ? _v => onSelect?.((0, _xor.default)(selectedKeys ?? [], [key])) : undefined,
147
398
  disabled: disabled || isRowDisabled,
148
- classNames: {
149
- tableRow: classNames?.tableRow,
150
- checkbox: classNames?.checkbox
151
- }
399
+ classNames: classNames,
400
+ onSelect: selectedKeys != null ? _v => onSelect?.((0, _xor.default)(selectedKeys ?? [], [key])) : undefined
152
401
  });
153
- }))));
402
+ }), /*#__PURE__*/React.createElement(VirtualizedEndRow, null), isEndLoading && /*#__PURE__*/React.createElement("tr", null, /*#__PURE__*/React.createElement("td", {
403
+ colSpan: headers.length + (handleHeaderCheckboxClick ? 1 : 0)
404
+ }, /*#__PURE__*/React.createElement("div", {
405
+ className: _TableModule.default.fetchMoreLoaderContainer
406
+ }, /*#__PURE__*/React.createElement(_CircularLoader.CircularLoader, null)))));
154
407
  }