@shopgate/pwa-ui-shared 7.30.0-alpha.7 → 7.30.0-alpha.8
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/AccordionContainer/index.js +39 -5
- package/AccordionContainer/spec.js +25 -2
- package/ActionButton/index.js +63 -7
- package/ActionButton/spec.js +59 -2
- package/ActionButton/style.js +22 -1
- package/AddToCartButton/index.js +184 -27
- package/AddToCartButton/mock.js +18 -4
- package/AddToCartButton/spec.js +51 -2
- package/AddToCartButton/style.js +127 -11
- package/Availability/index.js +34 -2
- package/Availability/spec.js +41 -1
- package/Availability/style.js +19 -1
- package/Button/index.js +76 -5
- package/Button/spec.js +33 -1
- package/Button/style.js +130 -21
- package/ButtonLink/connector.js +11 -2
- package/ButtonLink/index.js +44 -6
- package/ButtonLink/spec.js +23 -1
- package/Card/index.js +19 -2
- package/Card/style.js +11 -1
- package/CardList/components/Item/index.js +26 -2
- package/CardList/components/Item/style.js +7 -1
- package/CardList/index.js +34 -3
- package/CartTotalLine/components/Amount/index.js +28 -2
- package/CartTotalLine/components/Amount/style.js +8 -1
- package/CartTotalLine/components/Hint/index.js +23 -2
- package/CartTotalLine/components/Hint/style.js +12 -1
- package/CartTotalLine/components/Label/index.js +36 -2
- package/CartTotalLine/components/Label/style.js +17 -1
- package/CartTotalLine/components/Spacer/index.js +16 -2
- package/CartTotalLine/index.js +39 -2
- package/CartTotalLine/style.js +31 -1
- package/Checkbox/index.js +31 -2
- package/Checkbox/style.js +18 -1
- package/Chip/index.js +61 -2
- package/Chip/spec.js +24 -1
- package/Chip/style.js +71 -3
- package/ContextMenu/ContextMenu.hooks.js +6 -2
- package/ContextMenu/ContextMenuProvider.context.js +9 -3
- package/ContextMenu/ContextMenuProvider.js +21 -2
- package/ContextMenu/components/Item/index.js +67 -5
- package/ContextMenu/components/Item/style.js +32 -3
- package/ContextMenu/components/Position/index.js +61 -10
- package/ContextMenu/components/Position/style.js +11 -1
- package/ContextMenu/index.js +124 -3
- package/ContextMenu/spec.js +101 -2
- package/ContextMenu/style.js +45 -1
- package/Dialog/components/BasicDialog/index.js +5 -1
- package/Dialog/components/HtmlContentDialog/index.js +22 -2
- package/Dialog/components/HtmlContentDialog/spec.js +59 -1
- package/Dialog/components/PipelineErrorDialog/index.js +114 -25
- package/Dialog/components/PipelineErrorDialog/spec.js +92 -12
- package/Dialog/components/TextMessageDialog/index.js +28 -2
- package/Dialog/components/TextMessageDialog/spec.js +59 -1
- package/Dialog/components/VariantSelectModal/connector.js +11 -2
- package/Dialog/components/VariantSelectModal/index.js +65 -6
- package/Dialog/components/VariantSelectModal/spec.js +51 -2
- package/Dialog/constants.js +6 -1
- package/Dialog/index.js +114 -7
- package/Dialog/spec.js +81 -3
- package/DiscountBadge/index.js +30 -2
- package/DiscountBadge/spec.js +19 -1
- package/DiscountBadge/style.js +34 -2
- package/FavoritesButton/connector.js +18 -3
- package/FavoritesButton/index.js +118 -15
- package/FavoritesButton/mock.js +50 -4
- package/FavoritesButton/spec.js +120 -2
- package/FavoritesButton/style.js +26 -1
- package/Form/Builder/builders/buildCountryList.js +40 -6
- package/Form/Builder/builders/buildFormDefaults.js +35 -6
- package/Form/Builder/builders/buildFormElements.js +68 -10
- package/Form/Builder/builders/buildProvinceList.js +19 -2
- package/Form/Builder/builders/buildValidationErrorList.js +7 -2
- package/Form/Builder/classes/ActionListener/constants.js +22 -2
- package/Form/Builder/classes/ActionListener/index.js +441 -93
- package/Form/Builder/classes/ActionListener/spec.js +321 -19
- package/Form/Builder/components/CheckboxElement.js +35 -3
- package/Form/Builder/components/CountryElement.js +40 -3
- package/Form/Builder/components/ProvinceElement.js +40 -3
- package/Form/Builder/components/RadioElement.js +41 -3
- package/Form/Builder/components/SelectElement.js +39 -3
- package/Form/Builder/components/TextElement.js +49 -4
- package/Form/Builder/elementTypes.js +11 -1
- package/Form/Builder/index.js +298 -52
- package/Form/Builder/iso-3166-2.js +4943 -1
- package/Form/Builder/spec.js +300 -16
- package/Form/Checkbox/index.js +66 -4
- package/Form/Checkbox/style.js +25 -2
- package/Form/InfoField/index.js +50 -2
- package/Form/InfoField/spec.js +9 -1
- package/Form/InfoField/style.js +11 -1
- package/Form/Password/index.js +51 -6
- package/Form/Password/spec.js +34 -1
- package/Form/Password/style.js +11 -1
- package/Form/RadioGroup/components/Item/index.js +59 -3
- package/Form/RadioGroup/components/Item/style.js +32 -2
- package/Form/RadioGroup/index.js +101 -9
- package/Form/RadioGroup/spec.js +83 -3
- package/Form/RadioGroup/style.js +18 -2
- package/Form/Select/index.js +158 -10
- package/Form/Select/spec.js +36 -5
- package/Form/Select/style.js +27 -1
- package/Form/SelectContextChoices/index.js +77 -3
- package/Form/SelectContextChoices/spec.js +33 -4
- package/Form/SelectContextChoices/style.js +23 -1
- package/Form/TextField/index.js +92 -8
- package/Form/TextField/spec.js +110 -1
- package/Form/TextField/style.js +66 -8
- package/Form/index.js +54 -13
- package/FormElement/components/ErrorText/index.js +31 -2
- package/FormElement/components/ErrorText/style.js +13 -1
- package/FormElement/components/Label/index.js +35 -2
- package/FormElement/components/Label/style.js +76 -8
- package/FormElement/components/Placeholder/index.js +26 -2
- package/FormElement/components/Placeholder/style.js +48 -6
- package/FormElement/components/Underline/index.js +18 -2
- package/FormElement/components/Underline/style.js +51 -4
- package/FormElement/index.js +91 -6
- package/FormElement/spec.js +67 -2
- package/FormElement/style.js +13 -2
- package/Glow/index.js +90 -7
- package/Glow/spec.js +9 -1
- package/Glow/style.js +18 -1
- package/IndicatorCircle/index.js +33 -3
- package/IndicatorCircle/spec.js +28 -1
- package/IndicatorCircle/style.js +57 -3
- package/LoadingIndicator/index.js +29 -2
- package/LoadingIndicator/style.js +20 -1
- package/Manufacturer/index.js +20 -2
- package/Manufacturer/style.js +5 -1
- package/MessageBar/index.js +36 -2
- package/MessageBar/spec.js +79 -1
- package/MessageBar/style.js +38 -1
- package/NoResults/components/Icon/index.js +130 -2
- package/NoResults/components/Icon/style.js +17 -1
- package/NoResults/index.js +46 -2
- package/NoResults/style.js +31 -1
- package/Placeholder/index.js +25 -3
- package/Placeholder/style.js +11 -1
- package/PlaceholderLabel/index.js +27 -2
- package/PlaceholderLabel/spec.js +19 -1
- package/PlaceholderLabel/style.js +12 -1
- package/PlaceholderParagraph/index.js +36 -2
- package/PlaceholderParagraph/spec.js +19 -1
- package/Price/index.js +88 -7
- package/Price/style.js +22 -1
- package/PriceInfo/index.js +20 -2
- package/PriceInfo/style.js +5 -1
- package/PriceStriked/index.js +83 -12
- package/PriceStriked/style.js +33 -3
- package/ProductProperties/index.js +32 -2
- package/ProgressBar/index.js +101 -13
- package/ProgressBar/spec.js +13 -1
- package/ProgressBar/style.js +83 -2
- package/RadioButton/index.js +18 -2
- package/RadioButton/spec.js +21 -1
- package/RadioButton/style.js +21 -1
- package/RatingNumber/index.js +29 -2
- package/RatingStars/constants.js +2 -1
- package/RatingStars/index.js +130 -12
- package/RatingStars/spec.js +90 -3
- package/RatingStars/style.js +51 -2
- package/Ripple/components/RippleAnimation/index.js +88 -6
- package/Ripple/index.js +218 -40
- package/Ripple/style.js +18 -1
- package/RippleButton/index.js +52 -5
- package/RippleButton/spec.js +45 -1
- package/ScannerOverlay/components/CameraOverlay/index.js +13 -2
- package/ScannerOverlay/components/CameraOverlay/style.js +41 -1
- package/ScannerOverlay/components/ScannerBar/components/FlashlightButton/index.js +34 -2
- package/ScannerOverlay/components/ScannerBar/components/FlashlightButton/style.js +28 -1
- package/ScannerOverlay/components/ScannerBar/components/ScannerInstructions/index.js +11 -2
- package/ScannerOverlay/components/ScannerBar/index.js +31 -2
- package/ScannerOverlay/components/ScannerBar/style.js +20 -1
- package/ScannerOverlay/index.js +47 -7
- package/Sheet/components/Header/components/SearchBar/index.js +46 -2
- package/Sheet/components/Header/components/SearchBar/spec.js +21 -3
- package/Sheet/components/Header/components/SearchBar/style.js +47 -1
- package/Sheet/components/Header/index.js +75 -7
- package/Sheet/components/Header/spec.js +14 -1
- package/Sheet/components/Header/style.js +50 -1
- package/Sheet/index.js +170 -17
- package/Sheet/spec.js +85 -5
- package/Sheet/style.js +143 -2
- package/TaxDisclaimer/index.js +34 -4
- package/TaxDisclaimer/spec.js +31 -3
- package/TaxDisclaimer/style.js +9 -1
- package/TextField/components/ErrorText/index.js +33 -2
- package/TextField/components/ErrorText/style.js +25 -3
- package/TextField/components/FormElement/index.js +19 -2
- package/TextField/components/FormElement/style.js +32 -4
- package/TextField/components/Hint/index.js +21 -2
- package/TextField/components/Hint/style.js +40 -5
- package/TextField/components/Label/index.js +32 -3
- package/TextField/components/Label/style.js +68 -8
- package/TextField/components/Underline/index.js +19 -2
- package/TextField/components/Underline/style.js +51 -4
- package/TextField/index.js +189 -27
- package/TextField/spec.js +128 -3
- package/TextField/style.js +34 -4
- package/ToggleIcon/index.js +58 -8
- package/ToggleIcon/spec.js +35 -1
- package/icons/AccountBoxIcon.js +11 -2
- package/icons/AddMoreIcon.js +11 -2
- package/icons/ArrowDropIcon.js +11 -2
- package/icons/ArrowIcon.js +21 -2
- package/icons/BarcodeScannerIcon.js +11 -2
- package/icons/BoxIcon.js +11 -2
- package/icons/BrowseIcon.js +11 -2
- package/icons/BurgerIcon.js +11 -2
- package/icons/CalendarIcon.js +15 -3
- package/icons/CartCouponIcon.js +72 -2
- package/icons/CartIcon.js +11 -2
- package/icons/CartPlusIcon.js +11 -2
- package/icons/CheckIcon.js +11 -2
- package/icons/CheckedIcon.js +11 -2
- package/icons/ChevronIcon.js +11 -2
- package/icons/CreditCardIcon.js +11 -2
- package/icons/CrossIcon.js +11 -2
- package/icons/DescriptionIcon.js +11 -2
- package/icons/FilterIcon.js +11 -2
- package/icons/FlashDisabledIcon.js +11 -2
- package/icons/FlashEnabledIcon.js +11 -2
- package/icons/GridIcon.js +11 -2
- package/icons/HeartIcon.js +11 -2
- package/icons/HeartOutlineIcon.js +11 -2
- package/icons/HeartPlusIcon.js +12 -2
- package/icons/HeartPlusOutlineIcon.js +12 -2
- package/icons/HomeIcon.js +11 -2
- package/icons/InfoIcon.js +11 -2
- package/icons/InfoOutlineIcon.js +11 -2
- package/icons/ListIcon.js +11 -2
- package/icons/LocalShippingIcon.js +11 -2
- package/icons/LocationIcon.js +13 -3
- package/icons/LocatorIcon.js +11 -2
- package/icons/LockIcon.js +11 -2
- package/icons/LogoutIcon.js +11 -2
- package/icons/MagnifierIcon.js +11 -2
- package/icons/MapMarkerIcon.js +24 -3
- package/icons/MoreIcon.js +11 -2
- package/icons/MoreVertIcon.js +11 -2
- package/icons/NotificationIcon.js +14 -3
- package/icons/PersonIcon.js +12 -2
- package/icons/PhoneIcon.js +13 -3
- package/icons/PlaceholderIcon.js +11 -2
- package/icons/RadioCheckedIcon.js +11 -2
- package/icons/RadioUncheckedIcon.js +11 -2
- package/icons/SecurityIcon.js +11 -2
- package/icons/ShippingMethodIcon.js +18 -3
- package/icons/ShoppingCartIcon.js +11 -2
- package/icons/SortIcon.js +11 -2
- package/icons/StarHalfIcon.js +18 -2
- package/icons/StarIcon.js +18 -2
- package/icons/StarOutlineIcon.js +11 -2
- package/icons/StopIcon.js +11 -2
- package/icons/TickIcon.js +11 -2
- package/icons/TimeIcon.js +14 -3
- package/icons/TrashIcon.js +11 -2
- package/icons/TrashOutlineIcon.js +12 -2
- package/icons/UncheckedIcon.js +11 -2
- package/icons/ViewListIcon.js +11 -2
- package/icons/VisibilityIcon.js +11 -2
- package/icons/VisibilityOffIcon.js +11 -2
- package/icons/WarningIcon.js +11 -2
- package/index.js +13 -1
- package/package.json +5 -5
|
@@ -1,8 +1,42 @@
|
|
|
1
|
-
|
|
1
|
+
import { Component } from 'react';
|
|
2
|
+
import PropTypes from 'prop-types';
|
|
3
|
+
|
|
4
|
+
/**
|
|
2
5
|
* The Accordion container component.
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
|
|
6
|
+
*/
|
|
7
|
+
class AccordionContainer extends Component {
|
|
8
|
+
/**
|
|
6
9
|
* Init
|
|
7
10
|
* @param {Object} props Props
|
|
8
|
-
*/
|
|
11
|
+
*/
|
|
12
|
+
constructor(props) {
|
|
13
|
+
super(props);
|
|
14
|
+
this.open = () => {
|
|
15
|
+
this.setState({
|
|
16
|
+
open: true
|
|
17
|
+
});
|
|
18
|
+
};
|
|
19
|
+
this.close = () => {
|
|
20
|
+
this.setState({
|
|
21
|
+
open: false
|
|
22
|
+
});
|
|
23
|
+
};
|
|
24
|
+
this.state = {
|
|
25
|
+
open: props.open
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* @returns {JSX}
|
|
30
|
+
*/
|
|
31
|
+
render() {
|
|
32
|
+
return this.props.children({
|
|
33
|
+
handleClose: this.close,
|
|
34
|
+
open: this.state.open,
|
|
35
|
+
handleOpen: this.open
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
AccordionContainer.defaultProps = {
|
|
40
|
+
open: false
|
|
41
|
+
};
|
|
42
|
+
export default AccordionContainer;
|
|
@@ -1,3 +1,26 @@
|
|
|
1
|
-
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { shallow } from 'enzyme';
|
|
3
|
+
import AccordionContainer from "./index";
|
|
4
|
+
|
|
5
|
+
/**
|
|
2
6
|
* @returns {JSX}
|
|
3
|
-
*/
|
|
7
|
+
*/
|
|
8
|
+
const Child = () => /*#__PURE__*/React.createElement("div", null);
|
|
9
|
+
describe('<AccordionContainer />', () => {
|
|
10
|
+
it('should render children with props', () => {
|
|
11
|
+
const wrapper = shallow(/*#__PURE__*/React.createElement(AccordionContainer, null, props => /*#__PURE__*/React.createElement(Child, props)));
|
|
12
|
+
const props = wrapper.find('Child').props();
|
|
13
|
+
expect(wrapper).toMatchSnapshot();
|
|
14
|
+
expect(props.open).toEqual(false);
|
|
15
|
+
expect(typeof props.handleOpen).toEqual('function');
|
|
16
|
+
expect(typeof props.handleClose).toEqual('function');
|
|
17
|
+
});
|
|
18
|
+
it('should update children props when state changes', () => {
|
|
19
|
+
const wrapper = shallow(/*#__PURE__*/React.createElement(AccordionContainer, null, props => /*#__PURE__*/React.createElement(Child, props)));
|
|
20
|
+
wrapper.setState({
|
|
21
|
+
open: true
|
|
22
|
+
});
|
|
23
|
+
expect(wrapper).toMatchSnapshot();
|
|
24
|
+
expect(wrapper.find('Child').props().open).toEqual(true);
|
|
25
|
+
});
|
|
26
|
+
});
|
package/ActionButton/index.js
CHANGED
|
@@ -1,12 +1,68 @@
|
|
|
1
|
-
|
|
1
|
+
import _extends from "@babel/runtime/helpers/extends";
|
|
2
|
+
import React, { Component } from 'react';
|
|
3
|
+
import PropTypes from 'prop-types';
|
|
4
|
+
import IndicatorCircle from "../IndicatorCircle";
|
|
5
|
+
import RippleButton from "../RippleButton";
|
|
6
|
+
import styles from "./style";
|
|
7
|
+
|
|
8
|
+
/**
|
|
2
9
|
* The action button component.
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
10
|
+
*/
|
|
11
|
+
class ActionButton extends Component {
|
|
12
|
+
constructor(...args) {
|
|
13
|
+
super(...args);
|
|
14
|
+
/**
|
|
15
|
+
* The click handler
|
|
16
|
+
* @param {Object} event The event object for the click handler
|
|
17
|
+
*/
|
|
18
|
+
this.handleClick = event => {
|
|
19
|
+
const {
|
|
20
|
+
clickDelay
|
|
21
|
+
} = this.constructor;
|
|
22
|
+
setTimeout(() => {
|
|
23
|
+
this.props.onClick(event);
|
|
24
|
+
}, clickDelay);
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
7
28
|
* Getter for the calculated button props.
|
|
8
29
|
* @returns {Object}
|
|
9
|
-
*/
|
|
30
|
+
*/
|
|
31
|
+
get buttonProps() {
|
|
32
|
+
const buttonProps = {
|
|
33
|
+
className: this.props.className,
|
|
34
|
+
disabled: this.props.disabled,
|
|
35
|
+
flat: this.props.flat,
|
|
36
|
+
type: this.props.type
|
|
37
|
+
};
|
|
38
|
+
return buttonProps;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
10
41
|
* The render function.
|
|
11
42
|
* @returns {JSX}
|
|
12
|
-
*/
|
|
43
|
+
*/
|
|
44
|
+
render() {
|
|
45
|
+
const containerClass = this.props.noGap ? styles.noGapContainer : styles.container;
|
|
46
|
+
if (this.props.loading) {
|
|
47
|
+
return /*#__PURE__*/React.createElement("div", {
|
|
48
|
+
className: styles.containerCircle
|
|
49
|
+
}, /*#__PURE__*/React.createElement(IndicatorCircle, null));
|
|
50
|
+
}
|
|
51
|
+
return /*#__PURE__*/React.createElement("div", {
|
|
52
|
+
className: `ui-shared__action-button ${containerClass}`,
|
|
53
|
+
"data-test-id": this.props.testId
|
|
54
|
+
}, /*#__PURE__*/React.createElement(RippleButton, _extends({}, this.buttonProps, {
|
|
55
|
+
onClick: this.handleClick
|
|
56
|
+
}), this.props.children));
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
ActionButton.clickDelay = 300;
|
|
60
|
+
ActionButton.defaultProps = {
|
|
61
|
+
...RippleButton.defaultProps,
|
|
62
|
+
loading: false,
|
|
63
|
+
type: 'primary',
|
|
64
|
+
flat: true,
|
|
65
|
+
noGap: false,
|
|
66
|
+
testId: null
|
|
67
|
+
};
|
|
68
|
+
export default ActionButton;
|
package/ActionButton/spec.js
CHANGED
|
@@ -1,4 +1,61 @@
|
|
|
1
|
-
import React from'react';
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { shallow } from 'enzyme';
|
|
3
|
+
import IndicatorCircle from "../IndicatorCircle";
|
|
4
|
+
import RippleButton from "../RippleButton";
|
|
5
|
+
import ActionButton from "./index";
|
|
6
|
+
describe('<ActionButton />', () => {
|
|
7
|
+
let renderedElement;
|
|
8
|
+
let mockOnClick;
|
|
9
|
+
jest.useFakeTimers();
|
|
10
|
+
|
|
11
|
+
/**
|
|
2
12
|
* Renders the component.
|
|
3
13
|
* @param {Object} props The component props.
|
|
4
|
-
*/
|
|
14
|
+
*/
|
|
15
|
+
const renderComponent = (props = {}) => {
|
|
16
|
+
renderedElement = shallow(/*#__PURE__*/React.createElement(ActionButton, props, "Action Button"));
|
|
17
|
+
};
|
|
18
|
+
describe('Given the component was mounted to the DOM', () => {
|
|
19
|
+
beforeEach(() => {
|
|
20
|
+
mockOnClick = jest.fn();
|
|
21
|
+
renderComponent({
|
|
22
|
+
onClick: mockOnClick
|
|
23
|
+
});
|
|
24
|
+
});
|
|
25
|
+
it('should match snapshot', () => {
|
|
26
|
+
expect(renderedElement).toMatchSnapshot();
|
|
27
|
+
});
|
|
28
|
+
it('should not show the loading indicator by default', () => {
|
|
29
|
+
const indicator = renderedElement.find(IndicatorCircle);
|
|
30
|
+
expect(indicator.length).toBe(0);
|
|
31
|
+
});
|
|
32
|
+
describe('Given the loading prop is set to true', () => {
|
|
33
|
+
beforeEach(() => {
|
|
34
|
+
renderedElement.setProps({
|
|
35
|
+
loading: true
|
|
36
|
+
});
|
|
37
|
+
});
|
|
38
|
+
it('should match snapshot', () => {
|
|
39
|
+
expect(renderedElement).toMatchSnapshot();
|
|
40
|
+
});
|
|
41
|
+
it('should show the loading indicator', () => {
|
|
42
|
+
const indicator = renderedElement.find(IndicatorCircle);
|
|
43
|
+
expect(indicator.length).toBe(1);
|
|
44
|
+
});
|
|
45
|
+
});
|
|
46
|
+
describe('Given the component gets clicked', () => {
|
|
47
|
+
beforeEach(() => {
|
|
48
|
+
renderedElement.find(RippleButton).simulate('click');
|
|
49
|
+
});
|
|
50
|
+
it('should use setTimeout for delaying the onClick handler', () => {
|
|
51
|
+
expect(setTimeout.mock.calls.length).toBe(1);
|
|
52
|
+
expect(setTimeout.mock.calls[0][1]).toBe(ActionButton.clickDelay);
|
|
53
|
+
});
|
|
54
|
+
it('should eventually call the onClick handler', () => {
|
|
55
|
+
jest.runOnlyPendingTimers();
|
|
56
|
+
expect(mockOnClick).toBeCalled();
|
|
57
|
+
expect(mockOnClick.mock.calls.length).toBe(1);
|
|
58
|
+
});
|
|
59
|
+
});
|
|
60
|
+
});
|
|
61
|
+
});
|
package/ActionButton/style.js
CHANGED
|
@@ -1 +1,22 @@
|
|
|
1
|
-
|
|
1
|
+
import { css } from 'glamor';
|
|
2
|
+
import { themeConfig } from '@shopgate/pwa-common/helpers/config';
|
|
3
|
+
const halfGapBig = themeConfig.variables.gap.big / 2;
|
|
4
|
+
const containerBase = {
|
|
5
|
+
textAlign: 'center'
|
|
6
|
+
};
|
|
7
|
+
const container = css({
|
|
8
|
+
...containerBase,
|
|
9
|
+
margin: `${halfGapBig}px 0`
|
|
10
|
+
}).toString();
|
|
11
|
+
const noGapContainer = css({
|
|
12
|
+
...containerBase
|
|
13
|
+
}).toString();
|
|
14
|
+
const containerCircle = css({
|
|
15
|
+
...containerBase,
|
|
16
|
+
margin: `${halfGapBig + 5}px 0`
|
|
17
|
+
}).toString();
|
|
18
|
+
export default {
|
|
19
|
+
container,
|
|
20
|
+
containerCircle,
|
|
21
|
+
noGapContainer
|
|
22
|
+
};
|
package/AddToCartButton/index.js
CHANGED
|
@@ -1,44 +1,201 @@
|
|
|
1
|
-
import
|
|
1
|
+
import React, { Component } from 'react';
|
|
2
|
+
import PropTypes from 'prop-types';
|
|
3
|
+
import { themeConfig } from '@shopgate/pwa-common/helpers/config';
|
|
4
|
+
import { withForwardedRef } from '@shopgate/engage/core';
|
|
5
|
+
import CartPlusIcon from "../icons/CartPlusIcon";
|
|
6
|
+
import TickIcon from "../icons/TickIcon";
|
|
7
|
+
import IndicatorCircle from "../IndicatorCircle";
|
|
8
|
+
import styles from "./style";
|
|
9
|
+
|
|
10
|
+
/**
|
|
2
11
|
* AddToCartButton component.
|
|
3
|
-
*/
|
|
12
|
+
*/
|
|
13
|
+
class AddToCartButton extends Component {
|
|
14
|
+
/**
|
|
4
15
|
* Constructor for the AddToCartButton component.
|
|
5
16
|
* @param {Object} props Props for the component.
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
17
|
+
*/
|
|
18
|
+
constructor(props) {
|
|
19
|
+
super(props);
|
|
20
|
+
/**
|
|
21
|
+
* Handles the button click.
|
|
22
|
+
* - Show checkmark.
|
|
23
|
+
* - Add to cart.
|
|
24
|
+
* - Wait 900ms.
|
|
25
|
+
* - Show cart icon again.
|
|
26
|
+
* @param {Event} e Event
|
|
27
|
+
*/
|
|
28
|
+
this.handleClick = e => {
|
|
29
|
+
// Ignore clicks when check mark or loading spinner is shown or the button is disabled.
|
|
30
|
+
if (this.state.showCheckmark || this.props.isLoading || this.props.isDisabled) {
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/** */
|
|
35
|
+
const handleCompletion = () => {
|
|
36
|
+
this.setState({
|
|
37
|
+
showCheckmark: true
|
|
38
|
+
});
|
|
39
|
+
setTimeout(() => {
|
|
40
|
+
this.setState({
|
|
41
|
+
showCheckmark: false
|
|
42
|
+
});
|
|
43
|
+
}, 900);
|
|
44
|
+
};
|
|
45
|
+
const result = this.props.onClick(e);
|
|
46
|
+
if (result === false) {
|
|
47
|
+
// Do not trigger animation when adding to cart was aborted by the parent component (PWA-2764)
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
if (result instanceof Promise) {
|
|
51
|
+
(async () => {
|
|
52
|
+
try {
|
|
53
|
+
await result;
|
|
54
|
+
handleCompletion();
|
|
55
|
+
} catch (error) {
|
|
56
|
+
// ignore error in button.
|
|
57
|
+
}
|
|
58
|
+
})();
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
61
|
+
handleCompletion();
|
|
62
|
+
};
|
|
63
|
+
/**
|
|
64
|
+
* Handles the cart animation end event.
|
|
65
|
+
* Resets the showCheckmark state to null in order to
|
|
66
|
+
* prevent the icon from animating after changing visibility
|
|
67
|
+
* of the view.
|
|
68
|
+
* This is caused by CSS animations that get re-applied when
|
|
69
|
+
* setting an element from hidden (display: none) to visible.
|
|
70
|
+
*/
|
|
71
|
+
this.handleCartAnimationEnd = () => {
|
|
72
|
+
if (this.state.showCheckmark === false) {
|
|
73
|
+
this.setState({
|
|
74
|
+
showCheckmark: null
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
this.props.onReset();
|
|
78
|
+
};
|
|
79
|
+
this.state = {
|
|
80
|
+
showCheckmark: null
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
23
84
|
* Renders the component
|
|
24
85
|
* @returns {JSX}
|
|
25
|
-
*/
|
|
26
|
-
|
|
27
|
-
|
|
86
|
+
*/
|
|
87
|
+
render() {
|
|
88
|
+
// Set initial base styles
|
|
89
|
+
let buttonStyle = styles.buttonReady;
|
|
90
|
+
let tickIconStyle = styles.icon;
|
|
91
|
+
let cartPlusIconStyle = styles.icon;
|
|
92
|
+
|
|
93
|
+
// Depending on the isLoading prop we only show the spinner or the other way around.
|
|
94
|
+
const iconOpacity = this.props.isLoading ? {
|
|
95
|
+
opacity: 0
|
|
96
|
+
} : {
|
|
97
|
+
opacity: 1
|
|
98
|
+
};
|
|
99
|
+
const spinnerInlineStyle = this.props.isLoading ? {
|
|
100
|
+
opacity: 1
|
|
101
|
+
} : {
|
|
102
|
+
opacity: 0
|
|
103
|
+
};
|
|
104
|
+
|
|
105
|
+
/**
|
|
28
106
|
* The initial positions for the icons:
|
|
29
107
|
* Tick icon stays hidden on top, Cart icon stays visibly at the center
|
|
30
|
-
*/
|
|
108
|
+
*/
|
|
109
|
+
let tickInlineStyle = this.state.showCheckmark === null ? {
|
|
110
|
+
transform: 'translate3d(0, 300%, 0)',
|
|
111
|
+
...iconOpacity
|
|
112
|
+
} : null;
|
|
113
|
+
let cartInlineStyle = this.state.showCheckmark === null ? {
|
|
114
|
+
transform: 'translate3d(0, -50%, 0)',
|
|
115
|
+
...iconOpacity
|
|
116
|
+
} : null;
|
|
117
|
+
if (this.props.isDisabled && !this.props.isLoading) {
|
|
118
|
+
buttonStyle = styles.buttonDisabled;
|
|
119
|
+
} else if (this.state.showCheckmark) {
|
|
120
|
+
/**
|
|
31
121
|
* When checkmark should be shown, we start the spring transition
|
|
32
122
|
* Tick icon springs in, and cart icon springs out.
|
|
33
|
-
*/
|
|
123
|
+
*/
|
|
124
|
+
tickIconStyle += ` ${styles.springFromBottom}`;
|
|
125
|
+
cartPlusIconStyle += ` ${styles.springToTop}`;
|
|
126
|
+
buttonStyle = styles.buttonSuccess;
|
|
127
|
+
/**
|
|
34
128
|
* After the keyframe animation is done the transform values are reset
|
|
35
129
|
* We add the inline style to make sure the icons stay where they are even after the animation
|
|
36
|
-
*/
|
|
130
|
+
*/
|
|
131
|
+
tickInlineStyle = {
|
|
132
|
+
transform: 'translate3d(0, -50%, 0)',
|
|
133
|
+
...iconOpacity
|
|
134
|
+
};
|
|
135
|
+
cartInlineStyle = {
|
|
136
|
+
transform: 'translate3d(0, -300%, 0)',
|
|
137
|
+
...iconOpacity
|
|
138
|
+
};
|
|
139
|
+
} else if (this.state.showCheckmark !== null) {
|
|
140
|
+
/**
|
|
37
141
|
* When checkmark should no longer be shown we start the spring out transition.
|
|
38
142
|
* Tick icon springs out, cart icon spring in.
|
|
39
143
|
* We don't want a animation when we initially go to the page therefore this only happens
|
|
40
144
|
* after the user pressed the button.
|
|
41
|
-
*/
|
|
145
|
+
*/
|
|
146
|
+
tickIconStyle += ` ${styles.springToBottom}`;
|
|
147
|
+
cartPlusIconStyle += ` ${styles.springFromTop}`;
|
|
148
|
+
/**
|
|
42
149
|
* After the keyframe animation is done the transform values are reset
|
|
43
150
|
* We add the inline style to make sure the icons stay where they are even after the animation
|
|
44
|
-
*/
|
|
151
|
+
*/
|
|
152
|
+
cartInlineStyle = {
|
|
153
|
+
transform: 'translate3d(0, -50%, 0)',
|
|
154
|
+
...iconOpacity
|
|
155
|
+
};
|
|
156
|
+
tickInlineStyle = {
|
|
157
|
+
transform: 'translate3d(0, -300%, 0)',
|
|
158
|
+
...iconOpacity
|
|
159
|
+
};
|
|
160
|
+
}
|
|
161
|
+
let className = styles.buttonWrapper(this.props.buttonSize, this.props.iconSize);
|
|
162
|
+
if (this.props.noShadow) {
|
|
163
|
+
className = styles.buttonWrapperNoShadow(this.props.buttonSize, this.props.iconSize);
|
|
164
|
+
}
|
|
165
|
+
return /*#__PURE__*/React.createElement("button", {
|
|
166
|
+
"data-test-id": "addToCartButton",
|
|
167
|
+
className: `ui-shared__add-to-cart-button ${this.props.className} ${className} ${buttonStyle}`,
|
|
168
|
+
onClick: this.handleClick,
|
|
169
|
+
"aria-hidden": this.props['aria-hidden'],
|
|
170
|
+
"aria-label": this.props['aria-label'],
|
|
171
|
+
"aria-disabled": this.props.isDisabled,
|
|
172
|
+
ref: this.props.forwardedRef,
|
|
173
|
+
type: "button"
|
|
174
|
+
}, this.props.isLoading && /*#__PURE__*/React.createElement("div", {
|
|
175
|
+
className: `${styles.icon} ${styles.spinnerIcon}`,
|
|
176
|
+
style: spinnerInlineStyle
|
|
177
|
+
}, /*#__PURE__*/React.createElement(IndicatorCircle, {
|
|
178
|
+
color: themeConfig.colors.primaryContrast,
|
|
179
|
+
strokeWidth: 5,
|
|
180
|
+
paused: !this.props.isLoading
|
|
181
|
+
})), /*#__PURE__*/React.createElement("div", {
|
|
182
|
+
className: tickIconStyle,
|
|
183
|
+
style: tickInlineStyle
|
|
184
|
+
}, /*#__PURE__*/React.createElement(TickIcon, null)), /*#__PURE__*/React.createElement("div", {
|
|
185
|
+
className: cartPlusIconStyle,
|
|
186
|
+
style: cartInlineStyle,
|
|
187
|
+
onAnimationEnd: this.handleCartAnimationEnd
|
|
188
|
+
}, /*#__PURE__*/React.createElement(CartPlusIcon, null)));
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
AddToCartButton.defaultProps = {
|
|
192
|
+
'aria-hidden': false,
|
|
193
|
+
'aria-label': null,
|
|
194
|
+
buttonSize: styles.buttonSize,
|
|
195
|
+
className: null,
|
|
196
|
+
forwardedRef: null,
|
|
197
|
+
iconSize: styles.iconSize,
|
|
198
|
+
noShadow: false,
|
|
199
|
+
onReset: () => {}
|
|
200
|
+
};
|
|
201
|
+
export default withForwardedRef(AddToCartButton);
|
package/AddToCartButton/mock.js
CHANGED
|
@@ -1,9 +1,23 @@
|
|
|
1
|
-
var _Class
|
|
1
|
+
var _Class;
|
|
2
|
+
import React, { Component } from 'react';
|
|
3
|
+
import PropTypes from 'prop-types';
|
|
4
|
+
/**
|
|
2
5
|
* Mocked AddToCartButton.
|
|
3
6
|
* @type {MockedAddToCartButton}
|
|
4
7
|
* @deprecated
|
|
5
|
-
*/
|
|
6
|
-
|
|
8
|
+
*/
|
|
9
|
+
// eslint-disable-next-line react/prefer-stateless-function
|
|
10
|
+
export const MockedAddToCartButton = (_Class = class MockedAddToCartButton extends Component {
|
|
11
|
+
/**
|
|
7
12
|
* Renders mocked button.
|
|
8
13
|
* @return {JSX}
|
|
9
|
-
*/
|
|
14
|
+
*/
|
|
15
|
+
render() {
|
|
16
|
+
return /*#__PURE__*/React.createElement("button", {
|
|
17
|
+
onClick: this.props.onClick,
|
|
18
|
+
type: "button"
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
}, _Class.defaultProps = {
|
|
22
|
+
onClick: () => {}
|
|
23
|
+
}, _Class);
|
package/AddToCartButton/spec.js
CHANGED
|
@@ -1,4 +1,53 @@
|
|
|
1
|
-
import
|
|
1
|
+
import "core-js/modules/web.immediate.js";
|
|
2
|
+
import React from 'react';
|
|
3
|
+
import { mount } from 'enzyme';
|
|
4
|
+
import AddToCartButton from "./index";
|
|
5
|
+
|
|
6
|
+
/**
|
|
2
7
|
* Flushes the promise queue.
|
|
3
8
|
* @returns {Promise}
|
|
4
|
-
*/
|
|
9
|
+
*/
|
|
10
|
+
const flushPromises = () => new Promise(resolve => setImmediate(resolve));
|
|
11
|
+
describe('<AddToCartButton />', () => {
|
|
12
|
+
it('should render in loading state and should not be clickable', () => {
|
|
13
|
+
const spy = jest.fn(() => new Promise(resolve => resolve()));
|
|
14
|
+
const wrapper = mount(/*#__PURE__*/React.createElement(AddToCartButton, {
|
|
15
|
+
onClick: spy,
|
|
16
|
+
isLoading: true,
|
|
17
|
+
isOrderable: true,
|
|
18
|
+
isDisabled: false
|
|
19
|
+
}));
|
|
20
|
+
wrapper.find('button').prop('onClick')();
|
|
21
|
+
expect(wrapper).toMatchSnapshot();
|
|
22
|
+
expect(spy).toHaveBeenCalledTimes(0);
|
|
23
|
+
});
|
|
24
|
+
it('should render with checkmark icon and should not be clickable the second time', async () => {
|
|
25
|
+
const spy = jest.fn(() => new Promise(resolve => resolve()));
|
|
26
|
+
const wrapper = mount(/*#__PURE__*/React.createElement(AddToCartButton, {
|
|
27
|
+
onClick: spy,
|
|
28
|
+
isLoading: false,
|
|
29
|
+
isOrderable: true,
|
|
30
|
+
isDisabled: false
|
|
31
|
+
}));
|
|
32
|
+
wrapper.find('button').prop('onClick')();
|
|
33
|
+
wrapper.update();
|
|
34
|
+
await flushPromises();
|
|
35
|
+
wrapper.find('button').prop('onClick')();
|
|
36
|
+
wrapper.update();
|
|
37
|
+
await flushPromises();
|
|
38
|
+
expect(wrapper).toMatchSnapshot();
|
|
39
|
+
expect(spy).toHaveBeenCalledTimes(1);
|
|
40
|
+
});
|
|
41
|
+
it('should render with cart icon and should be clickable', () => {
|
|
42
|
+
const spy = jest.fn(() => new Promise(resolve => resolve()));
|
|
43
|
+
const wrapper = mount(/*#__PURE__*/React.createElement(AddToCartButton, {
|
|
44
|
+
onClick: spy,
|
|
45
|
+
isLoading: false,
|
|
46
|
+
isOrderable: true,
|
|
47
|
+
isDisabled: false
|
|
48
|
+
}));
|
|
49
|
+
wrapper.find('button').prop('onClick')();
|
|
50
|
+
expect(wrapper).toMatchSnapshot();
|
|
51
|
+
expect(spy).toHaveBeenCalledTimes(1);
|
|
52
|
+
});
|
|
53
|
+
});
|