@saleor/macaw-ui 0.3.2 → 0.5.0

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 (118) hide show
  1. package/README.md +20 -0
  2. package/dist/cjs/index.js +2 -2
  3. package/dist/cjs/index.js.map +3 -3
  4. package/dist/esm/index.js +2 -2
  5. package/dist/esm/index.js.map +3 -3
  6. package/dist/types/ActionBar/ActionBar.d.ts +1 -0
  7. package/dist/types/ActionBar/context.d.ts +6 -3
  8. package/dist/types/Autocomplete/Autocomplete.d.ts +23 -0
  9. package/dist/types/Autocomplete/Autocomplete.stories.d.ts +5 -0
  10. package/dist/types/Autocomplete/fixtures.d.ts +4 -0
  11. package/dist/types/Autocomplete/index.d.ts +1 -0
  12. package/dist/types/Autocomplete/styles.d.ts +2 -0
  13. package/dist/types/Chip/Chip.d.ts +8 -0
  14. package/dist/types/Chip/ChipAdornment.d.ts +6 -0
  15. package/dist/types/Chip/ChipMovable.d.ts +5 -0
  16. package/dist/types/Chip/ChipRemovable.d.ts +6 -0
  17. package/dist/types/Chip/ChipSwatch.d.ts +7 -0
  18. package/dist/types/Chip/index.d.ts +5 -0
  19. package/dist/types/Chip/private/ColorSwatch.d.ts +6 -0
  20. package/dist/types/Chip/styles.d.ts +2 -0
  21. package/dist/types/CircleIndicator/index.d.ts +1 -1
  22. package/dist/types/Filter/FilterField/AutocompleteFilterField.d.ts +6 -0
  23. package/dist/types/Filter/FilterField/MultipleValueAutocompleteFilterField.d.ts +6 -0
  24. package/dist/types/Filter/stories/Filter.stories.d.ts +5 -0
  25. package/dist/types/Filter/stories/FilterInteractive.stories.d.ts +4 -0
  26. package/dist/types/Filter/stories/labels.d.ts +8 -0
  27. package/dist/types/Filter/styles.d.ts +1 -1
  28. package/dist/types/Filter/types.d.ts +8 -2
  29. package/dist/types/Filter/utils.d.ts +4 -1
  30. package/dist/types/IconButton/IconButton.d.ts +2 -0
  31. package/dist/types/IconButton/partials.d.ts +1 -1
  32. package/dist/types/IconButton/styles.d.ts +1 -1
  33. package/dist/types/MultipleValueAutocomplete/MultipleValueAutocomplete.d.ts +26 -0
  34. package/dist/types/MultipleValueAutocomplete/MultipleValueAutocomplete.stories.d.ts +6 -0
  35. package/dist/types/MultipleValueAutocomplete/fixtures.d.ts +4 -0
  36. package/dist/types/MultipleValueAutocomplete/index.d.ts +1 -0
  37. package/dist/types/MultipleValueAutocomplete/styles.d.ts +2 -0
  38. package/dist/types/MultipleValueAutocomplete/useMultipleValueAutocomplete.d.ts +32 -0
  39. package/dist/types/Savebar/Savebar.d.ts +1 -0
  40. package/dist/types/Sidebar/MenuItem.d.ts +9 -3
  41. package/dist/types/Sidebar/types.d.ts +8 -0
  42. package/dist/types/Sidebar/utils.d.ts +12 -0
  43. package/dist/types/SidebarDrawer/MenuItemBtn.d.ts +2 -1
  44. package/dist/types/SwitchSelector/SwitchSelector.d.ts +2 -0
  45. package/dist/types/SwitchSelector/SwitchSelector.stories.d.ts +4 -0
  46. package/dist/types/SwitchSelector/SwitchSelectorButton.d.ts +8 -0
  47. package/dist/types/SwitchSelector/index.d.ts +2 -0
  48. package/dist/types/index.d.ts +3 -0
  49. package/dist/types/theme/ThemeProvider.d.ts +4 -0
  50. package/dist/types/theme/types.d.ts +1 -0
  51. package/dist/types/tools/useTextWidth.d.ts +2 -0
  52. package/dist/types/utils/guideStyles.d.ts +1 -1
  53. package/dist/types/utils/mergeRefs.d.ts +2 -0
  54. package/dist/types/utils/useMockAutocomplete.d.ts +10 -0
  55. package/package.json +11 -13
  56. package/src/ActionBar/ActionBar.tsx +8 -11
  57. package/src/ActionBar/context.tsx +15 -6
  58. package/src/ActionBar/styles.ts +1 -1
  59. package/src/Autocomplete/Autocomplete.stories.tsx +43 -0
  60. package/src/Autocomplete/Autocomplete.tsx +187 -0
  61. package/src/Autocomplete/fixtures.ts +122 -0
  62. package/src/Autocomplete/index.ts +1 -0
  63. package/src/Autocomplete/styles.ts +19 -0
  64. package/src/Backlink/Backlink.tsx +3 -1
  65. package/src/Chip/Chip.tsx +52 -0
  66. package/src/Chip/ChipAdornment.tsx +53 -0
  67. package/src/Chip/ChipMovable.tsx +40 -0
  68. package/src/Chip/ChipRemovable.tsx +29 -0
  69. package/src/Chip/ChipSwatch.tsx +42 -0
  70. package/src/Chip/index.ts +5 -0
  71. package/src/Chip/private/ColorSwatch.tsx +21 -0
  72. package/src/Chip/styles.ts +46 -0
  73. package/src/CircleIndicator/CircleIndicator.stories.tsx +6 -6
  74. package/src/CircleIndicator/index.ts +1 -1
  75. package/src/Filter/Filter.tsx +88 -44
  76. package/src/Filter/FilterBar.tsx +15 -9
  77. package/src/Filter/FilterContent.tsx +8 -1
  78. package/src/Filter/FilterField/AutocompleteFilterField.tsx +61 -0
  79. package/src/Filter/FilterField/MultipleSelectFilterField.tsx +9 -3
  80. package/src/Filter/FilterField/MultipleValueAutocompleteFilterField.tsx +60 -0
  81. package/src/Filter/context.tsx +1 -1
  82. package/src/Filter/{Filter.stories.tsx → stories/Filter.stories.tsx} +47 -13
  83. package/src/Filter/stories/FilterInteractive.stories.tsx +97 -0
  84. package/src/Filter/stories/labels.ts +8 -0
  85. package/src/Filter/styles.ts +37 -6
  86. package/src/Filter/types.ts +8 -1
  87. package/src/Filter/utils.ts +71 -5
  88. package/src/IconButton/IconButton.tsx +17 -2
  89. package/src/IconButton/partials.ts +1 -1
  90. package/src/IconButton/styles.ts +38 -16
  91. package/src/MultipleValueAutocomplete/MultipleValueAutocomplete.stories.tsx +76 -0
  92. package/src/MultipleValueAutocomplete/MultipleValueAutocomplete.tsx +185 -0
  93. package/src/MultipleValueAutocomplete/fixtures.ts +122 -0
  94. package/src/MultipleValueAutocomplete/index.ts +1 -0
  95. package/src/MultipleValueAutocomplete/styles.ts +39 -0
  96. package/src/MultipleValueAutocomplete/useMultipleValueAutocomplete.ts +172 -0
  97. package/src/Savebar/Savebar.tsx +3 -4
  98. package/src/Sidebar/MenuItem.tsx +35 -14
  99. package/src/Sidebar/Sidebar.tsx +27 -11
  100. package/src/Sidebar/types.ts +9 -0
  101. package/src/Sidebar/utils.ts +23 -0
  102. package/src/SidebarDrawer/MenuItemBtn.tsx +12 -6
  103. package/src/SidebarDrawer/SidebarDrawer.tsx +8 -2
  104. package/src/SwitchSelector/SwitchSelector.stories.tsx +63 -0
  105. package/src/SwitchSelector/SwitchSelector.tsx +19 -0
  106. package/src/SwitchSelector/SwitchSelectorButton.tsx +59 -0
  107. package/src/SwitchSelector/index.ts +2 -0
  108. package/src/index.tsx +4 -1
  109. package/src/theme/ThemeProvider.tsx +6 -0
  110. package/src/theme/createSaleorTheme/createSaleorTheme.tsx +2 -1
  111. package/src/theme/createSaleorTheme/overrides/controls.ts +4 -1
  112. package/src/theme/createSaleorTheme/overrides/inputs.ts +1 -1
  113. package/src/theme/themes.ts +1 -1
  114. package/src/theme/types.ts +1 -0
  115. package/src/tools/useTextWidth.ts +20 -0
  116. package/src/utils/guideStyles.ts +5 -0
  117. package/src/utils/mergeRefs.ts +14 -0
  118. package/src/utils/useMockAutocomplete.ts +37 -0
