@soul-refiner/design-system 0.2.73 → 0.2.75

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.
@@ -6,7 +6,7 @@ import { FilterOptionProps } from './filter_option';
6
6
  type FilterTriggerTypes = 'outlined' | 'pill' | 'labeled' | 'avatar' | 'text';
7
7
  export interface FilterProps {
8
8
  closeOnBlur?: boolean;
9
- defaultValue?: string;
9
+ defaultValue?: string | string[];
10
10
  disabled?: boolean;
11
11
  graphic?: React.ReactElement;
12
12
  label?: string;
@@ -14,10 +14,12 @@ export interface FilterProps {
14
14
  triggerType: FilterTriggerTypes;
15
15
  options: (Omit<FilterOptionProps, 'selected' | 'onClick'> | 'break')[];
16
16
  closeOnChange?: boolean;
17
- onChange?: (event: React.MouseEvent) => void;
17
+ optionOnChange?: (event: React.MouseEvent) => void;
18
+ checkbox?: boolean;
19
+ applyOnClick?: (event: React.MouseEvent) => void;
18
20
  }
19
21
  declare const Filter: {
20
- ({ closeOnBlur, disabled, graphic, label, sx, triggerType, options, defaultValue, closeOnChange, onChange, }: FilterProps): React.JSX.Element;
22
+ ({ closeOnBlur, disabled, graphic, label, sx, triggerType, options, defaultValue, closeOnChange, optionOnChange, checkbox, applyOnClick, }: FilterProps): React.JSX.Element;
21
23
  Trigger: {
22
24
  ({ disabled, graphic, label, onClick, open, type, value, }: FilterTriggerProps): React.JSX.Element;
23
25
  displayName: string;
@@ -1,20 +1,47 @@
1
1
  'use client';
2
2
  import React from 'react';
3
3
  import styled, { css } from 'styled-components';
4
- import { P } from '../../';
4
+ import { Box, Button, P } from '../../';
5
5
  import { ChevronDown, ChevronUp } from '../../../icons';
6
6
  import { Styles } from '../../../common';
7
7
  import { Spacer, Option } from './filter_option';
8
- const Filter = ({ closeOnBlur = true, disabled, graphic, label, sx, triggerType, options, defaultValue, closeOnChange = true, onChange, }) => {
8
+ const Filter = ({ closeOnBlur = true, disabled, graphic, label = '', sx, triggerType, options, defaultValue = '', closeOnChange = true, optionOnChange, checkbox, applyOnClick, }) => {
9
+ const multiple = !!checkbox;
9
10
  const wrapperRef = React.useRef(null);
10
11
  const optionsRef = React.useRef(null);
11
12
  const [open, setOpen] = React.useState(false);
12
- const [selected, setSelected] = React.useState(defaultValue || options[0]?.value);
13
+ const [selected, setSelected] = React.useState(() => defaultValue ? defaultValue : multiple ? [] : '');
14
+ const [filterLabel, setFilterLabel] = React.useState('');
13
15
  React.useEffect(() => {
14
16
  if (disabled) {
15
17
  setOpen(false);
16
18
  }
17
19
  }, [disabled]);
20
+ React.useEffect(() => {
21
+ if (triggerType === 'outlined' && !defaultValue) {
22
+ setSelected(multiple
23
+ ? [options[0]?.value]
24
+ : options[0]?.value);
25
+ }
26
+ }, [triggerType, defaultValue]);
27
+ React.useEffect(() => {
28
+ if (open) {
29
+ return;
30
+ }
31
+ if (!selected.length) {
32
+ setFilterLabel(label);
33
+ return;
34
+ }
35
+ // not using selected[0] since it is required to show the first
36
+ const firstSelected = options.find((option) => typeof option !== 'string' && isSelected(option.value));
37
+ if (typeof selected === 'string') {
38
+ setFilterLabel(firstSelected.label);
39
+ return;
40
+ }
41
+ setFilterLabel(selected.length > 1
42
+ ? `${firstSelected.label} +${selected.length - 1}`
43
+ : firstSelected.label);
44
+ }, [selected, options, open]);
18
45
  const handleOpen = () => {
19
46
  if (disabled) {
20
47
  return;
@@ -28,7 +55,7 @@ const Filter = ({ closeOnBlur = true, disabled, graphic, label, sx, triggerType,
28
55
  setOpen(false);
29
56
  }
30
57
  };
31
- const handleChange = (event) => {
58
+ const handleChangeSingle = (event) => {
32
59
  event.stopPropagation();
33
60
  const value = event.target.getAttribute('data-value') ?? '';
34
61
  if (selected !== value) {
@@ -37,27 +64,52 @@ const Filter = ({ closeOnBlur = true, disabled, graphic, label, sx, triggerType,
37
64
  else {
38
65
  setSelected('');
39
66
  }
40
- if (closeOnChange) {
67
+ if (closeOnChange && !applyOnClick) {
41
68
  setOpen(false);
42
69
  }
43
- if (onChange)
44
- onChange(event);
70
+ if (optionOnChange)
71
+ optionOnChange(event);
45
72
  };
46
- const isSelected = (value) => value === selected;
47
- const dropdownOptions = options.map((option, index) => {
48
- if (typeof option === 'string' && option === 'break') {
49
- return React.createElement(Spacer, { key: `${React.useId()}-spacer-${index}` });
73
+ const handleChangeMultiple = (event) => {
74
+ event.stopPropagation();
75
+ const value = event.target.getAttribute('data-value') ?? '';
76
+ if (Array.isArray(selected) && selected.includes(value)) {
77
+ setSelected((prev) => prev.filter((item) => item !== value));
50
78
  }
51
- return (React.createElement(Option, { key: option.value, onClick: handleChange, selected: isSelected(option.value), ...option }));
52
- });
79
+ else {
80
+ setSelected((prev) => [value, ...prev]);
81
+ }
82
+ if (closeOnChange && !applyOnClick) {
83
+ setOpen(false);
84
+ }
85
+ if (optionOnChange)
86
+ optionOnChange(event);
87
+ };
88
+ const handleChange = multiple ? handleChangeMultiple : handleChangeSingle;
89
+ const isSelected = (value) => multiple ? selected.includes(value) : value === selected;
90
+ const dropdownOptions = [
91
+ ...options.map((option, index) => {
92
+ if (typeof option === 'string' && option === 'break') {
93
+ return React.createElement(Spacer, { key: `${React.useId()}-spacer-${index}` });
94
+ }
95
+ return (React.createElement(Option, { key: option.value, onClick: handleChange, selected: isSelected(option.value), checkbox: checkbox, radio: !multiple && triggerType === 'pill', showClose: index === 0 && triggerType === 'pill', onClose: () => setOpen(false), ...option }));
96
+ }),
97
+ triggerType === 'pill' && React.createElement(Spacer, { key: `spacer-${options.length}` }),
98
+ ];
53
99
  return (React.createElement(Wrapper, { "$sx": sx, tabIndex: 0, ref: wrapperRef, onBlurCapture: handleBlur },
54
- React.createElement(FilterTrigger, { disabled: disabled, graphic: graphic, label: label, onClick: handleOpen, open: open, type: triggerType, value: options.find((option) => {
55
- if (typeof option === 'string' && option === 'break') {
56
- return false;
57
- }
58
- return isSelected(option.value);
59
- })?.label }),
60
- open && React.createElement(Container, { ref: optionsRef }, dropdownOptions)));
100
+ React.createElement(FilterTrigger, { disabled: disabled, graphic: graphic, label: label, onClick: handleOpen, open: open, type: triggerType, value: filterLabel }),
101
+ open && (React.createElement(Container, { ref: optionsRef },
102
+ React.createElement(React.Fragment, null,
103
+ dropdownOptions,
104
+ triggerType === 'pill' && (React.createElement(Box, { "$display": "flex", "$dir": "row", "$align": "center", "$justify": "flex-end", "$gap": 8, sx: "margin-top: 8px; padding-right: 8px; padding-bottom: 8px" },
105
+ React.createElement(Button, { onClick: () => {
106
+ setSelected(multiple ? [] : '');
107
+ setOpen(false);
108
+ }, size: "small", type: "text" }, "Reset"),
109
+ React.createElement(Button, { onClick: (event) => {
110
+ applyOnClick && applyOnClick(event);
111
+ setOpen(false);
112
+ }, size: "small", type: "primary" }, "Apply"))))))));
61
113
  };
62
114
  const Wrapper = styled.div `
63
115
  position: relative;
@@ -98,7 +150,7 @@ const wrapperProps = {
98
150
  };
99
151
  const FilterTrigger = ({ disabled, graphic, label, onClick, open, type, value, }) => {
100
152
  if (type === 'pill') {
101
- return (React.createElement(Pill, { disabled: disabled, onClick: onClick, ...wrapperProps },
153
+ return (React.createElement(Pill, { disabled: disabled, onClick: onClick, "$labelIsDefault": value === label, ...wrapperProps },
102
154
  graphic,
103
155
  React.createElement(P, { ...textProps }, value),
104
156
  !graphic && (open ? React.createElement(ChevronUp, null) : React.createElement(ChevronDown, null))));
@@ -164,18 +216,28 @@ const Outlined = styled.button `
164
216
  const Pill = styled.button `
165
217
  ${sharedStyles}
166
218
  ${Styles.flex}
219
+ border: 1px solid var(--color-grey-8);
167
220
  border-radius: 24px;
168
- background-color: var(--color-primary-blue-4);
221
+ background-color: var(--color-white);
169
222
  font-family: var(--font-inter);
170
223
 
171
- & > * {
172
- color: var(--color-primary-blue-2);
173
- fill: currentColor;
224
+ ${({ $labelIsDefault }) => !$labelIsDefault
225
+ ? `
226
+ & > * {
227
+ color: var(--color-primary-blue-2);
228
+ fill: currentColor;
174
229
 
175
- &:hover {
176
- color: var(--color-primary-blue-1);
177
- }
178
- }
230
+ &:hover {
231
+ color: var(--color-primary-blue-1);
232
+ background-color: var(--color-primary-blue-4);
233
+ }
234
+ }
235
+
236
+ &:hover {
237
+ background-color: var(--color-primary-blue-4);
238
+ }
239
+ `
240
+ : ''}
179
241
  `;
180
242
  const Labeled = styled.button `
181
243
  ${sharedStyles}
@@ -6,9 +6,13 @@ export interface FilterOptionProps {
6
6
  selected: boolean;
7
7
  sx?: string;
8
8
  value: string;
9
+ checkbox?: boolean;
10
+ radio?: boolean;
11
+ showClose?: boolean;
12
+ onClose?: () => void;
9
13
  }
10
14
  declare const Option: {
11
- ({ label, onClick, selected, sx, value }: FilterOptionProps): React.JSX.Element;
15
+ ({ label, onClick, selected, sx, value, checkbox, radio, showClose, onClose, }: FilterOptionProps): React.JSX.Element;
12
16
  displayName: string;
13
17
  };
14
18
  export interface FilterSpacerProps {
@@ -1,10 +1,17 @@
1
1
  'use client';
2
2
  import React from 'react';
3
3
  import styled from 'styled-components';
4
- import { Box, P } from '../..';
5
- const Option = ({ label, onClick, selected, sx, value }) => {
6
- return (React.createElement(OptionWrapper, { "data-value": value, onClick: onClick, "$selected": selected, "$sx": sx },
7
- React.createElement(Box, { "$dir": "column", "$display": "flex" }, label && (React.createElement(P, { "$color": "grey-4", "$fontSize": 14, "$lineHeight": 20, "$mediumBold": true, "$textClampLines": 1 }, label)))));
4
+ import { Box, P, Checkbox, Radio } from '../..';
5
+ import { Close } from '../../../icons';
6
+ const Option = ({ label, onClick, selected, sx, value, checkbox, radio = false, showClose = false, onClose, }) => {
7
+ return (React.createElement(OptionWrapper, { "data-value": value, onClick: onClick, "$selected": selected, "$sx": sx, "$hasCheckbox": !!checkbox },
8
+ checkbox && React.createElement(Checkbox, { selected: selected }),
9
+ radio && React.createElement(Radio, { checked: selected, value: value }),
10
+ React.createElement(Box, { "$dir": "column", "$display": "flex" }, label && (React.createElement(P, { "$color": "grey-4", "$fontSize": 14, "$lineHeight": 20, "$mediumBold": true, "$textClampLines": 1 }, label))),
11
+ showClose && (React.createElement(Close, { sx: "margin-left: auto; pointer-events: auto !important;", size: 16, onClick: (event) => {
12
+ event.stopPropagation();
13
+ onClose && onClose();
14
+ } }))));
8
15
  };
9
16
  Option.displayName = 'Filter.Option';
10
17
  const OptionWrapper = styled.div `
@@ -15,13 +22,13 @@ const OptionWrapper = styled.div `
15
22
  display: flex;
16
23
  align-items: center;
17
24
  gap: 8px;
18
- min-width: 164px;
25
+ min-width: 217px;
19
26
 
20
27
  & > * {
21
28
  pointer-events: none;
22
29
  }
23
30
 
24
- ${({ $selected }) => {
31
+ ${({ $selected, $hasCheckbox }) => {
25
32
  if ($selected) {
26
33
  return `
27
34
  background-color: var(--color-grey-9);
@@ -29,6 +36,11 @@ const OptionWrapper = styled.div `
29
36
  background-color: var(--color-grey-8);
30
37
  }`;
31
38
  }
39
+ if ($hasCheckbox) {
40
+ return `&:hover {
41
+ background-color: var(--color-grey-10);
42
+ }`;
43
+ }
32
44
  return `
33
45
  &:hover {
34
46
  background-color: var(--color-grey-10);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@soul-refiner/design-system",
3
- "version": "0.2.73",
3
+ "version": "0.2.75",
4
4
  "main": "dist/index.js",
5
5
  "license": "MIT",
6
6
  "publishConfig": {