@canonical/react-components 0.35.0 → 0.36.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.
@@ -19,6 +19,8 @@ var _TableHeader = _interopRequireDefault(require("../TableHeader"));
19
19
 
20
20
  var _TableCell = _interopRequireDefault(require("../TableCell"));
21
21
 
22
+ var _hooks = require("../../hooks");
23
+
22
24
  var _excluded = ["content", "sortKey"],
23
25
  _excluded2 = ["columns", "expanded", "expandedContent", "key", "sortData"],
24
26
  _excluded3 = ["content"],
@@ -102,10 +104,59 @@ var generateHeaders = function generateHeaders(currentSortKey, currentSortDirect
102
104
  })));
103
105
  };
104
106
 
105
- var generateRows = function generateRows(currentSortDirection, currentSortKey, emptyStateMsg, expanding, responsive, headers, paginate, rows, currentPage, setCurrentPage, sortable, sortFunction) {
106
- // If the table has no rows, return empty state message
107
- if (Object.entries(rows).length === 0 && emptyStateMsg) {
108
- return /*#__PURE__*/_react.default.createElement("caption", null, emptyStateMsg);
107
+ var generateRows = function generateRows(_ref2) {
108
+ var rows = _ref2.rows,
109
+ headers = _ref2.headers,
110
+ responsive = _ref2.responsive,
111
+ expanding = _ref2.expanding;
112
+ return rows.map(function (_ref3, index) {
113
+ var columns = _ref3.columns,
114
+ expanded = _ref3.expanded,
115
+ expandedContent = _ref3.expandedContent,
116
+ key = _ref3.key,
117
+ sortData = _ref3.sortData,
118
+ rowProps = _objectWithoutProperties(_ref3, _excluded2);
119
+
120
+ var cellItems = columns === null || columns === void 0 ? void 0 : columns.map(function (_ref4, index) {
121
+ var content = _ref4.content,
122
+ cellProps = _objectWithoutProperties(_ref4, _excluded3);
123
+
124
+ var headerContent = headers && headers[index]["content"];
125
+ var headerReplacement = headers && headers[index]["heading"];
126
+
127
+ if (responsive) {
128
+ cellProps["data-heading"] = typeof headerContent === "string" ? headerContent : headerReplacement;
129
+ }
130
+
131
+ return /*#__PURE__*/_react.default.createElement(_TableCell.default, _extends({
132
+ key: index
133
+ }, cellProps), content);
134
+ }); // if key was not provided as a prop, use row's index instead
135
+
136
+ if (key === null || typeof key === "undefined") {
137
+ key = index;
138
+ } // The expanding cell is alway created to match the correct number of
139
+ // table cells in rows that do have expanding content.
140
+
141
+
142
+ return /*#__PURE__*/_react.default.createElement(_TableRow.default, _extends({
143
+ key: key
144
+ }, rowProps), cellItems, expanding && /*#__PURE__*/_react.default.createElement(_TableCell.default, {
145
+ expanding: true,
146
+ hidden: !expanded
147
+ }, expandedContent));
148
+ });
149
+ };
150
+
151
+ var sortRows = function sortRows(_ref5) {
152
+ var currentSortDirection = _ref5.currentSortDirection,
153
+ currentSortKey = _ref5.currentSortKey,
154
+ rows = _ref5.rows,
155
+ sortable = _ref5.sortable,
156
+ sortFunction = _ref5.sortFunction;
157
+
158
+ if (!rows) {
159
+ return [];
109
160
  } // Clone the rows so we can restore the original order.
110
161
 
111
162
 
@@ -133,74 +184,23 @@ var generateRows = function generateRows(currentSortDirection, currentSortKey, e
133
184
  });
134
185
  }
135
186
 
136
- var slicedRows = sortedRows;
137
-
138
- if (paginate) {
139
- var startIndex = (currentPage - 1) * paginate;
140
-
141
- if (startIndex > rows.length) {
142
- // If the rows have changed e.g. when filtering and the user is on a page
143
- // that no longer exists then send them to the start.
144
- setCurrentPage(1);
145
- }
146
-
147
- slicedRows = sortedRows.slice(startIndex, startIndex + paginate);
148
- }
149
-
150
- var rowItems = slicedRows.map(function (_ref2, index) {
151
- var columns = _ref2.columns,
152
- expanded = _ref2.expanded,
153
- expandedContent = _ref2.expandedContent,
154
- key = _ref2.key,
155
- sortData = _ref2.sortData,
156
- rowProps = _objectWithoutProperties(_ref2, _excluded2);
157
-
158
- var cellItems = columns.map(function (_ref3, index) {
159
- var content = _ref3.content,
160
- cellProps = _objectWithoutProperties(_ref3, _excluded3);
161
-
162
- var headerContent = headers && headers[index]["content"];
163
- var headerReplacement = headers && headers[index]["heading"];
164
-
165
- if (responsive) {
166
- cellProps["data-heading"] = typeof headerContent === "string" ? headerContent : headerReplacement;
167
- }
168
-
169
- return /*#__PURE__*/_react.default.createElement(_TableCell.default, _extends({
170
- key: index
171
- }, cellProps), content);
172
- }); // if key was not provided as a prop, use row's index instead
173
-
174
- if (key === null || typeof key === "undefined") {
175
- key = index;
176
- } // The expanding cell is alway created to match the correct number of
177
- // table cells in rows that do have expanding content.
178
-
179
-
180
- return /*#__PURE__*/_react.default.createElement(_TableRow.default, _extends({
181
- key: key
182
- }, rowProps), cellItems, expanding && /*#__PURE__*/_react.default.createElement(_TableCell.default, {
183
- expanding: true,
184
- hidden: !expanded
185
- }, expandedContent));
186
- });
187
- return /*#__PURE__*/_react.default.createElement("tbody", null, rowItems);
187
+ return sortedRows;
188
188
  };
