@shopgate/engage 7.32.0-beta.14 → 7.32.0-beta.15

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 (55) hide show
  1. package/filter/components/FilterItem/index.js +9 -2
  2. package/filter/components/FilterPageContent/components/ApplyButton/index.d.ts +21 -0
  3. package/filter/components/FilterPageContent/components/ApplyButton/index.d.ts.map +1 -0
  4. package/filter/components/FilterPageContent/components/ApplyButton/index.js +25 -52
  5. package/filter/components/FilterPageContent/components/FilterButtonBar/index.d.ts +8 -0
  6. package/filter/components/FilterPageContent/components/FilterButtonBar/index.d.ts.map +1 -0
  7. package/filter/components/FilterPageContent/components/FilterButtonBar/index.js +63 -0
  8. package/filter/components/FilterPageContent/components/ResetButton/index.d.ts +17 -0
  9. package/filter/components/FilterPageContent/components/ResetButton/index.d.ts.map +1 -0
  10. package/filter/components/FilterPageContent/components/ResetButton/index.js +24 -46
  11. package/filter/components/FilterPageContent/components/Selector/components/Selected/index.d.ts +19 -0
  12. package/filter/components/FilterPageContent/components/Selector/components/Selected/index.d.ts.map +1 -0
  13. package/filter/components/FilterPageContent/components/Selector/components/Selected/index.js +25 -46
  14. package/filter/components/FilterPageContent/components/Selector/components/Toggle/index.d.ts +14 -0
  15. package/filter/components/FilterPageContent/components/Selector/components/Toggle/index.d.ts.map +1 -0
  16. package/filter/components/FilterPageContent/components/Selector/components/Toggle/index.js +13 -46
  17. package/filter/components/FilterPageContent/components/Selector/components/ValueCheckbox/index.d.ts +25 -0
  18. package/filter/components/FilterPageContent/components/Selector/components/ValueCheckbox/index.d.ts.map +1 -0
  19. package/filter/components/FilterPageContent/components/Selector/components/ValueCheckbox/index.js +77 -0
  20. package/filter/components/FilterPageContent/components/Selector/index.d.ts +43 -0
  21. package/filter/components/FilterPageContent/components/Selector/index.d.ts.map +1 -0
  22. package/filter/components/FilterPageContent/components/Selector/index.js +52 -40
  23. package/filter/components/FilterPageContent/index.d.ts +16 -0
  24. package/filter/components/FilterPageContent/index.d.ts.map +1 -0
  25. package/filter/components/FilterPageContent/index.js +51 -57
  26. package/filter/components/PriceSlider/components/Label/index.js +69 -94
  27. package/filter/components/PriceSlider/index.js +43 -33
  28. package/filter/helpers/buildFilterParamsForFetchFiltersRequest.d.ts +8 -0
  29. package/filter/helpers/buildFilterParamsForFetchFiltersRequest.d.ts.map +1 -0
  30. package/filter/helpers/buildInitialFilters.d.ts +7 -0
  31. package/filter/helpers/buildInitialFilters.d.ts.map +1 -0
  32. package/filter/helpers/buildUpdatedFilters.d.ts +7 -0
  33. package/filter/helpers/buildUpdatedFilters.d.ts.map +1 -0
  34. package/filter/helpers/index.d.ts +5 -0
  35. package/filter/helpers/index.d.ts.map +1 -0
  36. package/filter/helpers/translateFilterLabel.d.ts +8 -0
  37. package/filter/helpers/translateFilterLabel.d.ts.map +1 -0
  38. package/filter/providers/FilterPageProvider.context.d.ts +157 -0
  39. package/filter/providers/FilterPageProvider.context.d.ts.map +1 -0
  40. package/filter/providers/FilterPageProvider.d.ts +24 -0
  41. package/filter/providers/FilterPageProvider.d.ts.map +1 -0
  42. package/filter/providers/FilterPageProvider.js +77 -132
  43. package/locations/components/GlobalLocationSwitcher/GlobalLocationSwitcherBar.js +4 -2
  44. package/package.json +7 -7
  45. package/product/components/FilterBar/components/Content/components/FilterButton/index.js +38 -46
  46. package/product/components/FilterBar/components/Content/components/FilterChips/components/FilterChip/index.d.ts +38 -0
  47. package/product/components/FilterBar/components/Content/components/FilterChips/components/FilterChip/index.d.ts.map +1 -0
  48. package/product/components/FilterBar/components/Content/components/FilterChips/components/FilterChip/index.js +88 -0
  49. package/product/components/FilterBar/components/Content/components/FilterChips/index.js +54 -35
  50. package/product/components/FilterBar/components/Content/components/Sort/index.js +1 -1
  51. package/product/components/FilterBar/components/Content/index.js +7 -3
  52. package/product/components/FilterBar/index.js +11 -22
  53. package/product/components/ProductFilters/index.js +2 -6
  54. package/filter/components/FilterPageContent/components/Selector/components/ValueButton/index.js +0 -69
  55. package/product/components/FilterBar/components/Content/components/FilterChips/connector.js +0 -22
