@canonical/react-components 2.14.0 → 2.15.1

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 (61) hide show
  1. package/dist/components/ScrollableContainer/ScrollableContainer.d.ts +27 -0
  2. package/dist/components/ScrollableContainer/ScrollableContainer.js +51 -0
  3. package/dist/components/ScrollableContainer/ScrollableContainer.scss +7 -0
  4. package/dist/components/ScrollableContainer/ScrollableContainer.stories.d.ts +6 -0
  5. package/dist/components/ScrollableContainer/ScrollableContainer.stories.js +36 -0
  6. package/dist/components/ScrollableContainer/ScrollableContainer.test.d.ts +1 -0
  7. package/dist/components/ScrollableContainer/index.d.ts +2 -0
  8. package/dist/components/ScrollableContainer/index.js +13 -0
  9. package/dist/components/ScrollableTable/ScrollableTable.d.ts +27 -0
  10. package/dist/components/ScrollableTable/ScrollableTable.js +44 -0
  11. package/dist/components/ScrollableTable/ScrollableTable.scss +58 -0
  12. package/dist/components/ScrollableTable/ScrollableTable.stories.d.ts +7 -0
  13. package/dist/components/ScrollableTable/ScrollableTable.stories.js +81 -0
  14. package/dist/components/ScrollableTable/ScrollableTable.test.d.ts +1 -0
  15. package/dist/components/ScrollableTable/index.d.ts +2 -0
  16. package/dist/components/ScrollableTable/index.js +13 -0
  17. package/dist/components/SidePanel/SidePanel.js +1 -1
  18. package/dist/components/TablePagination/TablePagination.scss +6 -6
  19. package/dist/components/TablePagination/TablePagination.stories.d.ts +8 -0
  20. package/dist/components/TablePagination/TablePagination.stories.js +53 -1
  21. package/dist/components/TablePagination/TablePaginationControls/TablePaginationControls.js +7 -4
  22. package/dist/components/TablePagination/utils.d.ts +2 -1
  23. package/dist/components/TablePagination/utils.js +10 -3
  24. package/dist/esm/components/ScrollableContainer/ScrollableContainer.d.ts +27 -0
  25. package/dist/esm/components/ScrollableContainer/ScrollableContainer.js +43 -0
  26. package/dist/esm/components/ScrollableContainer/ScrollableContainer.scss +7 -0
  27. package/dist/esm/components/ScrollableContainer/ScrollableContainer.stories.d.ts +6 -0
  28. package/dist/esm/components/ScrollableContainer/ScrollableContainer.stories.js +29 -0
  29. package/dist/esm/components/ScrollableContainer/ScrollableContainer.test.d.ts +1 -0
  30. package/dist/esm/components/ScrollableContainer/index.d.ts +2 -0
  31. package/dist/esm/components/ScrollableContainer/index.js +1 -0
  32. package/dist/esm/components/ScrollableTable/ScrollableTable.d.ts +27 -0
  33. package/dist/esm/components/ScrollableTable/ScrollableTable.js +37 -0
  34. package/dist/esm/components/ScrollableTable/ScrollableTable.scss +58 -0
  35. package/dist/esm/components/ScrollableTable/ScrollableTable.stories.d.ts +7 -0
  36. package/dist/esm/components/ScrollableTable/ScrollableTable.stories.js +78 -0
  37. package/dist/esm/components/ScrollableTable/ScrollableTable.test.d.ts +1 -0
  38. package/dist/esm/components/ScrollableTable/index.d.ts +2 -0
  39. package/dist/esm/components/ScrollableTable/index.js +1 -0
  40. package/dist/esm/components/SidePanel/SidePanel.js +1 -1
  41. package/dist/esm/components/TablePagination/TablePagination.scss +6 -6
  42. package/dist/esm/components/TablePagination/TablePagination.stories.d.ts +8 -0
  43. package/dist/esm/components/TablePagination/TablePagination.stories.js +52 -0
  44. package/dist/esm/components/TablePagination/TablePaginationControls/TablePaginationControls.js +7 -4
  45. package/dist/esm/components/TablePagination/utils.d.ts +2 -1
  46. package/dist/esm/components/TablePagination/utils.js +10 -3
  47. package/dist/esm/hooks/useId.d.ts +1 -1
  48. package/dist/esm/hooks/useId.js +1 -1
  49. package/dist/esm/hooks/useListener.js +8 -7
  50. package/dist/esm/index.d.ts +5 -1
  51. package/dist/esm/index.js +3 -1
  52. package/dist/esm/utils.d.ts +4 -0
  53. package/dist/esm/utils.js +32 -1
  54. package/dist/hooks/useId.d.ts +1 -1
  55. package/dist/hooks/useId.js +1 -1
  56. package/dist/hooks/useListener.js +8 -7
  57. package/dist/index.d.ts +5 -1
  58. package/dist/index.js +37 -0
  59. package/dist/utils.d.ts +4 -0
  60. package/dist/utils.js +37 -2
  61. package/package.json +2 -2
