@shopgate/pwa-common 7.30.3 → 7.31.0-alpha.1
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/App.js +0 -2
- package/actions/app/handleLink.js +1 -0
- package/collections/AuthRoutes.js +1 -0
- package/collections/PersistedReducers.js +1 -0
- package/collections/media-providers/Vimeo.js +1 -1
- package/collections/media-providers/style.js +1 -1
- package/components/Backdrop/index.js +18 -3
- package/components/Button/index.js +40 -52
- package/components/Checkbox/index.js +1 -1
- package/components/Drawer/index.js +118 -132
- package/components/Drawer/spec.js +4 -2
- package/components/Dropdown/index.js +52 -68
- package/components/Grid/components/Item/index.js +37 -40
- package/components/Grid/index.js +36 -34
- package/components/HtmlSanitizer/index.js +60 -7
- package/components/I18n/components/FormatNumber/spec.js +1 -0
- package/components/Icon/index.d.ts +36 -0
- package/components/Icon/index.d.ts.map +1 -0
- package/components/Icon/index.js +39 -28
- package/components/Image/Image.js +27 -6
- package/components/Image/ImageInner.js +32 -25
- package/components/InfiniteContainer/index.js +5 -7
- package/components/InfiniteContainer/spec.js +13 -17
- package/components/Link/index.js +75 -84
- package/components/List/components/Item/index.js +19 -10
- package/components/List/spec.js +1 -3
- package/components/Loading/index.d.ts +6 -0
- package/components/Loading/index.d.ts.map +1 -0
- package/components/Modal/index.js +41 -7
- package/components/Picker/index.js +18 -194
- package/components/Portal/index.d.ts +50 -0
- package/components/Portal/index.d.ts.map +1 -0
- package/components/ProductCharacteristics/index.js +14 -276
- package/components/RangeSlider/index.js +15 -258
- package/components/Select/components/Item/index.js +18 -7
- package/components/Select/index.js +108 -144
- package/components/Select/spec.js +49 -16
- package/components/SelectBox/components/Item/index.js +49 -51
- package/components/SelectBox/index.js +140 -160
- package/components/SurroundPortals/index.d.ts +24 -0
- package/components/SurroundPortals/index.d.ts.map +1 -0
- package/components/SurroundPortals/index.js +3 -13
- package/components/Swiper/components/SwiperItem/index.js +13 -4
- package/components/Swiper/components/SwiperItem/spec.js +3 -2
- package/components/Swiper/index.js +80 -12
- package/components/Widgets/components/Widget/index.js +54 -56
- package/components/Widgets/components/Widget/spec.js +12 -8
- package/components/Widgets/components/WidgetGrid/index.js +39 -53
- package/components/Widgets/components/WidgetGrid/spec.js +12 -8
- package/constants/Configuration.js +2 -1
- package/constants/Portals.d.ts +101 -0
- package/constants/Portals.d.ts.map +1 -0
- package/helpers/config/index.d.ts +94 -0
- package/helpers/config/index.d.ts.map +1 -0
- package/helpers/config/mock.d.ts +23 -0
- package/helpers/config/mock.d.ts.map +1 -0
- package/helpers/config/theme.d.ts +7 -0
- package/helpers/config/theme.d.ts.map +1 -0
- package/helpers/data/index.d.ts +35 -0
- package/helpers/data/index.d.ts.map +1 -0
- package/helpers/data/index.js +1 -0
- package/helpers/html/handleDOM.js +1 -0
- package/helpers/portals/portalCollection.d.ts +30 -0
- package/helpers/portals/portalCollection.d.ts.map +1 -0
- package/helpers/style/index.js +1 -0
- package/helpers/validation/index.d.ts +10 -0
- package/helpers/validation/index.d.ts.map +1 -0
- package/package.json +4 -3
- package/selectors/client.js +1 -0
- package/styles/reset/form.js +46 -51
- package/styles/reset/media.js +21 -19
- package/styles/reset/root.js +28 -26
- package/styles/reset/table.js +9 -7
- package/styles/reset/typography.js +24 -22
- package/subscriptions/error.js +1 -0
- package/subscriptions/helpers/handleLinks.js +1 -0
- package/subscriptions/router.js +1 -0
- package/tsconfig.build.json +16 -0
- package/tsconfig.json +3 -0
- package/components/Backdrop/style.js +0 -11
- package/components/Button/style.js +0 -6
- package/components/Drawer/style.js +0 -37
- package/components/Dropdown/style.js +0 -4
- package/components/Grid/components/Item/style.js +0 -23
- package/components/Grid/style.js +0 -14
- package/components/Icon/style.js +0 -6
- package/components/Image/style.js +0 -32
- package/components/Link/style.js +0 -10
- package/components/List/components/Item/style.js +0 -16
- package/components/Modal/style.js +0 -36
- package/components/Picker/components/Button/index.js +0 -42
- package/components/Picker/components/Button/style.js +0 -19
- package/components/Picker/components/List/index.js +0 -38
- package/components/Picker/components/List/style.js +0 -17
- package/components/Picker/components/Modal/index.js +0 -76
- package/components/Picker/components/Modal/style.js +0 -78
- package/components/Picker/spec.js +0 -88
- package/components/ProductCharacteristics/connector.js +0 -41
- package/components/ProductCharacteristics/context.js +0 -2
- package/components/ProductCharacteristics/helpers/index.js +0 -162
- package/components/RangeSlider/components/Handle/index.js +0 -34
- package/components/RangeSlider/components/Handle/style.js +0 -14
- package/components/RangeSlider/helper.js +0 -85
- package/components/RangeSlider/style.js +0 -14
- package/components/Select/components/Item/style.js +0 -4
- package/components/Select/style.js +0 -17
- package/components/SelectBox/components/Item/style.js +0 -7
- package/components/SelectBox/style.js +0 -18
- package/components/Swiper/components/SwiperItem/styles.js +0 -5
- package/components/Swiper/styles.js +0 -76
- package/components/Widgets/components/Widget/style.js +0 -27
- package/components/Widgets/components/WidgetGrid/style.js +0 -8
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
import React from 'react';
|
|
2
|
-
import PropTypes from 'prop-types';
|
|
3
|
-
import classNames from 'classnames';
|
|
4
|
-
import styles from "./style";
|
|
5
|
-
|
|
6
|
-
/**
|
|
7
|
-
* The default button for the Picker component.
|
|
8
|
-
* @returns {JSX} The button component.
|
|
9
|
-
*/
|
|
10
|
-
import { jsx as _jsx } from "react/jsx-runtime";
|
|
11
|
-
const PickerList = ({
|
|
12
|
-
items,
|
|
13
|
-
onClose,
|
|
14
|
-
onSelect,
|
|
15
|
-
selectedIndex
|
|
16
|
-
}) => /*#__PURE__*/_jsx("ul", {
|
|
17
|
-
className: "common__picker__list",
|
|
18
|
-
children: items.map((item, currentIndex) => /*#__PURE__*/_jsx("li", {
|
|
19
|
-
className: classNames({
|
|
20
|
-
[styles.active]: currentIndex === selectedIndex
|
|
21
|
-
}),
|
|
22
|
-
children: /*#__PURE__*/_jsx("button", {
|
|
23
|
-
className: styles.button,
|
|
24
|
-
disabled: item.disabled,
|
|
25
|
-
onClick: () => {
|
|
26
|
-
onSelect(item.value);
|
|
27
|
-
onClose();
|
|
28
|
-
},
|
|
29
|
-
type: "button",
|
|
30
|
-
children: item.label
|
|
31
|
-
})
|
|
32
|
-
}, item.value))
|
|
33
|
-
});
|
|
34
|
-
PickerList.defaultProps = {
|
|
35
|
-
onClose: () => {},
|
|
36
|
-
selectedIndex: null
|
|
37
|
-
};
|
|
38
|
-
export default PickerList;
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
import { css } from 'glamor';
|
|
2
|
-
const button = css({
|
|
3
|
-
display: 'block',
|
|
4
|
-
width: '100%',
|
|
5
|
-
padding: '10px 20px',
|
|
6
|
-
outline: 'none',
|
|
7
|
-
textAlign: 'left'
|
|
8
|
-
}).toString();
|
|
9
|
-
const active = css({
|
|
10
|
-
button: {
|
|
11
|
-
fontWeight: 'bold'
|
|
12
|
-
}
|
|
13
|
-
}).toString();
|
|
14
|
-
export default {
|
|
15
|
-
button,
|
|
16
|
-
active
|
|
17
|
-
};
|
|
@@ -1,76 +0,0 @@
|
|
|
1
|
-
import _inheritsLoose from "@babel/runtime/helpers/inheritsLoose";
|
|
2
|
-
import React, { Component } from 'react';
|
|
3
|
-
import PropTypes from 'prop-types';
|
|
4
|
-
import classNames from 'classnames';
|
|
5
|
-
import styles from "./style";
|
|
6
|
-
|
|
7
|
-
/**
|
|
8
|
-
* The picker modal.
|
|
9
|
-
*/
|
|
10
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
11
|
-
let PickerModal = /*#__PURE__*/function (_Component) {
|
|
12
|
-
/**
|
|
13
|
-
* The constructor.
|
|
14
|
-
* @param {Object} props The props.
|
|
15
|
-
*/
|
|
16
|
-
function PickerModal(props) {
|
|
17
|
-
var _this;
|
|
18
|
-
_this = _Component.call(this, props) || this;
|
|
19
|
-
/**
|
|
20
|
-
* Closes the modal after the closing animations have finished.
|
|
21
|
-
*/
|
|
22
|
-
_this.closeModal = () => {
|
|
23
|
-
_this.setState({
|
|
24
|
-
active: false
|
|
25
|
-
});
|
|
26
|
-
clearTimeout(_this.timeout);
|
|
27
|
-
_this.timeout = setTimeout(_this.props.onClose, styles.duration);
|
|
28
|
-
};
|
|
29
|
-
_this.timeout = null;
|
|
30
|
-
_this.state = {
|
|
31
|
-
active: true
|
|
32
|
-
};
|
|
33
|
-
return _this;
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
/**
|
|
37
|
-
* Update state when isOpen changes.
|
|
38
|
-
* @param {Object} nextProps The next component props.
|
|
39
|
-
*/
|
|
40
|
-
_inheritsLoose(PickerModal, _Component);
|
|
41
|
-
var _proto = PickerModal.prototype;
|
|
42
|
-
_proto.UNSAFE_componentWillReceiveProps = function UNSAFE_componentWillReceiveProps(nextProps) {
|
|
43
|
-
if (this.props.isOpen !== nextProps.isOpen) {
|
|
44
|
-
this.setState({
|
|
45
|
-
active: nextProps.isOpen
|
|
46
|
-
});
|
|
47
|
-
}
|
|
48
|
-
};
|
|
49
|
-
/**
|
|
50
|
-
* Render all the things!
|
|
51
|
-
* @returns {JSX} The picker modal with the picker list inside.
|
|
52
|
-
*/
|
|
53
|
-
_proto.render = function render() {
|
|
54
|
-
const backgroundClassName = classNames(styles.background.base, {
|
|
55
|
-
[styles.background.inactive]: !this.state.active
|
|
56
|
-
});
|
|
57
|
-
const containerClassName = classNames(styles.container.base, {
|
|
58
|
-
[styles.container.inactive]: !this.state.active
|
|
59
|
-
});
|
|
60
|
-
return this.props.isOpen ? /*#__PURE__*/_jsxs("div", {
|
|
61
|
-
className: `${styles.wrapper} common__picker__modal`,
|
|
62
|
-
children: [/*#__PURE__*/_jsx("div", {
|
|
63
|
-
"aria-hidden": true,
|
|
64
|
-
className: backgroundClassName,
|
|
65
|
-
onClick: this.closeModal
|
|
66
|
-
}), /*#__PURE__*/_jsx("div", {
|
|
67
|
-
className: containerClassName,
|
|
68
|
-
children: /*#__PURE__*/React.cloneElement(this.props.children, {
|
|
69
|
-
onClose: this.closeModal
|
|
70
|
-
})
|
|
71
|
-
})]
|
|
72
|
-
}) : null;
|
|
73
|
-
};
|
|
74
|
-
return PickerModal;
|
|
75
|
-
}(Component);
|
|
76
|
-
export default PickerModal;
|
|
@@ -1,78 +0,0 @@
|
|
|
1
|
-
import { css } from 'glamor';
|
|
2
|
-
import { themeColors } from '@shopgate/pwa-common/helpers/config';
|
|
3
|
-
const fadeDuration = 150;
|
|
4
|
-
const slideDuration = 150;
|
|
5
|
-
const easing = 'cubic-bezier(0.25, 0.1, 0.25, 1)';
|
|
6
|
-
const slideInPickerModal = css.keyframes({
|
|
7
|
-
'0%': {
|
|
8
|
-
transform: 'translateY(100%)'
|
|
9
|
-
},
|
|
10
|
-
'100%': {
|
|
11
|
-
transform: 'translateY(0)'
|
|
12
|
-
}
|
|
13
|
-
});
|
|
14
|
-
const slideOutPickerModal = css.keyframes({
|
|
15
|
-
'0%': {
|
|
16
|
-
transform: 'translateY(0)'
|
|
17
|
-
},
|
|
18
|
-
'100%': {
|
|
19
|
-
transform: 'translateY(100%)'
|
|
20
|
-
}
|
|
21
|
-
});
|
|
22
|
-
const fadeInPickerBackground = css.keyframes({
|
|
23
|
-
'0%': {
|
|
24
|
-
opacity: 0
|
|
25
|
-
},
|
|
26
|
-
'100%': {
|
|
27
|
-
opacity: 0.5
|
|
28
|
-
}
|
|
29
|
-
});
|
|
30
|
-
const fadeOutPickerBackground = css.keyframes({
|
|
31
|
-
'0%': {
|
|
32
|
-
opacity: 0.5
|
|
33
|
-
},
|
|
34
|
-
'100%': {
|
|
35
|
-
opacity: 0
|
|
36
|
-
}
|
|
37
|
-
});
|
|
38
|
-
const wrapper = css({
|
|
39
|
-
zIndex: 1000,
|
|
40
|
-
position: 'fixed',
|
|
41
|
-
top: 0,
|
|
42
|
-
bottom: 0,
|
|
43
|
-
left: 0,
|
|
44
|
-
right: 0
|
|
45
|
-
}).toString();
|
|
46
|
-
const background = {
|
|
47
|
-
base: css({
|
|
48
|
-
position: 'absolute',
|
|
49
|
-
top: 0,
|
|
50
|
-
bottom: 0,
|
|
51
|
-
left: 0,
|
|
52
|
-
right: 0,
|
|
53
|
-
backgroundColor: 'black',
|
|
54
|
-
animation: `${fadeInPickerBackground} ${fadeDuration}ms 1 both`
|
|
55
|
-
}).toString(),
|
|
56
|
-
inactive: css({
|
|
57
|
-
animation: `${fadeOutPickerBackground} ${fadeDuration}ms 1 both`
|
|
58
|
-
}).toString()
|
|
59
|
-
};
|
|
60
|
-
const container = {
|
|
61
|
-
base: css({
|
|
62
|
-
position: 'absolute',
|
|
63
|
-
bottom: 0,
|
|
64
|
-
left: 0,
|
|
65
|
-
right: 0,
|
|
66
|
-
backgroundColor: themeColors.light,
|
|
67
|
-
animation: `${slideInPickerModal} ${slideDuration}ms 1 both ${easing}`
|
|
68
|
-
}).toString(),
|
|
69
|
-
inactive: css({
|
|
70
|
-
animation: `${slideOutPickerModal} ${slideDuration}ms 1 both ${easing}`
|
|
71
|
-
}).toString()
|
|
72
|
-
};
|
|
73
|
-
export default {
|
|
74
|
-
background,
|
|
75
|
-
container,
|
|
76
|
-
wrapper,
|
|
77
|
-
duration: Math.max(slideDuration, fadeDuration)
|
|
78
|
-
};
|
|
@@ -1,88 +0,0 @@
|
|
|
1
|
-
import React from 'react';
|
|
2
|
-
import { mount } from 'enzyme';
|
|
3
|
-
import Picker from "./index";
|
|
4
|
-
import PickerList from "./components/List";
|
|
5
|
-
import { jsx as _jsx } from "react/jsx-runtime";
|
|
6
|
-
jest.mock('@shopgate/engage/components');
|
|
7
|
-
jest.mock('@shopgate/engage/core');
|
|
8
|
-
describe('<Picker />', () => {
|
|
9
|
-
let renderedElement;
|
|
10
|
-
let renderedInstance;
|
|
11
|
-
const mockItems = ['String only', {
|
|
12
|
-
value: 'Value only'
|
|
13
|
-
}, {
|
|
14
|
-
value: 'value',
|
|
15
|
-
label: 'Value and label'
|
|
16
|
-
}];
|
|
17
|
-
const mockOnChange = jest.fn();
|
|
18
|
-
const mockOnSelect = jest.fn();
|
|
19
|
-
|
|
20
|
-
/**
|
|
21
|
-
* The view component
|
|
22
|
-
* @param {Object} props The component props.
|
|
23
|
-
*/
|
|
24
|
-
const renderComponent = props => {
|
|
25
|
-
renderedElement = mount(/*#__PURE__*/_jsx(Picker, {
|
|
26
|
-
...props
|
|
27
|
-
}));
|
|
28
|
-
renderedInstance = renderedElement.find('Picker').instance();
|
|
29
|
-
};
|
|
30
|
-
beforeEach(() => {
|
|
31
|
-
renderComponent({
|
|
32
|
-
items: mockItems,
|
|
33
|
-
onChange: mockOnChange,
|
|
34
|
-
onSelect: mockOnSelect
|
|
35
|
-
});
|
|
36
|
-
renderedElement.update();
|
|
37
|
-
});
|
|
38
|
-
describe('Given the component was mounted to the DOM', () => {
|
|
39
|
-
it('should match snapshot', () => {
|
|
40
|
-
expect(renderedElement).toMatchSnapshot();
|
|
41
|
-
});
|
|
42
|
-
it('should have no selected value', () => {
|
|
43
|
-
expect(renderedInstance.selectedItem).toBe(null);
|
|
44
|
-
});
|
|
45
|
-
describe('Given picker component gets opened', () => {
|
|
46
|
-
beforeEach(() => {
|
|
47
|
-
renderedInstance.toggleOpenState(true);
|
|
48
|
-
renderedElement.update();
|
|
49
|
-
});
|
|
50
|
-
it('should have isOpen state', () => {
|
|
51
|
-
expect(renderedInstance.state.isOpen).toBe(true);
|
|
52
|
-
});
|
|
53
|
-
it('should render the picker list', () => {
|
|
54
|
-
expect(renderedElement.find(PickerList).length).toBe(1);
|
|
55
|
-
});
|
|
56
|
-
it('should render the picker items', () => {
|
|
57
|
-
expect(renderedElement.find('li button').length).toBe(mockItems.length);
|
|
58
|
-
});
|
|
59
|
-
describe('Given a item gets selected', () => {
|
|
60
|
-
jest.useFakeTimers();
|
|
61
|
-
beforeEach(() => {
|
|
62
|
-
jest.clearAllMocks();
|
|
63
|
-
renderedElement.find('li button').first().simulate('click');
|
|
64
|
-
jest.runAllTimers();
|
|
65
|
-
});
|
|
66
|
-
afterEach(() => {
|
|
67
|
-
jest.clearAllTimers();
|
|
68
|
-
});
|
|
69
|
-
it('should trigger onChange when the value changed', () => {
|
|
70
|
-
expect(mockOnChange).toHaveBeenCalledTimes(1);
|
|
71
|
-
});
|
|
72
|
-
it('should trigger onSelect when the value changed', () => {
|
|
73
|
-
expect(mockOnSelect).toHaveBeenCalledTimes(1);
|
|
74
|
-
});
|
|
75
|
-
it('should not trigger onChange when the value did not change, but trigger onSelect', () => {
|
|
76
|
-
renderedInstance.setState({
|
|
77
|
-
selectedIndex: 0
|
|
78
|
-
});
|
|
79
|
-
renderedInstance.toggleOpenState(true);
|
|
80
|
-
renderedElement.find('li button').first().simulate('click');
|
|
81
|
-
jest.runAllTimers();
|
|
82
|
-
expect(mockOnChange).toHaveBeenCalledTimes(1);
|
|
83
|
-
expect(mockOnSelect).toHaveBeenCalledTimes(2);
|
|
84
|
-
});
|
|
85
|
-
});
|
|
86
|
-
});
|
|
87
|
-
});
|
|
88
|
-
});
|
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
import { connect } from 'react-redux';
|
|
2
|
-
import { router } from '@shopgate/pwa-common/helpers/router';
|
|
3
|
-
import isEqual from 'lodash/isEqual';
|
|
4
|
-
import { getProductVariants } from '@shopgate/pwa-common-commerce/product/selectors/product';
|
|
5
|
-
|
|
6
|
-
/**
|
|
7
|
-
* Maps the contents of the state to the component props.
|
|
8
|
-
* @param {Object} state The current application state.
|
|
9
|
-
* @param {Object} props The component props.
|
|
10
|
-
* @return {Object} The extended component props.
|
|
11
|
-
*/
|
|
12
|
-
const mapStateToProps = (state, props) => ({
|
|
13
|
-
variants: getProductVariants(state, props)
|
|
14
|
-
});
|
|
15
|
-
|
|
16
|
-
/**
|
|
17
|
-
* @return {Object}
|
|
18
|
-
*/
|
|
19
|
-
const mapDispatchToProps = () => ({
|
|
20
|
-
navigate: productId => {
|
|
21
|
-
const route = router.getCurrentRoute();
|
|
22
|
-
router.update(route.id, {
|
|
23
|
-
productId
|
|
24
|
-
});
|
|
25
|
-
}
|
|
26
|
-
});
|
|
27
|
-
|
|
28
|
-
/**
|
|
29
|
-
* @param {Object} next The next component props.
|
|
30
|
-
* @param {Object} prev The previous component props.
|
|
31
|
-
* @returns {boolean}
|
|
32
|
-
*/
|
|
33
|
-
const areStatePropsEqual = (next, prev) => {
|
|
34
|
-
if (!prev.variants && next.variants || !isEqual(prev.variants, next.variants)) {
|
|
35
|
-
return false;
|
|
36
|
-
}
|
|
37
|
-
return true;
|
|
38
|
-
};
|
|
39
|
-
export default connect(mapStateToProps, mapDispatchToProps, null, {
|
|
40
|
-
areStatePropsEqual
|
|
41
|
-
});
|
|
@@ -1,162 +0,0 @@
|
|
|
1
|
-
import "core-js/modules/es.array.reduce.js";
|
|
2
|
-
import isMatch from 'lodash/isMatch';
|
|
3
|
-
import appConfig from '@shopgate/pwa-common/helpers/config';
|
|
4
|
-
const {
|
|
5
|
-
variantSelectionMode,
|
|
6
|
-
product: {
|
|
7
|
-
variantPreselect
|
|
8
|
-
} = {}
|
|
9
|
-
} = appConfig;
|
|
10
|
-
const preselectVariant = variantPreselect || parseInt(variantSelectionMode, 10) === 1;
|
|
11
|
-
|
|
12
|
-
/**
|
|
13
|
-
* Returns the index of a particular characteristic from a set of characteristics.
|
|
14
|
-
* @param {Array} characteristics The characteristics of a product.
|
|
15
|
-
* @param {number} characteristicId The id of the characteristic to find.
|
|
16
|
-
* @return {number}
|
|
17
|
-
*/
|
|
18
|
-
export function findSelectionIndex(characteristics, characteristicId) {
|
|
19
|
-
return characteristics.findIndex(char => char.id === characteristicId);
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
/**
|
|
23
|
-
* Returns true if the characteristic at the given index is the next characteristic to be selected.
|
|
24
|
-
* @param {Array} characteristics The characteristics of a product.
|
|
25
|
-
* @param {number} index The index of the characteristic to check.
|
|
26
|
-
* @return {boolean}
|
|
27
|
-
*/
|
|
28
|
-
export function isCharacteristicEnabled(characteristics, index) {
|
|
29
|
-
if (index === 0) {
|
|
30
|
-
return true;
|
|
31
|
-
}
|
|
32
|
-
return !!Object.values(characteristics)[index - 1];
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
/**
|
|
36
|
-
* Returns the selected value by characteristic ID.
|
|
37
|
-
* @param {string} charId The characteristic ID.
|
|
38
|
-
* @param {Object} characteristics The already selected characteristics.
|
|
39
|
-
* @return {string|null}
|
|
40
|
-
*/
|
|
41
|
-
export function getSelectedValue(charId, characteristics) {
|
|
42
|
-
return characteristics[charId] ? characteristics[charId] : null;
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
/**
|
|
46
|
-
* Prepares the new state after a selection has been made.
|
|
47
|
-
* @param {string} id The selection ID
|
|
48
|
-
* @param {string} value The selection value.
|
|
49
|
-
* @param {Object} selections The selections stored in the state.
|
|
50
|
-
* @param {Array} characteristics The characteristics of a product.
|
|
51
|
-
* @param {Array} products All available products.
|
|
52
|
-
* @return {Object}
|
|
53
|
-
*/
|
|
54
|
-
export function prepareState(id, value, selections, characteristics, products) {
|
|
55
|
-
const updateValid = !!characteristics.find(({
|
|
56
|
-
id: cId,
|
|
57
|
-
values
|
|
58
|
-
}) => {
|
|
59
|
-
if (cId !== id) {
|
|
60
|
-
return false;
|
|
61
|
-
}
|
|
62
|
-
return !!values.find(({
|
|
63
|
-
id: vId
|
|
64
|
-
}) => vId === value);
|
|
65
|
-
});
|
|
66
|
-
if (!updateValid) {
|
|
67
|
-
// Input parameters are invalid.
|
|
68
|
-
return selections;
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
// Merge the just changed value into the previous selection.
|
|
72
|
-
const currentSelection = {
|
|
73
|
-
...selections,
|
|
74
|
-
[id]: value
|
|
75
|
-
};
|
|
76
|
-
|
|
77
|
-
/**
|
|
78
|
-
* Determine if there are products for the current user selection.
|
|
79
|
-
*/
|
|
80
|
-
const matches = products.filter(product => isMatch(product.characteristics, currentSelection));
|
|
81
|
-
if (matches.length === 1) {
|
|
82
|
-
// Product found for the current selection.
|
|
83
|
-
return {
|
|
84
|
-
...matches[0].characteristics
|
|
85
|
-
};
|
|
86
|
-
}
|
|
87
|
-
if (!selections[id]) {
|
|
88
|
-
// Changed value wasn't set before.
|
|
89
|
-
return currentSelection;
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
// Find the current index.
|
|
93
|
-
const index = findSelectionIndex(characteristics, id);
|
|
94
|
-
|
|
95
|
-
/**
|
|
96
|
-
* When the given index is the same as the complete set
|
|
97
|
-
* of characteristics then there is nothing to reset.
|
|
98
|
-
*/
|
|
99
|
-
if (index === characteristics.length - 1) {
|
|
100
|
-
return currentSelection;
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
// Find the selections after the given index.
|
|
104
|
-
const after = characteristics.slice(index + 1);
|
|
105
|
-
|
|
106
|
-
// Delete the found selections.
|
|
107
|
-
after.forEach(item => {
|
|
108
|
-
delete currentSelection[item.id];
|
|
109
|
-
});
|
|
110
|
-
return currentSelection;
|
|
111
|
-
}
|
|
112
|
-
/**
|
|
113
|
-
* Preselect characteristics for variant
|
|
114
|
-
* or pre-select the first available product
|
|
115
|
-
* @param {string} [variantId=null] The selected variant
|
|
116
|
-
* @param {{products: Object[], characteristics: Object[]}} [variants=null] All possible variants.
|
|
117
|
-
* @return {Object}
|
|
118
|
-
*/
|
|
119
|
-
export function selectCharacteristics({
|
|
120
|
-
variantId,
|
|
121
|
-
variants = {}
|
|
122
|
-
}) {
|
|
123
|
-
if (!variants || !variants.products || !variants.products.length) {
|
|
124
|
-
return {};
|
|
125
|
-
}
|
|
126
|
-
if (variantId) {
|
|
127
|
-
const variant = variants.products.find(product => product.id === variantId) || {};
|
|
128
|
-
return {
|
|
129
|
-
...variant.characteristics
|
|
130
|
-
};
|
|
131
|
-
}
|
|
132
|
-
// If product has only 1 variant preselect no matter if "preselect" is chosen or not.
|
|
133
|
-
if (variants.products.length === 1) {
|
|
134
|
-
return {
|
|
135
|
-
...variants.products[0].characteristics
|
|
136
|
-
};
|
|
137
|
-
}
|
|
138
|
-
// Pre-selection is off
|
|
139
|
-
if (!preselectVariant) {
|
|
140
|
-
return {};
|
|
141
|
-
}
|
|
142
|
-
// Find the first selectable product by characteristics
|
|
143
|
-
return variants.characteristics.reduce((acc, char) => {
|
|
144
|
-
// Find the first char value with selectable products
|
|
145
|
-
const firstVal = char.values.find(val => {
|
|
146
|
-
// eslint-disable-next-line extra-rules/no-single-line-objects
|
|
147
|
-
const source = {
|
|
148
|
-
...acc,
|
|
149
|
-
[char.id]: val.id
|
|
150
|
-
};
|
|
151
|
-
return variants.products.filter(p => isMatch(p.characteristics, source)).length > 0;
|
|
152
|
-
});
|
|
153
|
-
if (!firstVal) {
|
|
154
|
-
return acc;
|
|
155
|
-
}
|
|
156
|
-
// eslint-disable-next-line extra-rules/no-single-line-objects
|
|
157
|
-
return {
|
|
158
|
-
...acc,
|
|
159
|
-
[char.id]: firstVal.id
|
|
160
|
-
};
|
|
161
|
-
}, {});
|
|
162
|
-
}
|
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
import React from 'react';
|
|
2
|
-
import PropTypes from 'prop-types';
|
|
3
|
-
import styles from "./style";
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* The range slider handle component.
|
|
7
|
-
* @param {Object} props The component properties
|
|
8
|
-
* @param {boolean} props.active Whether this handle is currently touched or was recently touched.
|
|
9
|
-
* @param {number} props.index The index of the handle.
|
|
10
|
-
* @param {Function} props.onTouchStart The touch start event callback.
|
|
11
|
-
* @param {Object} props.classNames (Optional) An additional style classes for the handle.
|
|
12
|
-
* @returns {JSX}
|
|
13
|
-
*/
|
|
14
|
-
import { jsx as _jsx } from "react/jsx-runtime";
|
|
15
|
-
const RangeSliderHandle = ({
|
|
16
|
-
active,
|
|
17
|
-
index,
|
|
18
|
-
onTouchStart,
|
|
19
|
-
classNames
|
|
20
|
-
}) => /*#__PURE__*/_jsx("div", {
|
|
21
|
-
className: `${classNames.handleOuter || ''} ${styles}`,
|
|
22
|
-
style: {
|
|
23
|
-
zIndex: Number(active) || 0
|
|
24
|
-
},
|
|
25
|
-
onTouchStart: event => onTouchStart(event, index),
|
|
26
|
-
children: /*#__PURE__*/_jsx("div", {
|
|
27
|
-
className: classNames.handleInner || ''
|
|
28
|
-
})
|
|
29
|
-
});
|
|
30
|
-
RangeSliderHandle.defaultProps = {
|
|
31
|
-
active: false,
|
|
32
|
-
classNames: {}
|
|
33
|
-
};
|
|
34
|
-
export default RangeSliderHandle;
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
import { css } from 'glamor';
|
|
2
|
-
export default css({
|
|
3
|
-
top: '50%',
|
|
4
|
-
position: 'absolute',
|
|
5
|
-
':first-child': {
|
|
6
|
-
left: 0,
|
|
7
|
-
transform: 'translate(-50%, -50%)'
|
|
8
|
-
},
|
|
9
|
-
':last-child': {
|
|
10
|
-
left: 'auto',
|
|
11
|
-
right: 0,
|
|
12
|
-
transform: 'translate(50%, -50%)'
|
|
13
|
-
}
|
|
14
|
-
});
|
|
@@ -1,85 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* The linear easing callback.
|
|
3
|
-
* @param {number} relativeValue The relative value between [0...1].
|
|
4
|
-
* @param {number} resolution The resolution, must be a value between [0,1...1].
|
|
5
|
-
* @returns {number} The interpolated value.
|
|
6
|
-
*/
|
|
7
|
-
const easeLinear = (relativeValue, resolution) => {
|
|
8
|
-
const inverseResolution = 1.0 / resolution;
|
|
9
|
-
return relativeValue * inverseResolution / inverseResolution;
|
|
10
|
-
};
|
|
11
|
-
|
|
12
|
-
/**
|
|
13
|
-
* Generates a linear easing callback.
|
|
14
|
-
* @param {number} resolution The discrete step size.
|
|
15
|
-
* @returns {Function} The generated callback.
|
|
16
|
-
*/
|
|
17
|
-
export const generateLinearEasingCallback = (resolution = 0.1) => relativeValue => easeLinear(relativeValue, resolution);
|
|
18
|
-
|
|
19
|
-
/**
|
|
20
|
-
* The exponential easing callback.
|
|
21
|
-
* @param {number} relativeValue The relative value between [0...1].
|
|
22
|
-
* @param {number} factor The exponential scale factor.
|
|
23
|
-
* @returns {number} The interpolated value.
|
|
24
|
-
*/
|
|
25
|
-
const easeExponential = (relativeValue, factor) => relativeValue ** factor;
|
|
26
|
-
|
|
27
|
-
/**
|
|
28
|
-
* Generates an exponential easing callback.
|
|
29
|
-
* @param {number} factor The exponential scale factor.
|
|
30
|
-
* @returns {Function} The generated callback.
|
|
31
|
-
*/
|
|
32
|
-
export const generateExponentialEasingCallback = (factor = 2.5) => relativeValue => easeExponential(relativeValue, factor);
|
|
33
|
-
|
|
34
|
-
/**
|
|
35
|
-
* Converts a range of [0...1] into a style object.
|
|
36
|
-
* @param {number} min A value in interval [0...1]
|
|
37
|
-
* @param {number} max A value in interval [0...1]
|
|
38
|
-
* @param {number} transitionDuration The duration of the transition.
|
|
39
|
-
* @returns {Object} The generated style object
|
|
40
|
-
*/
|
|
41
|
-
export const getRangeStyle = (min, max, transitionDuration) => ({
|
|
42
|
-
left: `${Math.min(1, Math.max(0, min)) * 100}%`,
|
|
43
|
-
right: `${(1 - Math.min(1, Math.max(0, max))) * 100}%`,
|
|
44
|
-
transition: transitionDuration > 0 ? `left ${transitionDuration}ms, right ${transitionDuration}ms` : null
|
|
45
|
-
});
|
|
46
|
-
|
|
47
|
-
/**
|
|
48
|
-
* Shortcut for retrieving x position of a touch event.
|
|
49
|
-
* @param {TouchEvent} event The TouchEvent
|
|
50
|
-
* @returns {number} The x position
|
|
51
|
-
*/
|
|
52
|
-
export const getTouchPositionX = event => event.touches[0].pageX;
|
|
53
|
-
|
|
54
|
-
/**
|
|
55
|
-
* Converts a relative slider value into an absolute value.
|
|
56
|
-
* A relative value is a value between [0...1] indicating the position
|
|
57
|
-
* on the slider given its absolute width.
|
|
58
|
-
* An absolute value is a value in screen space coordinates. This value must be
|
|
59
|
-
* between [0...offsetWidth] of the range slider.
|
|
60
|
-
* @param {number} value The actual value.
|
|
61
|
-
* @param {number} min The minimum.
|
|
62
|
-
* @param {number} max The maximum.
|
|
63
|
-
* @param {boolean} allowRealValues Whether the value should be rounded to the nearest integer.
|
|
64
|
-
* @returns {number} The converted absolute value.
|
|
65
|
-
*/
|
|
66
|
-
export const getAbsoluteValue = (value, min, max, allowRealValues = false) => {
|
|
67
|
-
const result = min + (max - min) * value;
|
|
68
|
-
return Math.min(max, Math.max(min, allowRealValues ? result : Math.round(result)));
|
|
69
|
-
};
|
|
70
|
-
|
|
71
|
-
/**
|
|
72
|
-
* Converts an absolute slider value into a relative value.
|
|
73
|
-
* An absolute value is a value in screen space coordinates. This value must be
|
|
74
|
-
* between [0...offsetWidth] of the price range slider.
|
|
75
|
-
* A relative value is a value between [0...1] indicating the position
|
|
76
|
-
* on the slider given its absolute width.
|
|
77
|
-
* @param {number} value The actual value.
|
|
78
|
-
* @param {number} min The minimum.
|
|
79
|
-
* @param {number} max The maximum.
|
|
80
|
-
* @returns {number} The converted relative value.
|
|
81
|
-
*/
|
|
82
|
-
export const getRelativeValue = (value, min, max) => {
|
|
83
|
-
const result = (value - min) / (max - min);
|
|
84
|
-
return Math.min(1, Math.max(0, result));
|
|
85
|
-
};
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
import { css } from 'glamor';
|
|
2
|
-
const container = css({
|
|
3
|
-
margin: 0,
|
|
4
|
-
padding: 0
|
|
5
|
-
}).toString();
|
|
6
|
-
const selectHandle = css({
|
|
7
|
-
float: 'right'
|
|
8
|
-
}).toString();
|
|
9
|
-
const items = css({
|
|
10
|
-
position: 'absolute',
|
|
11
|
-
width: '100%'
|
|
12
|
-
}).toString();
|
|
13
|
-
export default {
|
|
14
|
-
container,
|
|
15
|
-
selectHandle,
|
|
16
|
-
items
|
|
17
|
-
};
|