@zohodesk/components 1.6.8 → 1.6.11
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/README.md +7 -0
- package/assets/Appearance/dark/mode/Component_v1_DarkMode.module.css +68 -0
- package/assets/Appearance/light/mode/Component_v1_LightMode.module.css +68 -0
- package/assets/Appearance/pureDark/mode/Component_v1_PureDarkMode.module.css +68 -0
- package/es/Buttongroup/Buttongroup.module.css +10 -30
- package/es/CheckBox/CheckBox.module.css +3 -10
- package/es/DateTime/DateTime.module.css +22 -35
- package/es/DateTime/YearView.module.css +8 -10
- package/es/DropBox/DropBoxElement/css/DropBoxElement.module.css +3 -2
- package/es/DropDown/DropDown.module.css +2 -1
- package/es/DropDown/DropDownItem.module.css +1 -8
- package/es/DropDown/DropDownSeparator.module.css +2 -1
- package/es/ListItem/ListItem.module.css +4 -15
- package/es/MultiSelect/MobileHeader/MobileHeader.module.css +3 -2
- package/es/MultiSelect/MultiSelect.module.css +21 -34
- package/es/MultiSelect/SelectedOptions.module.css +6 -10
- package/es/Radio/Radio.module.css +3 -3
- package/es/ResponsiveDropBox/ResponsiveDropBox.module.css +1 -1
- package/es/Ribbon/Ribbon.module.css +9 -12
- package/es/Select/Select.module.css +22 -17
- package/es/Switch/Switch.module.css +1 -8
- package/es/Tab/Tab.module.css +8 -15
- package/es/Tab/Tabs.module.css +12 -22
- package/es/Tag/Tag.module.css +4 -3
- package/es/Tooltip/Tooltip.module.css +3 -2
- package/es/shared/ArrowIcon/ArrowIcon.module.css +3 -2
- package/es/v1/Button/Button.js +201 -0
- package/es/v1/Button/README.md +110 -0
- package/es/v1/Button/__tests__/Button.spec.js +272 -0
- package/es/v1/Button/__tests__/__snapshots__/Button.spec.js.snap +1160 -0
- package/es/v1/Button/_shared/Loader/Loader.js +33 -0
- package/es/v1/Button/_shared/Loader/Loader.module.css +42 -0
- package/es/v1/Button/_shared/Loader/__tests__/Loader.spec.js +21 -0
- package/es/v1/Button/_shared/Loader/__tests__/__snapshots__/Loader.spec.js.snap +49 -0
- package/es/v1/Button/_shared/Loader/props/defaultProps.js +4 -0
- package/es/v1/Button/_shared/Loader/props/propTypes.js +7 -0
- package/es/v1/Button/_shared/SuccessTick/SuccessTick.js +25 -0
- package/es/v1/Button/_shared/SuccessTick/SuccessTick.module.css +21 -0
- package/es/v1/Button/_shared/SuccessTick/__tests__/SuccessTick.spec.js +21 -0
- package/es/v1/Button/_shared/SuccessTick/__tests__/__snapshots__/SuccessTick.spec.js.snap +31 -0
- package/es/v1/Button/_shared/SuccessTick/props/defaultProps.js +4 -0
- package/es/v1/Button/_shared/SuccessTick/props/propTypes.js +7 -0
- package/es/v1/Button/constants/index.js +82 -0
- package/es/v1/Button/css/Button_v1.module.css +119 -0
- package/es/v1/Button/css/cssJSLogic.js +96 -0
- package/es/v1/Button/index.js +2 -0
- package/es/v1/Button/props/defaultProps.js +26 -0
- package/es/v1/Button/props/propTypes.js +43 -0
- package/es/v1/helpers/colorHelpers/background/backgroundColor.module.css +629 -0
- package/es/v1/helpers/colorHelpers/border/borderColor.module.css +489 -0
- package/es/v1/helpers/colorHelpers/colorHelper.js +176 -0
- package/es/v1/helpers/colorHelpers/constants/index.js +79 -0
- package/es/v1/helpers/colorHelpers/index.js +4 -0
- package/es/v1/helpers/colorHelpers/paletteUtilities.README.md +415 -0
- package/es/v1/helpers/colorHelpers/text/textColor.module.css +368 -0
- package/lib/Buttongroup/Buttongroup.module.css +10 -30
- package/lib/CheckBox/CheckBox.module.css +3 -10
- package/lib/DateTime/DateTime.module.css +22 -35
- package/lib/DateTime/YearView.module.css +8 -10
- package/lib/DropBox/DropBoxElement/css/DropBoxElement.module.css +3 -2
- package/lib/DropDown/DropDown.module.css +2 -1
- package/lib/DropDown/DropDownItem.module.css +1 -8
- package/lib/DropDown/DropDownSeparator.module.css +2 -1
- package/lib/ListItem/ListItem.module.css +4 -15
- package/lib/MultiSelect/MobileHeader/MobileHeader.module.css +3 -2
- package/lib/MultiSelect/MultiSelect.module.css +21 -34
- package/lib/MultiSelect/SelectedOptions.module.css +6 -10
- package/lib/Radio/Radio.module.css +3 -3
- package/lib/ResponsiveDropBox/ResponsiveDropBox.module.css +1 -1
- package/lib/Ribbon/Ribbon.module.css +9 -12
- package/lib/Select/Select.module.css +22 -17
- package/lib/Switch/Switch.module.css +1 -8
- package/lib/Tab/Tab.module.css +8 -15
- package/lib/Tab/Tabs.module.css +12 -22
- package/lib/Tag/Tag.module.css +4 -3
- package/lib/Tooltip/Tooltip.module.css +3 -2
- package/lib/shared/ArrowIcon/ArrowIcon.module.css +3 -2
- package/lib/v1/Button/Button.js +239 -0
- package/lib/v1/Button/README.md +110 -0
- package/lib/v1/Button/__tests__/Button.spec.js +293 -0
- package/lib/v1/Button/__tests__/__snapshots__/Button.spec.js.snap +1160 -0
- package/lib/v1/Button/_shared/Loader/Loader.js +43 -0
- package/lib/v1/Button/_shared/Loader/Loader.module.css +42 -0
- package/lib/v1/Button/_shared/Loader/__tests__/Loader.spec.js +28 -0
- package/lib/v1/Button/_shared/Loader/__tests__/__snapshots__/Loader.spec.js.snap +49 -0
- package/lib/v1/Button/_shared/Loader/props/defaultProps.js +11 -0
- package/lib/v1/Button/_shared/Loader/props/propTypes.js +18 -0
- package/lib/v1/Button/_shared/SuccessTick/SuccessTick.js +35 -0
- package/lib/v1/Button/_shared/SuccessTick/SuccessTick.module.css +21 -0
- package/lib/v1/Button/_shared/SuccessTick/__tests__/SuccessTick.spec.js +28 -0
- package/lib/v1/Button/_shared/SuccessTick/__tests__/__snapshots__/SuccessTick.spec.js.snap +31 -0
- package/lib/v1/Button/_shared/SuccessTick/props/defaultProps.js +11 -0
- package/lib/v1/Button/_shared/SuccessTick/props/propTypes.js +18 -0
- package/lib/v1/Button/constants/index.js +114 -0
- package/lib/v1/Button/css/Button_v1.module.css +119 -0
- package/lib/v1/Button/css/cssJSLogic.js +88 -0
- package/lib/v1/Button/index.js +21 -0
- package/lib/v1/Button/props/defaultProps.js +36 -0
- package/lib/v1/Button/props/propTypes.js +56 -0
- package/lib/v1/helpers/colorHelpers/background/backgroundColor.module.css +629 -0
- package/lib/v1/helpers/colorHelpers/border/borderColor.module.css +489 -0
- package/lib/v1/helpers/colorHelpers/colorHelper.js +190 -0
- package/lib/v1/helpers/colorHelpers/constants/index.js +87 -0
- package/lib/v1/helpers/colorHelpers/index.js +57 -0
- package/lib/v1/helpers/colorHelpers/paletteUtilities.README.md +415 -0
- package/lib/v1/helpers/colorHelpers/text/textColor.module.css +368 -0
- package/package.json +4 -4
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
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); }
|
|
2
|
+
|
|
3
|
+
import React, { forwardRef, memo, useMemo } from 'react';
|
|
4
|
+
import { withComponentRegistrar } from '@zohodesk/dotkit/es/react/ComponentRegistry';
|
|
5
|
+
import Icon from '@zohodesk/icons/es/Icon';
|
|
6
|
+
import Flex from '@zohodesk/layout/es/Flex/Flex';
|
|
7
|
+
import Typography from "../../Typography/Typography";
|
|
8
|
+
import { isRenderable } from '@zohodesk/utils/es/renderNode';
|
|
9
|
+
import renderNode from '@zohodesk/utils/es/renderNode';
|
|
10
|
+
import propTypes from "./props/propTypes";
|
|
11
|
+
import defaultProps from "./props/defaultProps";
|
|
12
|
+
import { DUMMY_OBJECT } from '@zohodesk/dotkit/es/utils/constants';
|
|
13
|
+
import { ICON_PLACEMENT, LOADER_PLACEMENT, STATUS, TYPOGRAPHY_SIZE_MAP, VARIANT } from "./constants";
|
|
14
|
+
import Loader from "./_shared/Loader/Loader";
|
|
15
|
+
import SuccessTick from "./_shared/SuccessTick/SuccessTick";
|
|
16
|
+
import cssJSLogic from "./css/cssJSLogic";
|
|
17
|
+
|
|
18
|
+
const getTypographySize = size => TYPOGRAPHY_SIZE_MAP[size] || '13';
|
|
19
|
+
|
|
20
|
+
const Button = /*#__PURE__*/forwardRef(function Button(props, ref) {
|
|
21
|
+
const {
|
|
22
|
+
palette,
|
|
23
|
+
bgAppearance,
|
|
24
|
+
borderAppearance,
|
|
25
|
+
variant,
|
|
26
|
+
status,
|
|
27
|
+
loaderPlacement,
|
|
28
|
+
size,
|
|
29
|
+
iconName,
|
|
30
|
+
iconSize,
|
|
31
|
+
iconPlacement,
|
|
32
|
+
renderIcon,
|
|
33
|
+
renderBefore,
|
|
34
|
+
renderAfter,
|
|
35
|
+
renderLoader,
|
|
36
|
+
renderSuccess,
|
|
37
|
+
children,
|
|
38
|
+
type,
|
|
39
|
+
onClick,
|
|
40
|
+
isDisabled,
|
|
41
|
+
isReadOnly,
|
|
42
|
+
isSelected,
|
|
43
|
+
shape,
|
|
44
|
+
paletteShade,
|
|
45
|
+
disabledAppearance,
|
|
46
|
+
title,
|
|
47
|
+
customProps,
|
|
48
|
+
customAttributes,
|
|
49
|
+
a11yAttributes,
|
|
50
|
+
customId,
|
|
51
|
+
testId
|
|
52
|
+
} = props;
|
|
53
|
+
const isLoading = status === STATUS.LOADING;
|
|
54
|
+
const isSuccess = status === STATUS.SUCCESS;
|
|
55
|
+
const isDisabledState = isDisabled || isLoading;
|
|
56
|
+
const isInteractionDisabled = isDisabledState || isReadOnly;
|
|
57
|
+
const overlayActive = (isLoading || isSuccess) && loaderPlacement === LOADER_PLACEMENT.OVERLAY;
|
|
58
|
+
const {
|
|
59
|
+
text: contentProps = DUMMY_OBJECT,
|
|
60
|
+
icon: iconProps = DUMMY_OBJECT
|
|
61
|
+
} = customProps;
|
|
62
|
+
const iconTagAttributes = useMemo(() => ({ ...(iconProps.tagAttributes || DUMMY_OBJECT),
|
|
63
|
+
'data-test-id': testId ? `${testId}_icon` : undefined
|
|
64
|
+
}), [iconProps.tagAttributes, testId]);
|
|
65
|
+
const classes = useMemo(() => cssJSLogic({
|
|
66
|
+
props
|
|
67
|
+
}), [palette, bgAppearance, borderAppearance, paletteShade, size, variant, status, isDisabled, isReadOnly, isSelected, shape, loaderPlacement, disabledAppearance, props.customClass]);
|
|
68
|
+
const {
|
|
69
|
+
loaderOverlayClass,
|
|
70
|
+
successOverlayClass,
|
|
71
|
+
contentWrapperClass,
|
|
72
|
+
textClassName,
|
|
73
|
+
buttonClassName
|
|
74
|
+
} = classes;
|
|
75
|
+
const showIcon = variant !== VARIANT.TEXT && (renderIcon || iconName);
|
|
76
|
+
|
|
77
|
+
const _handleClick = event => {
|
|
78
|
+
if (isInteractionDisabled) {
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
onClick(event);
|
|
83
|
+
};
|
|
84
|
+
|
|
85
|
+
const _renderLoader = () => {
|
|
86
|
+
if (!isLoading) {
|
|
87
|
+
return null;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
if (isRenderable(renderLoader)) {
|
|
91
|
+
return renderNode(renderLoader, {
|
|
92
|
+
status
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
const loaderClassName = loaderPlacement === LOADER_PLACEMENT.OVERLAY ? loaderOverlayClass : '';
|
|
97
|
+
return /*#__PURE__*/React.createElement(Flex, {
|
|
98
|
+
$ui_displayMode: "flex",
|
|
99
|
+
$ui_alignItems: "center",
|
|
100
|
+
$ui_justifyContent: "center",
|
|
101
|
+
$ui_className: loaderClassName,
|
|
102
|
+
testId: testId ? `${testId}_loader` : undefined
|
|
103
|
+
}, /*#__PURE__*/React.createElement(Loader, null));
|
|
104
|
+
};
|
|
105
|
+
|
|
106
|
+
const _renderSuccess = () => {
|
|
107
|
+
if (!isSuccess) {
|
|
108
|
+
return null;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
if (isRenderable(renderSuccess)) {
|
|
112
|
+
return renderNode(renderSuccess, {
|
|
113
|
+
status
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
const successClassName = loaderPlacement === LOADER_PLACEMENT.OVERLAY ? successOverlayClass : '';
|
|
118
|
+
return /*#__PURE__*/React.createElement(Flex, {
|
|
119
|
+
$ui_displayMode: "flex",
|
|
120
|
+
$ui_alignItems: "center",
|
|
121
|
+
$ui_justifyContent: "center",
|
|
122
|
+
$ui_className: successClassName,
|
|
123
|
+
testId: testId ? `${testId}_success` : undefined
|
|
124
|
+
}, /*#__PURE__*/React.createElement(SuccessTick, null));
|
|
125
|
+
};
|
|
126
|
+
|
|
127
|
+
const _renderIconNode = () => {
|
|
128
|
+
if (!showIcon) {
|
|
129
|
+
return null;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
if (isRenderable(renderIcon)) {
|
|
133
|
+
return renderNode(renderIcon);
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
return /*#__PURE__*/React.createElement(Icon, _extends({}, iconProps, {
|
|
137
|
+
name: iconName,
|
|
138
|
+
size: iconSize,
|
|
139
|
+
tagAttributes: iconTagAttributes,
|
|
140
|
+
dataId: testId ? `${testId}_icon` : undefined
|
|
141
|
+
}));
|
|
142
|
+
};
|
|
143
|
+
|
|
144
|
+
const _renderBeforeNode = () => {
|
|
145
|
+
if (!isRenderable(renderBefore)) {
|
|
146
|
+
return null;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
return renderNode(renderBefore, props);
|
|
150
|
+
};
|
|
151
|
+
|
|
152
|
+
const _renderAfterNode = () => {
|
|
153
|
+
if (!isRenderable(renderAfter)) {
|
|
154
|
+
return null;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
return renderNode(renderAfter, props);
|
|
158
|
+
};
|
|
159
|
+
|
|
160
|
+
const _renderContent = () => {
|
|
161
|
+
const shouldShowText = variant !== VARIANT.ICON && children !== undefined && children !== null;
|
|
162
|
+
const showLoaderStart = isLoading && loaderPlacement === LOADER_PLACEMENT.START;
|
|
163
|
+
const showLoaderAfter = isLoading && loaderPlacement === LOADER_PLACEMENT.END;
|
|
164
|
+
const showSuccessStart = isSuccess && loaderPlacement === LOADER_PLACEMENT.START;
|
|
165
|
+
const showSuccessAfter = isSuccess && loaderPlacement === LOADER_PLACEMENT.END;
|
|
166
|
+
return /*#__PURE__*/React.createElement(Flex, {
|
|
167
|
+
$ui_displayMode: "flex",
|
|
168
|
+
$ui_direction: "row",
|
|
169
|
+
$flag_shrink: true,
|
|
170
|
+
$ui_alignItems: "center",
|
|
171
|
+
$ui_justifyContent: "center",
|
|
172
|
+
$ui_className: contentWrapperClass
|
|
173
|
+
}, showLoaderStart ? _renderLoader() : null, showSuccessStart ? _renderSuccess() : null, _renderBeforeNode(), iconPlacement === ICON_PLACEMENT.LEFT ? _renderIconNode() : null, shouldShowText ? /*#__PURE__*/React.createElement(Typography, _extends({}, contentProps, {
|
|
174
|
+
$ui_className: textClassName,
|
|
175
|
+
$ui_size: getTypographySize(size),
|
|
176
|
+
$flag_dotted: variant !== VARIANT.ICON
|
|
177
|
+
}), children) : null, iconPlacement === ICON_PLACEMENT.RIGHT ? _renderIconNode() : null, _renderAfterNode(), showLoaderAfter ? _renderLoader() : null, showSuccessAfter ? _renderSuccess() : null);
|
|
178
|
+
};
|
|
179
|
+
|
|
180
|
+
const containerAttributes = { ...customAttributes,
|
|
181
|
+
'data-id': customId,
|
|
182
|
+
'data-test-id': testId,
|
|
183
|
+
'data-title': title
|
|
184
|
+
};
|
|
185
|
+
return /*#__PURE__*/React.createElement("button", _extends({}, containerAttributes, a11yAttributes, {
|
|
186
|
+
ref: ref,
|
|
187
|
+
type: type,
|
|
188
|
+
className: buttonClassName,
|
|
189
|
+
"aria-busy": isLoading,
|
|
190
|
+
"aria-disabled": isDisabledState,
|
|
191
|
+
"aria-readonly": isReadOnly,
|
|
192
|
+
"aria-pressed": isSelected,
|
|
193
|
+
onClick: _handleClick
|
|
194
|
+
}), _renderContent(), overlayActive ? isLoading ? _renderLoader() : _renderSuccess() : null);
|
|
195
|
+
});
|
|
196
|
+
Button.propTypes = propTypes;
|
|
197
|
+
Button.defaultProps = defaultProps;
|
|
198
|
+
Button.displayName = 'Button';
|
|
199
|
+
export default withComponentRegistrar( /*#__PURE__*/memo(Button), {
|
|
200
|
+
name: 'ZDC_V1_Button'
|
|
201
|
+
});
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
# Button
|
|
2
|
+
|
|
3
|
+
A composable button component with palette-based theming, loading/success status states, and flexible icon/content slots.
|
|
4
|
+
|
|
5
|
+
## Import
|
|
6
|
+
|
|
7
|
+
```jsx
|
|
8
|
+
import Button from '@zohodesk/components/es/v1/Button/Button';
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Usage
|
|
12
|
+
|
|
13
|
+
### Default
|
|
14
|
+
|
|
15
|
+
```jsx
|
|
16
|
+
<Button customId="saveBtn" testId="saveBtn">
|
|
17
|
+
Save changes
|
|
18
|
+
</Button>
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
### With Palette Variants
|
|
22
|
+
|
|
23
|
+
```jsx
|
|
24
|
+
<Button palette="primary">Save</Button>
|
|
25
|
+
<Button palette="danger">Delete</Button>
|
|
26
|
+
<Button palette="success">Confirm</Button>
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
### With Icon
|
|
30
|
+
|
|
31
|
+
```jsx
|
|
32
|
+
<Button variant="icon" iconName="ZD-plus" iconSize={20} />
|
|
33
|
+
|
|
34
|
+
<Button variant="iconWithText" iconName="ZD-plus" iconPlacement="left">
|
|
35
|
+
Add Item
|
|
36
|
+
</Button>
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
### Loading State
|
|
40
|
+
|
|
41
|
+
```jsx
|
|
42
|
+
<Button status="loading" loaderPlacement="overlay">
|
|
43
|
+
Saving...
|
|
44
|
+
</Button>
|
|
45
|
+
|
|
46
|
+
<Button status="loading" loaderPlacement="start">
|
|
47
|
+
Loading
|
|
48
|
+
</Button>
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
### Disabled / Read Only
|
|
52
|
+
|
|
53
|
+
```jsx
|
|
54
|
+
<Button isDisabled>Disabled</Button>
|
|
55
|
+
<Button isReadOnly>Read Only</Button>
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
## Props
|
|
59
|
+
|
|
60
|
+
| Prop | Type | Default | Description |
|
|
61
|
+
|---|---|---|---|
|
|
62
|
+
| `customId` | `string` | — | `data-id` attribute for automation |
|
|
63
|
+
| `testId` | `string` | — | `data-test-id` attribute for testing |
|
|
64
|
+
| `palette` | `oneOf: default, primary, secondary, danger, success` | `default` | Color palette |
|
|
65
|
+
| `bgAppearance` | `oneOf: filled, onHover, none` | `filled` | Background behavior |
|
|
66
|
+
| `borderAppearance` | `oneOf: default, onHover, none` | `default` | Border behavior |
|
|
67
|
+
| `variant` | `oneOf: text, icon, iconWithText` | `text` | Display variant |
|
|
68
|
+
| `size` | `oneOf: small, medium, large, full` | `medium` | Size variant |
|
|
69
|
+
| `status` | `oneOf: default, loading, success` | `default` | Status state |
|
|
70
|
+
| `loaderPlacement` | `oneOf: start, end, overlay` | `overlay` | Where loader appears |
|
|
71
|
+
| `iconName` | `string` | — | Icon name from `@zohodesk/icons` |
|
|
72
|
+
| `iconSize` | `number` | `16` | Icon size in pixels |
|
|
73
|
+
| `iconPlacement` | `oneOf: left, right` | `left` | Icon position relative to text |
|
|
74
|
+
| `paletteShade` | `oneOf: default, lighter` | `default` | Shade variant |
|
|
75
|
+
| `disabledAppearance` | `oneOf: none, dull, strike` | `dull` | Disabled visual style |
|
|
76
|
+
| `renderIcon` | `node \| func` | — | Custom icon render slot |
|
|
77
|
+
| `renderBefore` | `node \| func` | — | Slot before main content |
|
|
78
|
+
| `renderAfter` | `node \| func` | — | Slot after main content |
|
|
79
|
+
| `renderLoader` | `node \| func` | — | Custom loader render slot |
|
|
80
|
+
| `renderSuccess` | `node \| func` | — | Custom success render slot |
|
|
81
|
+
| `children` | `node` | — | Button text content |
|
|
82
|
+
| `type` | `oneOf: button, submit, reset` | `button` | HTML button type |
|
|
83
|
+
| `onClick` | `func` | — | Click event handler |
|
|
84
|
+
| `isDisabled` | `bool` | `false` | Disables the button |
|
|
85
|
+
| `isReadOnly` | `bool` | `false` | Read-only state |
|
|
86
|
+
| `isSelected` | `bool` | `false` | Selected/pressed state |
|
|
87
|
+
| `isRounded` | `bool` | `false` | Rounded border radius |
|
|
88
|
+
| `title` | `string` | — | Title/tooltip text |
|
|
89
|
+
|
|
90
|
+
## Customization
|
|
91
|
+
|
|
92
|
+
### Parts
|
|
93
|
+
|
|
94
|
+
| Part | Element | Description |
|
|
95
|
+
|---|---|---|
|
|
96
|
+
| `wrapper` | `<button>` root | The outermost button element |
|
|
97
|
+
| `text` | Typography | The text label |
|
|
98
|
+
|
|
99
|
+
### CSS Custom Properties
|
|
100
|
+
|
|
101
|
+
The `.varClass` block in `Button.module.css` defines local custom properties that size variants override:
|
|
102
|
+
|
|
103
|
+
| Property | Default | Description |
|
|
104
|
+
|---|---|---|
|
|
105
|
+
| `--local-Button-radius` | `4px` | Border radius |
|
|
106
|
+
| `--local-Button-gap` | `8px` | Content gap |
|
|
107
|
+
| `--local-Button-padding-block` | `6px` | Block padding |
|
|
108
|
+
| `--local-Button-padding-inline` | `15px` | Inline padding |
|
|
109
|
+
| `--local-Button-min-width` | `90px` | Minimum width |
|
|
110
|
+
| `--local-Button-spinner-size` | `16px` | Spinner/tick size |
|
|
@@ -0,0 +1,272 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { cleanup, render, screen } from '@testing-library/react';
|
|
3
|
+
import userEvent from '@testing-library/user-event';
|
|
4
|
+
import Button from "../Button";
|
|
5
|
+
import '@testing-library/jest-dom';
|
|
6
|
+
afterEach(() => {
|
|
7
|
+
cleanup();
|
|
8
|
+
});
|
|
9
|
+
describe('Button - Component', () => {
|
|
10
|
+
test('Should render with the basic set of default props', () => {
|
|
11
|
+
const {
|
|
12
|
+
asFragment
|
|
13
|
+
} = render( /*#__PURE__*/React.createElement(Button, null));
|
|
14
|
+
expect(asFragment()).toMatchSnapshot();
|
|
15
|
+
});
|
|
16
|
+
test('Should render with children', () => {
|
|
17
|
+
const {
|
|
18
|
+
asFragment
|
|
19
|
+
} = render( /*#__PURE__*/React.createElement(Button, null, "Click Me"));
|
|
20
|
+
expect(asFragment()).toMatchSnapshot();
|
|
21
|
+
});
|
|
22
|
+
const palette = ['default', 'primary', 'secondary', 'danger', 'success'];
|
|
23
|
+
test.each(palette)('Should render palette of buttons - %s', palette => {
|
|
24
|
+
const {
|
|
25
|
+
asFragment
|
|
26
|
+
} = render( /*#__PURE__*/React.createElement(Button, {
|
|
27
|
+
palette: palette
|
|
28
|
+
}));
|
|
29
|
+
expect(asFragment()).toMatchSnapshot();
|
|
30
|
+
});
|
|
31
|
+
const bgAppearance = ['default', 'onHover', 'none'];
|
|
32
|
+
test.each(bgAppearance)('Should render bgAppearance of buttons - %s', bg => {
|
|
33
|
+
const {
|
|
34
|
+
asFragment
|
|
35
|
+
} = render( /*#__PURE__*/React.createElement(Button, {
|
|
36
|
+
bgAppearance: bg
|
|
37
|
+
}));
|
|
38
|
+
expect(asFragment()).toMatchSnapshot();
|
|
39
|
+
});
|
|
40
|
+
const borderAppearance = ['default', 'onHover', 'none'];
|
|
41
|
+
test.each(borderAppearance)('Should render borderAppearance of buttons - %s', border => {
|
|
42
|
+
const {
|
|
43
|
+
asFragment
|
|
44
|
+
} = render( /*#__PURE__*/React.createElement(Button, {
|
|
45
|
+
borderAppearance: border
|
|
46
|
+
}));
|
|
47
|
+
expect(asFragment()).toMatchSnapshot();
|
|
48
|
+
});
|
|
49
|
+
const variant = ['text', 'icon', 'iconWithText'];
|
|
50
|
+
test.each(variant)('Should render variant of buttons - %s', variant => {
|
|
51
|
+
const {
|
|
52
|
+
asFragment
|
|
53
|
+
} = render( /*#__PURE__*/React.createElement(Button, {
|
|
54
|
+
variant: variant
|
|
55
|
+
}));
|
|
56
|
+
expect(asFragment()).toMatchSnapshot();
|
|
57
|
+
});
|
|
58
|
+
const size = ['small', 'medium', 'large', 'full'];
|
|
59
|
+
test.each(size)('Should render Sizes of buttons - %s', size => {
|
|
60
|
+
const {
|
|
61
|
+
asFragment
|
|
62
|
+
} = render( /*#__PURE__*/React.createElement(Button, {
|
|
63
|
+
size: size
|
|
64
|
+
}));
|
|
65
|
+
expect(asFragment()).toMatchSnapshot();
|
|
66
|
+
});
|
|
67
|
+
const status = ['default', 'loading', 'success'];
|
|
68
|
+
test.each(status)('Should render Status of buttons - %s', status => {
|
|
69
|
+
const {
|
|
70
|
+
asFragment
|
|
71
|
+
} = render( /*#__PURE__*/React.createElement(Button, {
|
|
72
|
+
status: status
|
|
73
|
+
}));
|
|
74
|
+
expect(asFragment()).toMatchSnapshot();
|
|
75
|
+
});
|
|
76
|
+
const loaderPlacement = ['start', 'end', 'overlay'];
|
|
77
|
+
test.each(loaderPlacement)('Should render loaderPlacement of buttons - %s', loaderPlacement => {
|
|
78
|
+
const {
|
|
79
|
+
asFragment
|
|
80
|
+
} = render( /*#__PURE__*/React.createElement(Button, {
|
|
81
|
+
status: "loading",
|
|
82
|
+
loaderPlacement: loaderPlacement
|
|
83
|
+
}));
|
|
84
|
+
expect(asFragment()).toMatchSnapshot();
|
|
85
|
+
});
|
|
86
|
+
test('Should render with iconName and iconSize ', () => {
|
|
87
|
+
const {
|
|
88
|
+
asFragment
|
|
89
|
+
} = render( /*#__PURE__*/React.createElement(Button, {
|
|
90
|
+
variant: "icon",
|
|
91
|
+
iconName: "ZD-plus",
|
|
92
|
+
iconSize: 20
|
|
93
|
+
}));
|
|
94
|
+
expect(asFragment()).toMatchSnapshot();
|
|
95
|
+
});
|
|
96
|
+
test('Should render with iconPlacement ', () => {
|
|
97
|
+
const {
|
|
98
|
+
asFragment
|
|
99
|
+
} = render( /*#__PURE__*/React.createElement(Button, {
|
|
100
|
+
variant: "iconWithText",
|
|
101
|
+
iconName: "ZD-plus",
|
|
102
|
+
iconPlacement: "right"
|
|
103
|
+
}, "Button"));
|
|
104
|
+
expect(asFragment()).toMatchSnapshot();
|
|
105
|
+
});
|
|
106
|
+
test('Should render with renderIcon', () => {
|
|
107
|
+
const {
|
|
108
|
+
asFragment
|
|
109
|
+
} = render( /*#__PURE__*/React.createElement(Button, {
|
|
110
|
+
variant: "icon",
|
|
111
|
+
renderIcon: () => /*#__PURE__*/React.createElement("span", null, "CustomIcon")
|
|
112
|
+
}));
|
|
113
|
+
expect(asFragment()).toMatchSnapshot();
|
|
114
|
+
});
|
|
115
|
+
test('Should render with renderBefore and renderAfter', () => {
|
|
116
|
+
const {
|
|
117
|
+
asFragment
|
|
118
|
+
} = render( /*#__PURE__*/React.createElement(Button, {
|
|
119
|
+
renderBefore: () => /*#__PURE__*/React.createElement("span", null, "Before"),
|
|
120
|
+
renderAfter: () => /*#__PURE__*/React.createElement("span", null, "After")
|
|
121
|
+
}, "Button"));
|
|
122
|
+
expect(asFragment()).toMatchSnapshot();
|
|
123
|
+
});
|
|
124
|
+
test('Should render with renderLoader', () => {
|
|
125
|
+
const {
|
|
126
|
+
asFragment
|
|
127
|
+
} = render( /*#__PURE__*/React.createElement(Button, {
|
|
128
|
+
status: "loading",
|
|
129
|
+
renderLoader: () => /*#__PURE__*/React.createElement("span", null, "Loading...")
|
|
130
|
+
}));
|
|
131
|
+
expect(asFragment()).toMatchSnapshot();
|
|
132
|
+
});
|
|
133
|
+
test('Should render with renderSuccess', () => {
|
|
134
|
+
const {
|
|
135
|
+
asFragment
|
|
136
|
+
} = render( /*#__PURE__*/React.createElement(Button, {
|
|
137
|
+
status: "success",
|
|
138
|
+
renderSuccess: () => /*#__PURE__*/React.createElement("span", null, "Success!")
|
|
139
|
+
}));
|
|
140
|
+
expect(asFragment()).toMatchSnapshot();
|
|
141
|
+
});
|
|
142
|
+
const type = ['button', 'submit', 'reset'];
|
|
143
|
+
test.each(type)('Should render type of buttons - %s', type => {
|
|
144
|
+
const {
|
|
145
|
+
asFragment
|
|
146
|
+
} = render( /*#__PURE__*/React.createElement(Button, {
|
|
147
|
+
type: type
|
|
148
|
+
}));
|
|
149
|
+
expect(asFragment()).toMatchSnapshot();
|
|
150
|
+
});
|
|
151
|
+
test('Should trigger onClick function', () => {
|
|
152
|
+
const onClick = jest.fn();
|
|
153
|
+
const {
|
|
154
|
+
getByRole
|
|
155
|
+
} = render( /*#__PURE__*/React.createElement(Button, {
|
|
156
|
+
onClick: onClick
|
|
157
|
+
}));
|
|
158
|
+
userEvent.click(getByRole('button'));
|
|
159
|
+
expect(onClick).toHaveBeenCalled();
|
|
160
|
+
});
|
|
161
|
+
test('Should be disabled when isDisabled prop is true', () => {
|
|
162
|
+
const {
|
|
163
|
+
asFragment
|
|
164
|
+
} = render( /*#__PURE__*/React.createElement(Button, {
|
|
165
|
+
isDisabled: true
|
|
166
|
+
}));
|
|
167
|
+
expect(asFragment()).toMatchSnapshot();
|
|
168
|
+
});
|
|
169
|
+
test('Should render with readOnly style when isReadOnly prop is true', () => {
|
|
170
|
+
const {
|
|
171
|
+
asFragment
|
|
172
|
+
} = render( /*#__PURE__*/React.createElement(Button, {
|
|
173
|
+
isReadOnly: true
|
|
174
|
+
}));
|
|
175
|
+
expect(asFragment()).toMatchSnapshot();
|
|
176
|
+
});
|
|
177
|
+
test('Should render with selected style when isSelected prop is true', () => {
|
|
178
|
+
const {
|
|
179
|
+
asFragment
|
|
180
|
+
} = render( /*#__PURE__*/React.createElement(Button, {
|
|
181
|
+
isSelected: true
|
|
182
|
+
}));
|
|
183
|
+
expect(asFragment()).toMatchSnapshot();
|
|
184
|
+
});
|
|
185
|
+
const shape = ['pill', 'rectangle', 'roundedRectangle'];
|
|
186
|
+
test.each(shape)('Should render shape of buttons - %s', shape => {
|
|
187
|
+
const {
|
|
188
|
+
asFragment
|
|
189
|
+
} = render( /*#__PURE__*/React.createElement(Button, {
|
|
190
|
+
shape: shape
|
|
191
|
+
}));
|
|
192
|
+
expect(asFragment()).toMatchSnapshot();
|
|
193
|
+
});
|
|
194
|
+
const paletteShade = ['default', 'lighter'];
|
|
195
|
+
test.each(paletteShade)('Should render paletteShade of buttons - %s', shade => {
|
|
196
|
+
const {
|
|
197
|
+
asFragment
|
|
198
|
+
} = render( /*#__PURE__*/React.createElement(Button, {
|
|
199
|
+
paletteShade: shade
|
|
200
|
+
}));
|
|
201
|
+
expect(asFragment()).toMatchSnapshot();
|
|
202
|
+
});
|
|
203
|
+
const disabledAppearance = ['none', 'dull', 'strike'];
|
|
204
|
+
test.each(disabledAppearance)('Should render disabledAppearance of buttons - %s', style => {
|
|
205
|
+
const {
|
|
206
|
+
asFragment
|
|
207
|
+
} = render( /*#__PURE__*/React.createElement(Button, {
|
|
208
|
+
isDisabled: true,
|
|
209
|
+
disabledAppearance: style
|
|
210
|
+
}));
|
|
211
|
+
expect(asFragment()).toMatchSnapshot();
|
|
212
|
+
});
|
|
213
|
+
test('Should render with title attribute', () => {
|
|
214
|
+
const {
|
|
215
|
+
asFragment
|
|
216
|
+
} = render( /*#__PURE__*/React.createElement(Button, {
|
|
217
|
+
title: "Button test title"
|
|
218
|
+
}));
|
|
219
|
+
expect(asFragment()).toMatchSnapshot();
|
|
220
|
+
});
|
|
221
|
+
test('Should apply customClass to wrapper and text', () => {
|
|
222
|
+
const {
|
|
223
|
+
asFragment
|
|
224
|
+
} = render( /*#__PURE__*/React.createElement(Button, {
|
|
225
|
+
customClass: {
|
|
226
|
+
wrapper: 'customButtonClass',
|
|
227
|
+
text: 'customTextClass'
|
|
228
|
+
}
|
|
229
|
+
}, "Button"));
|
|
230
|
+
expect(asFragment()).toMatchSnapshot();
|
|
231
|
+
});
|
|
232
|
+
test('Should apply customProps to wrapper, text and icon', () => {
|
|
233
|
+
const {
|
|
234
|
+
asFragment
|
|
235
|
+
} = render( /*#__PURE__*/React.createElement(Button, {
|
|
236
|
+
variant: "iconWithText",
|
|
237
|
+
iconName: "check",
|
|
238
|
+
customProps: {
|
|
239
|
+
wrapper: {
|
|
240
|
+
'data-wrapper': 'wrapperProps'
|
|
241
|
+
},
|
|
242
|
+
text: {
|
|
243
|
+
'data-text': 'textProps'
|
|
244
|
+
},
|
|
245
|
+
icon: {
|
|
246
|
+
'data-icon': 'iconProps'
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
}, "Button"));
|
|
250
|
+
expect(asFragment()).toMatchSnapshot();
|
|
251
|
+
});
|
|
252
|
+
test('Should render with customId and testId', () => {
|
|
253
|
+
const {
|
|
254
|
+
asFragment
|
|
255
|
+
} = render( /*#__PURE__*/React.createElement(Button, {
|
|
256
|
+
customId: "customIdValue",
|
|
257
|
+
testId: "testIdValue"
|
|
258
|
+
}));
|
|
259
|
+
expect(asFragment()).toMatchSnapshot();
|
|
260
|
+
});
|
|
261
|
+
test('Should apply a11yAttributes to the button', () => {
|
|
262
|
+
const {
|
|
263
|
+
asFragment
|
|
264
|
+
} = render( /*#__PURE__*/React.createElement(Button, {
|
|
265
|
+
a11yAttributes: {
|
|
266
|
+
'aria-label': 'Smart Button',
|
|
267
|
+
'aria-describedby': 'button-description'
|
|
268
|
+
}
|
|
269
|
+
}, "Button"));
|
|
270
|
+
expect(asFragment()).toMatchSnapshot();
|
|
271
|
+
});
|
|
272
|
+
});
|