189
189
 
190
- var MainTable = function MainTable(_ref4) {
191
- var defaultSort = _ref4.defaultSort,
192
- defaultSortDirection = _ref4.defaultSortDirection,
193
- _ref4$emptyStateMsg = _ref4.emptyStateMsg,
194
- emptyStateMsg = _ref4$emptyStateMsg === void 0 ? "" : _ref4$emptyStateMsg,
195
- expanding = _ref4.expanding,
196
- headers = _ref4.headers,
197
- onUpdateSort = _ref4.onUpdateSort,
198
- paginate = _ref4.paginate,
199
- rows = _ref4.rows,
200
- responsive = _ref4.responsive,
201
- sortable = _ref4.sortable,
202
- sortFunction = _ref4.sortFunction,
203
- props = _objectWithoutProperties(_ref4, _excluded4);
190
+ var MainTable = function MainTable(_ref6) {
191
+ var defaultSort = _ref6.defaultSort,
192
+ defaultSortDirection = _ref6.defaultSortDirection,
193
+ _ref6$emptyStateMsg = _ref6.emptyStateMsg,
194
+ emptyStateMsg = _ref6$emptyStateMsg === void 0 ? "" : _ref6$emptyStateMsg,
195
+ expanding = _ref6.expanding,
196
+ headers = _ref6.headers,
197
+ onUpdateSort = _ref6.onUpdateSort,
198
+ paginate = _ref6.paginate,
199
+ rows = _ref6.rows,
200
+ responsive = _ref6.responsive,
201
+ sortable = _ref6.sortable,
202
+ sortFunction = _ref6.sortFunction,
203
+ props = _objectWithoutProperties(_ref6, _excluded4);
204
204
 
205
205
  var _useState = (0, _react.useState)(defaultSort),
206
206
  _useState2 = _slicedToArray(_useState, 2),
@@ -210,12 +210,7 @@ var MainTable = function MainTable(_ref4) {
210
210
  var _useState3 = (0, _react.useState)(defaultSortDirection),
211
211
  _useState4 = _slicedToArray(_useState3, 2),
212
212
  currentSortDirection = _useState4[0],
213
- setSortDirection = _useState4[1];
214
-
215
- var _useState5 = (0, _react.useState)(1),
216
- _useState6 = _slicedToArray(_useState5, 2),
217
- currentPage = _useState6[0],
218
- setCurrentPage = _useState6[1]; // Update the current sort state if the prop changes.
213
+ setSortDirection = _useState4[1]; // Update the current sort state if the prop changes.
219
214
 
220
215
 
221
216
  (0, _react.useEffect)(function () {
@@ -231,10 +226,34 @@ var MainTable = function MainTable(_ref4) {
231
226
  onUpdateSort && onUpdateSort(newSort);
232
227
  };
233
228
 
229
+ var sortedRows = (0, _react.useMemo)(function () {
230
+ return sortRows({
231
+ currentSortDirection: currentSortDirection,
232
+ currentSortKey: currentSortKey,
233
+ rows: rows,
234
+ sortable: sortable,
235
+ sortFunction: sortFunction
236
+ });
237
+ }, [currentSortDirection, currentSortKey, rows, sortable, sortFunction]);
238
+
239
+ var _usePagination = (0, _hooks.usePagination)(sortedRows, {
240
+ itemsPerPage: paginate,
241
+ autoResetPage: true
242
+ }),
243
+ finalRows = _usePagination.pageData,
244
+ currentPage = _usePagination.currentPage,
245
+ setCurrentPage = _usePagination.paginate;
246
+
234
247
  return /*#__PURE__*/_react.default.createElement(_react.default.Fragment, null, /*#__PURE__*/_react.default.createElement(_Table.default, _extends({
235
248
  expanding: expanding,
236
249
  responsive: responsive
237
- }, props), !!headers && generateHeaders(currentSortKey, currentSortDirection, expanding, headers, sortable, updateSort, setSortDirection), !!rows && generateRows(currentSortDirection, currentSortKey, emptyStateMsg, expanding, responsive, headers, paginate, rows, currentPage, setCurrentPage, sortable, sortFunction)), paginate && rows && rows.length > 0 && /*#__PURE__*/_react.default.createElement(_Pagination.default, {
250
+ }, props), !!headers && generateHeaders(currentSortKey, currentSortDirection, expanding, headers, sortable, updateSort, setSortDirection), // If the table has no rows, return empty state message
251
+ Object.entries(finalRows).length === 0 && emptyStateMsg ? /*#__PURE__*/_react.default.createElement("caption", null, emptyStateMsg) : /*#__PURE__*/_react.default.createElement("tbody", null, generateRows({
252
+ rows: finalRows,
253
+ headers: headers,
254
+ responsive: responsive,
255
+ expanding: expanding
256
+ }))), paginate && rows && rows.length > 0 && /*#__PURE__*/_react.default.createElement(_Pagination.default, {
238
257
  currentPage: currentPage,
239
258
  itemsPerPage: paginate,
240
259
  paginate: setCurrentPage,
@@ -3,4 +3,5 @@ export { useListener } from "./useListener";
3
3
  export { usePrevious } from "./usePrevious";
4
4
  export { useThrottle } from "./useThrottle";
5
5
  export { useId } from "./useId";
6
+ export { usePagination } from "./usePagination";
6
7
  export type { WindowFitment } from "./useWindowFitment";
@@ -15,6 +15,12 @@ Object.defineProperty(exports, "useListener", {
15
15
  return _useListener.useListener;
16
16
  }
17
17
  });
18
+ Object.defineProperty(exports, "usePagination", {
19
+ enumerable: true,
20
+ get: function get() {
21
+ return _usePagination.usePagination;
22
+ }
23
+ });
18
24
  Object.defineProperty(exports, "usePrevious", {
19
25
  enumerable: true,
20
26
  get: function get() {
@@ -42,4 +48,6 @@ var _usePrevious = require("./usePrevious");
42
48
 
43
49
  var _useThrottle = require("./useThrottle");
44
50
 
45
- var _useId = require("./useId");
51
+ var _useId = require("./useId");
52
+
53
+ var _usePagination = require("./usePagination");
@@ -0,0 +1,19 @@
1
+ /**
2
+ * A hook that handles pagination.
3
+ * @param data - The data array to paginate.
4
+ * @param {Object} options
5
+ * @param {number} [options.itemsPerPage] - Number of items per page. Returns all items if no value has been provided.
6
+ * @param {number} [options.initialPage=1] - Initial page number. Defaults to 1.
7
+ * @param {boolean} [options.autoResetPage=false] - Whether to reset the page number to 1 when the data changes.
8
+ */
9
+ export declare function usePagination<D, I = number | null>(data: Array<D>, options?: {
10
+ itemsPerPage: I;
11
+ initialPage?: number;
12
+ autoResetPage?: boolean;
13
+ }): {
14
+ pageData: Array<D>;
15
+ currentPage: number;
16
+ paginate: (pageNumber: number) => void;
17
+ itemsPerPage: I;
18
+ totalItems: number;
19
+ };
@@ -0,0 +1,74 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.usePagination = usePagination;
7
+
8
+ var _react = require("react");
9
+
10
+ function _slicedToArray(arr, i) { return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _unsupportedIterableToArray(arr, i) || _nonIterableRest(); }
11
+
12
+ function _nonIterableRest() { throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); }
13
+
14
+ 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); }
15
+
16
+ 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; }
17
+
18
+ function _iterableToArrayLimit(arr, i) { var _i = arr == null ? null : typeof Symbol !== "undefined" && arr[Symbol.iterator] || arr["@@iterator"]; if (_i == null) return; var _arr = []; var _n = true; var _d = false; var _s, _e; try { for (_i = _i.call(arr); !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i["return"] != null) _i["return"](); } finally { if (_d) throw _e; } } return _arr; }
19
+
20
+ function _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; }
21
+
22
+ /**
23
+ * A hook that handles pagination.
24
+ * @param data - The data array to paginate.
25
+ * @param {Object} options
26
+ * @param {number} [options.itemsPerPage] - Number of items per page. Returns all items if no value has been provided.
27
+ * @param {number} [options.initialPage=1] - Initial page number. Defaults to 1.
28
+ * @param {boolean} [options.autoResetPage=false] - Whether to reset the page number to 1 when the data changes.
29
+ */
30
+ function usePagination(data, options) {
31
+ var _data$length;
32
+
33
+ var defaultOptions = {
34
+ initialPage: 1,
35
+ autoResetPage: false
36
+ };
37
+
38
+ var _Object$assign = Object.assign(defaultOptions, options),
39
+ itemsPerPage = _Object$assign.itemsPerPage,
40
+ initialPage = _Object$assign.initialPage,
41
+ autoResetPage = _Object$assign.autoResetPage;
42
+
43
+ var totalItems = (_data$length = data === null || data === void 0 ? void 0 : data.length) !== null && _data$length !== void 0 ? _data$length : 0;
44
+ var initialPageIndex = initialPage > 0 ? initialPage - 1 : 0;
45
+
46
+ var _useState = (0, _react.useState)(initialPageIndex),
47
+ _useState2 = _slicedToArray(_useState, 2),
48
+ pageIndex = _useState2[0],
49
+ setPageIndex = _useState2[1];
50
+
51
+ var startIndex = typeof itemsPerPage === "number" ? pageIndex * itemsPerPage : 0;
52
+
53
+ var paginate = function paginate(pageNumber) {
54
+ return setPageIndex(pageNumber - 1);
55
+ };
56
+
57
+ (0, _react.useEffect)(function () {
58
+ if (typeof itemsPerPage === "number" && startIndex >= totalItems) {
59
+ !autoResetPage && Math.floor(totalItems / itemsPerPage) > 0 ? // go to the last available page if the current page is out of bounds
60
+ setPageIndex(Math.floor(totalItems / itemsPerPage) - 1) : // go to the initial page if autoResetPage is true
61
+ setPageIndex(0);
62
+ }
63
+ }, [pageIndex, startIndex, setPageIndex, totalItems, itemsPerPage, autoResetPage]);
64
+ var pageData = (0, _react.useMemo)(function () {
65
+ return typeof itemsPerPage === "number" ? data === null || data === void 0 ? void 0 : data.slice(startIndex, startIndex + itemsPerPage) : data;
66
+ }, [startIndex, data, itemsPerPage]);
67
+ return {
68
+ pageData: pageData,
69
+ currentPage: pageIndex + 1,
70
+ paginate: paginate,
71
+ itemsPerPage: itemsPerPage,
72
+ totalItems: totalItems
73
+ };
74
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@canonical/react-components",
3
- "version": "0.35.0",
3
+ "version": "0.36.0",
4
4
  "main": "dist/index.js",
5
5
  "module": "dist/index.js",
6
6
  "author": "Huw Wilkins <huw.wilkins@canonical.com>",
@@ -81,7 +81,7 @@
81
81
  "ts-jest": "27.1.4",
82
82
  "tsc-alias": "1.6.5",
83
83
  "typescript": "4.6.3",
84
- "vanilla-framework": "3.2.0",
84
+ "vanilla-framework": "3.3.0",
85
85
  "wait-on": "5.3.0"
86
86
  },
87
87
  "dependencies": {
@@ -102,7 +102,7 @@
102
102
  "peerDependencies": {
103
103
  "react": "17.0.2",
104
104
  "react-dom": "17.0.2",
105
- "vanilla-framework": "3.2.0"
105
+ "vanilla-framework": "3.3.0"
106
106
  },
107
107
  "scripts": {
108
108
  "build": "rm -rf dist && yarn build-local; yarn build-declaration",