@@ -1,28 +1,40 @@
1
- import React, { useMemo, useState, useEffect, useCallback } from 'react';
2
- import PropTypes from 'prop-types';
1
+ import "core-js/modules/es.array.includes.js";
2
+ import "core-js/modules/es.string.replace.js";
3
+ import { useMemo, useState, useEffect, useCallback } from 'react';
3
4
  import { connect } from 'react-redux';
4
5
  import debounce from 'lodash/debounce';
5
6
  import isEqual from 'lodash/isEqual';
6
7
  import { router } from '@shopgate/engage/core';
8
+ import { useRoute } from '@shopgate/engage/core/hooks';
9
+ import { parseObjectToQueryString } from '@shopgate/engage/core/helpers';
7
10
  import { getFiltersByHash } from '@shopgate/engage/filter';
8
- // eslint-disable-next-line no-unused-vars, import/named
9
- import Context, { APIFilter, RouteFilters } from "./FilterPageProvider.context";
11
+ import Context from "./FilterPageProvider.context";
10
12
  import { buildInitialFilters, buildUpdatedFilters } from "../helpers";
13
+ import { jsx as _jsx } from "react/jsx-runtime";
14
+ const FILTER_PATH_SUFFIX = '/filter';
11
15
 
12
16
  /**
13
- * @param {Object} state The application state.
14
- * @param {Object} props The component props.
15
- * @returns {Object}
17
+ * A single stored filter value carrying id and label.
18
+ */
19
+
20
+ /**
21
+ * A filter as kept in the provider's internal state. `value` holds either the selected values of a
22
+ * list filter or the `[min, max]` tuple of a range filter.
23
+ */
24
+
25
+ const buildInitialFiltersTyped = buildInitialFilters;
26
+ const buildUpdatedFiltersTyped = buildUpdatedFilters;
27
+ /**
28
+ * Maps the available filters from the application state onto the provider props.
29
+ * @returns The mapped state props.
16
30
  */
17
- import { jsx as _jsx } from "react/jsx-runtime";
18
31
  const mapStateToProps = (state, props) => ({
19
32
  filters: getFiltersByHash(state, props)
20
33
  });
21
34
 
22
35
  /**
23
- * @param {Object} next The next component props.
24
- * @param {Object} prev The previous component props.
25
- * @returns {boolean}
36
+ * Compares the mapped state props to decide whether the connected component needs to re-render.
37
+ * @returns Whether the state props are considered equal.
26
38
  */
