@tecsinapse/react-web-kit 1.8.0 → 1.10.2

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 (91) hide show
  1. package/CHANGELOG.md +64 -0
  2. package/dist/components/atoms/Button/Button.d.ts +3 -3
  3. package/dist/components/atoms/Button/Button.js.map +1 -1
  4. package/dist/components/atoms/Input/Input.js +5 -3
  5. package/dist/components/atoms/Input/Input.js.map +1 -1
  6. package/dist/components/atoms/Table/Header/THead.js +2 -2
  7. package/dist/components/atoms/Table/Header/THead.js.map +1 -1
  8. package/dist/components/atoms/Tooltip/Tooltip.d.ts +12 -0
  9. package/dist/components/atoms/Tooltip/Tooltip.js +50 -0
  10. package/dist/components/atoms/Tooltip/Tooltip.js.map +1 -0
  11. package/dist/components/atoms/Tooltip/index.d.ts +1 -0
  12. package/dist/components/atoms/Tooltip/index.js +24 -0
  13. package/dist/components/atoms/Tooltip/index.js.map +1 -0
  14. package/dist/components/atoms/Tooltip/styled.d.ts +9 -0
  15. package/dist/components/atoms/Tooltip/styled.js +140 -0
  16. package/dist/components/atoms/Tooltip/styled.js.map +1 -0
  17. package/dist/components/molecules/Drawer/styled.js.map +1 -1
  18. package/dist/components/molecules/InputPassword/InputPassword.js +5 -3
  19. package/dist/components/molecules/InputPassword/InputPassword.js.map +1 -1
  20. package/dist/components/molecules/Menubar/Menubar.js +1 -1
  21. package/dist/components/molecules/Menubar/Menubar.js.map +1 -1
  22. package/dist/components/molecules/Select/Dropdown/Dropdown.d.ts +1 -1
  23. package/dist/components/molecules/Select/Dropdown/Dropdown.js +39 -26
  24. package/dist/components/molecules/Select/Dropdown/Dropdown.js.map +1 -1
  25. package/dist/components/molecules/Select/Dropdown/components/SearchInput.d.ts +8 -0
  26. package/dist/components/molecules/Select/Dropdown/components/SearchInput.js +43 -0
  27. package/dist/components/molecules/Select/Dropdown/components/SearchInput.js.map +1 -0
  28. package/dist/components/molecules/Select/Dropdown/components/index.d.ts +1 -0
  29. package/dist/components/molecules/Select/Dropdown/components/index.js +16 -0
  30. package/dist/components/molecules/Select/Dropdown/components/index.js.map +1 -0
  31. package/dist/components/molecules/Select/Dropdown/styled.d.ts +2 -1
  32. package/dist/components/molecules/Select/Dropdown/styled.js +6 -3
  33. package/dist/components/molecules/Select/Dropdown/styled.js.map +1 -1
  34. package/dist/components/molecules/Select/Select.d.ts +2 -1
  35. package/dist/components/molecules/Select/Select.js +9 -11
  36. package/dist/components/molecules/Select/Select.js.map +1 -1
  37. package/dist/components/molecules/Select/SelectItem/SelectItem.d.ts +3 -3
  38. package/dist/components/molecules/Select/SelectItem/SelectItem.js +10 -9
  39. package/dist/components/molecules/Select/SelectItem/SelectItem.js.map +1 -1
  40. package/dist/components/molecules/Select/functions.d.ts +1 -1
  41. package/dist/components/molecules/Select/functions.js +1 -1
  42. package/dist/components/molecules/Select/functions.js.map +1 -1
  43. package/dist/components/molecules/Select/styled.d.ts +4 -3
  44. package/dist/components/molecules/Select/styled.js +16 -1
  45. package/dist/components/molecules/Select/styled.js.map +1 -1
  46. package/dist/components/molecules/TextArea/TextArea.d.ts +1 -2
  47. package/dist/components/molecules/TextArea/TextArea.js.map +1 -1
  48. package/dist/components/organisms/DataGrid/DataGrid.js +1 -1
  49. package/dist/components/organisms/DataGrid/DataGrid.js.map +1 -1
  50. package/dist/components/organisms/DataGrid/Footer/Footer.js +2 -1
  51. package/dist/components/organisms/DataGrid/Footer/Footer.js.map +1 -1
  52. package/dist/components/organisms/DataGrid/Header/Header.js.map +1 -1
  53. package/dist/components/organisms/DataGrid/Header/utils.d.ts +6 -8
  54. package/dist/components/organisms/DataGrid/Header/utils.js.map +1 -1
  55. package/dist/components/organisms/DataGrid/types.d.ts +2 -1
  56. package/dist/hooks/useClickAwayListener.d.ts +1 -1
  57. package/dist/hooks/useClickAwayListener.js +3 -3
  58. package/dist/hooks/useClickAwayListener.js.map +1 -1
  59. package/dist/index.d.ts +1 -0
  60. package/dist/index.js +17 -1
  61. package/dist/index.js.map +1 -1
  62. package/package.json +3 -3
  63. package/src/components/atoms/Button/Button.tsx +3 -3
  64. package/src/components/atoms/Input/Input.stories.tsx +1 -1
  65. package/src/components/atoms/Input/Input.tsx +65 -57
  66. package/src/components/atoms/Table/Header/THead.tsx +1 -1
  67. package/src/components/atoms/Tooltip/Tooltip.stories.tsx +30 -0
  68. package/src/components/atoms/Tooltip/Tooltip.tsx +51 -0
  69. package/src/components/atoms/Tooltip/index.ts +1 -0
  70. package/src/components/atoms/Tooltip/styled.ts +158 -0
  71. package/src/components/molecules/Drawer/styled.ts +1 -1
  72. package/src/components/molecules/InputPassword/InputPassword.stories.tsx +1 -1
  73. package/src/components/molecules/InputPassword/InputPassword.tsx +24 -22
  74. package/src/components/molecules/Menubar/Menubar.tsx +1 -1
  75. package/src/components/molecules/Select/Dropdown/Dropdown.tsx +45 -28
  76. package/src/components/molecules/Select/Dropdown/components/SearchInput.tsx +26 -0
  77. package/src/components/molecules/Select/Dropdown/components/index.ts +1 -0
  78. package/src/components/molecules/Select/Dropdown/styled.ts +10 -4
  79. package/src/components/molecules/Select/Select.stories.tsx +42 -16
  80. package/src/components/molecules/Select/Select.tsx +16 -12
  81. package/src/components/molecules/Select/SelectItem/SelectItem.tsx +27 -24
  82. package/src/components/molecules/Select/functions.ts +10 -18
  83. package/src/components/molecules/Select/{styled.ts → styled.tsx} +11 -1
  84. package/src/components/molecules/TextArea/TextArea.tsx +1 -2
  85. package/src/components/organisms/DataGrid/DataGrid.tsx +14 -12
  86. package/src/components/organisms/DataGrid/Footer/Footer.tsx +1 -0
  87. package/src/components/organisms/DataGrid/Header/Header.tsx +2 -2
  88. package/src/components/organisms/DataGrid/Header/utils.ts +15 -5
  89. package/src/components/organisms/DataGrid/types.ts +3 -1
  90. package/src/hooks/useClickAwayListener.ts +5 -4
  91. package/src/index.ts +1 -0
