@shopgate/engage 7.28.0-beta.3 → 7.28.0-beta.4

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.
Files changed (29) hide show
  1. package/package.json +7 -7
  2. package/product/components/FilterBar/FilterBarProvider.connector.js +6 -0
  3. package/product/components/FilterBar/FilterBarProvider.context.js +4 -0
  4. package/product/components/FilterBar/FilterBarProvider.js +8 -0
  5. package/product/components/FilterBar/components/Content/actions/openFilterRoute.js +5 -0
  6. package/product/components/FilterBar/components/Content/components/FilterButton/index.js +5 -0
  7. package/product/components/FilterBar/components/Content/components/FilterButton/style.js +1 -0
  8. package/product/components/FilterBar/components/Content/components/FilterChips/connector.js +9 -0
  9. package/product/components/FilterBar/components/Content/components/FilterChips/index.js +10 -0
  10. package/product/components/FilterBar/components/Content/components/FilterChips/style.js +1 -0
  11. package/product/components/FilterBar/components/Content/components/Sort/components/Item/index.js +5 -0
  12. package/product/components/FilterBar/components/Content/components/Sort/components/Item/style.js +1 -0
  13. package/product/components/FilterBar/components/Content/components/Sort/index.js +5 -0
  14. package/product/components/FilterBar/components/Content/components/Sort/style.js +1 -0
  15. package/product/components/FilterBar/components/Content/index.js +4 -0
  16. package/product/components/FilterBar/components/Content/spec.js +6 -0
  17. package/product/components/FilterBar/components/Content/style.js +1 -0
  18. package/product/components/FilterBar/components/FilterModal/FilterModal.js +4 -0
  19. package/product/components/FilterBar/components/FilterModal/FilterModalContent.js +4 -0
  20. package/product/components/FilterBar/components/FilterModal/FilterModalTitle.js +5 -0
  21. package/product/components/FilterBar/components/FilterModal/index.js +1 -0
  22. package/product/components/FilterBar/index.js +5 -0
  23. package/product/components/FilterBar/mock.js +9 -0
  24. package/product/components/FilterBar/selectors.js +4 -0
  25. package/product/components/FilterBar/style.js +1 -0
  26. package/product/components/ProductFilters/index.js +14 -0
  27. package/product/components/ProductFilters/style.js +1 -0
  28. package/product/components/index.js +1 -1
  29. package/product/index.js +1 -1
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@shopgate/engage",
3
- "version": "7.28.0-beta.3",
3
+ "version": "7.28.0-beta.4",
4
4
  "description": "Shopgate's ENGAGE library.",
5
5
  "license": "Apache-2.0",
6
6
  "author": "Shopgate <support@shopgate.com>",
@@ -16,12 +16,12 @@
16
16
  ],
