UNPKG

wix-style-react

Version:
525 lines (443 loc) • 19.1 kB
'use strict'; Object.defineProperty(exports, "__esModule", { value: true }); exports.default = undefined; var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); var _class, _temp2; var _react = require('react'); var _react2 = _interopRequireDefault(_react); var _propTypes = require('prop-types'); var _WixComponent2 = require('../BaseComponents/WixComponent'); var _WixComponent3 = _interopRequireDefault(_WixComponent2); var _Loader = require('../Loader/Loader'); var _Loader2 = _interopRequireDefault(_Loader); var _HeaderLayout = require('../MessageBox/HeaderLayout'); var _HeaderLayout2 = _interopRequireDefault(_HeaderLayout); var _FooterLayout = require('../MessageBox/FooterLayout'); var _FooterLayout2 = _interopRequireDefault(_FooterLayout); var _Selector = require('../Selector/Selector'); var _Selector2 = _interopRequireDefault(_Selector); var _Search = require('../Search/Search'); var _Search2 = _interopRequireDefault(_Search); var _InfiniteScroll = require('../utils/InfiniteScroll'); var _InfiniteScroll2 = _interopRequireDefault(_InfiniteScroll); var _Text = require('../Text'); var _Text2 = _interopRequireDefault(_Text); var _ModalSelectorLayout = require('./ModalSelectorLayout.helpers'); var _Checkbox = require('../Checkbox'); var _Checkbox2 = _interopRequireDefault(_Checkbox); var _ModalSelectorLayout2 = require('./ModalSelectorLayout.scss'); var _ModalSelectorLayout3 = _interopRequireDefault(_ModalSelectorLayout2); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } function _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } else { return Array.from(arr); } } function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } var DEFAULT_EMPTY = _react2.default.createElement( 'div', { className: _ModalSelectorLayout3.default.defaultEmptyStateWrapper }, _react2.default.createElement( _Text2.default, null, "You don't have any items" ) ); /** * Use this component when needed to select one / multiple items having complex descriptions. * E.g.: choosing products to promote via ShoutOuts */ var ModalSelectorLayout = (_temp2 = _class = function (_WixComponent) { _inherits(ModalSelectorLayout, _WixComponent); function ModalSelectorLayout() { var _ref; var _temp, _this, _ret; _classCallCheck(this, ModalSelectorLayout); for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) { args[_key] = arguments[_key]; } return _ret = (_temp = (_this = _possibleConstructorReturn(this, (_ref = ModalSelectorLayout.__proto__ || Object.getPrototypeOf(ModalSelectorLayout)).call.apply(_ref, [this].concat(args))), _this), _this.state = { isLoaded: false, isSearching: false, items: [], searchValue: '', selectedItems: [], shouldShowNoResultsFoundState: false, isEmpty: false }, _this._getEnabledItems = function (items) { return items.filter(function (_ref2) { var disabled = _ref2.disabled; return !disabled; }); }, _this._renderFooter = function () { var selectedItems = _this.state.selectedItems; var _this$props = _this.props, onCancel = _this$props.onCancel, _onOk = _this$props.onOk, cancelButtonText = _this$props.cancelButtonText, okButtonText = _this$props.okButtonText, multiple = _this$props.multiple; var enabledItems = _this._getEnabledItems(selectedItems); return _react2.default.createElement(_FooterLayout2.default, { onCancel: onCancel, onOk: function onOk() { return _onOk(multiple ? enabledItems : enabledItems[0]); }, cancelText: cancelButtonText, confirmText: okButtonText, enableOk: !!selectedItems.length, children: multiple && _this._renderFooterSelector() }); }, _this._renderFooterSelector = function () { var _this$props2 = _this.props, selectAllText = _this$props2.selectAllText, deselectAllText = _this$props2.deselectAllText; var _this$state = _this.state, selectedItems = _this$state.selectedItems, items = _this$state.items; var enabledItems = _this._getEnabledItems(items); var selectedEnabled = selectedItems.filter(function (_ref3) { var disabled = _ref3.disabled; return !disabled; }); var cases = { select: { text: selectAllText, number: enabledItems.length, onChange: function onChange() { return _this.setState({ selectedItems: selectedItems.concat(enabledItems) }); }, indeterminate: false, checked: false }, deselect: { text: deselectAllText, number: selectedEnabled.length, onChange: function onChange() { return _this.setState({ selectedItems: selectedItems.filter(function (_ref4) { var disabled = _ref4.disabled; return disabled; }) }); }, indeterminate: selectedEnabled.length < enabledItems.length, checked: true } }; var _ref5 = selectedEnabled.length ? cases.deselect : cases.select, text = _ref5.text, num = _ref5.number, onChange = _ref5.onChange, checked = _ref5.checked, indeterminate = _ref5.indeterminate; return _react2.default.createElement( _Checkbox2.default, { dataHook: 'footer-selector', checked: checked, onChange: onChange, indeterminate: indeterminate }, _react2.default.createElement( _Text2.default, { weight: 'normal' }, ' ' + text + ' (' + num + ')' ) ); }, _temp), _possibleConstructorReturn(_this, _ret); } _createClass(ModalSelectorLayout, [{ key: 'render', value: function render() { var _this2 = this; var _props = this.props, title = _props.title, subtitle = _props.subtitle, onClose = _props.onClose, searchPlaceholder = _props.searchPlaceholder, emptyState = _props.emptyState, noResultsFoundStateFactory = _props.noResultsFoundStateFactory, withSearch = _props.withSearch, height = _props.height; var _state = this.state, items = _state.items, isLoaded = _state.isLoaded, isEmpty = _state.isEmpty, isSearching = _state.isSearching, searchValue = _state.searchValue, shouldShowNoResultsFoundState = _state.shouldShowNoResultsFoundState; return _react2.default.createElement( 'div', { className: _ModalSelectorLayout3.default.modalContent, style: { height: height } }, _react2.default.createElement(_HeaderLayout2.default, { title: title, onCancel: onClose }), isLoaded && !isEmpty && _react2.default.createElement( 'div', { className: _ModalSelectorLayout3.default.subheaderWrapper }, subtitle && _react2.default.createElement( 'div', { className: _ModalSelectorLayout3.default.subtitleWrapper }, _react2.default.createElement( _Text2.default, { dataHook: _ModalSelectorLayout.dataHooks.subtitle }, subtitle ) ), withSearch && _react2.default.createElement( 'div', { className: _ModalSelectorLayout3.default.searchWrapper }, _react2.default.createElement(_Search2.default, { dataHook: _ModalSelectorLayout.dataHooks.search, placeholder: searchPlaceholder, value: searchValue, onChange: function onChange(e) { return _this2._onSearchChange(e); } }) ) ), _react2.default.createElement( 'div', { className: _ModalSelectorLayout3.default.modalBody, 'data-hook': _ModalSelectorLayout.dataHooks.modalBody }, (items.length === 0 && !isLoaded || isSearching) && _react2.default.createElement( 'div', { className: _ModalSelectorLayout3.default.mainLoaderWrapper }, _react2.default.createElement(_Loader2.default, { size: 'medium', dataHook: _ModalSelectorLayout.dataHooks.mainLoader }) ), isEmpty && _react2.default.createElement('div', { 'data-hook': _ModalSelectorLayout.dataHooks.emptyState, className: _ModalSelectorLayout3.default.emptyStateWrapper, children: emptyState }), (!isLoaded || items.length > 0 || isSearching) && _react2.default.createElement(_InfiniteScroll2.default, { key: searchValue, loadMore: function loadMore() { return _this2._loadMore(); }, hasMore: this._hasMore(), useWindow: false, children: this._renderItems(), loader: items.length > 0 && _react2.default.createElement( 'div', { className: _ModalSelectorLayout3.default.nextPageLoaderWrapper }, _react2.default.createElement(_Loader2.default, { size: 'small', dataHook: _ModalSelectorLayout.dataHooks.nextPageLoader }) ) }), shouldShowNoResultsFoundState && _react2.default.createElement('div', { 'data-hook': _ModalSelectorLayout.dataHooks.noResultsFoundState, className: _ModalSelectorLayout3.default.noResultsFoundStateWrapper, children: noResultsFoundStateFactory(searchValue) }) ), this._renderFooter() ); } }, { key: '_renderItems', value: function _renderItems() { var _this3 = this; var _state2 = this.state, items = _state2.items, selectedItems = _state2.selectedItems; var _props2 = this.props, imageSize = _props2.imageSize, imageShape = _props2.imageShape, multiple = _props2.multiple; var isSelected = function isSelected(item) { return !!selectedItems.find(function (_ref6) { var id = _ref6.id; return item.id === id; }); }; var _onToggle = function _onToggle(item) { return _this3.setState({ selectedItems: multiple ? isSelected(item) ? selectedItems.filter(function (_ref7) { var id = _ref7.id; return item.id !== id; }) : selectedItems.concat(item) : [item] }); }; if (items.length > 0) { return _react2.default.createElement( 'ul', { 'data-hook': _ModalSelectorLayout.dataHooks.list, className: _ModalSelectorLayout3.default.list }, items.map(function (item) { return _react2.default.createElement(_Selector2.default, { id: item.id, key: item.id, dataHook: _ModalSelectorLayout.dataHooks.selector, imageSize: imageSize, imageShape: imageShape, toggleType: multiple ? 'checkbox' : 'radio', image: item.image, title: item.title, subtitle: item.subtitle, extraNode: item.extraNode ? item.extraNode : _react2.default.createElement( _Text2.default, { secondary: true }, item.extraText ), isSelected: isSelected(item), isDisabled: item.disabled, onToggle: function onToggle() { return !item.disabled && _onToggle(item); } }); }) ); } } }, { key: '_onSearchChange', value: function _onSearchChange(e) { this.setState({ searchValue: e.target.value, isSearching: true, items: [] }); } }, { key: '_loadMore', value: function _loadMore() { var _this4 = this; var _props3 = this.props, dataSource = _props3.dataSource, itemsPerPage = _props3.itemsPerPage; var _state3 = this.state, items = _state3.items, searchValue = _state3.searchValue; dataSource(searchValue, items.length, itemsPerPage).then(function (_ref8) { var itemsFromNextPage = _ref8.items, totalCount = _ref8.totalCount; if (_this4.state.searchValue === searchValue) { // react only to the resolve of the relevant search var newItems = [].concat(_toConsumableArray(items), _toConsumableArray(itemsFromNextPage)); var selectedItems = _this4.state.selectedItems.concat(itemsFromNextPage.filter(function (_ref9) { var selected = _ref9.selected; return selected; })); var shouldShowNoResultsFoundState = newItems.length === 0 && searchValue; var isEmpty = newItems.length === 0 && !searchValue; _this4.setState({ items: newItems, selectedItems: selectedItems, isLoaded: true, isEmpty: isEmpty, isSearching: false, totalCount: totalCount, shouldShowNoResultsFoundState: shouldShowNoResultsFoundState }); } }); } }, { key: '_hasMore', value: function _hasMore() { var _state4 = this.state, items = _state4.items, isLoaded = _state4.isLoaded, totalCount = _state4.totalCount, isSearching = _state4.isSearching; return items.length === 0 && !isLoaded || items.length < totalCount || isSearching; } }]); return ModalSelectorLayout; }(_WixComponent3.default), _class.displayName = 'ModalSelectorLayout', _class.propTypes = { /** Title of the modal */ title: _propTypes.node, /** Fixed text displayed above the list */ subtitle: _propTypes.node, /** OK button callback, called with the currently selected item */ onOk: _propTypes.func, /** X button callback */ onClose: _propTypes.func, /** Cancel button callback */ onCancel: _propTypes.func, /** * paging function that should have a signature of * ```typescript * (searchQuery: string, offset: number, limit: number) => * Promise<{ * items: Array<{ * id: number | string, * title: string, * subtitle?: string, * extraText?: string, * extraNode?: string, * disabled?: boolean // show item as disabled, dont count it in "select all", exclude from `onOk` * selected?: boolean // force item as selected * image?: node * }>, * totalCount: number * }> * ``` * `offset` - next requested item's index<br> * `limit` - number of items requested<br> * `totalCount` - total number of items that suffice the current search query * */ dataSource: _propTypes.func.isRequired, /** Cancel button's text */ cancelButtonText: _propTypes.string, /** OK button's text */ okButtonText: _propTypes.string, /** Image icon size */ imageSize: (0, _propTypes.oneOf)(['tiny', 'small', 'portrait', 'large', 'cinema']), /** * Image icon shape, `rectangular` or `circle`.<br> * NOTE: `circle` is not compatible with `imageSize` of `portrait` or `cinema` * */ imageShape: function imageShape(props, propName, componentName) { if (['portrait', 'cinema'].includes(props.imageSize) && props[propName] === 'circle') { return new Error(componentName + ': prop "imageSize" with value of "' + props.imageSize + '" is incompatible with prop imageShape with value of "circle" \u2014 use "rectangular" instead.'); } }, /** Placeholder text of the search input */ searchPlaceholder: _propTypes.string, /** * Component/element that will be rendered when there is nothing to display, * i.e. empty `{items:[], totalCount: 0}` was returned on the first call to `dataSource` * */ emptyState: _propTypes.node.isRequired, /** * Function that will get the current `searchQuery` and should return the component/element * that will be rendered when there are no items that suffice the entered search query * */ noResultsFoundStateFactory: _propTypes.func, /** Number of items loaded each time the user scrolls down */ itemsPerPage: _propTypes.number, /** Whether to display the search input or not */ withSearch: _propTypes.bool, height: _propTypes.string, /** display checkbox and allow multi selection */ multiple: _propTypes.bool, /** string to be displayed in footer when `multiple` prop is used and no items are selected */ selectAllText: _propTypes.string, /** string to be displayed in footer when `multiple` prop is used and some or all items ar selected */ deselectAllText: _propTypes.string }, _class.defaultProps = { title: 'Choose Your Items', okButtonText: 'Select', cancelButtonText: 'Cancel', searchPlaceholder: 'Search...', imageSize: 'large', imageShape: 'rectangular', itemsPerPage: 50, withSearch: true, height: '100%', emptyState: DEFAULT_EMPTY, noResultsFoundStateFactory: function noResultsFoundStateFactory(searchValue) { return _react2.default.createElement( 'div', { className: _ModalSelectorLayout3.default.defaultNoResultsFoundStateWrapper }, _react2.default.createElement( _Text2.default, null, 'No items matched your search ', '"' + searchValue + '"' ) ); }, selectAllText: 'Select All', deselectAllText: 'Deselect All' }, _temp2); exports.default = ModalSelectorLayout;