@@ -0,0 +1,158 @@
1
+ import { css } from '@emotion/react';
2
+ import { StyleProps, ThemeProp } from '@tecsinapse/react-core';
3
+ import styled from '@emotion/styled';
4
+ import { ComputedType, Position } from './Tooltip';
5
+
6
+ type InjectedProps = { computed?: ComputedType; position?: Position };
7
+
8
+ /** Bottom/Top commons */
9
+ const bottomOrTopStylesCommon = (width: number, position) =>
10
+ ['top', 'bottom'].includes(position as Position) &&
11
+ css`
12
+ left: 50%;
13
+ margin-left: -${width / 2}px;
14
+ `;
15
+
16
+ const bottomOrTopArrowCommon = (position?: Position) =>
17
+ ['top', 'bottom'].includes(position as Position) &&
18
+ css`
19
+ left: 50%;
20
+ margin-left: -5px;
21
+ `;
22
+
23
+ /** Top */
24
+ const topStyles = (theme: ThemeProp, position?: Position) =>
25
+ position === 'top' &&
26
+ css`
27
+ bottom: 100%;
28
+ margin-bottom: ${theme.spacing.centi};
29
+ transform: translateY(10%);
30
+ `;
31
+
32
+ const topArrow = (theme: ThemeProp, position?: Position) =>
33
+ position === 'top' &&
34
+ css`
35
+ top: 100%;
36
+ border-color: ${theme.color.secondary.xdark} transparent transparent
37
+ transparent;
38
+ `;
39
+
40
+ /** Bottom */
41
+ const bottomStyles = (theme: ThemeProp, position?: Position) =>
42
+ position === 'bottom' &&
43
+ css`
44
+ top: 100%;
45
+ margin-top: ${theme.spacing.centi};
46
+ transform: translateY(-10%);
47
+ `;
48
+
49
+ const bottomArrow = (theme: ThemeProp, position?: Position) =>
50
+ position === 'bottom' &&
51
+ css`
52
+ bottom: 100%;
53
+ border-color: transparent transparent ${theme.color.secondary.xdark}
54
+ transparent;
55
+ `;
56
+
57
+ /** Bottom/Top commons */
58
+ const leftAndRightCommonStyles = (height: number, position?: Position) =>
59
+ ['right', 'left'].includes(position as Position) &&
60
+ css`
61
+ top: 50%;
62
+ margin-top: -${height / 2}px;
63
+ `;
64
+
65
+ const leftOrRightArrowCommon = (position?: Position) =>
66
+ ['right', 'left'].includes(position as Position) &&
67
+ css`
68
+ top: 50%;
69
+ margin-top: -5px;
70
+ `;
71
+
72
+ /** Left */
73
+ const leftStyles = (theme: ThemeProp, position?: Position) =>
74
+ position === 'left' &&
75
+ css`
76
+ right: 100%;
77
+ margin-right: ${theme.spacing.centi};
78
+ transform: translateX(10%);
79
+ `;
80
+
81
+ const leftArrow = (theme: ThemeProp, position?: Position) =>
82
+ position === 'left' &&
83
+ css`
84
+ left: 100%;
85
+ border-color: transparent transparent transparent
86
+ ${theme.color.secondary.xdark};
87
+ `;
88
+
89
+ /** Right */
90
+ const rightStyles = (theme: ThemeProp, position?: Position) =>
91
+ position === 'right' &&
92
+ css`
93
+ left: 100%;
94
+ margin-left: ${theme.spacing.centi};
95
+ transform: translateX(-10%);
96
+ `;
97
+
98
+ const rightArrow = (theme: ThemeProp, position?: Position) =>
99
+ position === 'right' &&
100
+ css`
101
+ right: 100%;
102
+ border-color: transparent ${theme.color.secondary.xdark} transparent
103
+ transparent;
104
+ `;
105
+
106
+ export const TooltipSpan = styled('span')<Partial<StyleProps> & InjectedProps>(
107
+ ({ theme, computed, position }) => {
108
+ const { width = 0, height = 0 } = computed || {};
109
+ return css`
110
+ position: absolute;
111
+ padding: ${theme.spacing.micro} ${theme.spacing.centi};
112
+ border-radius: ${theme.borderRadius.mili};
113
+ opacity: 0;
114
+ visibility: hidden;
115
+ transition: opacity 0.3s, visibility 0.3s, transform 0.3s;
116
+ background-color: ${theme.color.secondary.xdark};
117
+ z-index: ${theme.zIndex.absolute};
118
+
119
+ ${bottomOrTopStylesCommon(width, position)}
120
+ ${bottomStyles(theme, position)}
121
+ ${topStyles(theme, position)}
122
+
123
+ ${leftAndRightCommonStyles(height, position)}
124
+ ${leftStyles(theme, position)}
125
+ ${rightStyles(theme, position)}
126
+
127
+ &::after {
128
+ content: '';
129
+ position: absolute;
130
+ border-style: solid;
131
+ border-width: 5px;
132
+
133
+ ${bottomOrTopArrowCommon(position)}
134
+ ${bottomArrow(theme, position)}
135
+ ${topArrow(theme, position)}
136
+
137
+ ${leftOrRightArrowCommon(position)}
138
+ ${leftArrow(theme, position)}
139
+ ${rightArrow(theme, position)}
140
+ }
141
+ `;
142
+ }
143
+ );
144
+
145
+ export const Container = styled('div')<{ position?: Position }>`
146
+ position: relative;
147
+ &:hover {
148
+ & > span {
149
+ opacity: 1;
150
+ visibility: visible;
151
+
152
+ transform: ${({ position }) =>
153
+ position === 'left' || position === 'right'
154
+ ? 'translateX(0%)'
155
+ : 'translateY(0%)'};
156
+ }
157
+ }
158
+ `;
@@ -1,5 +1,5 @@
1
1
  import styled from '@emotion/styled';
