@spaced-out/ui-design-system 0.1.10 → 0.1.12

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.
package/CHANGELOG.md CHANGED
@@ -2,6 +2,21 @@
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.1.12](https://github.com/spaced-out/ui-design-system/compare/v0.1.11...v0.1.12) (2023-04-12)
6
+
7
+
8
+ ### Features
9
+
10
+ * pagination component ([#96](https://github.com/spaced-out/ui-design-system/issues/96)) ([d0bc11e](https://github.com/spaced-out/ui-design-system/commit/d0bc11e650f0eb4882fd35ea5fae0362b6454be5))
11
+
12
+ ### [0.1.11](https://github.com/spaced-out/ui-design-system/compare/v0.1.10...v0.1.11) (2023-04-11)
13
+
14
+
15
+ ### Bug Fixes
16
+
17
+ * added classnames for menu custom component ([#95](https://github.com/spaced-out/ui-design-system/issues/95)) ([a860c29](https://github.com/spaced-out/ui-design-system/commit/a860c2979592d5e69301fb46374853ae960a54de))
18
+ * propagating disabled to button ([b14be23](https://github.com/spaced-out/ui-design-system/commit/b14be23a352d136c1c73f091b36bd7d1df8c35df))
19
+
5
20
  ### [0.1.10](https://github.com/spaced-out/ui-design-system/compare/v0.1.9...v0.1.10) (2023-04-10)
6
21
 
7
22
 
@@ -80,6 +80,7 @@ const Button = /*#__PURE__*/React.forwardRef((_ref2, ref) => {
80
80
  } = _ref2;
81
81
  return /*#__PURE__*/React.createElement(UnstyledButton, _extends({}, props, {
82
82
  actionType: actionType,
83
+ disabled: disabled,
83
84
  className: (0, _classify.classify)(_ButtonModule.default.button, {
84
85
  [_ButtonModule.default.primary]: type === 'primary',
85
86
  [_ButtonModule.default.secondary]: type === 'secondary',
@@ -124,6 +124,7 @@ export const Button: React$AbstractComponent<ButtonProps, HTMLButtonElement> =
124
124
  <UnstyledButton
125
125
  {...props}
126
126
  actionType={actionType}
127
+ disabled={disabled}
127
128
  className={classify(
128
129
  css.button,
129
130
  {
@@ -13,6 +13,8 @@ type ClassNames = $ReadOnly<{
13
13
  wrapper?: string,
14
14
  option?: string,
15
15
  groupTitle?: string,
16
+ optionTextContainer?: string,
17
+ optionTextLabel?: string,
16
18
  }>;
17
19
 
18
20
  export type MenuOption = {
@@ -77,10 +77,10 @@ const MenuOptionButton = props => {
77
77
  size: "small",
78
78
  className: _MenuModule.default.icon
79
79
  }), /*#__PURE__*/React.createElement("div", {
80
- className: _MenuModule.default.optionTextContainer
81
- }, /*#__PURE__*/React.createElement("div", {
82
- className: _MenuModule.default.optionTextLabel
83
- }, /*#__PURE__*/React.isValidElement(customComponent) ? customComponent : /*#__PURE__*/React.createElement(_Truncate.Truncate, null, label)), !!secondaryLabel && /*#__PURE__*/React.createElement("div", {
80
+ className: (0, _classify.classify)(_MenuModule.default.optionTextContainer, classNames?.optionTextContainer)
81
+ }, /*#__PURE__*/React.isValidElement(customComponent) ? customComponent : /*#__PURE__*/React.createElement("div", {
82
+ className: (0, _classify.classify)(_MenuModule.default.optionTextLabel, classNames?.optionTextLabel)
83
+ }, /*#__PURE__*/React.createElement(_Truncate.Truncate, null, label)), !!secondaryLabel && /*#__PURE__*/React.createElement("div", {
84
84
  className: _MenuModule.default.optionTextSecondaryLabel
85
85
  }, /*#__PURE__*/React.createElement(_Truncate.Truncate, null, secondaryLabel))), !!iconRight && /*#__PURE__*/React.createElement(_Icon.Icon, {
86
86
  name: iconRight,
@@ -96,14 +96,24 @@ export const MenuOptionButton = (props: MenuOptionProps): React.Node => {
96
96
  className={css.icon}
97
97
  />
98
98
  )}
99
- <div className={css.optionTextContainer}>
100
- <div className={css.optionTextLabel}>
101
- {React.isValidElement(customComponent) ? (
102
- customComponent
103
- ) : (
99
+ <div
100
+ className={classify(
101
+ css.optionTextContainer,
102
+ classNames?.optionTextContainer,
103
+ )}
104
+ >
105
+ {React.isValidElement(customComponent) ? (
106
+ customComponent
107
+ ) : (
108
+ <div
109
+ className={classify(
110
+ css.optionTextLabel,
111
+ classNames?.optionTextLabel,
112
+ )}
113
+ >
104
114
  <Truncate>{label}</Truncate>
105
- )}
106
- </div>
115
+ </div>
116
+ )}
107
117
 
108
118
  {!!secondaryLabel && (
109
119
  <div className={css.optionTextSecondaryLabel}>
@@ -0,0 +1,79 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.Pagination = void 0;
7
+ var React = _interopRequireWildcard(require("react"));
8
+ var _usePagination = _interopRequireDefault(require("../../hooks/usePagination"));
9
+ var _classify = _interopRequireDefault(require("../../utils/classify"));
10
+ var _helpers = require("../../utils/helpers");
11
+ var _Dropdown = require("../Dropdown");
12
+ var _Text = require("../Text");
13
+ var _PaginationItem = require("./PaginationItem");
14
+ var _PaginationModule = _interopRequireDefault(require("./Pagination.module.css"));
15
+ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
16
+ function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function (nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }
17
+ function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
18
+ function _extends() { _extends = Object.assign ? Object.assign.bind() : function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }
19
+ const Pagination = /*#__PURE__*/React.forwardRef((props, ref) => {
20
+ const {
21
+ classNames,
22
+ style = 'primary',
23
+ children,
24
+ currentPage = 1,
25
+ totalPages = 1,
26
+ onChange,
27
+ showFirstButton = style !== 'primary',
28
+ showLastButton = style !== 'primary',
29
+ ...restPaginationProps
30
+ } = props;
31
+ const {
32
+ items
33
+ } = (0, _usePagination.default)({
34
+ style,
35
+ showFirstButton,
36
+ showLastButton,
37
+ currentPage,
38
+ totalPages,
39
+ onChange,
40
+ ...restPaginationProps
41
+ });
42
+ const allPages = (0, _helpers.range)(1, totalPages);
43
+ const options = style !== 'secondary' ? [] : allPages.map(page => ({
44
+ key: page.toString(),
45
+ label: page.toString()
46
+ }));
47
+ return /*#__PURE__*/React.createElement("div", {
48
+ ref: ref,
49
+ "data-testid": "Pagination",
50
+ className: (0, _classify.default)(_PaginationModule.default.wrapper, classNames?.wrapper)
51
+ }, /*#__PURE__*/React.createElement("div", {
52
+ className: (0, _classify.default)(_PaginationModule.default.childrenSlot, classNames?.children)
53
+ }, children), /*#__PURE__*/React.createElement("div", {
54
+ className: _PaginationModule.default.paginatorSlots
55
+ }, style === 'secondary' && /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(_Dropdown.Dropdown, {
56
+ size: "small",
57
+ classNames: {
58
+ wrapper: _PaginationModule.default.dropdownWrapper
59
+ },
60
+ menu: {
61
+ options,
62
+ isFluid: true,
63
+ classNames: {
64
+ wrapper: _PaginationModule.default.menuWrapper
65
+ },
66
+ selectedKeys: currentPage ? [currentPage.toString()] : []
67
+ },
68
+ dropdownInputText: currentPage.toString(),
69
+ onChange: option => onChange?.(parseInt(option.key))
70
+ }), !!totalPages && !!currentPage && /*#__PURE__*/React.createElement(_Text.SubTitleExtraSmall, {
71
+ color: "tertiary",
72
+ className: _PaginationModule.default.secondaryLabel
73
+ }, "of ", totalPages, " ", totalPages > 1 ? 'Pages' : 'Page')), /*#__PURE__*/React.createElement("div", {
74
+ className: (0, _classify.default)(_PaginationModule.default.paginatorSlot, classNames?.paginator)
75
+ }, items?.map(item => /*#__PURE__*/React.createElement(_PaginationItem.PaginationItem, _extends({
76
+ key: item.id
77
+ }, item))))));
78
+ });
79
+ exports.Pagination = Pagination;
@@ -0,0 +1,139 @@
1
+ // @flow strict
2
+
3
+ import * as React from 'react';
4
+
5
+ import usePagination from '../../hooks/usePagination';
6
+ import classify from '../../utils/classify';
7
+ import {range} from '../../utils/helpers';
8
+ import {Dropdown} from '../Dropdown';
9
+ import {SubTitleExtraSmall} from '../Text';
10
+
11
+ import {PaginationItem} from './PaginationItem';
12
+
13
+ import css from './Pagination.module.css';
14
+
15
+
16
+ type ClassNames = $ReadOnly<{
17
+ wrapper?: string,
18
+ children?: string,
19
+ paginator?: string,
20
+ }>;
21
+ type MixedEvent = SyntheticEvent<EventTarget> | Event;
22
+ type PaginationItemType =
23
+ | 'first'
24
+ | 'previous'
25
+ | 'page'
26
+ | 'start-ellipsis'
27
+ | 'end-ellipsis'
28
+ | 'last'
29
+ | 'next';
30
+
31
+ export type PaginationBaseProps = {
32
+ currentPage?: number,
33
+ disabled?: boolean,
34
+ onChange?: (value?: ?number, event?: ?MixedEvent) => void,
35
+ totalPages?: number,
36
+ showFirstButton?: boolean,
37
+ showLastButton?: boolean,
38
+ hideNextButton?: boolean,
39
+ hidePrevButton?: boolean,
40
+ boundaryCount?: number,
41
+ siblingCount?: number,
42
+ style?: 'primary' | 'secondary',
43
+ };
44
+
45
+ export type PaginationProps = {
46
+ children?: React.Node,
47
+ ...PaginationBaseProps,
48
+ classNames?: ClassNames,
49
+ };
50
+
51
+ export type PaginationItemProps = {
52
+ id: string,
53
+ disabled: boolean,
54
+ onClick: (event: SyntheticEvent<HTMLElement>) => void,
55
+ page: ?number,
56
+ selected: boolean,
57
+ type: PaginationItemType,
58
+ };
59
+
60
+ export const Pagination: React$AbstractComponent<
61
+ PaginationProps,
62
+ HTMLDivElement,
63
+ > = React.forwardRef<PaginationProps, HTMLDivElement>(
64
+ (props: PaginationProps, ref) => {
65
+ const {
66
+ classNames,
67
+ style = 'primary',
68
+ children,
69
+ currentPage = 1,
70
+ totalPages = 1,
71
+ onChange,
72
+ showFirstButton = style !== 'primary',
73
+ showLastButton = style !== 'primary',
74
+ ...restPaginationProps
75
+ } = props;
76
+ const {items} = usePagination({
77
+ style,
78
+ showFirstButton,
79
+ showLastButton,
80
+ currentPage,
81
+ totalPages,
82
+ onChange,
83
+ ...restPaginationProps,
84
+ });
85
+
86
+ const allPages = range(1, totalPages);
87
+ const options =
88
+ style !== 'secondary'
89
+ ? []
90
+ : allPages.map((page) => ({
91
+ key: page.toString(),
92
+ label: page.toString(),
93
+ }));
94
+
95
+ return (
96
+ <div
97
+ ref={ref}
98
+ data-testid="Pagination"
99
+ className={classify(css.wrapper, classNames?.wrapper)}
100
+ >
101
+ <div className={classify(css.childrenSlot, classNames?.children)}>
102
+ {children}
103
+ </div>
104
+ <div className={css.paginatorSlots}>
105
+ {style === 'secondary' && (
106
+ <>
107
+ <Dropdown
108
+ size="small"
109
+ classNames={{wrapper: css.dropdownWrapper}}
110
+ menu={{
111
+ options,
112
+ isFluid: true,
113
+ classNames: {wrapper: css.menuWrapper},
114
+ selectedKeys: currentPage ? [currentPage.toString()] : [],
115
+ }}
116
+ dropdownInputText={currentPage.toString()}
117
+ onChange={(option) => onChange?.(parseInt(option.key))}
118
+ />
119
+ {!!totalPages && !!currentPage && (
120
+ <SubTitleExtraSmall
121
+ color="tertiary"
122
+ className={css.secondaryLabel}
123
+ >
124
+ of {totalPages} {totalPages > 1 ? 'Pages' : 'Page'}
125
+ </SubTitleExtraSmall>
126
+ )}
127
+ </>
128
+ )}
129
+
130
+ <div className={classify(css.paginatorSlot, classNames?.paginator)}>
131
+ {items?.map((item) => (
132
+ <PaginationItem key={item.id} {...item} />
133
+ ))}
134
+ </div>
135
+ </div>
136
+ </div>
137
+ );
138
+ },
139
+ );
@@ -0,0 +1,73 @@
1
+ @value (colorFillPrimary, colorTextSecondary, colorTextDisabled) from '../../styles/variables/_color.css';
2
+ @value (spaceXXSmall, spaceNone, spaceSmall, spaceXSmall) from '../../styles/variables/_space.css';
3
+ @value (size34, sizeFluid, size40) from '../../styles/variables/_size.css';
4
+
5
+ .wrapper {
6
+ display: flex;
7
+ align-items: center;
8
+ width: sizeFluid;
9
+ height: fit-content;
10
+ justify-content: space-between;
11
+ }
12
+
13
+ .childrenSlot {
14
+ display: flex;
15
+ }
16
+
17
+ .paginatorSlot {
18
+ display: flex;
19
+ gap: spaceXXSmall;
20
+ }
21
+
22
+ .paginatorSlots {
23
+ display: flex;
24
+ gap: spaceSmall;
25
+ }
26
+
27
+ .secondaryLabel {
28
+ margin-right: spaceXSmall;
29
+ }
30
+
31
+ .paginatorButton {
32
+ min-width: size34;
33
+ padding: spaceNone;
34
+ color: colorTextSecondary;
35
+ }
36
+
37
+ .pageNumbers {
38
+ display: flex;
39
+ align-items: center;
40
+ gap: spaceXXSmall;
41
+ }
42
+
43
+ .separator {
44
+ display: flex;
45
+ width: size34;
46
+ height: size34;
47
+ align-items: center;
48
+ justify-content: center;
49
+ }
50
+
51
+ .paginatorButton.disabled {
52
+ background-color: initial;
53
+ }
54
+
55
+ .paginatorButton.selected {
56
+ pointer-events: none;
57
+ }
58
+
59
+ .icon {
60
+ color: colorTextSecondary;
61
+ }
62
+
63
+ .icon.disabled {
64
+ color: colorTextDisabled;
65
+ }
66
+
67
+ .dropdownWrapper {
68
+ width: calc(size40 * 2);
69
+ }
70
+
71
+ .menuWrapper {
72
+ min-width: calc(size40 * 2);
73
+ }
@@ -0,0 +1,126 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.PaginationItem = exports.PaginationButton = void 0;
7
+ var React = _interopRequireWildcard(require("react"));
8
+ var _classify = _interopRequireDefault(require("../../utils/classify"));
9
+ var _Button = require("../Button/Button.js");
10
+ var _Text = require("../Text/Text.js");
11
+ var _PaginationModule = _interopRequireDefault(require("./Pagination.module.css"));
12
+ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
13
+ function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function (nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }
14
+ function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
15
+
16
+ const PaginationButton = props => {
17
+ const {
18
+ disabled,
19
+ onClick,
20
+ page,
21
+ selected,
22
+ type
23
+ } = props;
24
+ const paginationBtnRef = React.useRef(null);
25
+ React.useEffect(() => {
26
+ if (disabled || selected) {
27
+ paginationBtnRef.current?.blur();
28
+ }
29
+ }, [disabled, selected]);
30
+ switch (type) {
31
+ case 'first':
32
+ return /*#__PURE__*/React.createElement(_Button.Button, {
33
+ classNames: {
34
+ icon: (0, _classify.default)(_PaginationModule.default.icon, {
35
+ [_PaginationModule.default.disabled]: disabled
36
+ }),
37
+ wrapper: (0, _classify.default)(_PaginationModule.default.paginatorButton, {
38
+ [_PaginationModule.default.disabled]: disabled
39
+ })
40
+ },
41
+ type: selected ? 'secondary' : 'ghost',
42
+ size: "small",
43
+ onClick: onClick,
44
+ disabled: disabled,
45
+ ref: paginationBtnRef,
46
+ iconLeftName: "chevrons-left"
47
+ });
48
+ case 'previous':
49
+ return /*#__PURE__*/React.createElement(_Button.Button, {
50
+ classNames: {
51
+ icon: (0, _classify.default)(_PaginationModule.default.icon, {
52
+ [_PaginationModule.default.disabled]: disabled
53
+ }),
54
+ wrapper: (0, _classify.default)(_PaginationModule.default.paginatorButton, {
55
+ [_PaginationModule.default.disabled]: disabled
56
+ })
57
+ },
58
+ type: selected ? 'secondary' : 'ghost',
59
+ size: "small",
60
+ onClick: onClick,
61
+ disabled: disabled,
62
+ ref: paginationBtnRef,
63
+ iconLeftName: "chevron-left"
64
+ });
65
+ case 'page':
66
+ return /*#__PURE__*/React.createElement(_Button.Button, {
67
+ classNames: {
68
+ wrapper: (0, _classify.default)(_PaginationModule.default.paginatorButton, {
69
+ [_PaginationModule.default.selected]: selected
70
+ })
71
+ },
72
+ type: selected ? 'secondary' : 'ghost',
73
+ size: "small",
74
+ onClick: onClick,
75
+ disabled: disabled,
76
+ ref: paginationBtnRef,
77
+ tabIndex: selected ? -1 : 0
78
+ }, page);
79
+ case 'start-ellipsis':
80
+ case 'end-ellipsis':
81
+ return /*#__PURE__*/React.createElement("div", {
82
+ className: (0, _classify.default)(_PaginationModule.default.separator)
83
+ }, /*#__PURE__*/React.createElement(_Text.ButtonTextSmall, {
84
+ color: "disabled"
85
+ }, "..."));
86
+ case 'next':
87
+ return /*#__PURE__*/React.createElement(_Button.Button, {
88
+ classNames: {
89
+ icon: (0, _classify.default)(_PaginationModule.default.icon, {
90
+ [_PaginationModule.default.disabled]: disabled
91
+ }),
92
+ wrapper: (0, _classify.default)(_PaginationModule.default.paginatorButton, {
93
+ [_PaginationModule.default.disabled]: disabled
94
+ })
95
+ },
96
+ type: selected ? 'secondary' : 'ghost',
97
+ size: "small",
98
+ onClick: onClick,
99
+ disabled: disabled,
100
+ ref: paginationBtnRef,
101
+ iconLeftName: "chevron-right"
102
+ });
103
+ case 'last':
104
+ return /*#__PURE__*/React.createElement(_Button.Button, {
105
+ classNames: {
106
+ icon: (0, _classify.default)(_PaginationModule.default.icon, {
107
+ [_PaginationModule.default.disabled]: disabled
108
+ }),
109
+ wrapper: (0, _classify.default)(_PaginationModule.default.paginatorButton, {
110
+ [_PaginationModule.default.disabled]: disabled
111
+ })
112
+ },
113
+ type: selected ? 'secondary' : 'ghost',
114
+ size: "small",
115
+ onClick: onClick,
116
+ disabled: disabled,
117
+ ref: paginationBtnRef,
118
+ iconLeftName: "chevrons-right"
119
+ });
120
+ default:
121
+ break;
122
+ }
123
+ };
124
+ exports.PaginationButton = PaginationButton;
125
+ const PaginationItem = props => /*#__PURE__*/React.createElement(PaginationButton, props);
126
+ exports.PaginationItem = PaginationItem;
@@ -0,0 +1,116 @@
1
+ // @flow strict
2
+
3
+ import * as React from 'react';
4
+
5
+ import classify from '../../utils/classify';
6
+ import {Button} from '../Button/Button.js';
7
+ import {ButtonTextSmall} from '../Text/Text.js';
8
+
9
+ import type {PaginationItemProps} from './Pagination.js';
10
+
11
+ import css from './Pagination.module.css';
12
+
13
+
14
+ export const PaginationButton = (props: PaginationItemProps): React.Node => {
15
+ const {disabled, onClick, page, selected, type} = props;
16
+ const paginationBtnRef = React.useRef(null);
17
+
18
+ React.useEffect(() => {
19
+ if (disabled || selected) {
20
+ paginationBtnRef.current?.blur();
21
+ }
22
+ }, [disabled, selected]);
23
+
24
+ switch (type) {
25
+ case 'first':
26
+ return (
27
+ <Button
28
+ classNames={{
29
+ icon: classify(css.icon, {[css.disabled]: disabled}),
30
+ wrapper: classify(css.paginatorButton, {[css.disabled]: disabled}),
31
+ }}
32
+ type={selected ? 'secondary' : 'ghost'}
33
+ size="small"
34
+ onClick={onClick}
35
+ disabled={disabled}
36
+ ref={paginationBtnRef}
37
+ iconLeftName="chevrons-left"
38
+ ></Button>
39
+ );
40
+ case 'previous':
41
+ return (
42
+ <Button
43
+ classNames={{
44
+ icon: classify(css.icon, {[css.disabled]: disabled}),
45
+ wrapper: classify(css.paginatorButton, {[css.disabled]: disabled}),
46
+ }}
47
+ type={selected ? 'secondary' : 'ghost'}
48
+ size="small"
49
+ onClick={onClick}
50
+ disabled={disabled}
51
+ ref={paginationBtnRef}
52
+ iconLeftName="chevron-left"
53
+ ></Button>
54
+ );
55
+ case 'page':
56
+ return (
57
+ <Button
58
+ classNames={{
59
+ wrapper: classify(css.paginatorButton, {[css.selected]: selected}),
60
+ }}
61
+ type={selected ? 'secondary' : 'ghost'}
62
+ size="small"
63
+ onClick={onClick}
64
+ disabled={disabled}
65
+ ref={paginationBtnRef}
66
+ tabIndex={selected ? -1 : 0}
67
+ >
68
+ {page}
69
+ </Button>
70
+ );
71
+ case 'start-ellipsis':
72
+ case 'end-ellipsis':
73
+ return (
74
+ <div className={classify(css.separator)}>
75
+ <ButtonTextSmall color="disabled">...</ButtonTextSmall>
76
+ </div>
77
+ );
78
+ case 'next':
79
+ return (
80
+ <Button
81
+ classNames={{
82
+ icon: classify(css.icon, {[css.disabled]: disabled}),
83
+ wrapper: classify(css.paginatorButton, {[css.disabled]: disabled}),
84
+ }}
85
+ type={selected ? 'secondary' : 'ghost'}
86
+ size="small"
87
+ onClick={onClick}
88
+ disabled={disabled}
89
+ ref={paginationBtnRef}
90
+ iconLeftName="chevron-right"
91
+ ></Button>
92
+ );
93
+ case 'last':
94
+ return (
95
+ <Button
96
+ classNames={{
97
+ icon: classify(css.icon, {[css.disabled]: disabled}),
98
+ wrapper: classify(css.paginatorButton, {[css.disabled]: disabled}),
99
+ }}
100
+ type={selected ? 'secondary' : 'ghost'}
101
+ size="small"
102
+ onClick={onClick}
103
+ disabled={disabled}
104
+ ref={paginationBtnRef}
105
+ iconLeftName="chevrons-right"
106
+ ></Button>
107
+ );
108
+
109
+ default:
110
+ break;
111
+ }
112
+ };
113
+
114
+ export const PaginationItem = (props: PaginationItemProps): React.Node => (
115
+ <PaginationButton {...props} />
116
+ );
@@ -0,0 +1,16 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ var _Pagination = require("./Pagination");
7
+ Object.keys(_Pagination).forEach(function (key) {
8
+ if (key === "default" || key === "__esModule") return;
9
+ if (key in exports && exports[key] === _Pagination[key]) return;
10
+ Object.defineProperty(exports, key, {
11
+ enumerable: true,
12
+ get: function () {
13
+ return _Pagination[key];
14
+ }
15
+ });
16
+ });
@@ -0,0 +1,3 @@
1
+ // @flow strict
2
+
3
+ export * from './Pagination';
@@ -14,6 +14,17 @@ Object.keys(_useMountTransition).forEach(function (key) {
14
14
  }
15
15
  });
16
16
  });
17
+ var _usePagination = require("./usePagination");
18
+ Object.keys(_usePagination).forEach(function (key) {
19
+ if (key === "default" || key === "__esModule") return;
20
+ if (key in exports && exports[key] === _usePagination[key]) return;
21
+ Object.defineProperty(exports, key, {
22
+ enumerable: true,
23
+ get: function () {
24
+ return _usePagination[key];
25
+ }
26
+ });
27
+ });
17
28
  var _useToastPortal = require("./useToastPortal");
18
29
  Object.keys(_useToastPortal).forEach(function (key) {
19
30
  if (key === "default" || key === "__esModule") return;
@@ -1,4 +1,5 @@
1
1
  // @flow strict
2
2
 
3
3
  export * from './useMountTransition';
4
+ export * from './usePagination';
4
5
  export * from './useToastPortal';
@@ -0,0 +1,102 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.default = usePagination;
7
+ var _helpers = require("../utils/helpers");
8
+
9
+ function usePagination(props) {
10
+ const {
11
+ boundaryCount = 1,
12
+ totalPages = 1,
13
+ disabled = false,
14
+ hideNextButton = false,
15
+ hidePrevButton = false,
16
+ onChange: handleChange,
17
+ currentPage = 1,
18
+ showFirstButton = false,
19
+ showLastButton = false,
20
+ siblingCount = 1,
21
+ style = 'primary'
22
+ } = props;
23
+ let itemList = [];
24
+ const handleClick = (event, value) => {
25
+ if (handleChange) {
26
+ handleChange(value, event);
27
+ }
28
+ };
29
+ const startPages = (0, _helpers.range)(1, Math.min(boundaryCount, totalPages));
30
+ const endPages = (0, _helpers.range)(Math.max(totalPages - boundaryCount + 1, boundaryCount + 1), totalPages);
31
+ const siblingsStart = Math.max(Math.min(
32
+ // Natural start
33
+ currentPage - siblingCount,
34
+ // Lower boundary when currentPage is high
35
+ totalPages - boundaryCount - siblingCount * 2 - 1),
36
+ // Greater than startPages
37
+ boundaryCount + 2);
38
+ const siblingsEnd = Math.min(Math.max(
39
+ // Natural end
40
+ currentPage + siblingCount,
41
+ // Upper boundary when currentPage is low
42
+ boundaryCount + siblingCount * 2 + 2),
43
+ // Less than endPages
44
+ endPages.length > 0 ? endPages[0] - 2 : totalPages - 1);
45
+
46
+ // Basic list of items to render
47
+ // For primary style: itemList = ['first', 'previous', 1, 'start-ellipsis', 4, 5, 6, 'end-ellipsis', 10, 'next', 'last']
48
+ // For secondary style: itemList = ['first', 'previous', 'next', 'last']
49
+ if (style === 'primary') {
50
+ itemList = [...(showFirstButton ? ['first'] : []), ...(hidePrevButton ? [] : ['previous']), ...startPages,
51
+ // Start ellipsis
52
+ // eslint-disable-next-line no-nested-ternary
53
+ ...(siblingsStart > boundaryCount + 2 ? ['start-ellipsis'] : boundaryCount + 1 < totalPages - boundaryCount ? [boundaryCount + 1] : []),
54
+ // Sibling pages
55
+ ...(0, _helpers.range)(siblingsStart, siblingsEnd),
56
+ // End ellipsis
57
+ // eslint-disable-next-line no-nested-ternary
58
+ ...(siblingsEnd < totalPages - boundaryCount - 1 ? ['end-ellipsis'] : totalPages - boundaryCount > boundaryCount ? [totalPages - boundaryCount] : []), ...endPages, ...(hideNextButton ? [] : ['next']), ...(showLastButton ? ['last'] : [])];
59
+ } else if (style === 'secondary') {
60
+ itemList = [...(showFirstButton ? ['first'] : []), ...(hidePrevButton ? [] : ['previous']), ...(hideNextButton ? [] : ['next']), ...(showLastButton ? ['last'] : [])];
61
+ }
62
+
63
+ // Map the button type to its page number
64
+ const buttonPage = type => {
65
+ switch (type) {
66
+ case 'first':
67
+ return 1;
68
+ case 'previous':
69
+ return currentPage - 1;
70
+ case 'next':
71
+ return currentPage + 1;
72
+ case 'last':
73
+ return totalPages;
74
+ default:
75
+ return null;
76
+ }
77
+ };
78
+
79
+ // Convert the basic item list to contain PaginationItem props objects
80
+ const items = itemList.map((item, idx) => typeof item === 'number' ? {
81
+ id: idx.toString(),
82
+ onClick: event => {
83
+ handleClick(event, item);
84
+ },
85
+ type: 'page',
86
+ page: item,
87
+ selected: item === currentPage,
88
+ disabled
89
+ } : {
90
+ id: idx.toString(),
91
+ onClick: event => {
92
+ handleClick(event, buttonPage(item));
93
+ },
94
+ type: item,
95
+ page: buttonPage(item),
96
+ selected: false,
97
+ disabled: disabled || item.indexOf('ellipsis') === -1 && (item === 'next' || item === 'last' ? currentPage >= totalPages : currentPage <= 1)
98
+ });
99
+ return {
100
+ items
101
+ };
102
+ }
@@ -0,0 +1,153 @@
1
+ // @flow strict
2
+
3
+ import type {
4
+ PaginationBaseProps,
5
+ PaginationItemProps,
6
+ } from '../components/Pagination/Pagination.js';
7
+ import {range} from '../utils/helpers';
8
+
9
+
10
+ export default function usePagination(props: PaginationBaseProps): {
11
+ items: ?(PaginationItemProps[]),
12
+ } {
13
+ const {
14
+ boundaryCount = 1,
15
+ totalPages = 1,
16
+ disabled = false,
17
+ hideNextButton = false,
18
+ hidePrevButton = false,
19
+ onChange: handleChange,
20
+ currentPage = 1,
21
+ showFirstButton = false,
22
+ showLastButton = false,
23
+ siblingCount = 1,
24
+ style = 'primary',
25
+ } = props;
26
+
27
+ let itemList = [];
28
+
29
+ const handleClick = (event, value) => {
30
+ if (handleChange) {
31
+ handleChange(value, event);
32
+ }
33
+ };
34
+
35
+ const startPages = range(1, Math.min(boundaryCount, totalPages));
36
+ const endPages = range(
37
+ Math.max(totalPages - boundaryCount + 1, boundaryCount + 1),
38
+ totalPages,
39
+ );
40
+
41
+ const siblingsStart = Math.max(
42
+ Math.min(
43
+ // Natural start
44
+ currentPage - siblingCount,
45
+ // Lower boundary when currentPage is high
46
+ totalPages - boundaryCount - siblingCount * 2 - 1,
47
+ ),
48
+ // Greater than startPages
49
+ boundaryCount + 2,
50
+ );
51
+
52
+ const siblingsEnd = Math.min(
53
+ Math.max(
54
+ // Natural end
55
+ currentPage + siblingCount,
56
+ // Upper boundary when currentPage is low
57
+ boundaryCount + siblingCount * 2 + 2,
58
+ ),
59
+ // Less than endPages
60
+ endPages.length > 0 ? endPages[0] - 2 : totalPages - 1,
61
+ );
62
+
63
+ // Basic list of items to render
64
+ // For primary style: itemList = ['first', 'previous', 1, 'start-ellipsis', 4, 5, 6, 'end-ellipsis', 10, 'next', 'last']
65
+ // For secondary style: itemList = ['first', 'previous', 'next', 'last']
66
+ if (style === 'primary') {
67
+ itemList = [
68
+ ...(showFirstButton ? ['first'] : []),
69
+ ...(hidePrevButton ? [] : ['previous']),
70
+ ...startPages,
71
+
72
+ // Start ellipsis
73
+ // eslint-disable-next-line no-nested-ternary
74
+ ...(siblingsStart > boundaryCount + 2
75
+ ? ['start-ellipsis']
76
+ : boundaryCount + 1 < totalPages - boundaryCount
77
+ ? [boundaryCount + 1]
78
+ : []),
79
+
80
+ // Sibling pages
81
+ ...range(siblingsStart, siblingsEnd),
82
+
83
+ // End ellipsis
84
+ // eslint-disable-next-line no-nested-ternary
85
+ ...(siblingsEnd < totalPages - boundaryCount - 1
86
+ ? ['end-ellipsis']
87
+ : totalPages - boundaryCount > boundaryCount
88
+ ? [totalPages - boundaryCount]
89
+ : []),
90
+
91
+ ...endPages,
92
+ ...(hideNextButton ? [] : ['next']),
93
+ ...(showLastButton ? ['last'] : []),
94
+ ];
95
+ } else if (style === 'secondary') {
96
+ itemList = [
97
+ ...(showFirstButton ? ['first'] : []),
98
+ ...(hidePrevButton ? [] : ['previous']),
99
+ ...(hideNextButton ? [] : ['next']),
100
+ ...(showLastButton ? ['last'] : []),
101
+ ];
102
+ }
103
+
104
+ // Map the button type to its page number
105
+ const buttonPage = (type) => {
106
+ switch (type) {
107
+ case 'first':
108
+ return 1;
109
+ case 'previous':
110
+ return currentPage - 1;
111
+ case 'next':
112
+ return currentPage + 1;
113
+ case 'last':
114
+ return totalPages;
115
+ default:
116
+ return null;
117
+ }
118
+ };
119
+
120
+ // Convert the basic item list to contain PaginationItem props objects
121
+ const items = itemList.map((item, idx) =>
122
+ typeof item === 'number'
123
+ ? {
124
+ id: idx.toString(),
125
+ onClick: (event) => {
126
+ handleClick(event, item);
127
+ },
128
+ type: 'page',
129
+ page: item,
130
+ selected: item === currentPage,
131
+ disabled,
132
+ }
133
+ : {
134
+ id: idx.toString(),
135
+ onClick: (event) => {
136
+ handleClick(event, buttonPage(item));
137
+ },
138
+ type: item,
139
+ page: buttonPage(item),
140
+ selected: false,
141
+ disabled:
142
+ disabled ||
143
+ (item.indexOf('ellipsis') === -1 &&
144
+ (item === 'next' || item === 'last'
145
+ ? currentPage >= totalPages
146
+ : currentPage <= 1)),
147
+ },
148
+ );
149
+
150
+ return {
151
+ items,
152
+ };
153
+ }
@@ -3,7 +3,7 @@
3
3
  Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
- exports.uuid = void 0;
6
+ exports.uuid = exports.range = void 0;
7
7
 
8
8
  const uuid = () => {
9
9
  let dt = new Date().getTime();
@@ -13,4 +13,11 @@ const uuid = () => {
13
13
  return (c === 'x' ? r : r & 0x3 | 0x8).toString(16);
14
14
  });
15
15
  };
16
- exports.uuid = uuid;
16
+ exports.uuid = uuid;
17
+ const range = (start, end) => {
18
+ const length = end - start + 1;
19
+ return Array.from({
20
+ length
21
+ }, (_, i) => start + i);
22
+ };
23
+ exports.range = range;
@@ -9,3 +9,8 @@ export const uuid = (): string => {
9
9
  return (c === 'x' ? r : (r & 0x3) | 0x8).toString(16);
10
10
  });
11
11
  };
12
+
13
+ export const range = (start: number, end: number): Array<number> => {
14
+ const length = end - start + 1;
15
+ return Array.from({length}, (_, i) => start + i);
16
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@spaced-out/ui-design-system",
3
- "version": "0.1.10",
3
+ "version": "0.1.12",
4
4
  "main": "index.js",
5
5
  "description": "Sense UI components library",
6
6
  "author": {