@spaced-out/ui-design-system 0.1.16 → 0.1.17

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 (84) hide show
  1. package/.cspell/custom-words.txt +3 -0
  2. package/.flowconfig +1 -1
  3. package/CHANGELOG.md +7 -0
  4. package/CONTRIBUTING.md +52 -6
  5. package/README.md +144 -8
  6. package/gulpfile.js +1 -0
  7. package/lib/components/AvatarGroup/AvatarGroup.js +4 -3
  8. package/lib/components/AvatarGroup/AvatarGroup.js.flow +119 -110
  9. package/lib/components/Badge/Badge.js +4 -3
  10. package/lib/components/Badge/Badge.js.flow +21 -21
  11. package/lib/components/Badge/index.js +11 -7
  12. package/lib/components/Badge/index.js.flow +1 -2
  13. package/lib/components/Banner/Banner.js +3 -2
  14. package/lib/components/Banner/Banner.js.flow +42 -35
  15. package/lib/components/Button/Button.js +50 -10
  16. package/lib/components/Button/Button.js.flow +87 -23
  17. package/lib/components/Button/Button.module.css +14 -0
  18. package/lib/components/ButtonTabs/ButtonTab/ButtonTab.js +3 -2
  19. package/lib/components/ButtonTabs/ButtonTab/ButtonTab.js.flow +48 -38
  20. package/lib/components/ButtonTabs/ButtonTabs.js +3 -2
  21. package/lib/components/ButtonTabs/ButtonTabs.js.flow +50 -41
  22. package/lib/components/Card/Card.js +16 -7
  23. package/lib/components/Card/Card.js.flow +73 -55
  24. package/lib/components/Chip/Chip.js +3 -2
  25. package/lib/components/Chip/Chip.js.flow +66 -59
  26. package/lib/components/CircularLoader/CircularLoader.js +9 -4
  27. package/lib/components/CircularLoader/CircularLoader.js.flow +38 -24
  28. package/lib/components/CollapsibleCard/CollapsibleCard.js +4 -3
  29. package/lib/components/CollapsibleCard/CollapsibleCard.js.flow +68 -59
  30. package/lib/components/Dropdown/Dropdown.js +4 -3
  31. package/lib/components/Dropdown/Dropdown.js.flow +83 -74
  32. package/lib/components/EmptyState/EmptyState.js +4 -3
  33. package/lib/components/EmptyState/EmptyState.js.flow +53 -44
  34. package/lib/components/ErrorMessage/ErrorMessage.js +4 -3
  35. package/lib/components/ErrorMessage/ErrorMessage.js.flow +58 -49
  36. package/lib/components/InContextAlert/InContextAlert.js +4 -3
  37. package/lib/components/InContextAlert/InContextAlert.js.flow +79 -73
  38. package/lib/components/InlineDropdown/InlineDropdown.js +4 -3
  39. package/lib/components/InlineDropdown/InlineDropdown.js.flow +94 -85
  40. package/lib/components/LinearLoader/LinearLoader.js +4 -3
  41. package/lib/components/LinearLoader/LinearLoader.js.flow +20 -18
  42. package/lib/components/Link/Link.js +8 -1
  43. package/lib/components/Link/Link.js.flow +44 -36
  44. package/lib/components/Notification/Notification.js +8 -6
  45. package/lib/components/Notification/Notification.js.flow +96 -84
  46. package/lib/components/OptionButton/OptionButton.js +7 -4
  47. package/lib/components/OptionButton/OptionButton.js.flow +69 -59
  48. package/lib/components/PageTitle/PageTitle.js +4 -3
  49. package/lib/components/PageTitle/PageTitle.js.flow +46 -44
  50. package/lib/components/Pagination/PaginationItem.js +2 -2
  51. package/lib/components/Pagination/PaginationItem.js.flow +2 -2
  52. package/lib/components/SearchInput/SearchInput.js +3 -2
  53. package/lib/components/SearchInput/SearchInput.js.flow +59 -50
  54. package/lib/components/SideMenuLink/SideMenuLink.js +4 -3
  55. package/lib/components/SideMenuLink/SideMenuLink.js.flow +54 -45
  56. package/lib/components/StatusIndicator/StatusIndicator.js +3 -2
  57. package/lib/components/StatusIndicator/StatusIndicator.js.flow +32 -23
  58. package/lib/components/SubMenu/SubMenu.js +4 -3
  59. package/lib/components/SubMenu/SubMenu.js.flow +41 -38
  60. package/lib/components/Table/StaticTable.js +3 -0
  61. package/lib/components/Table/StaticTable.js.flow +3 -0
  62. package/lib/components/Table/Table.js +10 -0
  63. package/lib/components/Table/Table.js.flow +10 -0
  64. package/lib/components/Table/hooks.js +1 -0
  65. package/lib/components/Table/hooks.js.flow +1 -0
  66. package/lib/components/Tabs/TabList/TabList.js +3 -2
  67. package/lib/components/Tabs/TabList/TabList.js.flow +127 -117
  68. package/lib/components/Toggle/index.js +11 -7
  69. package/lib/components/Toggle/index.js.flow +1 -1
  70. package/lib/components/Tooltip/Tooltip.js.flow +2 -2
  71. package/lib/components/index.js +511 -0
  72. package/lib/components/index.js.flow +48 -0
  73. package/lib/index.js +60 -0
  74. package/lib/index.js.flow +7 -0
  75. package/lib/styles/index.css +15 -0
  76. package/lib/styles/index.js +104 -0
  77. package/lib/styles/index.js.flow +12 -0
  78. package/lib/styles/typography.module.css +0 -1
  79. package/lib/styles/utils.module.css +26 -0
  80. package/lib/types/index.js +38 -0
  81. package/lib/types/index.js.flow +5 -0
  82. package/lib/utils/index.js +93 -0
  83. package/lib/utils/index.js.flow +10 -0
  84. package/package.json +2 -1
