wix-style-react
Version:
wix-style-react
525 lines (443 loc) • 19.1 kB
JavaScript
'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;