2
- import { hex2rgba, StyleProps } from '@tecsinapse/react-core';
2
+ import { StyleProps } from '@tecsinapse/react-core';
3
3
  import { DrawerProps } from './Drawer';
4
4
  import { css } from '@emotion/react';
5
5
 
@@ -10,7 +10,7 @@ export default {
10
10
  };
11
11
 
12
12
  const Template: Story<InputPasswordWebProps> = args => {
13
- const [value, setValue] = useState<string>();
13
+ const [value, setValue] = useState<string>('');
14
14
 
15
15
  const onChange = text => {
16
16
  setValue(text);
@@ -4,27 +4,29 @@ import { Input, InputWebProps } from '../../atoms/Input';
4
4
 
5
5
  export type InputPasswordWebProps = InputWebProps;
6
6
 
7
- const InputPassword: FC<InputPasswordWebProps> = ({
8
- rightComponent,
9
- ...rest
10
- }) => {
11
- const [revealed, setRevealed] = useState(false);
12
- return (
13
- <Input
14
- {...rest}
15
- secureTextEntry={!revealed}
16
- rightComponent={
17
- <>
18
- <InputPasswordIcon
19
- onChangeState={setRevealed}
20
- revealed={revealed}
21
- effect="none"
22
- />
23
- {rightComponent}
24
- </>
25
- }
26
- />
27
- );
28
- };
7
+ const InputPassword: FC<InputPasswordWebProps> = React.forwardRef(
8
+ ({ rightComponent, ...rest }, ref) => {
9
+ const [revealed, setRevealed] = useState(false);
10
+ return (
11
+ <Input
12
+ {...rest}
13
+ ref={ref}
14
+ secureTextEntry={!revealed}
15
+ rightComponent={
16
+ <>
17
+ <InputPasswordIcon
18
+ onChangeState={setRevealed}
19
+ revealed={revealed}
20
+ effect="none"
21
+ />
22
+ {rightComponent}
23
+ </>
24
+ }
25
+ />
26
+ );
27
+ }
28
+ );
29
+
30
+ InputPassword.displayName = 'InputPassword';
29
31
 
30
32
  export default InputPassword;
@@ -50,7 +50,7 @@ const Menubar: React.FC<MenubarProps> = ({
50
50
  const [input, setInput] = useDebouncedState<string>('', setSearch);
51
51
  const [open, setOpen] = React.useState<boolean>(false);
52
52
  const menuRef = useRef<HTMLDivElement | null>(null);
53
- useClickAwayListener(menuRef, setOpen);
53
+ useClickAwayListener(menuRef, setOpen, 'mouseup');
54
54
 
55
55
  const toggleOpen = React.useCallback(() => setOpen(state => !state), [
56
56
  setOpen,
@@ -1,11 +1,5 @@
1
1
  import React from 'react';
2
- import {
3
- Checkbox,
4
- Text,
5
- Icon,
6
- useDebouncedState,
7
- } from '@tecsinapse/react-core';
8
- import { Input } from '../../../atoms/Input';
2
+ import { Checkbox, Text, useDebouncedState } from '@tecsinapse/react-core';
9
3
  import { ItemSelect } from '../SelectItem';
10
4
  import { SelectProps } from '../Select';
11
5
  import {
@@ -15,7 +9,11 @@ import {
15
9
  StyledContainerTextLabel,
16
10
  StyledSpan,
17
11
  OptionsContainer,
12
+ PaddedContainer,
18
13
  } from './styled';
14
+ import { SearchInput } from './components';
15
+
16
+ const fullWidth = { width: '100%' };
19
17
 
20
18
  const Dropdown = <Data, Type extends 'single' | 'multi'>({
21
19
  options,
@@ -29,24 +27,41 @@ const Dropdown = <Data, Type extends 'single' | 'multi'>({
29
27
  setDropDownVisible,
30
28
  style,
31
29
  anchor,
30
+ selectAllLabel,
31
+ searchBarPlaceholder,
32
32
  }: SelectProps<Data, Type> & {
33
33
  setDropDownVisible: (t: boolean) => void;
34
34
  }): JSX.Element => {
35
35
  const [searchArg, setSearchArg] = useDebouncedState<string>('', onSearch);
36
- const lengthOptions = options.length;
36
+ const lengthOptions = React.useMemo(() => options.length, [options]);
37
37
 
38
38
  const [checkedAll, setCheckedAll] = React.useState<boolean>(
39
39
  type === 'multi' && (value as Data[])?.length === lengthOptions
40
40
  );
41
41
 
42
- const onClickCheckAll = () => {
42
+ React.useEffect(() => {
43
+ if (type === 'multi') {
44
+ lengthOptions === (value as Data[])?.length
45
+ ? setCheckedAll(true)
46
+ : setCheckedAll(false);
47
+ }
48
+ }, [value, type, lengthOptions]);
49
+
50
+ const onClickCheckAll = React.useCallback(() => {
43
51
  const items = options.map(option => option);
44
- setCheckedAll(!checkedAll);
45
- const aux = !checkedAll;
52
+ let aux;
53
+ setCheckedAll(prev => {
54
+ aux = !prev;
55
+ return !prev;
56
+ });
46
57
  type OnSelectArg = Parameters<typeof onSelect>[0];
47
58
  const auxArray: Data[] = [];
48
59
  !aux ? onSelect(auxArray as OnSelectArg) : onSelect(items as OnSelectArg);
49
- };
60
+ }, [options, setCheckedAll, onSelect]);
61
+
62
+ const onChange = React.useCallback(text => setSearchArg(text), [
63
+ setSearchArg,
64
+ ]);
50
65
 
51
66
  return (
52
67
  <StyledContainerDropdown
@@ -61,35 +76,37 @@ const Dropdown = <Data, Type extends 'single' | 'multi'>({
61
76
  <Checkbox checked={checkedAll} onChange={onClickCheckAll} />
62
77
  {!hideSearchBar ? (
63
78
  <SearchBarContainer>
64
- <Input
65
- style={{ width: '100%' }}
66
- placeholder="Busque a opção desejada"
67
- value={searchArg}
68
- leftComponent={
69
- <Icon
70
- name="magnify"
71
- type="material-community"
72
- size="centi"
73
- style={{ marginHorizontal: 12 }}
74
- />
75
- }
76
- onChange={text => setSearchArg(text)}
79
+ <SearchInput
80
+ searchArg={searchArg}
81
+ onChange={onChange}
82
+ fullWidth={fullWidth}
83
+ placeholder={searchBarPlaceholder}
77
84
  />
78
85
  </SearchBarContainer>
79
86
  ) : (
80
87
  <StyledContainerTextLabel>
81
88
  <Text fontWeight="bold">
82
- <StyledSpan>Selecionar todos</StyledSpan>
89
+ <StyledSpan>{selectAllLabel}</StyledSpan>
83
90
  </Text>
84
91
  </StyledContainerTextLabel>
85
92
  )}
86
93
  </StyledContainerCheckAll>
87
94
  )}
95
+ {type === 'single' && !hideSearchBar && (
96
+ <PaddedContainer>
97
+ <SearchInput
98
+ searchArg={searchArg}
99
+ onChange={onChange}
100
+ fullWidth={fullWidth}
101
+ placeholder={searchBarPlaceholder}
102
+ />
103
+ </PaddedContainer>
104
+ )}
88
105
  <OptionsContainer lengthOptions={options.length}>
89
106
  {options.map((item, index) => (
90
107
  <ItemSelect
91
108
  type={type}
92
- key={index}
109
+ key={keyExtractor(item)}
93
110
  item={item}
94
111
  onSelect={onSelect}
95
112
  value={value}
@@ -99,7 +116,7 @@ const Dropdown = <Data, Type extends 'single' | 'multi'>({
99
116
  setDropDownVisible={setDropDownVisible}
100
117
  checkedAll={checkedAll}
101
118
  setCheckedAll={setCheckedAll}
102
- lenghtOptions={options.length}
119
+ lenghtOptions={lengthOptions}
103
120
  />
104
121
  ))}
105
122
  </OptionsContainer>
@@ -0,0 +1,26 @@
1
+ import React from 'react';
2
+ import { Icon } from '@tecsinapse/react-core';
3
+ import { Input } from '../../../../atoms/Input';
4
+
5
+ const InputIcon = (
6
+ <Icon
7
+ name="magnify"
8
+ type="material-community"
9
+ size="centi"
10
+ style={{ marginHorizontal: 12 }}
11
+ />
12
+ );
13
+
14
+ const SearchInput = ({ fullWidth, searchArg, onChange, placeholder }) => {
15
+ return (
16
+ <Input
17
+ style={fullWidth}
18
+ placeholder={placeholder}
19
+ value={searchArg}
20
+ leftComponent={InputIcon}
21
+ onChange={onChange}
22
+ />
23
+ );
24
+ };
25
+
26
+ export default React.memo(SearchInput);
@@ -0,0 +1 @@
1
+ export { default as SearchInput } from './SearchInput';
@@ -4,7 +4,8 @@ import { SelectProps } from '../Select';
4
4
  import { css } from '@emotion/react';
5
5
 
6
6
  type InjectedProps = Partial<
7
- StyleProps & SelectProps<any, any> & { lengthOptions: number }
7
+ StyleProps &
8
+ SelectProps<unknown, 'single' | 'multi'> & { lengthOptions: number }
8
9
  >;
9
10
 
10
11
  const anchorBottom = ({
@@ -38,7 +39,7 @@ export const StyledContainerDropdown = styled('div')<InjectedProps>`
38
39
  padding-top: ${({
39
40
  theme,
40
41
  hideSearchBar,
41
- }: StyleProps & Partial<SelectProps<any, any>>) =>
42
+ }: StyleProps & Partial<SelectProps<unknown, 'single' | 'multi'>>) =>
42
43
  !hideSearchBar ? `${theme.spacing.deca}` : '0px'};
43
44
  padding-bottom: ${({ theme }: StyleProps) => theme.spacing.mili};
44
45
  z-index: ${({ theme }: StyleProps) => theme.zIndex.select};
@@ -68,8 +69,13 @@ export const SearchBarContainer = styled('div')<Partial<StyleProps>>`
68
69
  width: 100%;
69
70
  `;
70
71
 
71
- export const StyledContainerCheckAll = styled('div')<Partial<StyleProps>>`
72
+ export const PaddedContainer = styled('div')<Partial<StyleProps>>`
72
73
  padding: ${({ theme }) => `${theme.spacing.mili} ${theme.spacing.deca}`};
74
+ `;
75
+
76
+ export const StyledContainerCheckAll = styled(PaddedContainer)<
77
+ Partial<StyleProps>
78
+ >`
73
79
  flex-direction: row;
74
80
  display: flex;
75
81
  justify-content: flex-start;
@@ -84,7 +90,7 @@ export const StyledContainerCheckAll = styled('div')<Partial<StyleProps>>`
84
90
  `;
85
91
 
86
92
  export const StyledSpan = styled('span')<Partial<StyleProps>>`
87
- color: ${({ theme }) => theme.color.primary.medium};
93
+ color: ${({ theme }) => theme.font.color.dark};
88
94
  padding: ${({ theme }) => `${theme.spacing.mili} 0px`};
89
95
  `;
90
96
 
@@ -15,21 +15,33 @@ type Option = {
15
15
  };
16
16
 
17
17
  const OPTIONS_EXAMPLE: Option[] = [
18
- { label: 'Label 1', value: 'value1' },
19
- { label: 'Label 2', value: 'value2' },
20
- { label: 'Label 3', value: 'value3' },
21
- { label: 'Label 4', value: 'value4' },
22
- { label: 'Label 5', value: 'value5' },
23
- { label: 'Label 6', value: 'value6' },
18
+ { label: 'New York', value: 'value1' },
19
+ { label: 'São Paulo', value: 'value2' },
20
+ { label: 'Lisbon', value: 'value3' },
21
+ { label: 'Moscow', value: 'value4' },
22
+ { label: 'Sidney', value: 'value5' },
23
+ { label: 'Rio de Janeiro', value: 'value6' },
24
24
  ];
25
25
 
26
- const TemplateSingle: Story<SelectProps<Option, 'single'>> = args => {
26
+ const TemplateSingle: Story<SelectProps<Option, 'single'>> = ({
27
+ options: _options,
28
+ ...args
29
+ }) => {
27
30
  const [singleValue, setSingleValue] = useState(undefined);
31
+ const [options, setOptions] = useState(_options);
28
32
 
29
- const handleSelectSingleValue = key => setSingleValue(key);
33
+ const handleSelectSingleValue = React.useCallback(
34
+ key => setSingleValue(key),
35
+ [setSingleValue]
36
+ );
37
+
38
+ const labelExtractor = React.useCallback(item => item.label, []);
39
+ const keyExtractor = React.useCallback(item => String(item.value), []);
30
40
 
31
41
  const handleSearch = React.useCallback((searchArg: string) => {
32
- console.log(searchArg);
42
+ setOptions(
43
+ _options.filter(item => new RegExp(searchArg, 'ig').test(item.label))
44
+ );
33
45
  }, []);
34
46
 
35
47
  return (
@@ -37,11 +49,12 @@ const TemplateSingle: Story<SelectProps<Option, 'single'>> = args => {
37
49
  <ContainerSelect>
38
50
  <Select
39
51
  {...args}
52
+ options={options}
40
53
  value={singleValue}
41
54
  type="single"
42
55
  onSelect={handleSelectSingleValue}
43
- labelExtractor={item => item.label}
44
- keyExtractor={item => String(item.value)}
56
+ labelExtractor={labelExtractor}
57
+ keyExtractor={keyExtractor}
45
58
  onSearch={handleSearch}
46
59
  />
47
60
  </ContainerSelect>
@@ -58,13 +71,25 @@ Single.args = {
58
71
  hideSearchBar: false,
59
72
  };
60
73
 
61
- const TemplateMulti: Story<SelectProps<Option, 'multi'>> = args => {
74
+ const TemplateMulti: Story<SelectProps<Option, 'multi'>> = ({
75
+ options: _options,
76
+ ...args
77
+ }) => {
62
78
  const [multiValue, setMultiValue] = useState([]);
79
+ const [options, setOptions] = useState(_options);
80
+
81
+ const handleSelectMultipleValues = React.useCallback(
82
+ keys => setMultiValue(keys),
83
+ [setMultiValue]
84
+ );
63
85
 
64
- const handleSelectMultipleValues = keys => setMultiValue(keys);
86
+ const labelExtractor = React.useCallback(item => item.label, []);
87
+ const keyExtractor = React.useCallback(item => String(item.value), []);
65
88
 
66
89
  const handleSearch = React.useCallback((searchArg: string) => {
67
- console.log(searchArg);
90
+ setOptions(
91
+ _options.filter(item => new RegExp(searchArg, 'ig').test(item.label))
92
+ );
68
93
  }, []);
69
94
 
70
95
  return (
@@ -72,11 +97,12 @@ const TemplateMulti: Story<SelectProps<Option, 'multi'>> = args => {
72
97
  <ContainerSelect>
73
98
  <Select
74
99
  {...args}
100
+ options={options}
75
101
  value={multiValue}
76
102
  type="multi"
77
103
  onSelect={handleSelectMultipleValues}
78
- labelExtractor={item => item.label}
79
- keyExtractor={item => String(item.value)}
104
+ labelExtractor={labelExtractor}
105
+ keyExtractor={keyExtractor}
80
106
  onSearch={handleSearch}
81
107
  />
82
108
  </ContainerSelect>
@@ -1,12 +1,15 @@
1
1
  import React from 'react';
2
2
  import {
3
- Icon,
4
3
  PressableInputContainer,
5
4
  Text,
6
5
  TextProps,
7
6
  } from '@tecsinapse/react-core';
8
7
  import { useClickAwayListener } from '../../../hooks';
9
- import { StyledContainer, StyledInputContainer } from './styled';
8
+ import {
9
+ RightComponent,
10
+ StyledContainer,
11
+ StyledInputContainer,
12
+ } from './styled';
10
13
  import { Dropdown } from './Dropdown';
11
14
  import { getDisplayValue } from './functions';
12
15
  import { Transition } from 'react-transition-group';
@@ -26,12 +29,14 @@ export interface SelectProps<Data, Type extends 'single' | 'multi'>
26
29
  onSearch?: (searchArg: string) => void | never;
27
30
  searchBarPlaceholder?: string;
28
31
  hideSearchBar?: boolean;
32
+ selectAllLabel?: string;
29
33
  disabled?: boolean;
30
34
  label?: string;
31
35
  anchor?: 'top' | 'bottom';
32
36
  displayTextProps?: TextProps;
33
37
  }
34
38
 
39
+ /** NOTE: For better performance, you should memoize options and handlers */
35
40
  export const Select = <Data, Type extends 'single' | 'multi'>({
36
41
  value,
37
42
  options,
@@ -41,12 +46,13 @@ export const Select = <Data, Type extends 'single' | 'multi'>({
41
46
  labelExtractor,
42
47
  placeholder,
43
48
  onSearch,
44
- searchBarPlaceholder,
49
+ searchBarPlaceholder = 'Busque a opção desejada',
45
50
  hideSearchBar = true,
46
51
  label,
47
52
  disabled = false,
48
53
  anchor = 'bottom',
49
54
  displayTextProps,
55
+ selectAllLabel = 'Selecionar todos',
50
56
  ...rest
51
57
  }: SelectProps<Data, Type>): JSX.Element => {
52
58
  const [dropDownVisible, setDropDownVisible] = React.useState<boolean>(false);
@@ -62,21 +68,18 @@ export const Select = <Data, Type extends 'single' | 'multi'>({
62
68
  labelExtractor
63
69
  );
64
70
 
71
+ const onPress = React.useCallback(() => setDropDownVisible(prev => !prev), [
72
+ setDropDownVisible,
73
+ ]);
74
+
65
75
  return (
66
76
  <StyledContainer ref={refDropDown} {...rest}>
67
77
  <StyledInputContainer>
68
78
  <PressableInputContainer
69
79
  label={label}
70
- onPress={() => setDropDownVisible(!dropDownVisible)}
80
+ onPress={onPress}
71
81
  disabled={disabled}
72
- rightComponent={
73
- <Icon
74
- name="chevron-down"
75
- type="material-community"
76
- size="centi"
77
- style={{ marginRight: 12 }}
78
- />
79
- }
82
+ rightComponent={RightComponent}
80
83
  >
81
84
  <Text {...displayTextProps} ellipsizeMode="tail" numberOfLines={1}>
82
85
  {displayValue}
@@ -98,6 +101,7 @@ export const Select = <Data, Type extends 'single' | 'multi'>({
98
101
  style={{ ...defaultStyles, ...transition[anchor][state] }}
99
102
  setDropDownVisible={setDropDownVisible}
100
103
  anchor={anchor}
104
+ selectAllLabel={selectAllLabel}
101
105
  />
102
106
  )}
103
107
  </Transition>