@@ -35,24 +35,24 @@ export type BadgeProps = {
35
35
  fill?: BadgeColorType,
36
36
  };
37
37
 
38
- export const Badge = ({
39
- classNames,
40
- text,
41
- fill = 'gray',
42
- }: BadgeProps): React.Node => (
43
- <div
44
- data-testid="Badge"
45
- className={classify(
46
- css.badgeWrapper,
47
- {
48
- [css.fixedWidth]: text.length <= 2,
49
- },
50
- classNames?.wrapper,
51
- )}
52
- style={{
53
- backgroundColor: BADGE_COLOR[fill],
54
- }}
55
- >
56
- <ButtonTextSmall>{text}</ButtonTextSmall>
57
- </div>
58
- );
38
+ export const Badge: React$AbstractComponent<BadgeProps, HTMLDivElement> =
39
+ React.forwardRef<BadgeProps, HTMLDivElement>(
40
+ ({classNames, text, fill = 'gray'}: BadgeProps, ref): React.Node => (
41
+ <div
42
+ data-testid="Badge"
43
+ className={classify(
44
+ css.badgeWrapper,
45
+ {
46
+ [css.fixedWidth]: text.length <= 2,
47
+ },
48
+ classNames?.wrapper,
49
+ )}
50
+ style={{
51
+ backgroundColor: BADGE_COLOR[fill],
52
+ }}
53
+ ref={ref}
54
+ >
55
+ <ButtonTextSmall>{text}</ButtonTextSmall>
56
+ </div>
57
+ ),
58
+ );
@@ -3,10 +3,14 @@
3
3
  Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
- Object.defineProperty(exports, "Badge", {
7
- enumerable: true,
8
- get: function () {
9
- return _Badge.Badge;
10
- }
11
- });
12
- var _Badge = require("./Badge");
6
+ var _Badge = require("./Badge");
7
+ Object.keys(_Badge).forEach(function (key) {
8
+ if (key === "default" || key === "__esModule") return;
9
+ if (key in exports && exports[key] === _Badge[key]) return;
10
+ Object.defineProperty(exports, key, {
11
+ enumerable: true,
12
+ get: function () {
13
+ return _Badge[key];
14
+ }
15
+ });
16
+ });
@@ -1,4 +1,3 @@
1
1
  // @flow strict
2
2
 
