UNPKG

@shopgate/pwa-common

Version:

Common library for the Shopgate Connect PWA.

180 lines (174 loc) • 5.55 kB
import _inheritsLoose from "@babel/runtime/helpers/inheritsLoose"; import React, { Component } from 'react'; import PropTypes from 'prop-types'; import styles from "./style"; import SelectItem from "./components/Item"; import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime"; const DEFAULT_PLACEHOLDER_TEXT = 'Select ...'; /** * Finds an item in a list of items by value. * @param {Array} items - The list of items. * @param {*} value - The value to look for. * @returns {*} The found item or undefined. */ const findItemByValue = (items, value) => items.filter(item => item.value === value).shift(); /** * Converts an item of any type (e.g. string or number) * to an object representation containing value and label properties. * @param {*} item - An item of any type. * @returns {Object} An object representation of the item. */ const normalizeItem = item => ({ value: item.value || item, label: item.label || item.value || item }); /** * The select component. * @param {Object} props - The component props. * @param {React.Children} props.children - Some content to display inside. */ let Select = /*#__PURE__*/function (_Component) { /** * The constructor. * @param {Object} props - The component props. */ function Select(props) { var _this; _this = _Component.call(this, props) || this; /** * Triggers the onChange callback if the selected value has changed. * @param {Object} nextState - The next state. */ _this.triggerChangeCallback = nextState => { if (_this.state.selected && _this.state.selected.value === nextState.selected.value) { return; } if (_this.props.onChange instanceof Function) { _this.props.onChange(nextState.selected.value); } }; /** * Handles any interaction the user does outside of the component. * In this case the select gets closed. * @param {Event} event - The event of the user interaction (e.g. TouchEvent). */ _this.handleInteractionOutside = event => { if (!_this.domElement.contains(event.target)) { _this.setState({ isOpen: false }); } }; /** * Gets called when a new item is selected * @param {*} value - The selected value. * @param {string} label - The selected label. */ _this.handleItemSelect = (value, label) => { const stateUpdate = { selected: { label, value }, isOpen: false }; _this.triggerChangeCallback(stateUpdate); _this.setState(stateUpdate); }; /** * Toggles the open state of the component. */ _this.toggleOpenState = () => { _this.setState(({ isOpen }) => ({ isOpen: !isOpen })); }; _this.state = { selected: null, isOpen: false }; _this.domElement = null; if (props.value) { _this.state.selected = normalizeItem(findItemByValue(props.items, props.value)); } return _this; } /** * Adds event listener when the component is mounted. */ _inheritsLoose(Select, _Component); var _proto = Select.prototype; _proto.componentDidMount = function componentDidMount() { document.addEventListener('touchstart', this.handleInteractionOutside); } /** * Updates the selected item when the value prop changes. * @param {Object} nextProps - The next props. */; _proto.UNSAFE_componentWillReceiveProps = function UNSAFE_componentWillReceiveProps(nextProps) { if (!this.state.selected || nextProps.value !== this.state.selected.value) { this.state.selected = normalizeItem(findItemByValue(nextProps.items, nextProps.value)); } } /** * Removes event listener when the component will unmount. */; _proto.componentWillUnmount = function componentWillUnmount() { document.removeEventListener('touchstart', this.handleInteractionOutside); }; /** * Renders the component. * @returns {JSX} */ _proto.render = function render() { const hasSelection = this.state.selected && this.state.selected.value !== undefined; const selectedLabel = hasSelection ? this.state.selected.label : this.props.placeholder; const items = this.state.isOpen ? /*#__PURE__*/_jsx("div", { className: styles.items, children: this.props.items.map(item => { const normalizedItem = normalizeItem(item); const selected = hasSelection && this.state.selected.value === normalizedItem.value; return /*#__PURE__*/_jsx(SelectItem, { value: normalizedItem.value, label: normalizedItem.label, selected: selected, onSelect: this.handleItemSelect }, normalizedItem.value); }) }) : null; return /*#__PURE__*/_jsxs("div", { className: `${styles.container} ${this.props.className} common_select`, ref: ref => { this.domElement = ref; }, children: [/*#__PURE__*/_jsxs("div", { onTouchStart: this.toggleOpenState, children: [/*#__PURE__*/_jsx("span", { children: selectedLabel }), /*#__PURE__*/_jsx("span", { className: styles.selectHandle, children: "\u25BE" })] }), items] }); }; return Select; }(Component); /** * The component prop types. * @type {Object} */ /** * The component default props. * @type {Object} */ Select.defaultProps = { className: '', items: [], onChange: () => {}, placeholder: DEFAULT_PLACEHOLDER_TEXT, value: null }; export default Select;