27
39
  const areStatePropsEqual = (next, prev) => {
28
40
  if (!prev.filters && next.filters || !isEqual(prev.filters, next.filters)) {
@@ -34,25 +46,19 @@ const areStatePropsEqual = (next, prev) => {
34
46
  /**
35
47
  * The FilterPageProvider component provides all relevant data and callbacks to represent and modify
36
48
  * the current state of the "filter" page.
37
- * @param {Object} props Provider props
38
- * @param {APIFilter[]} props.filters Array of available filters
39
- * @param {RouteFilters} props.activeFilters Object with the active filters for a filtered product
40
- * list
41
- * @param {string} props.parentRouteId Id of the route with the product list that's supposed to be
42
- * filtered
43
- * @param {Function} [props.onApply] Callback invoked when users pressed the apply button
44
- * @param {string} [props.categoryId] A category to be used for filter selection from Redux
45
- * @param {string} [props.searchPhrase] A search phrase to be used for filter selection from Redux
46
- * @param {NodeList} children Provider children
47
- * @returns {JSX.Element}
49
+ * @returns The rendered component.
48
50
  */
49
51
  const FilterPageProvider = ({
50
- filters: filtersProp,
51
- activeFilters: activeFiltersProp,
52
- parentRouteId,
53
- onApply,
54
- children
52
+ filters: filtersProp = null,
53
+ activeFilters: activeFiltersProp = null,
54
+ parentRouteId = null,
55
+ onApply = () => setTimeout(router.pop, 250),
56
+ children = null
55
57
  }) => {
58
+ const {
59
+ pathname,
60
+ query
61
+ } = useRoute();
56
62
  const [currentFilters, setCurrentFilters] = useState(activeFiltersProp || {});
57
63
 
58
64
  /**
@@ -60,7 +66,7 @@ const FilterPageProvider = ({
60
66
  * It's created from the "filters" array that contains all available filters, and the
61
67
  * "activeFilters" object that represents filters with an active value selection.
62
68
  */
63
- const [initialFilters, setInitialFilters] = useState(buildInitialFilters(filtersProp, activeFiltersProp));
69
+ const [initialFilters, setInitialFilters] = useState(buildInitialFiltersTyped(filtersProp, activeFiltersProp));
64
70
 
65
71
  /**
66
72
  * Storage that hosts an object that represents the a partial state of the filters page with
@@ -82,7 +88,7 @@ const FilterPageProvider = ({
82
88
  if (Object.keys(currentState).length > 0) {
83
89
  return currentState;
84
90
  }
85
- return buildInitialFilters(filtersProp, activeFiltersProp);
91
+ return buildInitialFiltersTyped(filtersProp, activeFiltersProp);
86
92
  });
87
93
  }, [activeFiltersProp, filtersProp]);
88
94
 
@@ -91,37 +97,23 @@ const FilterPageProvider = ({
91
97
  *
92
98
  * Reset is possible whenever filters where selected by the user before, or when filters where
93
99
  * modified since the filters page was opened.
94
- * @type {boolean}
95
100
  */
96
101
  const resetPossible = useMemo(() => !!(Object.keys(currentFilters).length || Object.keys(changedFilters).length), [changedFilters, currentFilters]);
97
102
 
98
103
  /**
99
104
  * Whether the filter selection has changed since the filters page was opened
100
- * @type {boolean}
101
105
  */
102
106
  const hasChanged = useMemo(() => Object.keys(changedFilters).length > 0 || !!(Object.keys(currentFilters).length === 0 && activeFiltersProp), [activeFiltersProp, changedFilters, currentFilters]);
103
-
104
- /**
105
- * Retrieves a list of currently selected values for a filter
106
- * @callback getSelectedFilterValues
107
- * @param {string} filterId The id of the filter
108
- * @returns {string[]}
109
- */
110
- const getSelectedFilterValues = useCallback(
111
- /**
112
- * @param {string} filterId The id of the filter
113
- * @returns {string[]}
114
- */
115
- filterId => {
107
+ const getSelectedFilterValues = useCallback(filterId => {
116
108
  const value = changedFilters[filterId] ? changedFilters[filterId].value : initialFilters[filterId]?.value || [];
117
- return value.map(entry => entry.id || entry);
109
+ return value.map(entry => typeof entry === 'object' ? entry.id : entry);
118
110
  }, [changedFilters, initialFilters]);
119
111
 
120
112
  /**
121
113
  * Resets all filters which have been changed by the user
122
114
  */
123
115
  const resetAllFilters = useCallback(() => {
124
- setInitialFilters(buildInitialFilters(filtersProp, {}));
116
+ setInitialFilters(buildInitialFiltersTyped(filtersProp, {}));
125
117
  setCurrentFilters({});
126
118
  setChangedFilters({});
127
119
  }, [filtersProp]);
@@ -132,77 +124,33 @@ const FilterPageProvider = ({
132
124
  const resetChangedFilters = useCallback(() => {
133
125
  setChangedFilters({});
134
126
  }, []);
135
-
136
- /**
137
- * Adds or updates the selection for a changed filter
138
- * @callback updateChangedFilterInternal
139
- * @param {string} filterId The id of the filter to be updated
140
- * @param {string[]} selectedValues The updated selected values
141
- */
142
- const updateChangedFilterInternal = useCallback(
143
- /**
144
- * @param {string} filterId The id of the filter to be updated
145
- * @param {string[]} selectedValues The updated selected values
146
- */
147
- (filterId, selectedValues) => {
127
+ const updateChangedFilterInternal = useCallback((filterId, selectedValues) => {
148
128
  setChangedFilters(currentState => ({
149
129
  ...currentState,
150
130
  [filterId]: selectedValues
151
131
  }));
152
132
  }, []);
153
-
154
- /**
155
- * Removes a changed filter
156
- * @callback removeChangedFilterInternal
157
- * @param {string} filterId The id of the filter to be updated
158
- * @param {string[]} selectedValues The updated selected values
159
- */
160
- const removeChangedFilterInternal = useCallback(
161
- /**
162
- * @param {string} filterId The id of the filter to be removed
163
- */
164
- filterId => {
133
+ const removeChangedFilterInternal = useCallback(filterId => {
165
134
  setChangedFilters(currentState => {
166
- // Separate the given id from the other set filters.
167
- const {
168
- [filterId]: removed,
169
- ...remainingFilters
170
- } = currentState;
135
+ const remainingFilters = {
136
+ ...currentState
137
+ };
138
+ delete remainingFilters[filterId];
171
139
  return remainingFilters;
172
140
  });
173
141
  }, []);
174
-
175
- /**
176
- * Updates the selection for a filter
177
- *
178
- * @param {string} filterId The id of the filter to be updated
179
- * @param {string[]} selectedValues The updated selected values
180
- */
181
- const updateSelectedFilterValues = useCallback(debounce(
182
- /**
183
- * @param {string} filterId The id of the filter to be updated
184
- * @param {string[]} selectedValues The updated selected values
185
- */
186
- (filterId, selectedValues) => {
187
- // Retrieve data of filter to be updated from the filters array.
188
- const filter = filtersProp.find(entry => entry.id === filterId);
189
-
190
- // Retrieve the values for the updated filter that where set when the filter page was opened
142
+ const updateSelectedFilterValues = useCallback(debounce((filterId, selectedValues) => {
143
+ const filter = (filtersProp || []).find(entry => entry.id === filterId);
144
+ if (!filter) {
145
+ return;
146
+ }
191
147
  const {
192
148
  value: initialValues
193
149
  } = initialFilters[filterId];
194
-
195
- // Prepare the update payload
196
- let stateValue = [].concat(selectedValues);
197
-
198
- /**
199
- * No initial values where set for this filter, and the update contains no values. So we
200
- * can remove the filter from the changedFilters storage.
201
- */
202
- if (initialValues.length === 0 && selectedValues.length === 0) {
203
- removeChangedFilterInternal(filterId);
204
- return;
205
- }
150
+ const hasValueList = Array.isArray(filter.values);
151
+ const orderByFilter = ids => hasValueList ? filter.values.filter(entry => ids.includes(entry.id)).map(entry => entry.id) : ids;
152
+ const selectedValueIds = orderByFilter(selectedValues);
153
+ const initialValueIds = orderByFilter(initialValues.map(entry => typeof entry === 'object' ? entry.id : entry));
206
154
 
207
155
  /**
208
156
  * When the filter update would recreate the state that the filter initially had, we
@@ -210,25 +158,21 @@ const FilterPageProvider = ({
210
158
  *
211
159
  * That enables proper behavior for the "reset" and "update" button states.
212
160
  */
213
- if (initialValues.length !== 0 && selectedValues.length !== 0) {
214
- if (initialValues.every((initial, i) => initial === selectedValues[i])) {
215
- removeChangedFilterInternal(filterId);
216
- return;
217
- }
161
+ if (initialValueIds.length === selectedValueIds.length && initialValueIds.every((initial, i) => initial === selectedValueIds[i])) {
162
+ removeChangedFilterInternal(filterId);
163
+ return;
218
164
  }
219
- if (Array.isArray(filter.values)) {
165
+ let stateValue = [].concat(selectedValueIds);
166
+ if (hasValueList) {
220
167
  /**
221
168
  * The selectedValues array only contains a list of ids.
222
169
  * For the getProducts request that's dispatched after the current filter selection was
223
170
  * applied, id and label is required at the filter values level.
224
171
  */
225
- stateValue = selectedValues.map(valueId => {
226
- const match = filter.values.find(entry => entry.id === valueId);
227
- return {
228
- id: match.id,
229
- label: match.label
230
- };
231
- });
172
+ stateValue = selectedValueIds.map(valueId => filter.values.find(entry => entry.id === valueId)).filter(match => Boolean(match)).map(match => ({
173
+ id: match.id,
174
+ label: match.label
175
+ }));
232
176
  }
233
177
  updateChangedFilterInternal(filterId, {
234
178
  id: filterId,
@@ -242,15 +186,27 @@ const FilterPageProvider = ({
242
186
  }, 50), [filtersProp, initialFilters, removeChangedFilterInternal, updateChangedFilterInternal]);
243
187
 
244
188
  /**
245
- * Applies the current filter selection to the parent route with a product list to be filtered
189
+ * Applies the current filter selection to the parent route with a product list to be filtered.
190
+ * When the filter page was entered directly, no parent route exists in the history stack. In
191
+ * that case the product list route is derived from the current pathname and replaces the
192
+ * filter page.
246
193
  */
247
194
  const applyFilters = useCallback(() => {
248
- const filters = buildUpdatedFilters(currentFilters, changedFilters);
195
+ const filters = buildUpdatedFiltersTyped(currentFilters, changedFilters);
196
+ if (!parentRouteId) {
197
+ router.replace({
198
+ pathname: `${pathname.slice(0, -FILTER_PATH_SUFFIX.length)}${parseObjectToQueryString(query)}`,
199
+ state: {
200
+ filters
201
+ }
202
+ });
203
+ return;
204
+ }
249
205
  router.update(parentRouteId, {
250
206
  filters
251
207
  });
252
208
  onApply(filters);
253
- }, [changedFilters, currentFilters, onApply, parentRouteId]);
209
+ }, [changedFilters, currentFilters, onApply, parentRouteId, pathname, query]);
254
210
  const value = useMemo(() => ({
255
211
  resetPossible,
256
212
  hasChanged,
@@ -267,17 +223,6 @@ const FilterPageProvider = ({
267
223
  children: children
268
224
  });
269
225
  };
270
- FilterPageProvider.defaultProps = {
271
- children: null,
272
- activeFilters: null,
273
- parentRouteId: null,
274
- filters: null,
275
- onApply: () => setTimeout(router.pop, 250)
276
- };
277
-
278
- /**
279
- * @type FilterPageProvider
280
- */
281
226
  export default connect(mapStateToProps, null, null, {
282
227
  areStatePropsEqual
283
228
  })(FilterPageProvider);
@@ -8,7 +8,7 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
8
8
  const useStyles = makeStyles()(theme => ({
9
9
  wrapper: {
10
10
  color: theme.palette.text.primary,
11
- background: theme.palette.background.emphasized
11
+ background: theme.palette.background.surface
12
12
  },
13
13
  inner: {
14
14
  display: 'flex',
@@ -16,7 +16,8 @@ const useStyles = makeStyles()(theme => ({
16
16
  margin: theme.spacing(0, 2),
17
17
  borderBottom: `1px solid ${theme.components.border.light}`,
18
18
  alignItems: 'center',
19
- height: theme.components.filterBar.height
19
+ height: theme.components.filterBar.height,
20
+ justifyContent: 'space-between'
20
21
  },
21
22
  innerStandalone: {
22
23
  borderBottom: 'none'
@@ -26,6 +27,7 @@ const useStyles = makeStyles()(theme => ({
26
27
  },
27
28
  button: {
28
29
  marginLeft: theme.spacing(2),
30
+ marginTop: theme.spacing(0.5),
29
31
  textTransform: 'none'
30
32
  }
31
33
  }));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@shopgate/engage",
3
- "version": "7.32.0-beta.14",
3
+ "version": "7.32.0-beta.15",
4
4
  "description": "Shopgate's ENGAGE library.",
5
5
  "license": "Apache-2.0",
6
6
  "author": "Shopgate <support@shopgate.com>",
@@ -18,12 +18,12 @@
18
18
  "dependencies": {
19
19
  "@emotion/react": "^11.14.0",
20
20
  "@shopgate/native-modules": "1.0.0-beta.34",
21
- "@shopgate/pwa-common": "7.32.0-beta.14",
22
- "@shopgate/pwa-common-commerce": "7.32.0-beta.14",
23
- "@shopgate/pwa-core": "7.32.0-beta.14",
24
- "@shopgate/pwa-ui-ios": "7.32.0-beta.14",
25
- "@shopgate/pwa-ui-material": "7.32.0-beta.14",
26
- "@shopgate/pwa-ui-shared": "7.32.0-beta.14",
21
+ "@shopgate/pwa-common": "7.32.0-beta.15",
22
+ "@shopgate/pwa-common-commerce": "7.32.0-beta.15",
23
+ "@shopgate/pwa-core": "7.32.0-beta.15",
24
+ "@shopgate/pwa-ui-ios": "7.32.0-beta.15",
25
+ "@shopgate/pwa-ui-material": "7.32.0-beta.15",
26
+ "@shopgate/pwa-ui-shared": "7.32.0-beta.15",
27
27
  "@stripe/react-stripe-js": "^1.16.5",
28
28
  "@stripe/stripe-js": "^1.44.1",
29
29
  "@virtuous/conductor": "~2.5.0",
@@ -1,35 +1,28 @@
1
1
  import React from 'react';
2
2
  import PropTypes from 'prop-types';
3
3
  import { makeStyles } from '@shopgate/engage/styles';
4
- import { Grid, I18n, Ripple, FilterIcon, Typography } from '@shopgate/engage/components';
4
+ import { i18n } from '@shopgate/engage/core/helpers';
5
+ import { Badge, I18n, FilterIcon, Typography } from '@shopgate/engage/components';
5
6
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
6
7
  const useStyles = makeStyles()(theme => ({
7
8
  button: {
9
+ display: 'flex',
10
+ alignItems: 'center',
11
+ gap: theme.spacing(0.75),
8
12
  color: 'inherit',
9
- fontSize: theme.components.icon.medium,
10
13
  outline: 0,
11
- padding: 0,
12
- minWidth: theme.components.navigator.height,
13
- height: theme.components.filterBar.height,
14
- position: 'relative',
15
- zIndex: 1,
16
- overflow: 'hidden'
17
- },
18
- filterButton: {
19
- display: 'flex'
14
+ flexShrink: 0,
15
+ margin: theme.spacing(0, 1.5),
16
+ padding: theme.spacing(0.25, 1),
17
+ border: `1px solid ${theme.components.border.medium}`,
18
+ borderRadius: theme.shape.borderRadius
20
19
  },
21
- filterButtonLabel: {
22
- alignSelf: 'center',
23
- paddingRight: theme.spacing(1)
20
+ buttonActive: {
21
+ borderColor: theme.components.badge.background
24
22
  },
25
- filterButtonRipple: {
26
- display: 'flex',
27
- height: '100%',
28
- width: '100%',
29
- justifyContent: 'center',
30
- alignItems: 'center',
31
- margin: 0,
32
- padding: '6px 10px'
23
+ icon: {
24
+ fontSize: theme.components.icon.medium,
25
+ display: 'flex'
33
26
  }
34
27
  }));
35
28
 
@@ -39,39 +32,38 @@ const useStyles = makeStyles()(theme => ({
39
32
  * @return {JSX}
40
33
  */
41
34
  function FilterButton({
42
- openFilters
35
+ openFilters,
36
+ filterCount
43
37
  }) {
44
38
  const {
45
39
  classes,
46
40
  cx
47
41
  } = useStyles();
48
- return /*#__PURE__*/_jsx("button", {
49
- className: cx(classes.button, 'theme__filter-bar__filter-button'),
42
+ return /*#__PURE__*/_jsxs("button", {
43
+ className: cx(classes.button, {
44
+ [classes.buttonActive]: filterCount > 0
45
+ }, 'theme__filter-bar__filter-button'),
50
46
  onClick: openFilters,
51
47
  "data-test-id": "filterButton",
48
+ "aria-label": i18n.text('titles.filter'),
52
49
  type: "button",
53
- children: /*#__PURE__*/_jsx(Ripple, {
54
- className: classes.filterButtonRipple,
55
- fill: true,
56
- children: /*#__PURE__*/_jsxs(Grid, {
57
- component: "div",
58
- children: [/*#__PURE__*/_jsx(Grid.Item, {
59
- className: classes.filterButton,
60
- component: "div",
61
- children: /*#__PURE__*/_jsx(Typography, {
62
- variant: "subtitle2",
63
- component: "span",
64
- className: classes.filterButtonLabel,
65
- children: /*#__PURE__*/_jsx(I18n.Text, {
66
- string: "titles.filter"
67
- })
68
- })
69
- }), /*#__PURE__*/_jsx(Grid.Item, {
70
- component: "div",
71
- children: /*#__PURE__*/_jsx(FilterIcon, {})
72
- })]
50
+ children: [/*#__PURE__*/_jsx("span", {
51
+ className: classes.icon,
52
+ children: /*#__PURE__*/_jsx(FilterIcon, {})
53
+ }), /*#__PURE__*/_jsx(Typography, {
54
+ variant: "subtitle2",
55
+ component: "span",
56
+ children: /*#__PURE__*/_jsx(I18n.Text, {
57
+ string: "titles.filter"
73
58
  })
74
- })
59
+ }), /*#__PURE__*/_jsx(Badge, {
60
+ count: filterCount,
61
+ max: 9,
62
+ "aria-hidden": true
63
+ })]
75
64
  });
76
65
  }
66
+ FilterButton.defaultProps = {
67
+ filterCount: 0
68
+ };
77
69
  export default FilterButton;
@@ -0,0 +1,38 @@
1
+ import type { ReactNode } from 'react';
2
+ export interface FilterChipProps {
3
+ /**
4
+ * Id of the filter value. Used as the test id and passed back to `onRemove`.
5
+ */
6
+ id: string;
7
+ /**
8
+ * The chip label.
9
+ */
10
+ children: ReactNode;
11
+ /**
12
+ * Whether the chip renders a remove button (default `true`).
13
+ */
14
+ removable?: boolean;
15
+ /**
16
+ * Aria label for the label button, which opens the filter page.
17
+ */
18
+ editLabel?: string;
19
+ /**
20
+ * Aria label for the remove button.
21
+ */
22
+ removeLabel?: string;
23
+ /**
24
+ * Invoked when the chip label is clicked.
25
+ */
26
+ onClick?: () => void;
27
+ /**
28
+ * Invoked with the chip id when the remove button is clicked.
29
+ */
30
+ onRemove?: (id: string) => void;
31
+ }
32
+ /**
33
+ * A removable chip representing one active filter within the filter bar.
34
+ * @returns The rendered component.
35
+ */
36
+ declare const FilterChip: ({ id, children, removable, editLabel, removeLabel, onClick, onRemove, }: FilterChipProps) => import("react").JSX.Element;
37
+ export default FilterChip;
38
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../../../../../../product/components/FilterBar/components/Content/components/FilterChips/components/FilterChip/index.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAiB,SAAS,EAAE,MAAM,OAAO,CAAC;AAwDtD,MAAM,WAAW,eAAe;IAC9B;;OAEG;IACH,EAAE,EAAE,MAAM,CAAC;IACX;;OAEG;IACH,QAAQ,EAAE,SAAS,CAAC;IACpB;;OAEG;IACH,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB;;OAEG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;OAEG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;OAEG;IACH,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB;;OAEG;IACH,QAAQ,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAC;CACjC;AAED;;;GAGG;AACH,QAAA,MAAM,UAAU,GAAI,yEAQjB,eAAe,gCAwBjB,CAAC;AAEF,eAAe,UAAU,CAAC"}
@@ -0,0 +1,88 @@
1
+ import { useCallback } from 'react';
2
+ import noop from 'lodash/noop';
3
+ import Button from '@shopgate/pwa-common/components/Button';
4
+ import { CrossIcon } from '@shopgate/engage/components';
5
+ import { makeStyles } from '@shopgate/engage/styles';
6
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
7
+ const useStyles = makeStyles()((theme, {
8
+ removable
9
+ }) => ({
10
+ chip: {
11
+ display: 'flex',
12
+ alignItems: 'center',
13
+ minWidth: 0,
14
+ maxWidth: '72%',
15
+ height: 30,
16
+ borderRadius: theme.shape.borderRadius,
17
+ border: `1px solid ${theme.palette.secondary.main}`,
18
+ background: theme.palette.background.surface,
19
+ color: theme.palette.text.primary,
20
+ paddingLeft: removable ? theme.spacing(0.75) : theme.spacing(1.25),
21
+ paddingRight: theme.spacing(1.25),
22
+ outline: 0
23
+ },
24
+ name: {
25
+ ...theme.typography.body2,
26
+ fontWeight: theme.typography.fontWeightMedium,
27
+ display: 'block',
28
+ color: 'inherit',
29
+ padding: 0,
30
+ paddingLeft: removable ? theme.spacing(0.5) : 0,
31
+ maxWidth: '100%',
32
+ overflow: 'hidden',
33
+ textOverflow: 'ellipsis',
34
+ whiteSpace: 'nowrap'
35
+ },
36
+ removeButton: {
37
+ display: 'flex',
38
+ flexShrink: 0,
39
+ padding: 0,
40
+ color: theme.palette.secondary.main
41
+ }
42
+ }));
43
+
44
+ /**
45
+ * `Button` is untyped JavaScript whose optional props read as required from TypeScript.
46
+ */
47
+ const ChipButton = Button;
48
+ /**
49
+ * A removable chip representing one active filter within the filter bar.
50
+ * @returns The rendered component.
51
+ */
52
+ const FilterChip = ({
53
+ id,
54
+ children,
55
+ removable = true,
56
+ editLabel,
57
+ removeLabel,
58
+ onClick = noop,
59
+ onRemove = noop
60
+ }) => {
61
+ const {
62
+ classes
63
+ } = useStyles({
64
+ removable
65
+ });
66
+ const handleRemove = useCallback(() => {
67
+ onRemove(id);
68
+ }, [onRemove, id]);
69
+ return /*#__PURE__*/_jsxs("div", {
70
+ className: classes.chip,
71
+ "data-test-id": id,
72
+ children: [removable && /*#__PURE__*/_jsx(ChipButton, {
73
+ className: classes.removeButton,
74
+ onClick: handleRemove,
75
+ testId: "removeFilter",
76
+ "aria-label": removeLabel,
77
+ children: /*#__PURE__*/_jsx(CrossIcon, {
78
+ size: 16
79
+ })
80
+ }), /*#__PURE__*/_jsx(ChipButton, {
81
+ className: classes.name,
82
+ onClick: onClick,
83
+ "aria-label": editLabel,
84
+ children: children
85
+ })]
86
+ });
87
+ };
88
+ export default FilterChip;