3
- export type {BadgeProps} from './Badge';
4
- export {Badge} from './Badge';
3
+ export * from './Badge';
@@ -12,7 +12,7 @@ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { de
12
12
  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); }
13
13
  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; }
14
14
  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); }
15
- const Banner = _ref => {
15
+ const Banner = /*#__PURE__*/React.forwardRef((_ref, ref) => {
16
16
  let {
17
17
  classNames,
18
18
  semantic,
@@ -23,6 +23,7 @@ const Banner = _ref => {
23
23
  return /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(_InContextAlert.InContextAlert, _extends({}, props, {
24
24
  leftIconType: leftIconType,
25
25
  semantic: semantic,
26
+ ref: ref,
26
27
  classNames: {
27
28
  wrapper: (0, _classify.default)(_BannerModule.default.bannerContainer, {
28
29
  [_BannerModule.default.neutral]: semantic === _InContextAlert.ALERT_SEMANTIC.neutral,
@@ -37,5 +38,5 @@ const Banner = _ref => {
37
38
  actionContainer: (0, _classify.default)(_BannerModule.default.alertContainer, classNames?.actionContainer)
38
39
  }
39
40
  })));
40
- };
41
+ });
41
42
  exports.Banner = Banner;
@@ -14,38 +14,45 @@ export type BannerProps = {
14
14
  alignment?: 'top' | 'bottom',
15
15
  };
16
16
 
17
- export const Banner = ({
18
- classNames,
19
- semantic,
20
- leftIconType = 'solid',
21
- alignment = 'top',
22
- ...props
23
- }: BannerProps): React.Node => (
24
- <>
25
- <InContextAlert
26
- {...props}
27
- leftIconType={leftIconType}
28
- semantic={semantic}
29
- classNames={{
30
- wrapper: classify(
31
- css.bannerContainer,
32
- {
33
- [css.neutral]: semantic === ALERT_SEMANTIC.neutral,
34
- [css.success]: semantic === ALERT_SEMANTIC.success,
35
- [css.information]: semantic === ALERT_SEMANTIC.information,
36
- [css.warning]: semantic === ALERT_SEMANTIC.warning,
37
- [css.danger]: semantic === ALERT_SEMANTIC.danger,
38
- [css.topAligned]: alignment === 'top',
39
- [css.bottomAligned]: alignment === 'bottom',
40
- },
41
- classNames?.wrapper,
42
- ),
43
- alertText: classify(classNames?.alertText),
44
- actionContainer: classify(
45
- css.alertContainer,
46
- classNames?.actionContainer,
47
- ),
48
- }}
49
- />
50
- </>
51
- );
17
+ export const Banner: React$AbstractComponent<BannerProps, HTMLDivElement> =
18
+ React.forwardRef<BannerProps, HTMLDivElement>(
19
+ (
20
+ {
21
+ classNames,
22
+ semantic,
23
+ leftIconType = 'solid',
24
+ alignment = 'top',
25
+ ...props
26
+ }: BannerProps,
27
+ ref,
28
+ ): React.Node => (
29
+ <>
30
+ <InContextAlert
31
+ {...props}
32
+ leftIconType={leftIconType}
33
+ semantic={semantic}
34
+ ref={ref}
35
+ classNames={{
36
+ wrapper: classify(
37
+ css.bannerContainer,
38
+ {
39
+ [css.neutral]: semantic === ALERT_SEMANTIC.neutral,
40
+ [css.success]: semantic === ALERT_SEMANTIC.success,
41
+ [css.information]: semantic === ALERT_SEMANTIC.information,
42
+ [css.warning]: semantic === ALERT_SEMANTIC.warning,
43
+ [css.danger]: semantic === ALERT_SEMANTIC.danger,
44
+ [css.topAligned]: alignment === 'top',
45
+ [css.bottomAligned]: alignment === 'bottom',
46
+ },
47
+ classNames?.wrapper,
48
+ ),
49
+ alertText: classify(classNames?.alertText),
50
+ actionContainer: classify(
51
+ css.alertContainer,
52
+ classNames?.actionContainer,
53
+ ),
54
+ }}
55
+ />
56
+ </>
57
+ ),
58
+ );
@@ -6,6 +6,7 @@ Object.defineProperty(exports, "__esModule", {
6
6
  exports.UnstyledButton = exports.Button = exports.BUTTON_TYPES = exports.BUTTON_ACTION_TYPE = void 0;
7
7
  var React = _interopRequireWildcard(require("react"));
8
8
  var _classify = require("../../utils/classify");
9
+ var _CircularLoader = require("../CircularLoader");
9
10
  var _Icon = require("../Icon");
10
11
  var _Truncate = require("../Truncate");
11
12
  var _ButtonModule = _interopRequireDefault(require("./Button.module.css"));
@@ -34,6 +35,13 @@ const ButtonTypeToIconColorMap = {
34
35
  ghost: 'primary',
35
36
  danger: 'inversePrimary'
36
37
  };
38
+ const ButtonTypeToLoaderColorMap = {
39
+ primary: 'colorTextInversePrimary',
40
+ secondary: 'colorTextClickable',
41
+ tertiary: 'colorTextPrimary',
42
+ ghost: 'colorTextPrimary',
43
+ danger: 'colorTextInversePrimary'
44
+ };
37
45
  const UnstyledButton = /*#__PURE__*/React.forwardRef((_ref, ref) => {
38
46
  let {
39
47
  disabled,
@@ -42,6 +50,7 @@ const UnstyledButton = /*#__PURE__*/React.forwardRef((_ref, ref) => {
42
50
  ariaLabel,
43
51
  actionType,
44
52
  tabIndex = 0,
53
+ isLoading,
45
54
  ...props
46
55
  } = _ref;
47
56
  return /*#__PURE__*/React.createElement("button", _extends({}, props, ariaLabel ? {
@@ -54,7 +63,7 @@ const UnstyledButton = /*#__PURE__*/React.forwardRef((_ref, ref) => {
54
63
  tabIndex: disabled ? -1 : tabIndex,
55
64
  type: actionType,
56
65
  onClick: event => {
57
- if (disabled) {
66
+ if (disabled || isLoading) {
58
67
  event.preventDefault();
59
68
  } else if (onClick) {
60
69
  onClick(event);
@@ -76,11 +85,13 @@ const Button = /*#__PURE__*/React.forwardRef((_ref2, ref) => {
76
85
  disabled = false,
77
86
  actionType = 'button',
78
87
  size = 'medium',
88
+ isLoading,
79
89
  ...props
80
90
  } = _ref2;
81
91
  return /*#__PURE__*/React.createElement(UnstyledButton, _extends({}, props, {
82
92
  actionType: actionType,
83
93
  disabled: disabled,
94
+ isLoading: isLoading,
84
95
  className: (0, _classify.classify)(_ButtonModule.default.button, {
85
96
  [_ButtonModule.default.primary]: type === 'primary',
86
97
  [_ButtonModule.default.secondary]: type === 'secondary',
@@ -100,31 +111,60 @@ const Button = /*#__PURE__*/React.forwardRef((_ref2, ref) => {
100
111
  }), /*#__PURE__*/React.createElement("div", {
101
112
  className: _ButtonModule.default.buttonRow
102
113
  }, !(iconLeftName || iconRightName) ? /*#__PURE__*/React.createElement("div", {
103
- className: _ButtonModule.default.textContainerCenter
104
- }, /*#__PURE__*/React.createElement(_Truncate.Truncate, null, children)) :
114
+ className: _ButtonModule.default.textContainer
115
+ }, isLoading && /*#__PURE__*/React.createElement("div", {
116
+ className: _ButtonModule.default.loader
117
+ }, /*#__PURE__*/React.createElement(_CircularLoader.CircularLoader, {
118
+ size: size,
119
+ colorToken: disabled ? 'colorTextDisabled' : ButtonTypeToLoaderColorMap[type]
120
+ })), /*#__PURE__*/React.createElement(_Truncate.Truncate, {
121
+ className: (0, _classify.classify)({
122
+ [_ButtonModule.default.hidden]: isLoading
123
+ })
124
+ }, children)) :
105
125
  // has icon, but no child
106
- children == null ? /*#__PURE__*/React.createElement(_Icon.Icon, {
126
+ children == null ? /*#__PURE__*/React.createElement(React.Fragment, null, isLoading && /*#__PURE__*/React.createElement("div", {
127
+ className: _ButtonModule.default.loader
128
+ }, /*#__PURE__*/React.createElement(_CircularLoader.CircularLoader, {
129
+ size: size,
130
+ colorToken: disabled ? 'colorTextDisabled' : ButtonTypeToLoaderColorMap[type]
131
+ })), /*#__PURE__*/React.createElement(_Icon.Icon, {
107
132
  name: iconLeftName || iconRightName,
108
133
  color: disabled ? 'disabled' : ButtonTypeToIconColorMap[type],
109
134
  size: size === 'medium' ? 'medium' : 'small',
110
135
  type: iconLeftName ? iconLeftType : iconRightType,
111
- className: classNames?.icon
112
- }) :
136
+ className: (0, _classify.classify)({
137
+ [_ButtonModule.default.hidden]: isLoading
138
+ }, classNames?.icon)
139
+ })) :
113
140
  // has icon _and_ child
114
141
  (iconLeftName || iconRightName) && /*#__PURE__*/React.createElement(React.Fragment, null, iconLeftName && /*#__PURE__*/React.createElement(_Icon.Icon, {
115
142
  name: iconLeftName,
116
143
  color: disabled ? 'disabled' : ButtonTypeToIconColorMap[type],
117
144
  size: size === 'medium' ? 'medium' : 'small',
118
145
  type: iconLeftType,
119
- className: classNames?.icon
146
+ className: (0, _classify.classify)({
147
+ [_ButtonModule.default.hidden]: isLoading
148
+ }, classNames?.icon)
120
149
  }), /*#__PURE__*/React.createElement("div", {
121
- className: _ButtonModule.default.textContainerLeft
122
- }, /*#__PURE__*/React.createElement(_Truncate.Truncate, null, children)), iconRightName && /*#__PURE__*/React.createElement(_Icon.Icon, {
150
+ className: _ButtonModule.default.textContainer
151
+ }, isLoading && /*#__PURE__*/React.createElement("div", {
152
+ className: _ButtonModule.default.loader
153
+ }, /*#__PURE__*/React.createElement(_CircularLoader.CircularLoader, {
154
+ size: size,
155
+ colorToken: disabled ? 'colorTextDisabled' : ButtonTypeToLoaderColorMap[type]
156
+ })), /*#__PURE__*/React.createElement(_Truncate.Truncate, {
157
+ className: (0, _classify.classify)({
158
+ [_ButtonModule.default.hidden]: isLoading
159
+ })
160
+ }, children)), iconRightName && /*#__PURE__*/React.createElement(_Icon.Icon, {
123
161
  name: iconRightName,
124
162
  color: disabled ? 'disabled' : ButtonTypeToIconColorMap[type],
125
163
  size: size === 'medium' ? 'medium' : 'small',
126
164
  type: iconRightType,
127
- className: classNames?.icon
165
+ className: (0, _classify.classify)({
166
+ [_ButtonModule.default.hidden]: isLoading
167
+ }, classNames?.icon)
128
168
  }))));
129
169
  });
130
170
  exports.Button = Button;
@@ -3,6 +3,7 @@
3
3
  import * as React from 'react';
4
4
 
5
5
  import {classify} from '../../utils/classify';
6
+ import {CircularLoader} from '../CircularLoader';
6
7
  import type {IconType} from '../Icon';
7
8
  import {Icon} from '../Icon';
8
9
  import {Truncate} from '../Truncate';
@@ -29,32 +30,33 @@ export const BUTTON_ACTION_TYPE = Object.freeze({
29
30
  export type ButtonType = $Values<typeof BUTTON_TYPES>;
30
31
  export type ButtonActionType = $Values<typeof BUTTON_ACTION_TYPE>;
31
32
 
32
- export type UnstyledButtonProps = {
33
+ export type BaseButtonProps = {
33
34
  children?: React.Node,
34
35
  disabled?: mixed,
35
36
  actionType?: ButtonActionType,
36
37
  onClick?: ?(SyntheticEvent<HTMLElement>) => mixed,
37
- className?: string,
38
38
  ariaLabel?: string,
39
39
  tabIndex?: number,
40
+ isLoading?: boolean,
41
+ ...
42
+ };
43
+
44
+ export type UnstyledButtonProps = {
45
+ ...BaseButtonProps,
46
+ className?: string,
40
47
  ...
41
48
  };
42
49
 
43
50
  export type ButtonProps = {
44
- onClick?: ?(SyntheticEvent<HTMLElement>) => mixed,
51
+ ...BaseButtonProps,
45
52
  classNames?: ClassNames,
46
53
  iconLeftName?: string,
47
54
  iconLeftType?: IconType,
48
55
  iconRightName?: string,
49
56
  iconRightType?: IconType,
50
- children?: React.Node,
51
57
  type?: ButtonType,
52
- actionType?: ButtonActionType,
53
58
  isFluid?: boolean,
54
- disabled?: boolean,
55
59
  size?: 'medium' | 'small',
56
- ariaLabel?: string,
57
- tabIndex?: number,
58
60
  ...
59
61
  };
60
62
 
@@ -66,6 +68,14 @@ const ButtonTypeToIconColorMap = {
66
68
  danger: 'inversePrimary',
67
69
  };
68
70
 
71
+ const ButtonTypeToLoaderColorMap = {
72
+ primary: 'colorTextInversePrimary',
73
+ secondary: 'colorTextClickable',
74
+ tertiary: 'colorTextPrimary',
75
+ ghost: 'colorTextPrimary',
76
+ danger: 'colorTextInversePrimary',
77
+ };
78
+
69
79
  export const UnstyledButton: React$AbstractComponent<
70
80
  UnstyledButtonProps,
71
81
  HTMLButtonElement,
@@ -78,9 +88,10 @@ export const UnstyledButton: React$AbstractComponent<
78
88
  ariaLabel,
79
89
  actionType,
80
90
  tabIndex = 0,
91
+ isLoading,
81
92
  ...props
82
93
  }: UnstyledButtonProps,
83
- ref: React.Ref<'button'>,
94
+ ref,
84
95
  ) => (
85
96
  <button
86
97
  {...props}
@@ -92,7 +103,7 @@ export const UnstyledButton: React$AbstractComponent<
92
103
  tabIndex={disabled ? -1 : tabIndex}
93
104
  type={actionType}
94
105
  onClick={(event) => {
95
- if (disabled) {
106
+ if (disabled || isLoading) {
96
107
  event.preventDefault();
97
108
  } else if (onClick) {
98
109
  onClick(event);
@@ -117,6 +128,7 @@ export const Button: React$AbstractComponent<ButtonProps, HTMLButtonElement> =
117
128
  disabled = false,
118
129
  actionType = 'button',
119
130
  size = 'medium',
131
+ isLoading,
120
132
  ...props
121
133
  }: ButtonProps,
122
134
  ref,
@@ -125,6 +137,7 @@ export const Button: React$AbstractComponent<ButtonProps, HTMLButtonElement> =
125
137
  {...props}
126
138
  actionType={actionType}
127
139
  disabled={disabled}
140
+ isLoading={isLoading}
128
141
  className={classify(
129
142
  css.button,
130
143
  {
@@ -149,18 +162,49 @@ export const Button: React$AbstractComponent<ButtonProps, HTMLButtonElement> =
149
162
  <div className={css.buttonRow}>
150
163
  {/* Has no icon, only child */}
151
164
  {!(iconLeftName || iconRightName) ? (
152
- <div className={css.textContainerCenter}>
153
- <Truncate>{children}</Truncate>
165
+ <div className={css.textContainer}>
166
+ {isLoading && (
167
+ <div className={css.loader}>
168
+ <CircularLoader
169
+ size={size}
170
+ colorToken={
171
+ disabled
172
+ ? 'colorTextDisabled'
173
+ : ButtonTypeToLoaderColorMap[type]
174
+ }
175
+ />
176
+ </div>
177
+ )}
178
+ <Truncate className={classify({[css.hidden]: isLoading})}>
179
+ {children}
180
+ </Truncate>
154
181
  </div>
155
182
  ) : // has icon, but no child
156
183
  children == null ? (
157
- <Icon
158
- name={iconLeftName || iconRightName}
159
- color={disabled ? 'disabled' : ButtonTypeToIconColorMap[type]}
160
- size={size === 'medium' ? 'medium' : 'small'}
161
- type={iconLeftName ? iconLeftType : iconRightType}
162
- className={classNames?.icon}
163
- />
184
+ <>
185
+ {isLoading && (
186
+ <div className={css.loader}>
187
+ <CircularLoader
188
+ size={size}
189
+ colorToken={
190
+ disabled
191
+ ? 'colorTextDisabled'
192
+ : ButtonTypeToLoaderColorMap[type]
193
+ }
194
+ />
195
+ </div>
196
+ )}
197
+ <Icon
198
+ name={iconLeftName || iconRightName}
199
+ color={disabled ? 'disabled' : ButtonTypeToIconColorMap[type]}
200
+ size={size === 'medium' ? 'medium' : 'small'}
201
+ type={iconLeftName ? iconLeftType : iconRightType}
202
+ className={classify(
203
+ {[css.hidden]: isLoading},
204
+ classNames?.icon,
205
+ )}
206
+ />
207
+ </>
164
208
  ) : (
165
209
  // has icon _and_ child
166
210
  (iconLeftName || iconRightName) && (
@@ -173,11 +217,28 @@ export const Button: React$AbstractComponent<ButtonProps, HTMLButtonElement> =
173
217
  }
174
218
  size={size === 'medium' ? 'medium' : 'small'}
175
219
  type={iconLeftType}
176
- className={classNames?.icon}
220
+ className={classify(
221
+ {[css.hidden]: isLoading},
222
+ classNames?.icon,
223
+ )}
177
224
  />
178
225
  )}
179
- <div className={css.textContainerLeft}>
180
- <Truncate>{children}</Truncate>
226
+ <div className={css.textContainer}>
227
+ {isLoading && (
228
+ <div className={css.loader}>
229
+ <CircularLoader
230
+ size={size}
231
+ colorToken={
232
+ disabled
233
+ ? 'colorTextDisabled'
234
+ : ButtonTypeToLoaderColorMap[type]
235
+ }
236
+ />
237
+ </div>
238
+ )}
239
+ <Truncate className={classify({[css.hidden]: isLoading})}>
240
+ {children}
241
+ </Truncate>
181
242
  </div>
182
243
  {iconRightName && (
183
244
  <Icon
@@ -187,7 +248,10 @@ export const Button: React$AbstractComponent<ButtonProps, HTMLButtonElement> =
187
248
  }
188
249
  size={size === 'medium' ? 'medium' : 'small'}
189
250
  type={iconRightType}
190
- className={classNames?.icon}
251
+ className={classify(
252
+ {[css.hidden]: isLoading},
253
+ classNames?.icon,
254
+ )}
191
255
  />
192
256
  )}
193
257
  </>
@@ -63,6 +63,7 @@ button {
63
63
 
64
64
  .button {
65
65
  composes: motionEaseInEaseOut from '../../styles/animation.module.css';
66
+ position: relative;
66
67
  display: flex;
67
68
  flex-direction: row;
68
69
  padding: spaceNone spaceMedium;
@@ -84,6 +85,11 @@ button {
84
85
  column-gap: spaceXSmall;
85
86
  }
86
87
 
88
+ .textContainer {
89
+ display: flex;
90
+ align-items: center;
91
+ }
92
+
87
93
  .withIconLeft {
88
94
  padding: spaceNone spaceMedium spaceNone spaceSmall;
89
95
  }
@@ -226,3 +232,11 @@ button {
226
232
  background-color: colorFillDisabled;
227
233
  border: initial;
228
234
  }
235
+
236
+ .hidden {
237
+ visibility: hidden;
238
+ }
239
+
240
+ .loader {
241
+ composes: absoluteCenter from '../../styles/utils.module.css';
242
+ }
@@ -12,7 +12,7 @@ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { de
12
12
  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); }
13
13
  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; }
14
14
  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); }
15
- const ButtonTab = _ref => {
15
+ const ButtonTab = /*#__PURE__*/React.forwardRef((_ref, ref) => {
16
16
  let {
17
17
  classNames,
18
18
  children,
@@ -29,6 +29,7 @@ const ButtonTab = _ref => {
29
29
  disabled: disabled,
30
30
  size: size,
31
31
  type: id === selectedButtonTabId ? 'tertiary' : 'ghost',
32
+ ref: ref,
32
33
  classNames: {
33
34
  wrapper: (0, _classify.default)(_ButtonTabModule.default.buttonTabWrapper, {
34
35
  [_ButtonTabModule.default.mediumButtonTab]: size === 'medium',
@@ -44,5 +45,5 @@ const ButtonTab = _ref => {
44
45
  iconLeftType: iconType,
45
46
  onClick: e => onButtonTabSelect && onButtonTabSelect(id, e)
46
47
  }), children);
47
- };
48
+ });
48
49
  exports.ButtonTab = ButtonTab;
@@ -23,45 +23,55 @@ export type ButtonTabProps = {
23
23
  ariaLabel?: string,
24
24
  id: string,
25
25
  selectedButtonTabId?: string,
26
+ isLoading?: boolean,
26
27
  ...
27
28
  };
28
29
 
29
- export const ButtonTab = ({
30
- classNames,
31
- children,
32
- iconName,
33
- iconType = 'regular',
34
- size,
35
- onButtonTabSelect,
36
- id,
37
- selectedButtonTabId,
38
- disabled,
39
- ...props
40
- }: ButtonTabProps): React.Node => (
41
- <Button
42
- {...props}
43
- disabled={disabled}
44
- size={size}
45
- type={id === selectedButtonTabId ? 'tertiary' : 'ghost'}
46
- classNames={{
47
- wrapper: classify(
48
- css.buttonTabWrapper,
49
- {
50
- [css.mediumButtonTab]: size === 'medium',
51
- [css.smallButtonTab]: size === 'small',
52
- [css.onlyIcon]: iconName && !children,
53
- [css.isSelected]: id === selectedButtonTabId,
54
- [css.isUnSelected]: id !== selectedButtonTabId,
55
- [css.disabled]: disabled,
56
- },
57
- classNames?.wrapper,
58
- ),
59
- icon: css.icon,
60
- }}
61
- iconLeftName={iconName}
62
- iconLeftType={iconType}
63
- onClick={(e) => onButtonTabSelect && onButtonTabSelect(id, e)}
64
- >
65
- {children}
66
- </Button>
30
+ export const ButtonTab: React$AbstractComponent<
31
+ ButtonTabProps,
32
+ HTMLButtonElement,
33
+ > = React.forwardRef<ButtonTabProps, HTMLButtonElement>(
34
+ (
35
+ {
36
+ classNames,
37
+ children,
38
+ iconName,
39
+ iconType = 'regular',
40
+ size,
41
+ onButtonTabSelect,
42
+ id,
43
+ selectedButtonTabId,
44
+ disabled,
45
+ ...props
46
+ }: ButtonTabProps,
47
+ ref,
48
+ ): React.Node => (
49
+ <Button
50
+ {...props}
51
+ disabled={disabled}
52
+ size={size}
53
+ type={id === selectedButtonTabId ? 'tertiary' : 'ghost'}
54
+ ref={ref}
55
+ classNames={{
56
+ wrapper: classify(
57
+ css.buttonTabWrapper,
58
+ {
59
+ [css.mediumButtonTab]: size === 'medium',
60
+ [css.smallButtonTab]: size === 'small',
61
+ [css.onlyIcon]: iconName && !children,
62
+ [css.isSelected]: id === selectedButtonTabId,
63
+ [css.isUnSelected]: id !== selectedButtonTabId,
64
+ [css.disabled]: disabled,
65
+ },
66
+ classNames?.wrapper,
67
+ ),
68
+ icon: css.icon,
69
+ }}
70
+ iconLeftName={iconName}
71
+ iconLeftType={iconType}
72
+ onClick={(e) => onButtonTabSelect && onButtonTabSelect(id, e)}
73
+ >
74
+ {children}
75
+ </Button>
76
+ ),
67
77
  );