@@ -0,0 +1,42 @@
1
+ import React from "react";
2
+
3
+ import { CloseIcon } from "../icons";
4
+ import { makeStyles } from "../theme";
5
+ import { Chip, ChipProps } from "./Chip";
6
+ import { ChipAdornment } from "./ChipAdornment";
7
+ import { ColorSwatch } from "./private/ColorSwatch";
8
+
9
+ export interface ChipSwatchProps extends Omit<ChipProps, "startAdornment"> {
10
+ onRemove?: () => void;
11
+ color: string;
12
+ }
13
+
14
+ const useStyles = makeStyles({
15
+ swatchPosition: {
16
+ marginLeft: "-10px",
17
+ },
18
+ });
19
+
20
+ export const ChipSwatch = React.forwardRef<HTMLDivElement, ChipSwatchProps>(
21
+ ({ endAdornment, color, onRemove, ...props }, ref) => {
22
+ const classes = useStyles();
23
+
24
+ return (
25
+ <Chip
26
+ startAdornment={<ColorSwatch color={color} />}
27
+ startAdornmentClassName={classes.swatchPosition}
28
+ endAdornment={
29
+ onRemove && (
30
+ <ChipAdornment>
31
+ <CloseIcon role="button" onClick={() => onRemove()} />
32
+ </ChipAdornment>
33
+ )
34
+ }
35
+ {...props}
36
+ ref={ref}
37
+ />
38
+ );
39
+ }
40
+ );
41
+
42
+ ChipSwatch.displayName = "ChipSwatch";
@@ -0,0 +1,5 @@
1
+ export * from "./Chip";
2
+ export * from "./ChipAdornment";
3
+ export * from "./ChipMovable";
4
+ export * from "./ChipRemovable";
5
+ export * from "./ChipSwatch";
@@ -0,0 +1,21 @@
1
+ import clsx from "clsx";
2
+ import React from "react";
3
+
4
+ import useStyles from "../styles";
5
+
6
+ export interface ColorSwatchProps {
7
+ color: string;
8
+ className?: string;
9
+ }
10
+
11
+ export const ColorSwatch = ({ color, className }: ColorSwatchProps) => {
12
+ const classes = useStyles();
13
+
14
+ return (
15
+ <div
16
+ className={clsx(classes.swatch, className)}
17
+ style={{ background: color }}
18
+ aria-hidden="true"
19
+ />
20
+ );
21
+ };
@@ -0,0 +1,46 @@
1
+ import { makeStyles } from "../theme";
2
+
3
+ const useStyles = makeStyles(
4
+ (theme) => ({
5
+ chip: {
6
+ ...theme.typography.body2,
7
+ background: theme.palette.saleor.active[1],
8
+ color: theme.palette.primary.contrastText,
9
+ borderRadius: "8px",
10
+ display: "flex",
11
+ alignItems: "center",
12
+ padding: theme.spacing(0, 2),
13
+ gap: "4px",
14
+ lineHeight: 1,
15
+ minHeight: theme.spacing(4),
16
+ cursor: "default",
17
+ userSelect: "none",
18
+ textAlign: "center",
19
+ "& > span": {
20
+ overflow: "hidden",
21
+ textOverflow: "ellipsis",
22
+ },
23
+ },
24
+ startAdornment: {
25
+ marginLeft: "-8px",
26
+ flexShrink: 0,
27
+ },
28
+ endAdornment: {
29
+ marginRight: "-8px",
30
+ flexShrink: 0,
31
+ },
32
+ swatch: {
33
+ width: theme.spacing(3),
34
+ height: theme.spacing(3),
35
+ border: `2px solid #fff`,
36
+ flexShrink: 0,
37
+ marginRight: "7px",
38
+ borderRadius: "4px",
39
+ // default background when no style specified
40
+ background: "transparent",
41
+ },
42
+ }),
43
+ { name: "Chip" }
44
+ );
45
+
46
+ export default useStyles;
@@ -2,9 +2,9 @@ import { Typography } from "@material-ui/core";
2
2
  import { Meta, Story } from "@storybook/react";