17
17
  "dependencies": {
18
18
  "@shopgate/native-modules": "1.0.0-beta.25",
19
- "@shopgate/pwa-common": "7.28.0-beta.3",
20
- "@shopgate/pwa-common-commerce": "7.28.0-beta.3",
21
- "@shopgate/pwa-core": "7.28.0-beta.3",
22
- "@shopgate/pwa-ui-ios": "7.28.0-beta.3",
23
- "@shopgate/pwa-ui-material": "7.28.0-beta.3",
24
- "@shopgate/pwa-ui-shared": "7.28.0-beta.3",
19
+ "@shopgate/pwa-common": "7.28.0-beta.4",
20
+ "@shopgate/pwa-common-commerce": "7.28.0-beta.4",
21
+ "@shopgate/pwa-core": "7.28.0-beta.4",
22
+ "@shopgate/pwa-ui-ios": "7.28.0-beta.4",
23
+ "@shopgate/pwa-ui-material": "7.28.0-beta.4",
24
+ "@shopgate/pwa-ui-shared": "7.28.0-beta.4",
25
25
  "@stripe/react-stripe-js": "^1.16.5",
26
26
  "@stripe/stripe-js": "^1.3.1",
27
27
  "@virtuous/conductor": "~2.5.0",
@@ -0,0 +1,6 @@
1
+ import{connect}from'react-redux';import{getCurrentRoute}from'@shopgate/pwa-common/selectors/router';import{updateFilters}from'@shopgate/pwa-common-commerce/filter/action-creators';import openFilterRoute from"./components/Content/actions/openFilterRoute";/**
2
+ * @param {Object} state App state.
3
+ * @returns {Object}
4
+ */var mapStateToProps=function mapStateToProps(state){var _getCurrentRoute=getCurrentRoute(state),routeState=_getCurrentRoute.state;return{routeFilterState:routeState.filters||{}};};/**
5
+ * @return {Object}
6
+ */var mapDispatchToProps={navigate:function navigate(){return openFilterRoute();},updateFilters:updateFilters};export default connect(mapStateToProps,mapDispatchToProps);
@@ -0,0 +1,4 @@
1
+ import React from'react';var initialValue={};var Context=React.createContext(initialValue);export default Context;/**
2
+ * Hook to use the filter bar context.
3
+ * @returns {Object}
4
+ */export var useFilterBarContext=function useFilterBarContext(){return React.useContext(Context);};
@@ -0,0 +1,8 @@
1
+ function _slicedToArray(arr,i){return _arrayWithHoles(arr)||_iterableToArrayLimit(arr,i)||_nonIterableRest();}function _nonIterableRest(){throw new TypeError("Invalid attempt to destructure non-iterable instance");}function _iterableToArrayLimit(arr,i){var _arr=[];var _n=true;var _d=false;var _e=undefined;try{for(var _i=arr[Symbol.iterator](),_s;!(_n=(_s=_i.next()).done);_n=true){_arr.push(_s.value);if(i&&_arr.length===i)break;}}catch(err){_d=true;_e=err;}finally{try{if(!_n&&_i["return"]!=null)_i["return"]();}finally{if(_d)throw _e;}}return _arr;}function _arrayWithHoles(arr){if(Array.isArray(arr))return arr;}import React,{useMemo,useState}from'react';import PropTypes from'prop-types';import{responsiveCondition}from'@shopgate/engage/styles';import Context from"./FilterBarProvider.context";import connect from"./FilterBarProvider.connector";/**
2
+ * FilterBar provider
3
+ * @param {Object} props React props.
4
+ * @returns {JSX.Element}
5
+ */var FilterBarProvider=function FilterBarProvider(_ref){var children=_ref.children,navigate=_ref.navigate,routeFilterState=_ref.routeFilterState,updateFilters=_ref.updateFilters;var _useState=useState(false),_useState2=_slicedToArray(_useState,2),filterModalOpen=_useState2[0],setFilterModalOpen=_useState2[1];var contextValue=useMemo(function(){return{updateFilters:updateFilters,/**
6
+ * Opens the filter page or modal
7
+ * @returns {Object}
8
+ */openFilters:function openFilters(){if(responsiveCondition('>xs',{webOnly:true})){return setFilterModalOpen(true);}return navigate();},filters:routeFilterState,filterModalOpen:filterModalOpen,setFilterModalOpen:setFilterModalOpen};},[filterModalOpen,navigate,routeFilterState,updateFilters]);return React.createElement(Context.Provider,{value:contextValue},children);};FilterBarProvider.defaultProps={routeFilterState:{}};export default connect(FilterBarProvider);
@@ -0,0 +1,5 @@
1
+ import{historyPush}from'@shopgate/engage/core/actions';import{getCurrentRoute}from'@shopgate/engage/core/selectors';import{parseObjectToQueryString}from'@shopgate/engage/core/helpers';import{CATEGORY_PATH,CATEGORY_ALL_PATTERN}from'@shopgate/pwa-common-commerce/category/constants';import{SEARCH_PATH}from'@shopgate/pwa-common-commerce/search/constants';/**
2
+ * Opens the filter route with the relevant url.
3
+ * @param {Object} props The component props.
4
+ * @returns {Function} A redux thunk.
5
+ */var openFilterRoute=function openFilterRoute(){return function(dispatch,getState){var _getCurrentRoute=getCurrentRoute(getState()),id=_getCurrentRoute.id,categoryId=_getCurrentRoute.params.categoryId,query=_getCurrentRoute.query,state=_getCurrentRoute.state,pattern=_getCurrentRoute.pattern;var forwardState={filters:state.filters||null,parentId:id};if(pattern===CATEGORY_ALL_PATTERN){dispatch(historyPush({pathname:"".concat(CATEGORY_PATH,"/").concat(categoryId,"/all/filter"),state:forwardState}));}else if(categoryId){dispatch(historyPush({pathname:"".concat(CATEGORY_PATH,"/").concat(categoryId,"/filter"),state:forwardState}));}else if(query.s){var queryString=parseObjectToQueryString(query);dispatch(historyPush({pathname:"".concat(SEARCH_PATH,"/filter").concat(queryString),state:forwardState}));}};};export default openFilterRoute;
@@ -0,0 +1,5 @@
1
+ import React from'react';import PropTypes from'prop-types';import{Grid,I18n,Ripple,FilterIcon}from'@shopgate/engage/components';import styles from"./style";/**
2
+ * The Filter Bar Content Filter Button component.
3
+ * @param {Object} props The component props.
4
+ * @return {JSX}
5
+ */function FilterButton(_ref){var openFilters=_ref.openFilters;return React.createElement("button",{className:"".concat(styles.button," theme__filter-bar__filter-button"),onClick:openFilters,"data-test-id":"filterButton",type:"button"},React.createElement(Ripple,{className:styles.filterButtonRipple,fill:true},React.createElement(Grid,{component:"div"},React.createElement(Grid.Item,{className:styles.filterButton,component:"div"},React.createElement("span",{className:styles.filterButtonLabel},React.createElement(I18n.Text,{string:"titles.filter"}))),React.createElement(Grid.Item,{component:"div"},React.createElement(FilterIcon,null)))));}export default FilterButton;
@@ -0,0 +1 @@
1
+ import{css}from'glamor';import{themeConfig}from'@shopgate/pwa-common/helpers/config';var variables=themeConfig.variables;var button=css({color:'inherit',fontSize:'1.5rem',lineHeight:1,outline:0,padding:0,minWidth:variables.navigator.height,height:variables.filterbar.height,position:'relative',zIndex:1,overflow:'hidden'});var filterButton=css({display:'flex'}).toString();var filterButtonLabel=css({alignSelf:'center',fontSize:'0.875rem',fontWeight:'500',lineHeight:1,paddingRight:variables.gap.small}).toString();var filterButtonRipple=css({display:'flex',height:'100%',width:'100%',justifyContent:'center',alignItems:'center',margin:0,padding:'6px 10px'}).toString();export default{button:button,filterButton:filterButton,filterButtonLabel:filterButtonLabel,filterButtonRipple:filterButtonRipple};
@@ -0,0 +1,9 @@
1
+ import{connect}from'react-redux';import{getCurrentPathname}from'@shopgate/engage/core';import{updateFilters}from'@shopgate/pwa-common-commerce/filter/action-creators';/**
2
+ * Maps the contents of the state to the component props.
3
+ * @param {Object} state The current application state.
4
+ * @return {Object} The extended component props.
5
+ */var mapStateToProps=function mapStateToProps(state){return{currentPathname:getCurrentPathname(state)};};/**
6
+ * @param {Function} dispatch The redux dispatch function.
7
+ * @param {Object} props The components props.
8
+ * @return {Object}
9
+ */var mapDispatchToProps={updateFilters:updateFilters};export default connect(mapStateToProps,mapDispatchToProps);
@@ -0,0 +1,10 @@
1
+ function _typeof(obj){if(typeof Symbol==="function"&&typeof Symbol.iterator==="symbol"){_typeof=function _typeof(obj){return typeof obj;};}else{_typeof=function _typeof(obj){return obj&&typeof Symbol==="function"&&obj.constructor===Symbol&&obj!==Symbol.prototype?"symbol":typeof obj;};}return _typeof(obj);}function _slicedToArray(arr,i){return _arrayWithHoles(arr)||_iterableToArrayLimit(arr,i)||_nonIterableRest();}function _nonIterableRest(){throw new TypeError("Invalid attempt to destructure non-iterable instance");}function _iterableToArrayLimit(arr,i){var _arr=[];var _n=true;var _d=false;var _e=undefined;try{for(var _i=arr[Symbol.iterator](),_s;!(_n=(_s=_i.next()).done);_n=true){_arr.push(_s.value);if(i&&_arr.length===i)break;}}catch(err){_d=true;_e=err;}finally{try{if(!_n&&_i["return"]!=null)_i["return"]();}finally{if(_d)throw _e;}}return _arr;}function _arrayWithHoles(arr){if(Array.isArray(arr))return arr;}function _defineProperty(obj,key,value){if(key in obj){Object.defineProperty(obj,key,{value:value,enumerable:true,configurable:true,writable:true});}else{obj[key]=value;}return obj;}function _extends(){_extends=Object.assign||function(target){for(var i=1;i<arguments.length;i++){var source=arguments[i];for(var key in source){if(Object.prototype.hasOwnProperty.call(source,key)){target[key]=source[key];}}}return target;};return _extends.apply(this,arguments);}function _objectWithoutProperties(source,excluded){if(source==null)return{};var target=_objectWithoutPropertiesLoose(source,excluded);var key,i;if(Object.getOwnPropertySymbols){var sourceSymbolKeys=Object.getOwnPropertySymbols(source);for(i=0;i<sourceSymbolKeys.length;i++){key=sourceSymbolKeys[i];if(excluded.indexOf(key)>=0)continue;if(!Object.prototype.propertyIsEnumerable.call(source,key))continue;target[key]=source[key];}}return target;}function _objectWithoutPropertiesLoose(source,excluded){if(source==null)return{};var target={};var sourceKeys=Object.keys(source);var key,i;for(i=0;i<sourceKeys.length;i++){key=sourceKeys[i];if(excluded.indexOf(key)>=0)continue;target[key]=source[key];}return target;}function _toPropertyKey(arg){var key=_toPrimitive(arg,"string");return _typeof(key)==="symbol"?key:String(key);}function _toPrimitive(input,hint){if(_typeof(input)!=="object"||input===null)return input;var prim=input[Symbol.toPrimitive];if(prim!==undefined){var res=prim.call(input,hint||"default");if(_typeof(res)!=="object")return res;throw new TypeError("@@toPrimitive must return a primitive value.");}return(hint==="string"?String:Number)(input);}import React,{useCallback,useMemo,useEffect}from'react';import PropTypes from'prop-types';import noop from'lodash/noop';import{router}from'@virtuous/conductor';import appConfig from'@shopgate/pwa-common/helpers/config';import{Chip,ChipLayout}from'@shopgate/engage/components';import{FILTER_TYPE_RANGE,FILTER_TYPE_MULTISELECT,translateFilterLabel}from'@shopgate/engage/filter';import{i18n}from'@shopgate/engage/core';import connect from"./connector";import{container,label}from"./style";/**
2
+ * The FilterChips component.
3
+ * @returns {JSX}
4
+ */var FilterChips=function FilterChips(_ref){var filters=_ref.filters,routeId=_ref.routeId,updateFilters=_ref.updateFilters,scrollTop=_ref.scrollTop,openFilters=_ref.openFilters,currentPathname=_ref.currentPathname,onChipCountUpdate=_ref.onChipCountUpdate;var handleRemove=useCallback(function(id,value){var selected=filters[id],rest=_objectWithoutProperties(filters,[id].map(_toPropertyKey));if(selected.type===FILTER_TYPE_MULTISELECT){// Check for one key, just remove all in that case
5
+ if(selected.value.length>1){// Remove the index from the selected filter.
6
+ var newSelected=_extends({},selected,{value:selected.value.filter(function(entry){return entry.id!==value;})});var _newFilters=_extends({},filters,_defineProperty({},id,newSelected));// setTimeout prevents double click while VoiceOver is active (CCP-2485)
7
+ setTimeout(function(){router.update(routeId,{filters:_newFilters});updateFilters(_newFilters);scrollTop();},0);return;}}var newFilters=Object.keys(rest).length?rest:null;router.update(routeId,{filters:newFilters});updateFilters(newFilters);scrollTop();},[filters,routeId,scrollTop,updateFilters]);var chips=useMemo(function(){if(filters===null||!Object.keys(filters).length){return[];}var entries=[];Object.keys(filters).forEach(function(key){var filter=filters[key];if(filter===null||filter===void 0?void 0:filter.isHidden){return;}switch(filter.type){case FILTER_TYPE_RANGE:{/**
8
+ * The min and max price need to be rounded before they are passed to the I18n component,
9
+ * since it rounds to the full nearest number when fractions are deactivated.
10
+ */var _filter$value2=_slicedToArray(filter.value,2),minimum=_filter$value2[0],maximum=_filter$value2[1];var priceMin=Math.floor(minimum/100);var priceMax=Math.ceil(maximum/100);var fromPrice=i18n.price(priceMin,appConfig.currency,false);var toPrice=i18n.price(priceMax,appConfig.currency,false);var pricesFormatted="".concat(fromPrice," - ").concat(toPrice);var labelValue=i18n.text('price.range',{fromPrice:fromPrice,toPrice:toPrice});var removeLabel=i18n.text('filter.remove',{filter:labelValue});var editLabel=i18n.text('filter.edit',{filter:labelValue});entries.push(React.createElement(Chip,{id:key,key:"filter-".concat(key),onRemove:handleRemove,onClick:openFilters,removeLabel:removeLabel,editLabel:editLabel},React.createElement("span",{className:label},pricesFormatted)));break;}default:filter.value.forEach(function(value){if(value===null||value===void 0?void 0:value.isHidden){return;}var filterFormatted="".concat(translateFilterLabel(filter.id,filter.label),": ").concat(value.label);var removeLabel=i18n.text('filter.remove',{filter:filterFormatted});var editLabel=i18n.text('filter.edit',{filter:filterFormatted});entries.push(React.createElement(Chip,{id:value.id,key:"filter-".concat(value.id),onRemove:function onRemove(){return handleRemove(filter.id,value.id);},onClick:openFilters,removeLabel:removeLabel,editLabel:editLabel},React.createElement("span",{className:label},filterFormatted)));});break;}});return entries;},[filters,handleRemove,openFilters]);useEffect(function(){onChipCountUpdate(chips.length);},[chips.length,onChipCountUpdate]);if(chips.length===0){return null;}return React.createElement("div",{className:"".concat(container," theme__filter-bar__filter-chips")},React.createElement(ChipLayout,{moreLabel:"filter.more",handleMoreButton:openFilters,pathname:currentPathname},chips));};FilterChips.defaultProps={currentPathname:'',filters:null,scrollTop:noop,onChipCountUpdate:noop};export default connect(FilterChips);
@@ -0,0 +1 @@
1
+ import{css}from'glamor';import{themeConfig}from'@shopgate/pwa-common/helpers/config';var variables=themeConfig.variables,colors=themeConfig.colors;export var container=css({overflow:'auto',padding:"0 ".concat(variables.gap.small*1.5,"px"),width:'100%'});export var label=css({color:"var(--color-text-high-emphasis, ".concat(colors.accent,")")});
@@ -0,0 +1,5 @@
1
+ import React from'react';import PropTypes from'prop-types';import Ripple from'@shopgate/pwa-ui-shared/Ripple';import styles from"./style";/**
2
+ * Renders the Sort component.
3
+ * @param {Object} props The components props.
4
+ * @returns {JSX}
5
+ */var Item=function Item(_ref){var children=_ref.children;return React.createElement(Ripple,{fill:true,className:styles},children);};Item.defaultProps={children:null};export default Item;
@@ -0,0 +1 @@
1
+ import{css}from'glamor';export default css({padding:'6px 5px 6px 18px',textOverflow:'ellipsis',whiteSpace:'nowrap',overflow:'hidden'}).toString();
@@ -0,0 +1,5 @@
1
+ import React from'react';import{SelectBox,ArrowDropIcon,SurroundPortals}from'@shopgate/engage/components';import{useSort,PORTAL_FILTER_SORT_OPTIONS}from'@shopgate/engage/filter';import Item from"./components/Item";import styles from"./style";/**
2
+ * The Sort component.
3
+ * @param {Object} props The component props
4
+ * @returns {JSX}
5
+ */var Sort=function Sort(){var _useSort=useSort(),activeOption=_useSort.activeOption,options=_useSort.options,updateRoute=_useSort.updateRoute;return React.createElement(SurroundPortals,{portalName:PORTAL_FILTER_SORT_OPTIONS,portalProps:{items:options}},React.createElement(SelectBox,{handleSelectionUpdate:updateRoute,items:options,initialValue:activeOption,icon:ArrowDropIcon,item:Item,className:"".concat(styles.selectBox," theme__filter-bar__sort"),classNames:styles,testId:"sorting"}));};export default Sort;
@@ -0,0 +1 @@
1
+ function _defineProperty(obj,key,value){if(key in obj){Object.defineProperty(obj,key,{value:value,enumerable:true,configurable:true,writable:true});}else{obj[key]=value;}return obj;}import{css}from'glamor';import{responsiveMediaQuery}from'@shopgate/engage/styles';import{themeConfig}from'@shopgate/pwa-common/helpers/config';var shadows=themeConfig.shadows,colors=themeConfig.colors,variables=themeConfig.variables;var button=css({color:'inherit',outline:0,marginLeft:10,display:'flex',alignItems:'center',textOverflow:'ellipsis',justifyContent:'center',height:variables.filterbar.height,whiteSpace:'nowrap'}).toString();var selection=css({fontSize:'0.875rem',fontWeight:'500',lineHeight:1,paddingTop:1,alignSelf:'center'}).toString();var icon=css({fontSize:'1.5rem'}).toString();var iconOpen=css({transform:'rotate(180deg)'}).toString();var dropdown=css(_defineProperty({position:'absolute',width:'100%',zIndex:2,top:'100%',left:0,background:"var(--color-background-accent, ".concat(colors.background,")"),boxShadow:shadows.filter.sort},responsiveMediaQuery('>xs',{webOnly:true}),{top:'inherit'})).toString();var selectItem=css({padding:0,outline:0,overflow:'hidden',textAlign:'left',width:'100%',color:"var(--color-text-high-emphasis, ".concat(colors.dark,")"),':first-child':{marginTop:variables.gap.big/2},':last-child':{marginBottom:variables.gap.big/2}}).toString();var selectItemSelected=css({fontWeight:500}).toString();var selectBox=css({flexGrow:2}).toString();export default{button:button,selection:selection,icon:icon,iconOpen:iconOpen,dropdown:dropdown,selectItem:selectItem,selectItemSelected:selectItemSelected,selectBox:selectBox};
@@ -0,0 +1,4 @@
1
+ import React,{Fragment,useContext}from'react';import PropTypes from'prop-types';import noop from'lodash/noop';import{useRoute}from'@shopgate/engage/core';import{ViewContext}from'@shopgate/engage/components/View';import{useFilterBarContext}from"../../FilterBarProvider.context";import Sort from"./components/Sort";import FilterButton from"./components/FilterButton";import FilterChips from"./components/FilterChips";import styles from"./style";/**
2
+ * The filter bar content component.
3
+ * @returns {JSX}
4
+ */function FilterBarContent(_ref){var onChipCountUpdate=_ref.onChipCountUpdate;var _useRoute=useRoute(),state=_useRoute.state,routeId=_useRoute.id;var _useContext=useContext(ViewContext),scrollTop=_useContext.scrollTop;var _useFilterBarContext=useFilterBarContext(),openFilters=_useFilterBarContext.openFilters;var filters=state.filters;return React.createElement(Fragment,null,React.createElement("div",{className:styles},React.createElement(Sort,null),React.createElement(FilterButton,{openFilters:openFilters})),React.createElement(FilterChips,{openFilters:openFilters,filters:filters,routeId:routeId,scrollTop:scrollTop,onChipCountUpdate:onChipCountUpdate}));}FilterBarContent.defaultProps={onChipCountUpdate:noop};export default FilterBarContent;
@@ -0,0 +1,6 @@
1
+ import React from'react';import ReactDOM from'react-dom';import TestUtils from'react-dom/test-utils';import{mount,shallow}from'enzyme';import mockRenderOptions from'@shopgate/pwa-common/helpers/mocks/mockRenderOptions';import{FILTER_TYPE_MULTISELECT}from'@shopgate/pwa-common-commerce/filter/constants';import GridIcon from'@shopgate/pwa-ui-shared/icons/GridIcon';import ListIcon from'@shopgate/pwa-ui-shared/icons/ListIcon';// eslint-disable-next-line import/named
2
+ import{UnwrappedContent as FilterBarContent}from"./index";var activeFilters={Size:{label:'Size',source:'attributes',type:FILTER_TYPE_MULTISELECT,values:['31']}};describe.skip('<FilterBarContent />',function(){it('should execute handleToggleViewMode callback when left button is clicked',function(){var spy=jest.fn();var wrapper=mount(React.createElement(FilterBarContent,{handleToggleViewMode:spy,handleSortChange:function handleSortChange(){},handleOpenFiltersView:function handleOpenFiltersView(){},getFilters:function getFilters(){},componentUpdated:function componentUpdated(){}}),mockRenderOptions);var button=wrapper.find('button').first();var node=ReactDOM.findDOMNode(button.node);// eslint-disable-line react/no-find-dom-node
3
+ TestUtils.Simulate.click(node);expect(spy).toHaveBeenCalledTimes(1);});it('should execute handleOpenFiltersView callback when right button is clicked',function(){var spy=jest.fn();var wrapper=mount(React.createElement(FilterBarContent,{handleToggleViewMode:function handleToggleViewMode(){},handleSortChange:function handleSortChange(){},handleOpenFiltersView:spy,getFilters:function getFilters(){},componentUpdated:function componentUpdated(){}}),mockRenderOptions);var button=wrapper.find('button').last();var node=ReactDOM.findDOMNode(button.node);// eslint-disable-line react/no-find-dom-node
4
+ TestUtils.Simulate.click(node);expect(spy).toHaveBeenCalledTimes(1);});it('should render in grid view mode',function(){var wrapper=mount(React.createElement(FilterBarContent,{handleToggleViewMode:function handleToggleViewMode(){},handleSortChange:function handleSortChange(){},handleOpenFiltersView:function handleOpenFiltersView(){},getFilters:function getFilters(){},componentUpdated:function componentUpdated(){}}),mockRenderOptions);expect(wrapper).toMatchSnapshot();expect(wrapper.find(GridIcon).length).toEqual(0);expect(wrapper.find(ListIcon).length).toEqual(1);});it('should render in list view mode',function(){var wrapper=mount(React.createElement(FilterBarContent,{handleToggleViewMode:function handleToggleViewMode(){},handleSortChange:function handleSortChange(){},handleOpenFiltersView:function handleOpenFiltersView(){},getFilters:function getFilters(){},componentUpdated:function componentUpdated(){}}),mockRenderOptions);expect(wrapper).toMatchSnapshot();expect(wrapper.find(GridIcon).length).toEqual(1);expect(wrapper.find(ListIcon).length).toEqual(0);});describe('should call getFilters',function(){var getFiltersSpy=null;var filterBarWrapper=null;var filterBarInstance=null;beforeEach(function(){getFiltersSpy=jest.fn();filterBarWrapper=shallow(React.createElement(FilterBarContent,{handleToggleViewMode:function handleToggleViewMode(){},handleSortChange:function handleSortChange(){},getFilters:getFiltersSpy,componentUpdated:function componentUpdated(){}}),mockRenderOptions);filterBarInstance=filterBarWrapper.instance();});it('should call getFilters at componentDidMount',function(){filterBarInstance.componentDidMount();expect(getFiltersSpy).toHaveBeenCalledTimes(1);});it('should call getFilters at props.activeFilter changes',function(){filterBarWrapper.setProps({activeFilters:activeFilters});expect(getFiltersSpy).toHaveBeenCalledTimes(1);});});describe('Given activeFilters are handled correctly',function(){var filterBarWrapper=null;beforeEach(function(){filterBarWrapper=mount(React.createElement(FilterBarContent,{handleToggleViewMode:function handleToggleViewMode(){},handleSortChange:function handleSortChange(){},getFilters:function getFilters(){},activeFilters:activeFilters,componentUpdated:function componentUpdated(){}}),mockRenderOptions);});it('should render active filters',function(){expect(filterBarWrapper).toMatchSnapshot();});it('should open active filters',function(){var spy=jest.fn();filterBarWrapper.setProps({handleOpenFiltersView:spy});// Trigger a click on a active filter
5
+ filterBarWrapper.find('Chip').at(0).find('button').at(1).simulate('click');expect(spy).toHaveBeenCalledTimes(1);});it('should remove active filter',function(){var removeFilterSpy=jest.fn();var commmitFilterSpy=jest.fn();filterBarWrapper.setProps({removeTemporaryFilter:removeFilterSpy,commitTemporaryFilters:commmitFilterSpy});// Trigger a click on the "X"
6
+ filterBarWrapper.find('Chip').at(0).find('button').at(0).simulate('click');expect(removeFilterSpy).toHaveBeenCalledWith(Object.keys(activeFilters)[0],0);expect(commmitFilterSpy).toHaveBeenCalledTimes(1);});});});
@@ -0,0 +1 @@
1
+ import{css}from'glamor';export default css({display:'flex'});
@@ -0,0 +1,4 @@
1
+ import React,{useCallback,useContext}from'react';import{css}from'glamor';import{Modal,Backdrop}from'@shopgate/engage/components';import{RouteContext}from'@shopgate/pwa-common/context';import{FilterPageProvider}from'@shopgate/engage/filter/providers';import{useFilterBarContext}from"../../FilterBarProvider.context";import Content from"./FilterModalContent";var styles={root:css({display:'flex',justifyContent:'center',alignItems:'center',width:'100%',height:'100%'})};/**
2
+ * Filter modal
3
+ * @returns {JSX}
4
+ */var FilterModal=function FilterModal(){var _useFilterBarContext=useFilterBarContext(),filterModalOpen=_useFilterBarContext.filterModalOpen,setFilterModalOpen=_useFilterBarContext.setFilterModalOpen,filters=_useFilterBarContext.filters,updateFilters=_useFilterBarContext.updateFilters;var _useContext=useContext(RouteContext),id=_useContext.id,_useContext$params=_useContext.params,_useContext$params2=_useContext$params===void 0?{}:_useContext$params,categoryId=_useContext$params2.categoryId,_useContext$query=_useContext.query,_useContext$query2=_useContext$query===void 0?{}:_useContext$query,searchPhrase=_useContext$query2.s;var handleClose=useCallback(function(){setFilterModalOpen(false);},[setFilterModalOpen]);var handleApply=useCallback(function(update){handleClose();updateFilters(update);},[handleClose,updateFilters]);if(!filterModalOpen){return null;}return React.createElement(Modal,null,React.createElement("div",{className:styles.root},React.createElement(Backdrop,{isVisible:true,level:0,opacity:38,onClick:function onClick(){return setFilterModalOpen(false);}}),React.createElement(FilterPageProvider,{parentRouteId:id,activeFilters:filters,categoryId:categoryId,searchPhrase:searchPhrase,onApply:handleApply},React.createElement(Content,{onClose:handleClose}))));};export default FilterModal;
@@ -0,0 +1,4 @@
1
+ function _defineProperty(obj,key,value){if(key in obj){Object.defineProperty(obj,key,{value:value,enumerable:true,configurable:true,writable:true});}else{obj[key]=value;}return obj;}import React from'react';import PropTypes from'prop-types';import{css}from'glamor';import{themeConfig}from'@shopgate/engage';import{responsiveMediaQuery}from'@shopgate/engage/styles';import{useFilterPage}from'@shopgate/engage/filter/hooks';import FilterPageContent from'@shopgate/engage/filter/components/FilterPageContent';import Title from"./FilterModalTitle";var colors=themeConfig.colors;var styles={root:css(_defineProperty(_defineProperty(_defineProperty(_defineProperty(_defineProperty(_defineProperty(_defineProperty({zIndex:1,background:colors.light,borderRadius:4,minWidth:300},responsiveMediaQuery('>=md'),{minWidth:600}),"maxWidth",'50%'),"minHeight",300),"maxHeight",'90%'),"display",'flex'),"flexDirection",'column'),"overflow",'hidden')),scrollable:css({overflow:'auto',flex:1})};/**
2
+ * Filter modal content component
3
+ * @returns {JSX.Element}
4
+ */var FilterModalContent=function FilterModalContent(_ref){var onClose=_ref.onClose;var _useFilterPage=useFilterPage(),applyFilters=_useFilterPage.applyFilters,resetAllFilters=_useFilterPage.resetAllFilters;return React.createElement("div",{className:styles.root},React.createElement(Title,{apply:applyFilters,reset:resetAllFilters,close:onClose}),React.createElement("div",{className:styles.scrollable},React.createElement(FilterPageContent,null)));};FilterModalContent.defaultProps={};export default FilterModalContent;
@@ -0,0 +1,5 @@
1
+ import React from'react';import PropTypes from'prop-types';import{css}from'glamor';import{i18n}from'@shopgate/engage/core';import{Ripple,CrossIcon}from'@shopgate/engage/components';var styles={root:css({display:'flex',flexDirection:'row',margin:16,borderBottom:'1px solid rgba(0, 0, 0, 0.24)',alignItems:'center',paddingTop:5,paddingBottom:16}),title:css({flex:1,fontSize:'1.25rem'}),closeButton:css({fontSize:21,marginRight:12,cursor:'pointer',color:'var(--color-primary)'}).toString(),actionButton:css({cursor:'pointer',marginLeft:16,color:'var(--color-primary)',fontWeight:'600',padding:8}).toString(),actionButtonSecondary:css({cursor:'pointer',marginLeft:16,color:'var(--color-primary)',fontWeight:'500',padding:8}).toString()};/**
2
+ * Filter Modal Title
3
+ * @param {Object} props Props.
4
+ * @returns {JSX.Element}
5
+ */var FilterModalTitle=function FilterModalTitle(_ref){var apply=_ref.apply,reset=_ref.reset,close=_ref.close;return React.createElement("div",{className:styles.root},React.createElement(Ripple,{onClick:close,className:styles.closeButton},React.createElement(CrossIcon,null)),React.createElement("span",{className:styles.title},i18n.text('titles.filter')),React.createElement(Ripple,{fill:true,className:styles.actionButtonSecondary,onClick:reset},i18n.text('filter.reset')),React.createElement(Ripple,{fill:true,className:styles.actionButton,onClick:apply},i18n.text('filter.apply')));};export default FilterModalTitle;
@@ -0,0 +1 @@
1
+ export{default}from"./FilterModal";
@@ -0,0 +1,5 @@
1
+ function _slicedToArray(arr,i){return _arrayWithHoles(arr)||_iterableToArrayLimit(arr,i)||_nonIterableRest();}function _nonIterableRest(){throw new TypeError("Invalid attempt to destructure non-iterable instance");}function _iterableToArrayLimit(arr,i){var _arr=[];var _n=true;var _d=false;var _e=undefined;try{for(var _i=arr[Symbol.iterator](),_s;!(_n=(_s=_i.next()).done);_n=true){_arr.push(_s.value);if(i&&_arr.length===i)break;}}catch(err){_d=true;_e=err;}finally{try{if(!_n&&_i["return"]!=null)_i["return"]();}finally{if(_d)throw _e;}}return _arr;}function _arrayWithHoles(arr){if(Array.isArray(arr))return arr;}import React,{useState,useMemo,memo,useCallback}from'react';import PropTypes from'prop-types';import{ResponsiveContainer}from'@shopgate/engage/components';import{hasNewServices}from'@shopgate/engage/core/helpers';import{themeConfig}from'@shopgate/engage';import{SortProvider,SORT_SCOPE_CATEGORY,SORT_SCOPE_SEARCH}from'@shopgate/engage/filter';import Provider from"./FilterBarProvider";import Content from"./components/Content";import Modal from"./components/FilterModal";import styles from"./style";var colors=themeConfig.colors;/**
2
+ * The FilterBar component.
3
+ * @param {Object} props The component props.
4
+ * @returns {JSX}
5
+ */function FilterBar(_ref){var filters=_ref.filters,categoryId=_ref.categoryId;var _useState=useState(filters!==null&&Object.keys(filters).length>0),_useState2=_slicedToArray(_useState,2),active=_useState2[0],setActive=_useState2[1];var handleChipCountUpdate=useCallback(function(count){setActive(count>0);},[]);var style=useMemo(function(){return hasNewServices()?{background:active?'var(--color-background-accent)':'var(--color-background-accent)',color:active?'var(--color-primary)':'var(--color-text-high-emphasis)'}:{background:active?'var(--color-secondary)':colors.background,color:active?'var(--color-secondary-contrast)':colors.dark};},[active]);var sortScope=useMemo(function(){return categoryId?SORT_SCOPE_CATEGORY:SORT_SCOPE_SEARCH;},[categoryId]);return React.createElement("div",{className:"".concat(styles," theme__filter-bar"),"data-test-id":"filterBar",style:style},React.createElement(SortProvider,{scope:sortScope},React.createElement(Provider,null,React.createElement(Content,{onChipCountUpdate:handleChipCountUpdate}),React.createElement(ResponsiveContainer,{breakpoint:">xs",webOnly:true},React.createElement(Modal,null)))));}FilterBar.defaultProps={filters:null,categoryId:null};export default memo(FilterBar);
@@ -0,0 +1,9 @@
1
+ function _extends(){_extends=Object.assign||function(target){for(var i=1;i<arguments.length;i++){var source=arguments[i];for(var key in source){if(Object.prototype.hasOwnProperty.call(source,key)){target[key]=source[key];}}}return target;};return _extends.apply(this,arguments);}import configureStore from'redux-mock-store';import thunk from'redux-thunk';import{FILTER_TYPE_SINGLE_SELECT,FILTER_TYPE_MULTISELECT}from'@shopgate/pwa-common-commerce/filter/constants';import{themeConfig as mockThemeConfig}from'@shopgate/pwa-common/helpers/config/mock';var mockedStoreDefault={filter:{activeFilters:[],availableFilters:{},activeHash:null,temporaryFilters:{}},history:{queryParams:{sort:'desc'}}};var mockedStoreAllSelected=_extends({},mockedStoreDefault,{filter:_extends({},mockedStoreDefault.filter,{activeFilters:[{filters:{SingleSelect:{type:FILTER_TYPE_SINGLE_SELECT,label:'Single selection',value:'SingleSelected',valueLabel:'Single Selected'},MultiSelect:{type:FILTER_TYPE_MULTISELECT,label:'MultiSelect',values:['one','two'],valueLabels:['One','Two']},Range:{type:'range',label:'Range',minimum:1.1,maximum:99.99}}}]})});/**
2
+ * Returns a store with default state.
3
+ * @returns {Object}
4
+ */export function getDefaultStore(){return configureStore([thunk])(mockedStoreDefault);}/**
5
+ * Returns a store with state with all filter types selected.
6
+ * @returns {Object}
7
+ */export function getStoreWithSelectedFilters(){return configureStore([thunk])(mockedStoreAllSelected);}/**
8
+ * Mock app config
9
+ */export function mockAppConfig(){jest.mock('@shopgate/pwa-common/helpers/config',function(){return{"default":{currency:'USD'},themeConfig:mockThemeConfig};});}
@@ -0,0 +1,4 @@
1
+ import{createSelector}from'reselect';import{hasActiveFilters}from'@shopgate/pwa-common-commerce/filter/selectors';/**
2
+ * Checks if the filter bar has active filters
3
+ * @return {bool}
4
+ */export var isFilterBarActive=createSelector(hasActiveFilters,function(activeFilters){return activeFilters;});
@@ -0,0 +1 @@
1
+ import{css}from'glamor';export default css({transition:'transform 200ms cubic-bezier(0.25, 0.1, 0.25, 1)'});
@@ -0,0 +1,14 @@
1
+ import React from'react';import PropTypes from'prop-types';import{useWidgetSettings,useRoute,useResponsiveValue}from'@shopgate/engage/core/hooks';import{ResponsiveContainer,ScrollHeader,SurroundPortals}from'@shopgate/engage/components';import{GlobalLocationSwitcher,FulfillmentSlotSwitcher}from'@shopgate/engage/locations/components';import{themeConfig}from'@shopgate/engage';import FilterBar from'@shopgate/engage/product/components/FilterBar';import{filters}from"./style";var _ref=themeConfig||{},_ref$variables$scroll=_ref.variables.scroll,_ref$variables$scroll2=_ref$variables$scroll===void 0?{}:_ref$variables$scroll,_ref$variables$scroll3=_ref$variables$scroll2.offset,offset=_ref$variables$scroll3===void 0?100:_ref$variables$scroll3;/**
2
+ * The ProductFilters component renders the FilterBar component wrapped in a ScrollHeader.
3
+ *
4
+ * Depending on the "@shopgate/engage/components/FilterBar" widget settings, the FilterBar will
5
+ * either be fixed at the top of the page or hide when the user scrolls down.
6
+ * @param {Object} props The component props
7
+ * @param {Object} [props.categoryId] The category id when shown for a category page.
8
+ * @param {Object} [props.searchPhrase] The search phrase when shown for a search page.
9
+ * @param {Object} [props.showFilters=false] Whether to show the filter bar.
10
+ * @param {Object} [props.hasSubcategories=false] Whether a category has subcategories.
11
+ * @returns {JSX.Element}
12
+ */var ProductFilters=function ProductFilters(_ref2){var categoryId=_ref2.categoryId,showFilters=_ref2.showFilters,hasSubcategories=_ref2.hasSubcategories,searchPhrase=_ref2.searchPhrase;var _useWidgetSettings=useWidgetSettings('@shopgate/engage/components/FilterBar'),hideOnScroll=_useWidgetSettings.hideOnScroll;var _useRoute=useRoute(),state=_useRoute.state;// When the PWA is in website mode, we apply a higher offset value than usual because the AppBar
13
+ // is larger.
14
+ var responsiveOffset=useResponsiveValue('>xs',{webOnly:true,valueMatch:220,valueMiss:offset});return React.createElement(ScrollHeader,{className:filters,hideOnScroll:hideOnScroll,scrollOffset:responsiveOffset},React.createElement(SurroundPortals,{portalName:"filter-bar.content",portalProps:{categoryId:categoryId,hasSubcategories:hasSubcategories,searchPhrase:searchPhrase,showFilters:showFilters}},React.createElement(ResponsiveContainer,{appAlways:true,breakpoint:"<=xs"},React.createElement(GlobalLocationSwitcher,{renderBar:true}),React.createElement(FulfillmentSlotSwitcher,{renderBar:true})),showFilters&&React.createElement(FilterBar,{categoryId:categoryId,filters:state.filters})));};ProductFilters.defaultProps={showFilters:false,categoryId:null,hasSubcategories:false,searchPhrase:null};export default ProductFilters;
@@ -0,0 +1 @@
1
+ function _defineProperty(obj,key,value){if(key in obj){Object.defineProperty(obj,key,{value:value,enumerable:true,configurable:true,writable:true});}else{obj[key]=value;}return obj;}function _extends(){_extends=Object.assign||function(target){for(var i=1;i<arguments.length;i++){var source=arguments[i];for(var key in source){if(Object.prototype.hasOwnProperty.call(source,key)){target[key]=source[key];}}}return target;};return _extends.apply(this,arguments);}import{css}from'glamor';import{useScrollContainer}from'@shopgate/engage/core';import{responsiveMediaQuery}from'@shopgate/engage/styles';export var filters=css(_extends({},useScrollContainer()?{top:0}:{top:44},_defineProperty(_defineProperty(_defineProperty(_defineProperty({},responsiveMediaQuery('>xs',{webOnly:true}),{top:64,marginBottom:16}),responsiveMediaQuery('<=xs',{webOnly:true}),{top:56}),"display",'block'),"zIndex",1000))).toString();
@@ -1 +1 @@
1
- export*from"./Availability";export{default as Characteristics}from"./Characteristics";export{default as Description}from"./Description";export{default as EffectivityDates}from"./EffectivityDates";export{default as MapPriceHint}from"./MapPriceHint";export*from"./Media";export{default as MediaSlider}from"./MediaSlider";export{default as Options}from"./Options";export{SelectOption,TextOption}from"./Options";export{default as OrderQuantityHint}from"./OrderQuantityHint";export{default as PriceDifference}from"./PriceDifference";export*from"./PriceInfo";export{default as ProductBadges}from"./ProductBadges";export{default as ProductCard}from"./ProductCard";export{default as ProductCharacteristics}from"./ProductCharacteristics";export{default as ProductDiscountBadge}from"./ProductDiscountBadge";export{default as ProductGridPrice}from"./ProductGridPrice";export{default as ProductImage}from"./ProductImage";export{default as ProductList}from"./ProductList";export*from"./ProductName";export{default as ProductProperties}from"./ProductProperties/ProductProperties";export{default as ProductSlider}from"./ProductSlider";export*from"./ProductVariants";export{default as QuantityPicker}from"./QuantityPicker";export{default as Rating}from"./Rating";export*from"./RelationsSlider";export*from"./Swatch";export*from"./Swatches";export*from"./UnitQuantityPicker";
1
+ export*from"./Availability";export{default as Characteristics}from"./Characteristics";export{default as Description}from"./Description";export{default as EffectivityDates}from"./EffectivityDates";export{default as MapPriceHint}from"./MapPriceHint";export*from"./Media";export{default as MediaSlider}from"./MediaSlider";export{default as Options}from"./Options";export{SelectOption,TextOption}from"./Options";export{default as OrderQuantityHint}from"./OrderQuantityHint";export{default as PriceDifference}from"./PriceDifference";export*from"./PriceInfo";export{default as ProductBadges}from"./ProductBadges";export{default as ProductCard}from"./ProductCard";export{default as ProductCharacteristics}from"./ProductCharacteristics";export{default as ProductDiscountBadge}from"./ProductDiscountBadge";export{default as ProductGridPrice}from"./ProductGridPrice";export{default as ProductImage}from"./ProductImage";export{default as ProductList}from"./ProductList";export*from"./ProductName";export{default as ProductProperties}from"./ProductProperties/ProductProperties";export{default as ProductSlider}from"./ProductSlider";export*from"./ProductVariants";export{default as QuantityPicker}from"./QuantityPicker";export{default as Rating}from"./Rating";export*from"./RelationsSlider";export*from"./Swatch";export*from"./Swatches";export*from"./UnitQuantityPicker";export{default as FilterBar}from"./FilterBar";export{default as ProductFilters}from"./ProductFilters";
package/product/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /** @module product */ // ACTION-CREATORS
2
- export{default as productNotAvailable}from'@shopgate/pwa-common-commerce/product/action-creators/productNotAvailable';// ACTIONS
2
+ export{default as productNotAvailable}from'@shopgate/pwa-common-commerce/product/action-creators/productNotAvailable';export{default as expireProductData}from'@shopgate/pwa-common-commerce/product/action-creators/expireProductData';// ACTIONS
3
3
  export{default as changeSortOrder}from'@shopgate/pwa-common-commerce/product/actions/changeSortOrder';export{default as fetchHighlightProducts}from'@shopgate/pwa-common-commerce/product/actions/fetchHighlightProducts';export{default as fetchLiveshoppingProducts}from'@shopgate/pwa-common-commerce/product/actions/fetchLiveshoppingProducts';export{default as fetchProduct}from'@shopgate/pwa-common-commerce/product/actions/fetchProduct';export{default as fetchProductDescription}from'@shopgate/pwa-common-commerce/product/actions/fetchProductDescription';export{default as fetchProductImages}from'@shopgate/pwa-common-commerce/product/actions/fetchProductImages';export{default as fetchProductOptions}from'@shopgate/pwa-common-commerce/product/actions/fetchProductOptions';export{default as fetchProductProperties}from'@shopgate/pwa-common-commerce/product/actions/fetchProductProperties';export{default as fetchProductRelations}from'@shopgate/pwa-common-commerce/product/actions/fetchProductRelations';export{default as fetchProducts}from'@shopgate/pwa-common-commerce/product/actions/fetchProducts';export{default as fetchProductsById}from'@shopgate/pwa-common-commerce/product/actions/fetchProductsById';export{default as fetchProductsByQuery}from'@shopgate/pwa-common-commerce/product/actions/fetchProductsByQuery';export{default as fetchProductShipping}from'@shopgate/pwa-common-commerce/product/actions/fetchProductShipping';export{default as fetchProductVariants}from'@shopgate/pwa-common-commerce/product/actions/fetchProductVariants';// SELECTORS
4
4
  export*from'@shopgate/pwa-common-commerce/product/selectors/options';export*from'@shopgate/pwa-common-commerce/product/selectors/page';export*from'@shopgate/pwa-common-commerce/product/selectors/price';export*from'@shopgate/pwa-common-commerce/product/selectors/product';export*from'@shopgate/pwa-common-commerce/product/selectors/relations';export*from'@shopgate/pwa-common-commerce/product/selectors/variants';export*from"./selectors/media";export{getProductIsFetching,makeGetProductProperties,makeGetProductEffectivityDates,makeGetProductCharacteristics,makeGetProductFeaturedMedia,makeIsProductActive,makeIsBaseProductActive,makeGetProductType}from"./selectors/product";export*from"./selectors/price";export*from"./selectors/variants";export*from"./selectors/relations";// CONTEXTS
5
5
  export{ProductContext,VariantContext}from"./components/context";export{default as ProductListTypeContext}from"./providers/ProductListType/context";export{default as ProductListEntryContext}from"./providers/ProductListEntry/context";export*from"./collections";export*from"./constants";export*from"./helpers";export*from"./components";export*from"./hocs";export*from"./hooks";export*from"./providers";// eslint-disable-next-line import/export