@shopgate/pwa-ui-shared 7.30.0-alpha.7 → 7.30.0-alpha.9
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 +63 -2
- package/ActionButton/style.js +22 -1
- package/AddToCartButton/index.js +184 -27
- package/AddToCartButton/mock.js +18 -4
- package/AddToCartButton/spec.js +65 -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 +308 -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 +40 -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
package/RatingStars/style.js
CHANGED
|
@@ -1,4 +1,53 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { css } from 'glamor';
|
|
2
|
+
import { themeConfig } from '@shopgate/pwa-common/helpers/config';
|
|
3
|
+
const {
|
|
4
|
+
colors
|
|
5
|
+
} = themeConfig;
|
|
6
|
+
const container = css({
|
|
7
|
+
position: 'relative'
|
|
8
|
+
}).toString();
|
|
9
|
+
const icon = css({
|
|
10
|
+
display: 'inline-block',
|
|
11
|
+
verticalAlign: 'top',
|
|
12
|
+
outline: 0
|
|
13
|
+
}).toString();
|
|
14
|
+
const emptyStars = css({
|
|
15
|
+
color: themeConfig.colors.shade7
|
|
16
|
+
}).toString();
|
|
17
|
+
const filledStars = css({
|
|
18
|
+
position: 'absolute',
|
|
19
|
+
color: `var(--color-primary, ${colors.primary})`,
|
|
20
|
+
top: 0
|
|
21
|
+
}).toString();
|
|
22
|
+
|
|
23
|
+
/**
|
|
2
24
|
* The rating stars styles that can be selected by passing the style key to the
|
|
3
25
|
* @type {Object}
|
|
4
|
-
*/
|
|
26
|
+
*/
|
|
27
|
+
const iconStyles = {
|
|
28
|
+
small: {
|
|
29
|
+
iconSize: '1em',
|
|
30
|
+
iconStyle: css({
|
|
31
|
+
marginRight: '0.1em'
|
|
32
|
+
}).toString()
|
|
33
|
+
},
|
|
34
|
+
big: {
|
|
35
|
+
iconSize: '1.24em',
|
|
36
|
+
iconStyle: css({
|
|
37
|
+
marginRight: '0.12em'
|
|
38
|
+
}).toString()
|
|
39
|
+
},
|
|
40
|
+
large: {
|
|
41
|
+
iconSize: '2.3em',
|
|
42
|
+
iconStyle: css({
|
|
43
|
+
marginRight: '0.23em'
|
|
44
|
+
}).toString()
|
|
45
|
+
}
|
|
46
|
+
};
|
|
47
|
+
export default {
|
|
48
|
+
container,
|
|
49
|
+
icon,
|
|
50
|
+
iconStyles,
|
|
51
|
+
emptyStars,
|
|
52
|
+
filledStars
|
|
53
|
+
};
|
|
@@ -1,4 +1,10 @@
|
|
|
1
|
-
|
|
1
|
+
import React, { useEffect, useRef, useMemo } from 'react';
|
|
2
|
+
import PropTypes from 'prop-types';
|
|
3
|
+
import { Transition } from 'react-transition-group';
|
|
4
|
+
import { themeConfig } from '@shopgate/pwa-common/helpers/config';
|
|
5
|
+
import style from "../../style";
|
|
6
|
+
|
|
7
|
+
/**
|
|
2
8
|
* The RippleAnimation component
|
|
3
9
|
*
|
|
4
10
|
* Plays a one-shot ripple animation and calls `onComplete` when finished.
|
|
@@ -10,10 +16,86 @@ function _extends(){_extends=Object.assign||function(target){for(var i=1;i<argum
|
|
|
10
16
|
* @param {number} props.x The x coordinate of the ripple center.
|
|
11
17
|
* @param {number} props.y The y coordinate of the ripple center.
|
|
12
18
|
* @returns {JSX.Element}
|
|
13
|
-
*/
|
|
14
|
-
|
|
15
|
-
|
|
19
|
+
*/
|
|
20
|
+
function RippleAnimation({
|
|
21
|
+
color,
|
|
22
|
+
duration,
|
|
23
|
+
onComplete,
|
|
24
|
+
size,
|
|
25
|
+
x,
|
|
26
|
+
y
|
|
27
|
+
}) {
|
|
28
|
+
const nodeRef = useRef(null);
|
|
29
|
+
|
|
30
|
+
// Trigger the animation immediately
|
|
31
|
+
const inProp = true;
|
|
32
|
+
const baseStyle = useMemo(() => ({
|
|
33
|
+
position: 'absolute',
|
|
34
|
+
backgroundColor: color,
|
|
35
|
+
height: size,
|
|
36
|
+
width: size,
|
|
37
|
+
left: x,
|
|
38
|
+
top: y,
|
|
39
|
+
borderRadius: '50%',
|
|
40
|
+
transform: 'translate3d(-50%, -50%, 0) scale3d(0, 0, 1)',
|
|
41
|
+
opacity: 0.25,
|
|
42
|
+
transition: `opacity ${duration}ms cubic-bezier(0.25, 0.1, 0.25, 1), transform ${duration}ms cubic-bezier(0.25, 0.1, 0.25, 1)`,
|
|
43
|
+
pointerEvents: 'none'
|
|
44
|
+
}), [color, duration, size, x, y]);
|
|
45
|
+
const transitionStyles = useMemo(() => ({
|
|
46
|
+
entering: {
|
|
47
|
+
transform: 'translate3d(-50%, -50%, 0) scale3d(1, 1, 1)',
|
|
48
|
+
opacity: 0
|
|
49
|
+
},
|
|
50
|
+
entered: {
|
|
51
|
+
transform: 'translate3d(-50%, -50%, 0) scale3d(1, 1, 1)',
|
|
52
|
+
opacity: 0
|
|
53
|
+
},
|
|
54
|
+
exiting: {},
|
|
55
|
+
exited: {},
|
|
56
|
+
unmounted: {}
|
|
57
|
+
}), []);
|
|
58
|
+
|
|
59
|
+
// Run callback when transition ends
|
|
60
|
+
useEffect(() => {
|
|
61
|
+
const el = nodeRef.current;
|
|
62
|
+
if (!el) return undefined;
|
|
63
|
+
|
|
64
|
+
/**
|
|
16
65
|
* Handles the transition end event and calls onComplete for relevant properties.
|
|
17
66
|
* @param {TransitionEvent} e - The transition event object
|
|
18
|
-
*/
|
|
19
|
-
|
|
67
|
+
*/
|
|
68
|
+
const handleEnd = e => {
|
|
69
|
+
// Only handle transform or opacity transitions
|
|
70
|
+
if (e.propertyName === 'transform' || e.propertyName === 'opacity') {
|
|
71
|
+
onComplete();
|
|
72
|
+
}
|
|
73
|
+
};
|
|
74
|
+
el.addEventListener('transitionend', handleEnd);
|
|
75
|
+
return () => el.removeEventListener('transitionend', handleEnd);
|
|
76
|
+
}, [onComplete]);
|
|
77
|
+
return /*#__PURE__*/React.createElement(Transition, {
|
|
78
|
+
in: inProp,
|
|
79
|
+
timeout: duration,
|
|
80
|
+
appear: true,
|
|
81
|
+
mountOnEnter: true,
|
|
82
|
+
unmountOnExit: true,
|
|
83
|
+
nodeRef: nodeRef
|
|
84
|
+
}, state => /*#__PURE__*/React.createElement("div", {
|
|
85
|
+
ref: nodeRef,
|
|
86
|
+
className: style.ripple,
|
|
87
|
+
style: {
|
|
88
|
+
...baseStyle,
|
|
89
|
+
...transitionStyles[state]
|
|
90
|
+
}
|
|
91
|
+
}));
|
|
92
|
+
}
|
|
93
|
+
RippleAnimation.defaultProps = {
|
|
94
|
+
color: themeConfig.colors.dark,
|
|
95
|
+
duration: 300,
|
|
96
|
+
onComplete: () => {},
|
|
97
|
+
size: 48,
|
|
98
|
+
x: 0,
|
|
99
|
+
y: 0
|
|
100
|
+
};
|
|
101
|
+
export default /*#__PURE__*/React.memo(RippleAnimation);
|
package/Ripple/index.js
CHANGED
|
@@ -1,60 +1,238 @@
|
|
|
1
|
-
|
|
1
|
+
import React, { PureComponent } from 'react';
|
|
2
|
+
import PropTypes from 'prop-types';
|
|
3
|
+
import { findDOMNode } from 'react-dom';
|
|
4
|
+
import clamp from 'lodash/clamp';
|
|
5
|
+
import { shift } from '@shopgate/pwa-common/helpers/data';
|
|
6
|
+
import { getOffset } from '@shopgate/pwa-common/helpers/dom';
|
|
7
|
+
import { themeConfig } from '@shopgate/pwa-common/helpers/config';
|
|
8
|
+
import RippleAnimation from "./components/RippleAnimation";
|
|
9
|
+
import style from "./style";
|
|
10
|
+
|
|
11
|
+
/**
|
|
2
12
|
* The ripple component.
|
|
3
|
-
*/
|
|
13
|
+
*/
|
|
14
|
+
class Ripple extends PureComponent {
|
|
15
|
+
/**
|
|
4
16
|
* Constructor.
|
|
5
17
|
* @param {Object} props The component props.
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
18
|
+
*/
|
|
19
|
+
constructor(props) {
|
|
20
|
+
super(props);
|
|
21
|
+
/**
|
|
22
|
+
* Triggers adding of a new ripple on touch start event.
|
|
23
|
+
* @param {Object} event The even object.
|
|
24
|
+
*/
|
|
25
|
+
this.handleClick = event => {
|
|
26
|
+
if (this.props.disabled) {
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
this.addRipple(event, true);
|
|
30
|
+
this.props.onClick();
|
|
31
|
+
};
|
|
32
|
+
/**
|
|
33
|
+
* Will be triggered from the ripple animation component, when the
|
|
34
|
+
* ripple animation is over. It removes the ripple from the queue again.
|
|
35
|
+
*/
|
|
36
|
+
this.removeRipple = () => {
|
|
37
|
+
if (!this.mounted) {
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
this.setState(prevState => {
|
|
41
|
+
const ripples = shift(prevState.ripples);
|
|
42
|
+
this.props.onComplete();
|
|
43
|
+
return {
|
|
44
|
+
ripples,
|
|
45
|
+
hasRipples: !!ripples.length
|
|
46
|
+
};
|
|
47
|
+
});
|
|
48
|
+
};
|
|
49
|
+
this.state = {
|
|
50
|
+
ripples: [],
|
|
51
|
+
nextKey: 0,
|
|
52
|
+
hasRipples: false
|
|
53
|
+
};
|
|
54
|
+
this.duration = 500;
|
|
55
|
+
this.ignoreNextMouseDown = false;
|
|
56
|
+
this.mounted = false;
|
|
57
|
+
this.offset = null;
|
|
58
|
+
this.position = null;
|
|
59
|
+
this.rootNode = null;
|
|
60
|
+
this.style = null;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
13
64
|
* Sets the `mounted` flag to true.
|
|
14
|
-
*/
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
this.
|
|
22
|
-
|
|
65
|
+
*/
|
|
66
|
+
componentDidMount() {
|
|
67
|
+
const {
|
|
68
|
+
fill
|
|
69
|
+
} = this.props;
|
|
70
|
+
|
|
71
|
+
// Reference to Ripple container (for now and later).
|
|
72
|
+
this.rootNode = findDOMNode(this); // eslint-disable-line react/no-find-dom-node
|
|
73
|
+
|
|
74
|
+
// Initially set the position values to be in the middle of the element.
|
|
75
|
+
// If the Ripple's starting point has to follow the user's touch
|
|
76
|
+
// Location then this is checked later.
|
|
77
|
+
this.position = {
|
|
78
|
+
x: this.rootNode.offsetWidth / 2,
|
|
79
|
+
y: this.rootNode.offsetHeight / 2
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
// Determine the duration based on the size of the ripple.
|
|
83
|
+
this.duration = clamp(Math.round(Math.log(this.rippleSize) * 100 - (fill ? -75 : 50)), 0, 10000);
|
|
84
|
+
|
|
85
|
+
// Set the `mounted` flag to true.
|
|
86
|
+
this.mounted = true;
|
|
87
|
+
|
|
88
|
+
// If the Ripple is not allowed to overflow then apply some styles to the parent container.
|
|
89
|
+
this.style = !this.props.overflow ? {
|
|
90
|
+
overflow: 'hidden',
|
|
91
|
+
position: 'relative'
|
|
92
|
+
} : null;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/**
|
|
23
96
|
* Sets the `mounted` flag to false
|
|
24
|
-
*/
|
|
97
|
+
*/
|
|
98
|
+
componentWillUnmount() {
|
|
99
|
+
this.mounted = false;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/**
|
|
25
103
|
* Calculate the size of the ripple.
|
|
26
104
|
* @returns {number}
|
|
27
|
-
*/
|
|
105
|
+
*/
|
|
106
|
+
get rippleSize() {
|
|
107
|
+
if (this.props.size) {
|
|
108
|
+
if (this.props.fill) {
|
|
109
|
+
return this.props.size * 2;
|
|
110
|
+
}
|
|
111
|
+
return this.props.size;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/**
|
|
28
115
|
* We want the Ripple to fill the element. We set the diameter of the Ripple
|
|
29
116
|
* to double the distance of the opposing corners of the node. That way the Ripple
|
|
30
117
|
* will reach the furthest away corner if you click at a corner.
|
|
31
|
-
*/
|
|
32
|
-
|
|
118
|
+
*/
|
|
119
|
+
if (this.props.fill) {
|
|
120
|
+
return Math.sqrt(this.rootNode.offsetWidth ** 2 + this.rootNode.offsetHeight ** 2) * 2;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
// Otherwise we set the size to be the smaller of the element's height and width.
|
|
124
|
+
return Math.min(this.rootNode.offsetWidth, this.rootNode.offsetHeight);
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/**
|
|
33
128
|
* Calculates the ripple position from the event.
|
|
34
129
|
* @param {Object} event The event object.
|
|
35
130
|
* @returns {Object} An object containing x and y values for the ripple.
|
|
36
|
-
*/
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
131
|
+
*/
|
|
132
|
+
getRipplePosition(event) {
|
|
133
|
+
// If the Ripple is to fill the element then we should set the
|
|
134
|
+
// Starting position to be where the user clicked within that element.
|
|
135
|
+
if (this.props.fill) {
|
|
136
|
+
// Determine if event is a touch event.
|
|
137
|
+
const isTouchEvent = event.touches && event.touches.length;
|
|
138
|
+
|
|
139
|
+
// Find the center points of the event.
|
|
140
|
+
const pageX = isTouchEvent ? event.touches[0].pageX : event.pageX;
|
|
141
|
+
const pageY = isTouchEvent ? event.touches[0].pageY : event.pageY;
|
|
142
|
+
|
|
143
|
+
// The pointer location is relative to the element offset.
|
|
144
|
+
this.position.x = pageX - this.offset.left;
|
|
145
|
+
this.position.y = pageY - this.offset.top;
|
|
146
|
+
}
|
|
147
|
+
return this.position;
|
|
148
|
+
}
|
|
149
|
+
/**
|
|
42
150
|
* Adds a new Ripple to the queue.
|
|
43
151
|
* @param {Object} event The event object.
|
|
44
152
|
* @param {boolean} isTouchGenerated Whether the action was triggered by a touch or click.
|
|
45
|
-
*/
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
153
|
+
*/
|
|
154
|
+
addRipple(event, isTouchGenerated) {
|
|
155
|
+
// If the adding of the Ripple was already triggered
|
|
156
|
+
// By a touch start event, no further action will be done.
|
|
157
|
+
if (this.ignoreNextMouseDown && !isTouchGenerated) {
|
|
158
|
+
this.ignoreNextMouseDown = false;
|
|
159
|
+
return;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
// Get the position of the element and store it.
|
|
163
|
+
this.offset = getOffset(this.rootNode);
|
|
164
|
+
|
|
165
|
+
// Receive the x and y position for the new Ripple.
|
|
166
|
+
const {
|
|
167
|
+
x,
|
|
168
|
+
y
|
|
169
|
+
} = this.getRipplePosition(event);
|
|
170
|
+
const {
|
|
171
|
+
ripples
|
|
172
|
+
} = this.state;
|
|
173
|
+
|
|
174
|
+
// Append the new ripple to the ripples array.
|
|
175
|
+
ripples.push(/*#__PURE__*/React.createElement(RippleAnimation, {
|
|
176
|
+
color: this.props.color,
|
|
177
|
+
duration: this.duration,
|
|
178
|
+
fill: this.props.fill,
|
|
179
|
+
key: this.state.nextKey,
|
|
180
|
+
onComplete: this.removeRipple,
|
|
181
|
+
size: this.rippleSize,
|
|
182
|
+
x: x,
|
|
183
|
+
y: y
|
|
184
|
+
}));
|
|
185
|
+
this.ignoreNextMouseDown = isTouchGenerated;
|
|
186
|
+
|
|
187
|
+
// Update the state.
|
|
188
|
+
this.setState(({
|
|
189
|
+
nextKey
|
|
190
|
+
}) => ({
|
|
191
|
+
ripples,
|
|
192
|
+
nextKey: nextKey + 1,
|
|
193
|
+
hasRipples: true
|
|
194
|
+
}));
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
/**
|
|
52
198
|
* Renders all the ripples in the queue.
|
|
53
199
|
* @returns {JSX|null}
|
|
54
|
-
*/
|
|
55
|
-
|
|
200
|
+
*/
|
|
201
|
+
renderRipples() {
|
|
202
|
+
// It only needs to render, if there is at least one ripple in the queue.
|
|
203
|
+
if (!this.state.hasRipples) {
|
|
204
|
+
return null;
|
|
205
|
+
}
|
|
206
|
+
return /*#__PURE__*/React.createElement("div", {
|
|
207
|
+
className: style.container
|
|
208
|
+
}, this.state.ripples);
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
/**
|
|
56
212
|
* Renders the final ripple component including it's contents.
|
|
57
213
|
* @returns {JSX}
|
|
58
|
-
*/
|
|
59
|
-
|
|
60
|
-
jsx-a11y/
|
|
214
|
+
*/
|
|
215
|
+
render() {
|
|
216
|
+
/* eslint-disable jsx-a11y/click-events-have-key-events,
|
|
217
|
+
jsx-a11y/no-static-element-interactions */
|
|
218
|
+
return /*#__PURE__*/React.createElement("div", {
|
|
219
|
+
className: `ui-shared__ripple ${this.props.className}`,
|
|
220
|
+
"data-test-id": "Ripple",
|
|
221
|
+
onClick: this.handleClick,
|
|
222
|
+
style: this.style
|
|
223
|
+
}, this.renderRipples(), this.props.children);
|
|
224
|
+
/* eslint-enable jsx-a11y/click-events-have-key-events,
|
|
225
|
+
jsx-a11y/no-static-element-interactions */
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
Ripple.defaultProps = {
|
|
229
|
+
className: '',
|
|
230
|
+
color: themeConfig.colors.dark,
|
|
231
|
+
disabled: false,
|
|
232
|
+
fill: false,
|
|
233
|
+
onClick: () => {},
|
|
234
|
+
onComplete: () => {},
|
|
235
|
+
overflow: false,
|
|
236
|
+
size: null
|
|
237
|
+
};
|
|
238
|
+
export default Ripple;
|
package/Ripple/style.js
CHANGED
|
@@ -1 +1,18 @@
|
|
|
1
|
-
import{
|
|
1
|
+
import { css } from 'glamor';
|
|
2
|
+
const ripple = css({
|
|
3
|
+
position: 'absolute',
|
|
4
|
+
borderRadius: '50%',
|
|
5
|
+
transformOrigin: '50% 50% 0'
|
|
6
|
+
}).toString();
|
|
7
|
+
const container = css({
|
|
8
|
+
position: 'absolute',
|
|
9
|
+
zIndex: 0,
|
|
10
|
+
top: 0,
|
|
11
|
+
left: 0,
|
|
12
|
+
width: '100%',
|
|
13
|
+
height: '100%'
|
|
14
|
+
}).toString();
|
|
15
|
+
export default {
|
|
16
|
+
ripple,
|
|
17
|
+
container
|
|
18
|
+
};
|
package/RippleButton/index.js
CHANGED
|
@@ -1,11 +1,58 @@
|
|
|
1
|
-
|
|
1
|
+
import _extends from "@babel/runtime/helpers/extends";
|
|
2
|
+
import React, { Component } from 'react';
|
|
3
|
+
import PropTypes from 'prop-types';
|
|
4
|
+
import Ripple from "../Ripple";
|
|
5
|
+
import Button from "../Button";
|
|
6
|
+
import style from "../Button/style";
|
|
7
|
+
|
|
8
|
+
/**
|
|
2
9
|
* The ripple button component is a special derivation of the basic button component
|
|
3
10
|
* that adds a ripple effect when clicked.
|
|
4
|
-
*/
|
|
11
|
+
*/
|
|
12
|
+
class RippleButton extends Component {
|
|
13
|
+
/**
|
|
5
14
|
* Getter for the calculated button props.
|
|
6
15
|
* @returns {Object}
|
|
7
|
-
*/
|
|
16
|
+
*/
|
|
17
|
+
get buttonProps() {
|
|
18
|
+
return {
|
|
19
|
+
className: `${this.props.className} ui-shared__ripple-button`,
|
|
20
|
+
disabled: this.props.disabled,
|
|
21
|
+
onClick: this.props.onClick,
|
|
22
|
+
flat: this.props.flat,
|
|
23
|
+
type: this.props.type,
|
|
24
|
+
wrapContent: false,
|
|
25
|
+
'aria-label': this.props['aria-label'],
|
|
26
|
+
'aria-haspopup': this.props['aria-haspopup']
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
8
31
|
* Renders the component.
|
|
9
32
|
* @returns {JSX}
|
|
10
|
-
*/
|
|
11
|
-
|
|
33
|
+
*/
|
|
34
|
+
render() {
|
|
35
|
+
if (this.props.disabled) {
|
|
36
|
+
// Don't show the ripple effect when the button is disabled.
|
|
37
|
+
return /*#__PURE__*/React.createElement(Button, _extends({}, this.buttonProps, {
|
|
38
|
+
wrapContent: true
|
|
39
|
+
}), this.props.children);
|
|
40
|
+
}
|
|
41
|
+
const rippleProps = {
|
|
42
|
+
className: `${style.contentWrapper} ${this.props.rippleClassName}`,
|
|
43
|
+
fill: true,
|
|
44
|
+
size: this.props.rippleSize,
|
|
45
|
+
overflow: true
|
|
46
|
+
};
|
|
47
|
+
return /*#__PURE__*/React.createElement(Button, _extends({}, this.buttonProps, {
|
|
48
|
+
testId: this.props.testId
|
|
49
|
+
}), /*#__PURE__*/React.createElement(Ripple, rippleProps, this.props.children));
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
RippleButton.defaultProps = {
|
|
53
|
+
...Button.defaultProps,
|
|
54
|
+
rippleClassName: '',
|
|
55
|
+
rippleSize: null,
|
|
56
|
+
testId: 'Button'
|
|
57
|
+
};
|
|
58
|
+
export default RippleButton;
|
package/RippleButton/spec.js
CHANGED
|
@@ -1 +1,45 @@
|
|
|
1
|
-
import trim from'lodash/trim';
|
|
1
|
+
import trim from 'lodash/trim';
|
|
2
|
+
import React from 'react';
|
|
3
|
+
import { shallow, mount } from 'enzyme';
|
|
4
|
+
import Button from '@shopgate/pwa-common/components/Button';
|
|
5
|
+
import Ripple from "../Ripple";
|
|
6
|
+
import styles from "../Button/style";
|
|
7
|
+
import RippleButton from "./index";
|
|
8
|
+
describe('<RippleButton />', () => {
|
|
9
|
+
it('should render as a regular ripple button effect if type is omitted', () => {
|
|
10
|
+
const wrapper = shallow(/*#__PURE__*/React.createElement(RippleButton, null, "Press me"));
|
|
11
|
+
expect(wrapper).toMatchSnapshot();
|
|
12
|
+
expect(wrapper.find(Ripple).render().text()).toEqual('Press me');
|
|
13
|
+
});
|
|
14
|
+
it('should render as a regular ripple button if type is explicitly defined', () => {
|
|
15
|
+
const wrapper = mount(/*#__PURE__*/React.createElement(RippleButton, {
|
|
16
|
+
type: "regular"
|
|
17
|
+
}, "Press me"));
|
|
18
|
+
expect(trim(wrapper.find(Button).props().className)).toEqual(`ui-shared__button ${styles.regular(false).button} ui-shared__ripple-button`);
|
|
19
|
+
expect(wrapper.find(Ripple).render().text()).toEqual('Press me');
|
|
20
|
+
expect(wrapper).toMatchSnapshot();
|
|
21
|
+
});
|
|
22
|
+
it('should render as a primary ripple button', () => {
|
|
23
|
+
const wrapper = mount(/*#__PURE__*/React.createElement(RippleButton, {
|
|
24
|
+
type: "primary"
|
|
25
|
+
}, "Press me"));
|
|
26
|
+
expect(trim(wrapper.find(Button).props().className)).toEqual(`ui-shared__button ${styles.primary(false).button} ui-shared__ripple-button`);
|
|
27
|
+
expect(wrapper.find(Ripple).render().text()).toEqual('Press me');
|
|
28
|
+
expect(wrapper).toMatchSnapshot();
|
|
29
|
+
});
|
|
30
|
+
it('should render as a secondary ripple button', () => {
|
|
31
|
+
const wrapper = mount(/*#__PURE__*/React.createElement(RippleButton, {
|
|
32
|
+
type: "secondary"
|
|
33
|
+
}, "Press me"));
|
|
34
|
+
expect(trim(wrapper.find(Button).props().className)).toEqual(`ui-shared__button ${styles.secondary(false).button} ui-shared__ripple-button`);
|
|
35
|
+
expect(wrapper.find(Ripple).render().text()).toEqual('Press me');
|
|
36
|
+
expect(wrapper).toMatchSnapshot();
|
|
37
|
+
});
|
|
38
|
+
it('should render as a disabled ripple button', () => {
|
|
39
|
+
const wrapper = mount(/*#__PURE__*/React.createElement(RippleButton, {
|
|
40
|
+
disabled: true
|
|
41
|
+
}, "Press me"));
|
|
42
|
+
expect(wrapper.find(Button).props().disabled).toBe(true);
|
|
43
|
+
expect(wrapper).toMatchSnapshot();
|
|
44
|
+
});
|
|
45
|
+
});
|
|
@@ -1,3 +1,14 @@
|
|
|
1
|
-
import React from'react';
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import SurroundPortals from '@shopgate/pwa-common/components/SurroundPortals';
|
|
3
|
+
import { SCANNER_CAMERA } from '@shopgate/pwa-common-commerce/scanner/constants/Portals';
|
|
4
|
+
import styles from "./style";
|
|
5
|
+
|
|
6
|
+
/**
|
|
2
7
|
* @returns {JSX}
|
|
3
|
-
*/
|
|
8
|
+
*/
|
|
9
|
+
const CameraOverlay = () => /*#__PURE__*/React.createElement(SurroundPortals, {
|
|
10
|
+
portalName: SCANNER_CAMERA
|
|
11
|
+
}, /*#__PURE__*/React.createElement("div", {
|
|
12
|
+
className: styles
|
|
13
|
+
}, /*#__PURE__*/React.createElement("div", null)));
|
|
14
|
+
export default CameraOverlay;
|
|
@@ -1 +1,40 @@
|
|
|
1
|
-
import{
|
|
1
|
+
import { css } from 'glamor';
|
|
2
|
+
import { themeVariables, themeColors } from '@shopgate/pwa-common/helpers/config';
|
|
3
|
+
const edgeHeight = 45;
|
|
4
|
+
const edgeWidth = 35;
|
|
5
|
+
const edgeBorderWidth = 3;
|
|
6
|
+
const edgeOffsetHorizontal = themeVariables.gap.xbig;
|
|
7
|
+
const edgeOffsetVertical = themeVariables.gap.xxbig;
|
|
8
|
+
export default css({
|
|
9
|
+
height: '90%',
|
|
10
|
+
width: '100%',
|
|
11
|
+
':before,:after,>:before,>:after': {
|
|
12
|
+
display: 'block',
|
|
13
|
+
content: ' ',
|
|
14
|
+
width: edgeWidth,
|
|
15
|
+
height: edgeHeight,
|
|
16
|
+
position: 'absolute',
|
|
17
|
+
borderStyle: 'solid',
|
|
18
|
+
borderColor: themeColors.light
|
|
19
|
+
},
|
|
20
|
+
':before': {
|
|
21
|
+
top: edgeOffsetVertical,
|
|
22
|
+
left: edgeOffsetHorizontal,
|
|
23
|
+
borderWidth: `${edgeBorderWidth}px 0 0 ${edgeBorderWidth}px`
|
|
24
|
+
},
|
|
25
|
+
':after': {
|
|
26
|
+
top: edgeOffsetVertical,
|
|
27
|
+
right: edgeOffsetHorizontal,
|
|
28
|
+
borderWidth: `${edgeBorderWidth}px ${edgeBorderWidth}px 0 0`
|
|
29
|
+
},
|
|
30
|
+
'>:before': {
|
|
31
|
+
bottom: edgeOffsetVertical,
|
|
32
|
+
left: edgeOffsetHorizontal,
|
|
33
|
+
borderWidth: `0 0 ${edgeBorderWidth}px ${edgeBorderWidth}px`
|
|
34
|
+
},
|
|
35
|
+
'>:after': {
|
|
36
|
+
bottom: edgeOffsetVertical,
|
|
37
|
+
right: edgeOffsetHorizontal,
|
|
38
|
+
borderWidth: `0 ${edgeBorderWidth}px ${edgeBorderWidth}px 0`
|
|
39
|
+
}
|
|
40
|
+
}).toString();
|