3
3
  import clsx from "clsx";
4
4
  import React from "react";
5
+
5
6
  import { Decorator, GuideDecorator } from "../utils/Decorator";
6
7
  import useGuideStyles from "../utils/guideStyles";
7
-
8
8
  import { CircleIndicator } from "./CircleIndicator";
9
9
 
10
10
  const StoryWrapper: React.FC = () => {
@@ -16,7 +16,7 @@ const StoryWrapper: React.FC = () => {
16
16
  Circle Indicators
17
17
  </Typography>
18
18
  <Typography className={guideClasses.paragraph} component="p">
19
- Circle Indicators represent status of a certain element.
19
+ Circle Indicators represent status of a certain element.
20
20
  </Typography>
21
21
  <div style={{ display: "flex", gap: "24px" }}>
22
22
  <div
@@ -30,10 +30,10 @@ const StoryWrapper: React.FC = () => {
30
30
  padding: 24,
31
31
  }}
32
32
  >
33
- Error <CircleIndicator color="error" />
34
- Warning <CircleIndicator color="warning" />
35
- Success <CircleIndicator color="success" />
36
- Info <CircleIndicator color="info" />
33
+ Error <CircleIndicator color="error" />
34
+ Warning <CircleIndicator color="warning" />
35
+ Success <CircleIndicator color="success" />
36
+ Info <CircleIndicator color="info" />
37
37
  </div>
38
38
  </div>
39
39
  </div>
@@ -1 +1 @@
1
- export * from './CircleIndicator';
1
+ export * from "./CircleIndicator";
@@ -1,10 +1,10 @@
1
- import IconButton from "@material-ui/core/IconButton";
2
1
  import MenuItem from "@material-ui/core/MenuItem";
3
- import Select from "@material-ui/core/Select";
2
+ import Select, { SelectProps } from "@material-ui/core/Select";
4
3
  import Typography from "@material-ui/core/Typography";
5
- import { difference } from "lodash";
4
+ import { difference, uniqBy } from "lodash";
6
5
  import React from "react";
7
6
 
7
+ import { IconButton } from "../IconButton";
8
8
  import { DeleteIcon } from "../icons";
9
9
  import { useFilters } from "./context";
10
10
  import { FilterContent } from "./FilterContent";
@@ -19,9 +19,16 @@ import {
19
19
  import * as utils from "./utils";
20
20
 
21
21
  export type FilterProps = FilterOptions & FilterDetailedOptions;
22
- export const Filter: React.FC<FilterProps> = ({ name, label, ...options }) => {
23
- const { register, set, unregister } = useFilters();
22
+ export const Filter: React.FC<FilterProps> = ({
23
+ name: nameProp,
24
+ label,
25
+ ...options
26
+ }) => {
27
+ const name = utils.getFilterName(nameProp, options);
28
+ const { filters, register, set, unregister } = useFilters();
24
29
  const registered = React.useRef(false);
30
+ const filter = filters.find((fd) => fd.name === name);
31
+
25
32
  React.useEffect(() => {
26
33
  register(name, label, options);
27
34
  registered.current = true;
@@ -33,7 +40,8 @@ export const Filter: React.FC<FilterProps> = ({ name, label, ...options }) => {
33
40
  if (
34
41
  registered.current &&
35
42
  options.choices !== undefined &&
36
- difference(options.choices, options.choices).length
43
+ filter &&
44
+ difference(options.choices, filter!.options.choices!).length
37
45
  ) {
38
46
  set(name, {
39
47
  options: {
@@ -58,7 +66,7 @@ export const FilterRow: React.FC<FilterRowProps> = ({
58
66
  labels,
59
67
  }) => {
60
68
  const classes = useStyles();
61
- const { filters, toggle, toggleRange } = useFilters();
69
+ const { filters, toggle, toggleRange, swap } = useFilters();
62
70
 
63
71
  const filter = filters.find((filter) => filter.name === name);
64
72
 
@@ -67,50 +75,86 @@ export const FilterRow: React.FC<FilterRowProps> = ({
67
75
  }
68
76
 
69
77
  const availableFilters = utils.getAvailableFilters(filters);
70
- const options = [filter, ...availableFilters];
78
+ const options = uniqBy(
79
+ [filter.options.group ?? filter, ...availableFilters],
80
+ "name"
81
+ );
82
+ const groupOptions = [
83
+ filter,
84
+ ...filters.filter(
85
+ (f) =>
86
+ f.name !== filter.name &&
87
+ f.options.group?.name === filter.options.group?.name &&
88
+ !f.active
89
+ ),
90
+ ];
71
91
 
72
92
  const change = (event: React.ChangeEvent<EventTarget<unknown>>) => {
73
- toggle(name);
74
- toggle(event.target.value as string);
93
+ const targetFilterName = event.target.value as string;
94
+
95
+ swap(name, targetFilterName);
96
+ };
97
+
98
+ const selectProps: SelectProps = {
99
+ classes: {
100
+ selectMenu: classes.filterInputInner,
101
+ },
102
+ variant: "outlined",
75
103
  };
76
104
 
77
105
  return (
78
106
  <div className={classes.filter}>
79
- <Typography className={classes.filterConjunction}>
80
- {first ? labels.where : labels.and}
81
- </Typography>
82
- <Select
83
- className={classes.filterName}
84
- classes={{
85
- selectMenu: classes.filterInputInner,
86
- }}
87
- variant="outlined"
88
- onChange={change}
89
- value={filter.name}
90
- >
91
- {options.map((option) => (
92
- <MenuItem key={option.name} value={option.name}>
93
- {option.label}
94
- </MenuItem>
95
- ))}
96
- </Select>
97
- <Select
98
- disabled={filter.options.type !== FilterType.Range}
99
- className={classes.filterRange}
100
- classes={{
101
- selectMenu: classes.filterInputInner,
102
- }}
103
- variant="outlined"
104
- value={filter.range.toString()}
105
- onChange={() => toggleRange(name)}
106
- >
107
- <MenuItem value="false">{labels.is}</MenuItem>
108
- <MenuItem value="true">{labels.range}</MenuItem>
109
- </Select>
107
+ <div className={classes.filterOptions}>
108
+ <Typography className={classes.filterConjunction}>
109
+ {first ? labels.where : labels.and}
110
+ </Typography>
111
+ <Select
112
+ {...selectProps}
113
+ className={classes.filterName}
114
+ onChange={change}
115
+ value={filter.options.group?.name ?? filter.name}
116
+ >
117
+ {options.map((option) => (
118
+ <MenuItem key={option.name} value={option.name}>
119
+ {option.label}
120
+ </MenuItem>
121
+ ))}
122
+ </Select>
123
+ {!!filter.options.group && (
124
+ <Select
125
+ {...selectProps}
126
+ className={classes.filterName}
127
+ onChange={change}
128
+ value={filter.name}
129
+ >
130
+ {groupOptions.map((option) => (
131
+ <MenuItem key={option.name} value={option.name}>
132
+ {option.label}
133
+ </MenuItem>
134
+ ))}
135
+ </Select>
136
+ )}
137
+ <Select
138
+ {...selectProps}
139
+ disabled={filter.options.type !== FilterType.Range}
140
+ className={classes.filterRange}
141
+ value={filter.range.toString()}
142
+ onChange={() => toggleRange(name)}
143
+ >
144
+ <MenuItem value="false">{labels.is}</MenuItem>
145
+ <MenuItem value="true">{labels.range}</MenuItem>
146
+ </Select>
147
+ </div>
110
148
  <FilterContent filter={filter} labels={labels} />
111
- <IconButton className={classes.filterDelete} onClick={() => toggle(name)}>
112
- <DeleteIcon />
113
- </IconButton>
149
+ <div className={classes.filterDeleteContainer}>
150
+ <IconButton
151
+ variant="secondary"
152
+ className={classes.filterDelete}
153
+ onClick={() => toggle(name)}
154
+ >
155
+ <DeleteIcon />
156
+ </IconButton>
157
+ </div>
114
158
  </div>
115
159
  );
116
160
  };
@@ -1,11 +1,11 @@
1
- import Button from "@material-ui/core/Button";
2
1
  import Card from "@material-ui/core/Card";
3
2
  import CardContent from "@material-ui/core/CardContent";
4
3
  import CardHeader from "@material-ui/core/CardHeader";
5
- import IconButton from "@material-ui/core/IconButton";
6
- import Close from "@material-ui/icons/Close";
7
4
  import React from "react";
8
5
 
6
+ import { Button } from "../Button";
7
+ import { IconButton } from "../IconButton";
8
+ import { CloseIcon, PlusIcon } from "../icons";
9
9
  import { FilterContext } from "./context";
10
10
  import { FilterRow } from "./Filter";
11
11
  import { FilterMenu, FilterMenuLabels } from "./FilterMenu";
@@ -56,8 +56,10 @@ export const FilterBar: React.FC<FilterBarProps> = React.forwardRef(
56
56
  setFilterData((fd) => fd.filter((filter) => filter.name !== name));
57
57
  const set = (name: string, filter: Partial<FilterData>) =>
58
58
  setFilterData((fd) =>
59
- fd.map((f) => (f.name === name ? { ...f, filter } : f))
59
+ fd.map((f) => (f.name === name ? { ...f, ...filter } : f))
60
60
  );
61
+ const swap = (previousFilterName: string, nextFilterName: string) =>
62
+ setFilterData((fd) => utils.swap(fd, previousFilterName, nextFilterName));
61
63
 
62
64
  const availableFilters = utils.getAvailableFilters(filterData);
63
65
 
@@ -75,16 +77,17 @@ export const FilterBar: React.FC<FilterBarProps> = React.forwardRef(
75
77
  toggle,
76
78
  toggleRange,
77
79
  unregister,
80
+ swap,
78
81
  onChange,
79
82
  }}
80
83
  >
81
84
  {children}
82
- <Card className={classes.bar} ref={ref} elevation={20}>
85
+ <Card className={classes.bar} ref={ref} elevation={8}>
83
86
  <CardHeader
84
87
  title={labels.header}
85
88
  action={
86
- <IconButton onClick={onClose}>
87
- <Close />
89
+ <IconButton variant="secondary" onClick={onClose}>
90
+ <CloseIcon />
88
91
  </IconButton>
89
92
  }
90
93
  />
@@ -105,11 +108,14 @@ export const FilterBar: React.FC<FilterBarProps> = React.forwardRef(
105
108
  {!!availableFilters.length && (
106
109
  <>
107
110
  <Button
108
- color="primary"
111
+ className={classes.barAddBtn}
112
+ color="text"
113
+ variant="secondary"
109
114
  ref={button}
110
115
  onClick={() => setMenuOpen(true)}
111
116
  >
112
- + {labels.addButton}
117
+ {labels.addButton}
118
+ <PlusIcon />
113
119
  </Button>
114
120
  </>
115
121
  )}
@@ -1,6 +1,8 @@
1
1
  import React from "react";
2
2
 
3
+ import { AutocompleteFilterField } from "./FilterField/AutocompleteFilterField";
3
4
  import { MultipleSelectFilterField } from "./FilterField/MultipleSelectFilterField";
5
+ import { MultipleValueAutocompleteFilterField } from "./FilterField/MultipleValueAutocompleteFilterField";
4
6
  import { RangeFilterField } from "./FilterField/RangeFilterField";
5
7
  import { SelectFilterField } from "./FilterField/SelectFilterField";
6
8
  import { TextFilterField } from "./FilterField/TextFilterField";
@@ -18,7 +20,12 @@ export const FilterContent: React.FC<FilterContentProps> = ({
18
20
  const { options, range } = filter;
19
21
  const { type, multiple } = options;
20
22
 
21
- if (type === FilterType.Choice) {
23
+ if (type === FilterType.Autocomplete) {
24
+ if (multiple) {
25
+ return <MultipleValueAutocompleteFilterField filter={filter} />;
26
+ }
27
+ return <AutocompleteFilterField filter={filter} />;
28
+ } else if (type === FilterType.Choice) {
22
29
  if (multiple) {
23
30
  return <MultipleSelectFilterField filter={filter} />;
24
31
  }
@@ -0,0 +1,61 @@
1
+ import MenuItem from "@material-ui/core/MenuItem";
2
+ import React from "react";
3
+
4
+ import { SyntheticChangeEvent } from "../../../types/utils";
5
+ import { Autocomplete } from "../../Autocomplete/Autocomplete";
6
+ import { useFilters } from "../context";
7
+ import useStyles from "../styles";
8
+ import { FilterData } from "../types";
9
+
10
+ export interface FilterContentProps {
11
+ filter: FilterData;
12
+ }
13
+
14
+ export const AutocompleteFilterField: React.FC<FilterContentProps> = ({
15
+ filter,
16
+ }) => {
17
+ const classes = useStyles();
18
+ const { onChange } = useFilters();
19
+
20
+ const { name, options } = filter;
21
+ const { choices } = options;
22
+
23
+ if (options.choices === undefined) {
24
+ throw new Error("FilterType.Autocomplete must be used with choices prop");
25
+ }
26
+ if (options.onInputChange === undefined) {
27
+ throw new Error(
28
+ "FilterType.Autocomplete must be used with onInputChange prop"
29
+ );
30
+ }
31
+
32
+ const handleChoiceChange = (event: SyntheticChangeEvent) =>
33
+ onChange(name, event.target.value);
34
+
35
+ return (
36
+ <Autocomplete
37
+ className={classes.filterValue}
38
+ choices={options.choices!}
39
+ InputProps={{
40
+ classes: {
41
+ input: classes.filterInputInner,
42
+ },
43
+ }}
44
+ onChange={handleChoiceChange}
45
+ onInputChange={options.onInputChange}
46
+ value={filter.values}
47
+ >
48
+ {({ getItemProps, highlightedIndex }) =>
49
+ choices!.map((choice, choiceIndex) => (
50
+ <MenuItem
51
+ selected={highlightedIndex === choiceIndex}
52
+ {...getItemProps({ item: choice, index: choiceIndex })}
53
+ >
54
+ {choice.label}
55
+ </MenuItem>
56
+ ))
57
+ }
58
+ </Autocomplete>
59
+ );
60
+ };
61
+ AutocompleteFilterField.displayName = "AutocompleteFilterField";
@@ -1,10 +1,10 @@
1
1
  import Checkbox from "@material-ui/core/Checkbox";
2
- import Chip from "@material-ui/core/Chip";
3
2
  import MenuItem from "@material-ui/core/MenuItem";
4
3
  import Select from "@material-ui/core/Select";
5
4
  import clsx from "clsx";
6
5
  import React from "react";
7
6
 
7
+ import { Chip } from "../../Chip";
8
8
  import { useFilters } from "../context";
9
9
  import useStyles from "../styles";
10
10
  import { EventTarget, FilterData } from "../types";
@@ -18,6 +18,9 @@ export const MultipleSelectFilterField: React.FC<FilterContentProps> = ({
18
18
  }) => {
19
19
  const classes = useStyles();
20
20
  const { onChange } = useFilters();
21
+ const [displayValues] = React.useState(
22
+ filter.options.displayValues || filter.options.choices
23
+ );
21
24
 
22
25
  const { name, options } = filter;
23
26
  const { choices } = options;
@@ -29,7 +32,7 @@ export const MultipleSelectFilterField: React.FC<FilterContentProps> = ({
29
32
  <Select
30
33
  className={classes.filterValue}
31
34
  classes={{
32
- root: classes.filterInputInner,
35
+ root: classes.filterMultipleValueInputInner,
33
36
  }}
34
37
  multiple
35
38
  variant="outlined"
@@ -41,7 +44,10 @@ export const MultipleSelectFilterField: React.FC<FilterContentProps> = ({
41
44
  return (
42
45
  <div className={classes.filterChipContainer}>
43
46
  {typedValues.map((value) => (
44
- <Chip className={classes.filterChip} key={value} label={value} />
47
+ <Chip className={classes.filterChip} key={value}>
48
+ {displayValues?.find((dv) => dv.value === value)?.label ??
49
+ value}
50
+ </Chip>
45
51
  ))}
46
52
  </div>
47
53
  );
@@ -0,0 +1,60 @@
1
+ import MenuItem from "@material-ui/core/MenuItem";
2
+ import React from "react";
3
+
4
+ import { SyntheticChangeEvent } from "../../../types/utils";
5
+ import { MultipleValueAutocomplete } from "../../MultipleValueAutocomplete";
6
+ import { useFilters } from "../context";
7
+ import useStyles from "../styles";
8
+ import { FilterData } from "../types";
9
+
10
+ export interface FilterContentProps {
11
+ filter: FilterData;
12
+ }
13
+
14
+ export const MultipleValueAutocompleteFilterField: React.FC<FilterContentProps> =
15
+ ({ filter }) => {
16
+ const classes = useStyles();
17
+ const { onChange } = useFilters();
18
+
19
+ const { name, options } = filter;
20
+
21
+ if (options.choices === undefined) {
22
+ throw new Error("FilterType.Autocomplete must be used with choices prop");
23
+ }
24
+ if (options.onInputChange === undefined) {
25
+ throw new Error(
26
+ "FilterType.Autocomplete must be used with onInputChange prop"
27
+ );
28
+ }
29
+
30
+ const handleChoiceChange = (event: SyntheticChangeEvent<string[]>) =>
31
+ onChange(name, event.target.value);
32
+
33
+ return (
34
+ <MultipleValueAutocomplete
35
+ className={classes.filterValue}
36
+ choices={options.choices!}
37
+ InputProps={{
38
+ classes: {
39
+ root: classes.filterMultipleValueInputInner,
40
+ },
41
+ }}
42
+ onChange={handleChoiceChange}
43
+ onInputChange={options.onInputChange}
44
+ value={filter.values}
45
+ >
46
+ {({ choices: filteredChoices, getItemProps, highlightedIndex }) =>
47
+ filteredChoices.map((choice, choiceIndex) => (
48
+ <MenuItem
49
+ selected={highlightedIndex === choiceIndex}
50
+ {...getItemProps({ item: choice, index: choiceIndex })}
51
+ >
52
+ {choice.label}
53
+ </MenuItem>
54
+ ))
55
+ }
56
+ </MultipleValueAutocomplete>
57
+ );
58
+ };
59
+ MultipleValueAutocompleteFilterField.displayName =
60
+ "MultipleValueAutocompleteFilterField";
@@ -5,7 +5,7 @@ import { FilterContextType } from "./types";
5
5
  export const FilterContext = createContext<FilterContextType | null>(null);
6
6
  export const useFilters = (): FilterContextType => {
7
7
  const ctx = useContext(FilterContext);
8
- if (ctx === undefined) {
8
+ if (!ctx) {
9
9
  throw new Error("useFilters must be used within a FilterContext");
10
10
  }
11
11