@@ -0,0 +1,43 @@
1
+ import React from "react";
2
+ import { useEffect, useRef } from "react";
3
+ import classnames from "classnames";
4
+ import "./ScrollableContainer.scss";
5
+ import { getAbsoluteHeightBelowById, getParentsBottomSpacing } from "../../utils";
6
+ import { useListener } from "../../hooks";
7
+ /**
8
+ * This is a [React](https://reactjs.org/) component for use within the [Vanilla framework](https://docs.vanillaframework.io/).
9
+ *
10
+ * It is used to make any child element scrollable by adjusting the height based on the viewport height and the heights of elements above and below it. As a result the surrounding elements are sticky and only the wrapped element contents scroll
11
+ */
12
+ var ScrollableContainer = _ref => {
13
+ var {
14
+ dependencies,
15
+ children,
16
+ belowIds = ["status-bar"],
17
+ className
18
+ } = _ref;
19
+ var ref = useRef(null);
20
+ var updateChildContainerHeight = () => {
21
+ var _ref$current;
22
+ var childContainer = (_ref$current = ref.current) === null || _ref$current === void 0 ? void 0 : _ref$current.children[0];
23
+ if (!childContainer) {
24
+ return;
25
+ }
26
+ var above = childContainer.getBoundingClientRect().top + 1;
27
+ var below = belowIds.reduce((acc, belowId) => acc + getAbsoluteHeightBelowById(belowId), 0);
28
+ var parentsBottomSpacing = getParentsBottomSpacing(childContainer);
29
+ var offset = Math.ceil(above + below + parentsBottomSpacing);
30
+ var style = "height: calc(100dvh - ".concat(offset, "px); min-height: calc(100dvh - ").concat(offset, "px)");
31
+ childContainer.setAttribute("style", style);
32
+ };
33
+ useListener(window, updateChildContainerHeight, "resize", true);
34
+ useEffect(updateChildContainerHeight, [dependencies, belowIds, ref]);
35
+ return /*#__PURE__*/React.createElement("div", {
36
+ ref: ref,
37
+ className: classnames("scrollable-container", className)
38
+ }, /*#__PURE__*/React.createElement("div", {
39
+ id: "content-details",
40
+ className: "content-details"
41
+ }, children));
42
+ };
43
+ export default ScrollableContainer;
@@ -0,0 +1,7 @@
1
+ .scrollable-container {
2
+ .content-details {
3
+ display: block;
4
+ overflow: auto;
5
+ scrollbar-gutter: stable;
6
+ }
7
+ }
@@ -0,0 +1,6 @@
1
+ import { Meta, StoryObj } from "@storybook/react";
2
+ import ScrollableContainer from "./ScrollableContainer";
3
+ declare const meta: Meta<typeof ScrollableContainer>;
4
+ export default meta;
5
+ type Story = StoryObj<typeof ScrollableContainer>;
6
+ export declare const Default: Story;
@@ -0,0 +1,29 @@
1
+ import ScrollableContainer from "./ScrollableContainer";
2
+ import React from "react";
3
+ import { Description, Subtitle, Title } from "@storybook/blocks";
4
+ var meta = {
5
+ component: ScrollableContainer,
6
+ tags: ["autodocs"]
7
+ };
8
+ export default meta;
9
+ var StoryExample = args => {
10
+ return /*#__PURE__*/React.createElement("div", null, /*#__PURE__*/React.createElement("h1", null, "Above contents"), /*#__PURE__*/React.createElement(ScrollableContainer, {
11
+ belowIds: args.belowIds,
12
+ dependencies: []
13
+ }, /*#__PURE__*/React.createElement("p", null, "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Cras varius mi eu pretium vulputate. Nunc commodo sit amet nibh quis rhoncus. Aliquam rhoncus porttitor semper. Aenean faucibus consectetur neque in sodales. Sed cursus mauris id ex sollicitudin sodales. Quisque molestie rutrum odio, ornare pharetra ligula. Pellentesque ornare tristique feugiat. In a augue neque. Aenean eget arcu quis lacus tempus posuere in sit amet dui. Suspendisse faucibus sapien nisl, nec laoreet sem convallis nec."), /*#__PURE__*/React.createElement("p", null, "Vestibulum sed placerat lorem. Nam luctus ex id nisi luctus, id vestibulum sem bibendum. Vivamus turpis sem, pellentesque fermentum malesuada eu, faucibus porta libero. Duis eget venenatis odio. Etiam sed volutpat magna, non tempus erat. Nunc id tortor ac quam consectetur dapibus ac ut tellus. Pellentesque ut tellus venenatis elit vehicula condimentum eget quis lorem. Ut non consectetur est, a fringilla ipsum. Nunc vitae ligula ipsum. Etiam suscipit, libero ut lacinia viverra, nunc urna consequat ex, vel eleifend eros mauris vitae ipsum. Pellentesque sed dictum augue. Ut sit amet ullamcorper mauris. Nunc congue orci mollis purus sodales facilisis ac ut arcu. Maecenas feugiat sapien ac massa mollis sodales. Donec vitae turpis eu nisi laoreet pulvinar quis at nisl. Integer volutpat, metus eget elementum dictum, lacus sapien viverra felis, consequat fermentum nisl mi ac dui."), /*#__PURE__*/React.createElement("p", null, "Nullam nulla turpis, dignissim vel dapibus ut, volutpat ac dui. Donec vel elementum lacus. Mauris maximus nec felis at faucibus. Nunc faucibus gravida velit, id blandit lectus tincidunt ac. Vestibulum orci diam, elementum in congue eu, placerat id risus. Sed tempor tempus tellus, vitae iaculis turpis fringilla nec. Phasellus imperdiet facilisis velit, sit amet lobortis odio dignissim ut."), /*#__PURE__*/React.createElement("p", null, "Nam placerat urna vitae ligula hendrerit, ac tincidunt lorem maximus. Mauris eu odio nisi. Nulla facilisi. Sed egestas elit sed velit rutrum, sit amet bibendum metus hendrerit. Pellentesque luctus placerat tellus, eu bibendum justo. Cras eget leo ac ex volutpat gravida. Duis vitae mollis ante. Duis a congue nunc. Aenean aliquet, sapien quis tincidunt tincidunt, odio eros consectetur lacus, vel finibus mauris tortor id velit. Donec tincidunt vitae purus eu interdum. Pellentesque scelerisque dui viverra ex ullamcorper volutpat. Vestibulum lacinia vitae arcu volutpat porta. Etiam et cursus nulla, id aliquet felis. Nam ultricies, urna id mattis pretium, velit erat viverra elit, eu maximus diam eros id nisi."), /*#__PURE__*/React.createElement("p", null, "Nullam eget nisl lectus. Pellentesque eu mauris ut tortor malesuada sagittis. Cras dictum cursus est non ultricies. Duis mollis non neque at commodo. Nunc feugiat justo et consequat aliquam. Ut consectetur libero eu erat feugiat finibus. Duis varius convallis quam eu sagittis. Maecenas ac est arcu. Suspendisse at enim eget nibh ultricies dictum. Etiam aliquet tellus vel felis malesuada laoreet.")), /*#__PURE__*/React.createElement("div", {
14
+ id: "footer"
15
+ }, /*#__PURE__*/React.createElement("h2", {
16
+ className: "u-no-margin"
17
+ }, "Below contents"), /*#__PURE__*/React.createElement("div", null, "here be dragons.")));
18
+ };
19
+ export var Default = {
20
+ args: {
21
+ belowIds: ["footer"]
22
+ },
23
+ render: StoryExample,
24
+ parameters: {
25
+ docs: {
26
+ page: () => /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(Title, null), /*#__PURE__*/React.createElement(Subtitle, null), /*#__PURE__*/React.createElement(Description, null))
27
+ }
28
+ }
29
+ };
@@ -0,0 +1,2 @@
1
+ export { default } from "./ScrollableContainer";
2
+ export type { Props as ScrollableContainerProps } from "./ScrollableContainer";
@@ -0,0 +1 @@
1
+ export { default } from "./ScrollableContainer";
@@ -0,0 +1,27 @@
1
+ import type { DependencyList, FC, ReactNode } from "react";
2
+ import "./ScrollableTable.scss";
3
+ export type Props = {
4
+ /**
5
+ * A MainTable that will be made scrollable.
6
+ */
7
+ children: ReactNode;
8
+ /**
9
+ * An array of dependencies that will trigger a re-calculation of the table body height when they change.
10
+ */
11
+ dependencies: DependencyList;
12
+ /**
13
+ * The ID of the table element that contains the `<tbody>` to be made scrollable.
14
+ */
15
+ tableId: string;
16
+ /**
17
+ * An array of element IDs below the table that should be considered when calculating the height.
18
+ */
19
+ belowIds?: string[];
20
+ };
21
+ /**
22
+ * This is a [React](https://reactjs.org/) component for use within the [Vanilla framework](https://docs.vanillaframework.io/).
23
+ *
24
+ * It is used to make a table scrollable by adjusting the height of the `<tbody>` element based on the viewport height and the heights of elements above and below it. As a result the header is sticky and only the body scrolls
25
+ */
26
+ declare const ScrollableTable: FC<Props>;
27
+ export default ScrollableTable;
@@ -0,0 +1,37 @@
1
+ import React from "react";
2
+ import { useEffect } from "react";
3
+ import { getAbsoluteHeightBelowById, getParentsBottomSpacing } from "../../utils";
4
+ import "./ScrollableTable.scss";
5
+ import { useListener } from "../../hooks";
6
+ /**
7
+ * This is a [React](https://reactjs.org/) component for use within the [Vanilla framework](https://docs.vanillaframework.io/).
8
+ *
9
+ * It is used to make a table scrollable by adjusting the height of the `<tbody>` element based on the viewport height and the heights of elements above and below it. As a result the header is sticky and only the body scrolls
10
+ */
11
+ var ScrollableTable = _ref => {
12
+ var {
13
+ dependencies,
14
+ children,
15
+ tableId,
16
+ belowIds = []
17
+ } = _ref;
18
+ var updateTBodyHeight = () => {
19
+ var table = document.getElementById(tableId);
20
+ if (!table || table.children.length !== 2) {
21
+ return;
22
+ }
23
+ var tBody = table.children[1];
24
+ var above = tBody.getBoundingClientRect().top + 1;
25
+ var below = belowIds.reduce((acc, belowId) => acc + getAbsoluteHeightBelowById(belowId), 0);
26
+ var parentsBottomSpacing = getParentsBottomSpacing(table);
27
+ var offset = Math.ceil(above + below + parentsBottomSpacing);
28
+ var style = "height: calc(100dvh - ".concat(offset, "px); min-height: calc(100dvh - ").concat(offset, "px)");
29
+ tBody.setAttribute("style", style);
30
+ };
31
+ useListener(window, updateTBodyHeight, "resize", true);
32
+ useEffect(updateTBodyHeight, [...dependencies, belowIds, tableId]);
33
+ return /*#__PURE__*/React.createElement("div", {
34
+ className: "scrollable-table"
35
+ }, children);
36
+ };
37
+ export default ScrollableTable;
@@ -0,0 +1,58 @@
1
+ @import "vanilla-framework/scss/settings";
2
+
3
+ /* stylelint-disable selector-max-type */
4
+ .scrollable-table {
5
+ table {
6
+ margin-bottom: 0;
7
+ }
8
+
9
+ th,
10
+ td {
11
+ display: table-cell;
12
+ vertical-align: top;
13
+ }
14
+
15
+ th::before {
16
+ content: "";
17
+ height: 1rem;
18
+ }
19
+
20
+ thead,
21
+ tbody {
22
+ display: block;
23
+ overflow: hidden auto;
24
+ scrollbar-gutter: stable;
25
+ }
26
+
27
+ tbody {
28
+ height: calc(100dvh - 323px);
29
+ }
30
+
31
+ thead tr,
32
+ tbody tr {
33
+ display: table;
34
+ table-layout: fixed;
35
+ width: 100%;
36
+ }
37
+
38
+ @media screen and (width < $breakpoint-large) {
39
+ .p-table--mobile-card {
40
+ thead {
41
+ display: none;
42
+ }
43
+
44
+ td {
45
+ display: block;
46
+ }
47
+
48
+ tbody tr {
49
+ display: block;
50
+ }
51
+
52
+ tbody tr:first-child {
53
+ margin-top: $spv--x-large;
54
+ }
55
+ }
56
+ }
57
+ }
58
+ /* stylelint-enable selector-max-type */
@@ -0,0 +1,7 @@
1
+ import { Meta, StoryObj } from "@storybook/react";
2
+ import ScrollableTable from "./ScrollableTable";
3
+ declare const meta: Meta<typeof ScrollableTable>;
4
+ export default meta;
5
+ type Story = StoryObj<typeof ScrollableTable>;
6
+ export declare const Default: Story;
7
+ export declare const Responsive: Story;
@@ -0,0 +1,78 @@
1
+ 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; }
2
+ 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; }
3
+ 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; }
4
+ function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == typeof i ? i : String(i); }
5
+ function _toPrimitive(t, r) { if ("object" != typeof t || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != typeof i) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); }
6
+ import React from "react";
7
+ import ScrollableTable from "./ScrollableTable";
8
+ import { MainTable } from "../../index";
9
+ import { Description, Subtitle, Title } from "@storybook/blocks";
10
+ var meta = {
11
+ component: ScrollableTable,
12
+ tags: ["autodocs"]
13
+ };
14
+ export default meta;
15
+ var StoryExample = args => {
16
+ var headers = [{
17
+ content: "Fact"
18
+ }, {
19
+ content: "Relevancy score"
20
+ }, {
21
+ content: "Size"
22
+ }, {
23
+ content: "ID"
24
+ }];
25
+ var facts = ["Dragons are mythical creatures", "They can fly", "They breathe fire", "They hoard treasure", "They are often depicted as large reptiles", "They appear in various cultures' folklore", "They can be friendly or hostile", "They are often associated with wisdom", "They can shapeshift in some legends", "They are sometimes guardians of sacred places", "They can be found in literature and movies", "They are often depicted with wings", "They can be of various colors", "They are sometimes associated with knights"];
26
+ var rows = facts.map(item => {
27
+ return {
28
+ columns: [{
29
+ content: item,
30
+ role: "rowheader"
31
+ }, {
32
+ content: 1
33
+ }, {
34
+ content: "1 GiB"
35
+ }, {
36
+ content: 2
37
+ }]
38
+ };
39
+ });
40
+ return /*#__PURE__*/React.createElement("div", null, /*#__PURE__*/React.createElement("h1", null, "Above contents"), /*#__PURE__*/React.createElement(ScrollableTable, {
41
+ belowIds: args.belowIds,
42
+ dependencies: [headers, rows],
43
+ tableId: "facts-about-dragons"
44
+ }, /*#__PURE__*/React.createElement(MainTable, {
45
+ headers: headers,
46
+ rows: rows,
47
+ responsive: args["responsive"],
48
+ id: "facts-about-dragons"
49
+ })), /*#__PURE__*/React.createElement("div", {
50
+ id: "footer"
51
+ }, /*#__PURE__*/React.createElement("h2", {
52
+ className: "u-no-margin"
53
+ }, "Below contents"), /*#__PURE__*/React.createElement("div", null, "here be dragons.")));
54
+ };
55
+ export var Default = {
56
+ args: {
57
+ belowIds: ["footer"]
58
+ },
59
+ render: StoryExample,
60
+ parameters: {
61
+ docs: {
62
+ page: () => /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(Title, null), /*#__PURE__*/React.createElement(Subtitle, null), /*#__PURE__*/React.createElement(Description, null))
63
+ }
64
+ }
65
+ };
66
+ export var Responsive = {
67
+ args: {
68
+ belowIds: ["footer"]
69
+ },
70
+ render: args => StoryExample(_objectSpread(_objectSpread({}, args), {}, {
71
+ responsive: true
72
+ })),
73
+ parameters: {
74
+ docs: {
75
+ page: () => /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(Title, null), /*#__PURE__*/React.createElement(Subtitle, null), /*#__PURE__*/React.createElement(Description, null))
76
+ }
77
+ }
78
+ };
@@ -0,0 +1,2 @@
1
+ export { default } from "./ScrollableTable";
2
+ export type { Props as ScrollableTableProps } from "./ScrollableTable";
@@ -0,0 +1 @@
1
+ export { default } from "./ScrollableTable";
@@ -26,7 +26,7 @@ The sidepanel component should be used to show additional information relating t
26
26
 
27
27
  * **SidePanel.HeaderControls:** To show controls in the header, such as buttons or icons for actions like closing the panel.
28
28
 
29
- * **SidePanel.Sticky:** Can be wrapped around the header or footer to make them sticky when scrolling.
29
+ * **SidePanel.Sticky:** Can be wrapped around the header or footer to make them sticky when scrolling. The scrollbar will use the full area of the side panel, not just the content area. To limit the scrollbar to the content area, use the `ScrollableContainer` component instead of this one.
30
30
 
31
31
  * **SidePanel.Content:** To show the main content of the side panel.
32
32
 
@@ -26,7 +26,7 @@
26
26
  }
27
27
 
28
28
  .next {
29
- margin: 0 $spv--large;
29
+ margin: 0 $spv--large 0 0;
30
30
 
31
31
  .p-icon--chevron-down {
32
32
  rotate: 270deg;
@@ -34,11 +34,15 @@
34
34
  }
35
35
 
36
36
  .pagination-input {
37
- margin: 0 $spv--small 0 $spv--large;
37
+ margin: 0 $spv--large;
38
38
  min-width: 0;
39
39
  width: 4rem;
40
40
  }
41
41
 
42
+ .pagination-item-count {
43
+ margin: 0 $spv--large 0 0;
44
+ }
45
+
42
46
  .pagination-select {
43
47
  margin-bottom: 0;
44
48
  margin-left: $spv--x-large;
@@ -48,10 +52,6 @@
48
52
 
49
53
  @media screen and (max-width: $breakpoint-small) {
50
54
  .back,
51
- .pagination-input {
52
- margin-left: 0;
53
- }
54
-
55
55
  .next {
56
56
  margin-left: 0;
57
57
  margin-right: 0;
@@ -12,3 +12,11 @@ export declare const RenderBelow: Story;
12
12
  * using the `TablePaginationControls` component.
13
13
  */
14
14
  export declare const ControlsOnly: Story;
15
+ /** The `TablePaginationControls` component can be used when the total
16
+ * number of entries is unknown.
17
+ */
18
+ export declare const ControlsWithUnknownEntries: Story;
19
+ /** The `TablePaginationControls` component can be used when it is known
20
+ * that there are more entries than the amount displayed on the current page.
21
+ */
22
+ export declare const ControlsWithPartiallyKnownEntries: Story;
@@ -320,4 +320,56 @@ export var ControlsOnly = {
320
320
  visibleCount: 10
321
321
  });
322
322
  }
323
+ };
324
+
325
+ /** The `TablePaginationControls` component can be used when the total
326
+ * number of entries is unknown.
327
+ */
328
+ export var ControlsWithUnknownEntries = {
329
+ render: () => {
330
+ return /*#__PURE__*/React.createElement(TablePaginationControls, {
331
+ currentPage: 1,
332
+ itemName: "row",
333
+ nextButtonProps: {
334
+ disabled: false
335
+ },
336
+ onInputPageChange: console.log,
337
+ onNextPage: console.log,
338
+ onPageSizeChange: console.log,
339
+ onPreviousPage: console.log,
340
+ pageLimits: [10, 25, 50],
341
+ pageSize: 20,
342
+ previousButtonProps: {
343
+ disabled: false
344
+ },
345
+ showPageInput: true,
346
+ visibleCount: 10
347
+ });
348
+ }
349
+ };
350
+
351
+ /** The `TablePaginationControls` component can be used when it is known
352
+ * that there are more entries than the amount displayed on the current page.
353
+ */
354
+ export var ControlsWithPartiallyKnownEntries = {
355
+ render: () => {
356
+ return /*#__PURE__*/React.createElement(TablePaginationControls, {
357
+ currentPage: 3,
358
+ itemName: "row",
359
+ nextButtonProps: {
360
+ disabled: false
361
+ },
362
+ onInputPageChange: console.log,
363
+ onNextPage: console.log,
364
+ onPageSizeChange: console.log,
365
+ onPreviousPage: console.log,
366
+ pageLimits: [10, 25, 50],
367
+ pageSize: 20,
368
+ previousButtonProps: {
369
+ disabled: false
370
+ },
371
+ showPageInput: true,
372
+ visibleCount: 10
373
+ });
374
+ }
323
375
  };
@@ -23,7 +23,7 @@ var TablePaginationControls = _ref => {
23
23
  description,
24
24
  displayDescription = true,
25
25
  onInputPageChange,
26
- itemName,
26
+ itemName = "row",
27
27
  nextButtonProps,
28
28
  onNextPage,
29
29
  onPageChange,
@@ -44,7 +44,8 @@ var TablePaginationControls = _ref => {
44
44
  visibleCount,
45
45
  isSmallScreen,
46
46
  totalItems,
47
- itemName
47
+ itemName,
48
+ currentPage
48
49
  });
49
50
  var handleDecrementPage = currentPage => {
50
51
  if (currentPage > 1) {
@@ -66,7 +67,7 @@ var TablePaginationControls = _ref => {
66
67
  var handlePageSizeChange = e => {
67
68
  onPageSizeChange(parseInt(e.target.value));
68
69
  };
69
- var isInputDisabled = !totalPages || totalPages == 1;
70
+ var isInputDisabled = typeof totalItems === "number" && (!totalPages || totalPages == 1);
70
71
  var maxPageValue = typeof totalPages === "number" ? totalPages : 1;
71
72
  return /*#__PURE__*/React.createElement("div", _extends({
72
73
  className: classnames("pagination", className)
@@ -95,7 +96,9 @@ var TablePaginationControls = _ref => {
95
96
  disabled: isInputDisabled,
96
97
  min: 1,
97
98
  max: maxPageValue
98
- }), " ", typeof totalPages === "number" ? /*#__PURE__*/React.createElement(React.Fragment, null, "of\xA0", totalPages) : null) : null, /*#__PURE__*/React.createElement(Button, _extends({
99
+ }), " ", typeof totalPages === "number" ? /*#__PURE__*/React.createElement("div", {
100
+ className: "pagination-item-count"
101
+ }, "of\xA0", totalPages) : null) : null, /*#__PURE__*/React.createElement(Button, _extends({
99
102
  "aria-label": Label.NEXT_PAGE,
100
103
  className: "next",
101
104
  appearance: "base",
@@ -17,11 +17,12 @@ export declare const generatePagingOptions: (pageLimits: number[]) => {
17
17
  value: number;
18
18
  label: string;
19
19
  }[];
20
- export declare const getDescription: ({ description, isSmallScreen, totalItems, itemName, visibleCount, }: {
20
+ export declare const getDescription: ({ description, isSmallScreen, totalItems, itemName, visibleCount, currentPage, }: {
21
21
  description: ReactNode;
22
22
  isSmallScreen: boolean;
23
23
  totalItems: number;
24
24
  itemName: string;
25
25
  visibleCount: number;
26
+ currentPage: number;
26
27
  }) => string | number | bigint | true | import("react").ReactElement<unknown, string | import("react").JSXElementConstructor<any>> | Iterable<ReactNode> | Promise<string | number | bigint | boolean | import("react").ReactPortal | import("react").ReactElement<unknown, string | import("react").JSXElementConstructor<any>> | Iterable<ReactNode>>;
27
28
  export declare const useFigureSmallScreen: () => boolean;
@@ -39,18 +39,25 @@ export var getDescription = _ref => {
39
39
  isSmallScreen,
40
40
  totalItems,
41
41
  itemName,
42
- visibleCount
42
+ visibleCount,
43
+ currentPage
43
44
  } = _ref;
44
45
  if (description) {
45
46
  return description;
46
47
  }
48
+ var closing = "";
49
+ if (typeof totalItems === "number") {
50
+ closing = " out of ".concat(totalItems);
51
+ } else if (currentPage !== 1) {
52
+ closing = " of more than ".concat(visibleCount);
53
+ }
47
54
  if (isSmallScreen) {
48
- return "".concat(visibleCount, " out of ").concat(totalItems);
55
+ return "".concat(visibleCount).concat(closing);
49
56
  }
50
57
  if (visibleCount === totalItems && visibleCount > 1) {
51
58
  return "Showing all ".concat(totalItems, " ").concat(itemName, "s");
52
59
  }
53
- return "Showing ".concat(visibleCount, " out of ").concat(totalItems, " ").concat(itemName).concat(totalItems !== 1 ? "s" : "");
60
+ return "Showing ".concat(visibleCount).concat(closing, " ").concat(itemName).concat(totalItems !== 1 ? "s" : "");
54
61
  };
55
62
  export var useFigureSmallScreen = () => {
56
63
  var [isSmallScreen, setSmallScreen] = useState(false);
@@ -1,4 +1,4 @@
1
1
  /**
2
- * @deprecated Code component is deprecated. Use CodeSnippet component or inline `<code>` instead.
2
+ * @deprecated Code component is deprecated. Use useId from React directly instead.
3
3
  */
4
4
  export declare const useId: () => string;
@@ -2,7 +2,7 @@ import { useId as useIdReact } from "react";
2
2
  import { IS_DEV } from "../utils";
3
3
 
4
4
  /**
5
- * @deprecated Code component is deprecated. Use CodeSnippet component or inline `<code>` instead.
5
+ * @deprecated Code component is deprecated. Use useId from React directly instead.
6
6
  */
7
7
  export var useId = () => {
8
8
  var id = useIdReact();
@@ -40,12 +40,13 @@ export var useListener = function useListener(targetNode, callback, eventType) {
40
40
  targetNode.addEventListener(eventType, eventListener.current, options);
41
41
  isListening.current = true;
42
42
  }
43
+ return () => {
44
+ // Unattach the listener if the component gets unmounted while
45
+ // listening.
46
+ if (targetNode && eventListener.current && isListening.current) {
47
+ targetNode.removeEventListener(eventType, eventListener.current, options);
48
+ isListening.current = false;
49
+ }
50
+ };
43
51
  }, [callback, eventType, options, previousCallback, previousEventType, previousOptions, previousShouldThrottle, previousTargetNode, shouldListen, shouldThrottle, targetNode, throttle]);
44
- useEffect(() => () => {
45
- // Unattach the listener if the component gets unmounted while
46
- // listening.
47
- if (targetNode && isListening.current) {
48
- targetNode.removeEventListener(eventType, eventListener.current, options);
49
- }
50
- }, [eventType, targetNode, options]);
51
52
  };
@@ -44,6 +44,8 @@ export { default as Panel } from "./components/Panel";
44
44
  export { default as PasswordToggle } from "./components/PasswordToggle";
45
45
  export { default as RadioInput } from "./components/RadioInput";
46
46
  export { default as Row } from "./components/Row";
47
+ export { default as ScrollableContainer } from "./components/ScrollableContainer";
48
+ export { default as ScrollableTable } from "./components/ScrollableTable";
47
49
  export { default as SearchAndFilter } from "./components/SearchAndFilter";
48
50
  export { default as SearchBox } from "./components/SearchBox";
49
51
  export { default as Select } from "./components/Select";
@@ -116,6 +118,8 @@ export type { PaginationProps } from "./components/Pagination";
116
118
  export type { PanelProps } from "./components/Panel";
117
119
  export type { RadioInputProps } from "./components/RadioInput";
118
120
  export type { RowProps } from "./components/Row";
121
+ export type { ScrollableTableProps } from "./components/ScrollableTable";
122
+ export type { ScrollableContainerProps } from "./components/ScrollableContainer";
119
123
  export type { SearchAndFilterProps } from "./components/SearchAndFilter";
120
124
  export type { SearchBoxProps } from "./components/SearchBox";
121
125
  export type { SelectProps } from "./components/Select";
@@ -143,7 +147,7 @@ export type { TablePaginationProps } from "./components/TablePagination";
143
147
  export type { CustomSelectProps, CustomSelectDropdownProps, CustomSelectOption, } from "./components/CustomSelect";
144
148
  export { useOnClickOutside, useClickOutside, useId, useListener, useOnEscapePressed, usePagination, usePrevious, usePrefersReducedMotion, useThrottle, useWindowFitment, } from "./hooks";
145
149
  export type { WindowFitment } from "./hooks";
146
- export { isNavigationAnchor, isNavigationButton } from "./utils";
150
+ export { isNavigationAnchor, isNavigationButton, getElementAbsoluteHeight, getAbsoluteHeightBelowById, getParentsBottomSpacing, } from "./utils";
147
151
  export type { ClassName, Headings, PropsWithSpread, SortDirection, SubComponentProps, TSFixMe, ValueOf, } from "./types";
148
152
  export { Theme } from "./enums";
149
153
  export type { UsePortalOptions } from "./external";
package/dist/esm/index.js CHANGED
@@ -44,6 +44,8 @@ export { default as Panel } from "./components/Panel";
44
44
  export { default as PasswordToggle } from "./components/PasswordToggle";
45
45
  export { default as RadioInput } from "./components/RadioInput";
46
46
  export { default as Row } from "./components/Row";
47
+ export { default as ScrollableContainer } from "./components/ScrollableContainer";
48
+ export { default as ScrollableTable } from "./components/ScrollableTable";
47
49
  export { default as SearchAndFilter } from "./components/SearchAndFilter";
48
50
  export { default as SearchBox } from "./components/SearchBox";
49
51
  export { default as Select } from "./components/Select";
@@ -74,6 +76,6 @@ export { default as TablePaginationControls } from "./components/TablePagination
74
76
  export { default as CustomLayout } from "./components/CustomLayout";
75
77
  export { default as CustomSelect } from "./components/CustomSelect";
76
78
  export { useOnClickOutside, useClickOutside, useId, useListener, useOnEscapePressed, usePagination, usePrevious, usePrefersReducedMotion, useThrottle, useWindowFitment } from "./hooks";
77
- export { isNavigationAnchor, isNavigationButton } from "./utils";
79
+ export { isNavigationAnchor, isNavigationButton, getElementAbsoluteHeight, getAbsoluteHeightBelowById, getParentsBottomSpacing } from "./utils";
78
80
  export { Theme } from "./enums";
79
81
  export { usePortal } from "./external";
@@ -25,3 +25,7 @@ export declare const isNavigationButton: (link: NavLink) => link is NavLinkButto
25
25
  * A typeguard for whether an element is a ReactNode.
26
26
  */
27
27
  export declare const isReactNode: (element: unknown) => element is ReactNode;
28
+ export declare const getElementAbsoluteHeight: (element: HTMLElement) => number;
29
+ export declare const getAbsoluteHeightBelowById: (belowId: string) => number;
30
+ export declare const getParentsBottomSpacing: (element: Element) => number;
31
+ export declare const toFloat: (value: string) => number;