@bitrise/bitkit 13.318.0 → 13.320.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.
- package/package.json +19 -19
- package/src/Components/DatePicker/DatePicker.tsx +59 -54
- package/src/Components/Dialog/DialogProps.ts +1 -2
- package/src/Components/Drawer/Drawer.tsx +23 -7
- package/src/Components/ExpandableCard/ExpandableCard.tsx +23 -24
- package/src/Components/Filter/Desktop/Filter.tsx +92 -0
- package/src/Components/Filter/Desktop/FilterAdd/FilterAdd.tsx +89 -0
- package/src/Components/Filter/{FilterDate → Desktop/FilterDate}/FilterDate.tsx +21 -10
- package/src/Components/Filter/{FilterForm → Desktop}/FilterForm.tsx +24 -115
- package/src/Components/Filter/{FilterItem → Desktop}/FilterItem.tsx +1 -1
- package/src/Components/Filter/{FilterSwitch → Desktop/FilterSwitch}/FilterSwitch.theme.ts +1 -1
- package/src/Components/Filter/{FilterSwitch → Desktop/FilterSwitch}/FilterSwitch.tsx +4 -4
- package/src/Components/Filter/{FilterSwitchAdapter → Desktop/FilterSwitch}/FilterSwitchAdapter.tsx +5 -5
- package/src/Components/Filter/Filter.storyData.ts +14 -1
- package/src/Components/Filter/Filter.tsx +16 -106
- package/src/Components/Filter/Filter.types.ts +34 -1
- package/src/Components/Filter/Filter.utils.ts +13 -0
- package/src/Components/Filter/Mobile/DateSelectOption.tsx +53 -0
- package/src/Components/Filter/Mobile/Filter.tsx +57 -0
- package/src/Components/Filter/Mobile/FilterAdd.tsx +97 -0
- package/src/Components/Filter/Mobile/FilterDrawer.tsx +96 -0
- package/src/Components/Filter/Mobile/FilterForm.tsx +236 -0
- package/src/Components/Filter/Mobile/FilterItem.tsx +95 -0
- package/src/Components/Filter/Mobile/MultiSelectOptions.tsx +69 -0
- package/src/Components/Filter/Mobile/SingleSelectOptions.tsx +136 -0
- package/src/Components/Filter/hooks/useFilterAdd.ts +68 -0
- package/src/Components/Filter/hooks/useFilterForm.ts +131 -0
- package/src/Components/Filter/hooks/useIsScrollable.ts +35 -0
- package/src/Components/Filter/hooks/useListBox.ts +66 -0
- package/src/Components/Form/Checkbox/Checkbox.tsx +4 -2
- package/src/Components/Form/Input/Input.theme.ts +27 -11
- package/src/Components/Form/Input/Input.tsx +4 -1
- package/src/Components/Form/Radio/Radio.tsx +4 -2
- package/src/Components/SearchInput/SearchInput.tsx +3 -2
- package/src/Components/components.theme.ts +1 -1
- package/src/index.ts +3 -4
- package/src/Components/Filter/FilterAdd/FilterAdd.tsx +0 -111
- /package/src/Components/Filter/{FilterSearch → Desktop}/FilterSearch.tsx +0 -0
- /package/src/Components/Filter/{FilterSwitch → Desktop/FilterSwitch}/FilterSwitchGroup.tsx +0 -0
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
import { ReactNode } from 'react';
|
|
2
|
+
import Icon from '../../Icon/Icon';
|
|
3
|
+
import Box from '../../Box/Box';
|
|
4
|
+
import Text from '../../Text/Text';
|
|
5
|
+
import { getOptionLabel } from '../Filter.utils';
|
|
6
|
+
import { FilterOptionsMap } from '../Filter.types';
|
|
7
|
+
import { MAX_ITEMS } from '../hooks/useFilterForm';
|
|
8
|
+
import useListBox from '../hooks/useListBox';
|
|
9
|
+
|
|
10
|
+
type SingleSelectOptionsProps = {
|
|
11
|
+
currentOptionMap?: FilterOptionsMap;
|
|
12
|
+
emptyText?: string;
|
|
13
|
+
hasNotFilteredOption: boolean;
|
|
14
|
+
isLoading: boolean;
|
|
15
|
+
items: string[];
|
|
16
|
+
onChange: (option: string) => void;
|
|
17
|
+
selectedItems: string[];
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
const Option = ({
|
|
21
|
+
onChange,
|
|
22
|
+
index,
|
|
23
|
+
isActive,
|
|
24
|
+
isSelected,
|
|
25
|
+
option,
|
|
26
|
+
children,
|
|
27
|
+
}: Pick<SingleSelectOptionsProps, 'onChange'> & {
|
|
28
|
+
index: number;
|
|
29
|
+
isActive?: boolean;
|
|
30
|
+
isSelected: boolean;
|
|
31
|
+
option: string;
|
|
32
|
+
children: ReactNode;
|
|
33
|
+
}) => {
|
|
34
|
+
const getBackgroundColor = () => {
|
|
35
|
+
if (isActive && isSelected) return 'background/selected-hover';
|
|
36
|
+
if (isSelected) return 'background/selected';
|
|
37
|
+
if (isActive) return 'background/hover';
|
|
38
|
+
return undefined;
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
const getHoverBackgroundColor = () => {
|
|
42
|
+
if (isSelected) return 'background/selected-hover';
|
|
43
|
+
return 'background/hover';
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
return (
|
|
47
|
+
<Box
|
|
48
|
+
display="flex"
|
|
49
|
+
alignItems="center"
|
|
50
|
+
backgroundColor={getBackgroundColor()}
|
|
51
|
+
gap="16"
|
|
52
|
+
id={`option-${index}`}
|
|
53
|
+
onClick={(e) => {
|
|
54
|
+
e.stopPropagation();
|
|
55
|
+
onChange(option);
|
|
56
|
+
}}
|
|
57
|
+
paddingBlock="12"
|
|
58
|
+
paddingInlineStart={isSelected ? '16' : '56'}
|
|
59
|
+
paddingInlineEnd="24"
|
|
60
|
+
cursor="pointer"
|
|
61
|
+
role="option"
|
|
62
|
+
tabIndex={-1}
|
|
63
|
+
sx={{
|
|
64
|
+
backgroundColor: getBackgroundColor(),
|
|
65
|
+
'&:hover': {
|
|
66
|
+
backgroundColor: getHoverBackgroundColor(),
|
|
67
|
+
},
|
|
68
|
+
'&:active': {
|
|
69
|
+
backgroundColor: 'background/active',
|
|
70
|
+
},
|
|
71
|
+
}}
|
|
72
|
+
>
|
|
73
|
+
{children}
|
|
74
|
+
</Box>
|
|
75
|
+
);
|
|
76
|
+
};
|
|
77
|
+
|
|
78
|
+
const SingleSelectOptions = ({
|
|
79
|
+
currentOptionMap,
|
|
80
|
+
emptyText,
|
|
81
|
+
hasNotFilteredOption,
|
|
82
|
+
isLoading,
|
|
83
|
+
items,
|
|
84
|
+
onChange,
|
|
85
|
+
selectedItems,
|
|
86
|
+
}: SingleSelectOptionsProps) => {
|
|
87
|
+
const { activeIndex, handleKeyDown, handleFocus, handleBlur, handleMouseDown, handleMouseMove } = useListBox({
|
|
88
|
+
items: hasNotFilteredOption ? [''].concat(items) : items,
|
|
89
|
+
hasNotFilteredOption,
|
|
90
|
+
onChange,
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
if (isLoading) {
|
|
94
|
+
return null;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
return (
|
|
98
|
+
<Box
|
|
99
|
+
aria-label="Filter options"
|
|
100
|
+
onKeyDown={handleKeyDown}
|
|
101
|
+
onFocus={handleFocus}
|
|
102
|
+
onBlur={handleBlur}
|
|
103
|
+
onMouseDown={handleMouseDown}
|
|
104
|
+
onMouseMove={handleMouseMove}
|
|
105
|
+
outline="none"
|
|
106
|
+
role="listbox"
|
|
107
|
+
tabIndex={0}
|
|
108
|
+
_focusVisible={{
|
|
109
|
+
boxShadow: 'none',
|
|
110
|
+
outline: 'none',
|
|
111
|
+
}}
|
|
112
|
+
>
|
|
113
|
+
{items.length ? (
|
|
114
|
+
items?.slice(0, MAX_ITEMS).map((option, index) => {
|
|
115
|
+
const isSelected = selectedItems.includes(option);
|
|
116
|
+
return (
|
|
117
|
+
<Option
|
|
118
|
+
index={index}
|
|
119
|
+
isActive={activeIndex === index}
|
|
120
|
+
isSelected={isSelected}
|
|
121
|
+
onChange={onChange}
|
|
122
|
+
option={option}
|
|
123
|
+
>
|
|
124
|
+
{isSelected && <Icon name="Check" color="icon/interactive" />}
|
|
125
|
+
{getOptionLabel(option, currentOptionMap)}
|
|
126
|
+
</Option>
|
|
127
|
+
);
|
|
128
|
+
})
|
|
129
|
+
) : (
|
|
130
|
+
<Text paddingInline={16}>{emptyText}</Text>
|
|
131
|
+
)}
|
|
132
|
+
</Box>
|
|
133
|
+
);
|
|
134
|
+
};
|
|
135
|
+
|
|
136
|
+
export default SingleSelectOptions;
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { useState } from 'react';
|
|
2
|
+
import { useDisclosure } from 'chakra-ui-2--react';
|
|
3
|
+
import { useFilterContext } from '../Filter.context';
|
|
4
|
+
import { hasAllDependencies } from '../Filter.utils';
|
|
5
|
+
import { FilterValue } from '../Filter.types';
|
|
6
|
+
|
|
7
|
+
type UseFilterAddProps = {
|
|
8
|
+
isMobile?: boolean;
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
const useFilterAdd = ({ isMobile }: UseFilterAddProps) => {
|
|
12
|
+
const { isOpen: isMenuOpen, onClose: closeMenu, onOpen: openMenu } = useDisclosure();
|
|
13
|
+
|
|
14
|
+
const { data, filtersDependOn, onFilterChange, setPopoverOpen, state } = useFilterContext();
|
|
15
|
+
|
|
16
|
+
const [selectedCategory, setSelectedCategory] = useState<string | undefined>();
|
|
17
|
+
|
|
18
|
+
const onCategorySelect = (category: string) => {
|
|
19
|
+
setSelectedCategory(category);
|
|
20
|
+
if (isMobile) {
|
|
21
|
+
closeMenu();
|
|
22
|
+
}
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
const onOpen = () => {
|
|
26
|
+
openMenu();
|
|
27
|
+
|
|
28
|
+
if (!isMobile) {
|
|
29
|
+
setPopoverOpen(true);
|
|
30
|
+
setSelectedCategory(undefined);
|
|
31
|
+
}
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
const onClose = () => {
|
|
35
|
+
setPopoverOpen(false);
|
|
36
|
+
closeMenu();
|
|
37
|
+
setSelectedCategory(undefined);
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
const onChange = (category: string, value: FilterValue) => {
|
|
41
|
+
onClose();
|
|
42
|
+
onFilterChange(category, value);
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
const stateKeys = Object.keys(state);
|
|
46
|
+
|
|
47
|
+
const categoryList = Object.keys(data).filter((category) => {
|
|
48
|
+
return !stateKeys.includes(category) && data[category].type === 'tag';
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
const isDisabled = !hasAllDependencies(stateKeys, filtersDependOn) || categoryList.length === 0;
|
|
52
|
+
|
|
53
|
+
return {
|
|
54
|
+
categoryList,
|
|
55
|
+
closeMenu,
|
|
56
|
+
isDisabled,
|
|
57
|
+
isMenuOpen,
|
|
58
|
+
onCategorySelect,
|
|
59
|
+
onChange,
|
|
60
|
+
onClose,
|
|
61
|
+
onOpen,
|
|
62
|
+
selectedCategory,
|
|
63
|
+
setSelectedCategory,
|
|
64
|
+
stateKeys,
|
|
65
|
+
};
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
export default useFilterAdd;
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
import { FormEvent, useEffect, useMemo, useState } from 'react';
|
|
2
|
+
import { isEqual, useDebounce } from '../../../utils/utils';
|
|
3
|
+
import { useFilterContext } from '../Filter.context';
|
|
4
|
+
import { FilterFormProps, FilterOptions, FilterOptionsMap, FilterValue } from '../Filter.types';
|
|
5
|
+
|
|
6
|
+
export const MAX_ITEMS = 100;
|
|
7
|
+
|
|
8
|
+
const useFilterForm = (props: Omit<FilterFormProps, 'onCancel'>) => {
|
|
9
|
+
const { category, onChange } = props;
|
|
10
|
+
|
|
11
|
+
const { data, state } = useFilterContext();
|
|
12
|
+
|
|
13
|
+
const categoryData = data[category] || {};
|
|
14
|
+
const { isPatternEnabled, preserveOptionOrder, isInitialLoading, onAsyncSearch, options, optionsMap } = categoryData;
|
|
15
|
+
|
|
16
|
+
const value = useMemo(() => state[category] || [], [category, state]);
|
|
17
|
+
|
|
18
|
+
const [selected, setSelected] = useState<FilterValue>(value);
|
|
19
|
+
|
|
20
|
+
useEffect(() => {
|
|
21
|
+
setSelected(value);
|
|
22
|
+
}, [value]);
|
|
23
|
+
|
|
24
|
+
const [mode, setMode] = useState<'manually' | 'pattern'>(
|
|
25
|
+
isPatternEnabled && value?.length && value[0].includes('*') ? 'pattern' : 'manually',
|
|
26
|
+
);
|
|
27
|
+
|
|
28
|
+
const [searchValue, setSearchValue] = useState<string>('');
|
|
29
|
+
const debouncedSearchValue = useDebounce<string>(searchValue, 1000);
|
|
30
|
+
|
|
31
|
+
const [isLoading, setLoading] = useState(Boolean(isInitialLoading));
|
|
32
|
+
const [foundOptions, setFoundOptions] = useState<FilterOptions>([]);
|
|
33
|
+
const [foundOptionsMap, setFoundOptionsMap] = useState<FilterOptionsMap>();
|
|
34
|
+
|
|
35
|
+
const isAsync = !!onAsyncSearch;
|
|
36
|
+
const withSearch = (options && options.length > 5) || isAsync;
|
|
37
|
+
|
|
38
|
+
const isSubmitDisabled =
|
|
39
|
+
isEqual(selected, value) || (mode === 'pattern' && !!selected[0] && !selected[0].includes('*'));
|
|
40
|
+
const filteredOptions = useMemo(() => {
|
|
41
|
+
if (options?.length) {
|
|
42
|
+
return options.filter((opt) => {
|
|
43
|
+
const optLabel = (optionsMap && optionsMap[opt]) || opt;
|
|
44
|
+
return optLabel.toLowerCase().includes(searchValue.toLowerCase());
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
return [];
|
|
48
|
+
}, [searchValue, options]);
|
|
49
|
+
|
|
50
|
+
const onSearchChange = (q: string) => {
|
|
51
|
+
setSearchValue(q);
|
|
52
|
+
if (isAsync) {
|
|
53
|
+
if (q.length > 0) {
|
|
54
|
+
setLoading(true);
|
|
55
|
+
} else {
|
|
56
|
+
setFoundOptions([]);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
const onSubmit = (e?: FormEvent<HTMLDivElement>) => {
|
|
62
|
+
e?.preventDefault();
|
|
63
|
+
const newSelected = selected[0] === '' ? [] : selected;
|
|
64
|
+
onChange(category, newSelected, value);
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
const onClearClick = () => {
|
|
68
|
+
setSelected([]);
|
|
69
|
+
onChange(category, [], value);
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
const getEmptyText = () => {
|
|
73
|
+
if (searchValue.length) {
|
|
74
|
+
return 'No result. Refine your search term.';
|
|
75
|
+
}
|
|
76
|
+
return '';
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
const getAsyncList = async () => {
|
|
80
|
+
if (onAsyncSearch) {
|
|
81
|
+
const response = await onAsyncSearch(category, searchValue);
|
|
82
|
+
setLoading(false);
|
|
83
|
+
setFoundOptions(response.options);
|
|
84
|
+
setFoundOptionsMap(response.optionsMap || optionsMap);
|
|
85
|
+
}
|
|
86
|
+
};
|
|
87
|
+
|
|
88
|
+
useEffect(() => {
|
|
89
|
+
setLoading(Boolean(isInitialLoading));
|
|
90
|
+
}, [isInitialLoading]);
|
|
91
|
+
|
|
92
|
+
useEffect(() => {
|
|
93
|
+
if (debouncedSearchValue.length > 0) {
|
|
94
|
+
getAsyncList();
|
|
95
|
+
} else {
|
|
96
|
+
setLoading(Boolean(isInitialLoading));
|
|
97
|
+
}
|
|
98
|
+
}, [debouncedSearchValue]);
|
|
99
|
+
|
|
100
|
+
const isEditMode = value.length !== 0;
|
|
101
|
+
|
|
102
|
+
const isAsyncSearch = isAsync && !!searchValue;
|
|
103
|
+
|
|
104
|
+
const items = isAsyncSearch
|
|
105
|
+
? Array.from(new Set(preserveOptionOrder ? [...foundOptions] : [...value, ...foundOptions]))
|
|
106
|
+
: Array.from(new Set(preserveOptionOrder ? [...filteredOptions] : [...value, ...filteredOptions]));
|
|
107
|
+
|
|
108
|
+
const currentOptionMap = isAsyncSearch ? foundOptionsMap : optionsMap;
|
|
109
|
+
|
|
110
|
+
return {
|
|
111
|
+
currentOptionMap,
|
|
112
|
+
getEmptyText,
|
|
113
|
+
isAsync,
|
|
114
|
+
isLoading,
|
|
115
|
+
isSubmitDisabled,
|
|
116
|
+
mode,
|
|
117
|
+
onClearClick,
|
|
118
|
+
onSearchChange,
|
|
119
|
+
onSubmit,
|
|
120
|
+
isEditMode,
|
|
121
|
+
items,
|
|
122
|
+
selected,
|
|
123
|
+
searchValue,
|
|
124
|
+
setMode,
|
|
125
|
+
setSelected,
|
|
126
|
+
value,
|
|
127
|
+
withSearch,
|
|
128
|
+
};
|
|
129
|
+
};
|
|
130
|
+
|
|
131
|
+
export default useFilterForm;
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { useState, useEffect } from 'react';
|
|
2
|
+
|
|
3
|
+
type UseIsScrollableProps = {
|
|
4
|
+
items: string[];
|
|
5
|
+
hasNotFilteredOption: boolean;
|
|
6
|
+
ref: React.RefObject<HTMLDivElement>;
|
|
7
|
+
};
|
|
8
|
+
|
|
9
|
+
const useIsScrollable = ({ items, hasNotFilteredOption, ref }: UseIsScrollableProps) => {
|
|
10
|
+
const [isScrollable, setIsScrollable] = useState(false);
|
|
11
|
+
|
|
12
|
+
useEffect(() => {
|
|
13
|
+
const checkScrollable = () => {
|
|
14
|
+
if (ref.current) {
|
|
15
|
+
const { scrollHeight, clientHeight } = ref.current;
|
|
16
|
+
setIsScrollable(scrollHeight > clientHeight);
|
|
17
|
+
}
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
checkScrollable();
|
|
21
|
+
|
|
22
|
+
const timer = setTimeout(checkScrollable, 100);
|
|
23
|
+
|
|
24
|
+
window.addEventListener('resize', checkScrollable);
|
|
25
|
+
|
|
26
|
+
return () => {
|
|
27
|
+
clearTimeout(timer);
|
|
28
|
+
window.removeEventListener('resize', checkScrollable);
|
|
29
|
+
};
|
|
30
|
+
}, [items, hasNotFilteredOption]);
|
|
31
|
+
|
|
32
|
+
return { isScrollable };
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
export default useIsScrollable;
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { useState, useRef } from 'react';
|
|
2
|
+
import { MAX_ITEMS } from './useFilterForm';
|
|
3
|
+
|
|
4
|
+
type UseListBoxProps = {
|
|
5
|
+
items: string[];
|
|
6
|
+
hasNotFilteredOption: boolean;
|
|
7
|
+
onChange: (option: string) => void;
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
const useListBox = ({ items, hasNotFilteredOption, onChange }: UseListBoxProps) => {
|
|
11
|
+
const [activeIndex, setActiveIndex] = useState(-1);
|
|
12
|
+
const allOptions = hasNotFilteredOption ? ['', ...items.slice(0, MAX_ITEMS)] : items.slice(0, MAX_ITEMS);
|
|
13
|
+
const mouseInteractionRef = useRef(false);
|
|
14
|
+
|
|
15
|
+
const handleKeyDown = (e: React.KeyboardEvent) => {
|
|
16
|
+
mouseInteractionRef.current = false;
|
|
17
|
+
switch (e.key) {
|
|
18
|
+
case 'ArrowDown':
|
|
19
|
+
e.preventDefault();
|
|
20
|
+
setActiveIndex((prev) => (prev < allOptions.length - 1 ? prev + 1 : 0));
|
|
21
|
+
break;
|
|
22
|
+
case 'ArrowUp':
|
|
23
|
+
e.preventDefault();
|
|
24
|
+
setActiveIndex((prev) => (prev > 0 ? prev - 1 : allOptions.length - 1));
|
|
25
|
+
break;
|
|
26
|
+
case 'Enter':
|
|
27
|
+
case ' ':
|
|
28
|
+
e.preventDefault();
|
|
29
|
+
if (activeIndex >= 0) {
|
|
30
|
+
onChange(allOptions[activeIndex]);
|
|
31
|
+
}
|
|
32
|
+
break;
|
|
33
|
+
}
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
const handleFocus = () => {
|
|
37
|
+
if (activeIndex === -1 && !mouseInteractionRef.current) {
|
|
38
|
+
setActiveIndex(0);
|
|
39
|
+
}
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
const handleBlur = () => {
|
|
43
|
+
setActiveIndex(-1);
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
const handleMouseDown = () => {
|
|
47
|
+
mouseInteractionRef.current = true;
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
const handleMouseMove = () => {
|
|
51
|
+
if (activeIndex !== -1) {
|
|
52
|
+
setActiveIndex(-1);
|
|
53
|
+
}
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
return {
|
|
57
|
+
activeIndex,
|
|
58
|
+
handleKeyDown,
|
|
59
|
+
handleFocus,
|
|
60
|
+
handleBlur,
|
|
61
|
+
handleMouseDown,
|
|
62
|
+
handleMouseMove,
|
|
63
|
+
};
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
export default useListBox;
|
|
@@ -15,8 +15,10 @@ type CheckboxInputProps = ChakraCheckboxProps['inputProps'] & {
|
|
|
15
15
|
'data-testid'?: string;
|
|
16
16
|
};
|
|
17
17
|
|
|
18
|
-
export interface CheckboxProps
|
|
19
|
-
|
|
18
|
+
export interface CheckboxProps extends Omit<
|
|
19
|
+
FormControlProps,
|
|
20
|
+
'icon' | 'iconColor' | 'iconSize' | 'inputProps' | 'value' | 'onChange'
|
|
21
|
+
> {
|
|
20
22
|
inputProps?: CheckboxInputProps;
|
|
21
23
|
helperText?: ReactNode;
|
|
22
24
|
errorText?: string;
|
|
@@ -14,12 +14,6 @@ const InputTheme = defineStyle({
|
|
|
14
14
|
background: 'background.disabled',
|
|
15
15
|
cursor: 'not-allowed',
|
|
16
16
|
},
|
|
17
|
-
_focus: {
|
|
18
|
-
boxShadow: 'formFocus',
|
|
19
|
-
},
|
|
20
|
-
_focusVisible: {
|
|
21
|
-
boxShadow: 'formFocus',
|
|
22
|
-
},
|
|
23
17
|
_hover: {
|
|
24
18
|
borderColor: 'border.hover',
|
|
25
19
|
},
|
|
@@ -41,12 +35,9 @@ const InputTheme = defineStyle({
|
|
|
41
35
|
},
|
|
42
36
|
appearance: 'none',
|
|
43
37
|
background: 'background.primary',
|
|
44
|
-
|
|
45
|
-
borderColor: 'border.regular',
|
|
38
|
+
|
|
46
39
|
borderRadius: '4',
|
|
47
|
-
|
|
48
|
-
outline: 0,
|
|
49
|
-
transition: '200ms',
|
|
40
|
+
|
|
50
41
|
width: '100%',
|
|
51
42
|
},
|
|
52
43
|
icon: {
|
|
@@ -75,6 +66,28 @@ const InputTheme = defineStyle({
|
|
|
75
66
|
position: 'relative',
|
|
76
67
|
},
|
|
77
68
|
},
|
|
69
|
+
variants: {
|
|
70
|
+
desktop: {
|
|
71
|
+
field: {
|
|
72
|
+
border: '1px solid',
|
|
73
|
+
borderColor: 'border.regular',
|
|
74
|
+
boxShadow: 'inner',
|
|
75
|
+
outline: 0,
|
|
76
|
+
transition: '200ms',
|
|
77
|
+
_focus: {
|
|
78
|
+
boxShadow: 'formFocus',
|
|
79
|
+
},
|
|
80
|
+
_focusVisible: {
|
|
81
|
+
boxShadow: 'formFocus',
|
|
82
|
+
},
|
|
83
|
+
},
|
|
84
|
+
},
|
|
85
|
+
mobile: {
|
|
86
|
+
field: {
|
|
87
|
+
boxShadow: 'none',
|
|
88
|
+
},
|
|
89
|
+
},
|
|
90
|
+
},
|
|
78
91
|
sizes: {
|
|
79
92
|
lg: {
|
|
80
93
|
field: {
|
|
@@ -89,6 +102,9 @@ const InputTheme = defineStyle({
|
|
|
89
102
|
},
|
|
90
103
|
},
|
|
91
104
|
},
|
|
105
|
+
defaultProps: {
|
|
106
|
+
variant: 'desktop',
|
|
107
|
+
},
|
|
92
108
|
});
|
|
93
109
|
|
|
94
110
|
export default InputTheme;
|
|
@@ -64,6 +64,7 @@ export interface InputProps extends UsedFormControlProps, UsedChakraInputProps {
|
|
|
64
64
|
rightIconName?: TypeIconName;
|
|
65
65
|
rightIconColor?: IconProps['color'];
|
|
66
66
|
size?: 'lg' | 'md';
|
|
67
|
+
variant?: 'desktop' | 'mobile';
|
|
67
68
|
warningText?: ReactNode;
|
|
68
69
|
}
|
|
69
70
|
|
|
@@ -111,6 +112,7 @@ const Input = forwardRef<InputProps, 'div'>((props, ref) => {
|
|
|
111
112
|
step,
|
|
112
113
|
type,
|
|
113
114
|
value,
|
|
115
|
+
variant,
|
|
114
116
|
warningText,
|
|
115
117
|
...rest
|
|
116
118
|
} = props;
|
|
@@ -167,7 +169,7 @@ const Input = forwardRef<InputProps, 'div'>((props, ref) => {
|
|
|
167
169
|
};
|
|
168
170
|
|
|
169
171
|
const iconSize = size === 'lg' ? '24' : '16';
|
|
170
|
-
const style = useMultiStyleConfig('Input');
|
|
172
|
+
const style = useMultiStyleConfig('Input', { variant });
|
|
171
173
|
|
|
172
174
|
const [leftIconPos, setLeftIconPos] = useState(rem(12));
|
|
173
175
|
|
|
@@ -220,6 +222,7 @@ const Input = forwardRef<InputProps, 'div'>((props, ref) => {
|
|
|
220
222
|
{...inputProps}
|
|
221
223
|
{...dataAttributes}
|
|
222
224
|
onChange={onInputChange}
|
|
225
|
+
variant={variant}
|
|
223
226
|
/>
|
|
224
227
|
{rightAddon && (
|
|
225
228
|
<RightContentWrapper ref={rightAddonRef} bottom="0">
|
|
@@ -13,8 +13,10 @@ type RadioInputProps = ChakraRadioProps['inputProps'] & {
|
|
|
13
13
|
'data-testid'?: string;
|
|
14
14
|
};
|
|
15
15
|
|
|
16
|
-
export interface RadioProps
|
|
17
|
-
|
|
16
|
+
export interface RadioProps extends Omit<
|
|
17
|
+
FormControlProps,
|
|
18
|
+
'icon' | 'iconColor' | 'iconSize' | 'inputProps' | 'value' | 'onChange'
|
|
19
|
+
> {
|
|
18
20
|
inputProps?: RadioInputProps;
|
|
19
21
|
helperText?: ReactNode;
|
|
20
22
|
errorText?: string;
|
|
@@ -7,7 +7,7 @@ export interface SearchInputProps extends Omit<InputProps, 'onChange'> {
|
|
|
7
7
|
}
|
|
8
8
|
|
|
9
9
|
const SearchInput = (props: SearchInputProps) => {
|
|
10
|
-
const { onChange, value, ...rest } = props;
|
|
10
|
+
const { onChange, value, variant, ...rest } = props;
|
|
11
11
|
|
|
12
12
|
const onInputChange = (event: ChangeEvent<HTMLInputElement>) => {
|
|
13
13
|
const q = event.target.value;
|
|
@@ -29,6 +29,7 @@ const SearchInput = (props: SearchInputProps) => {
|
|
|
29
29
|
/>
|
|
30
30
|
);
|
|
31
31
|
const inputProps: InputProps = {
|
|
32
|
+
boxShadow: variant === 'mobile' ? 'none' : undefined,
|
|
32
33
|
leftIconColor: 'neutral.60',
|
|
33
34
|
leftIconName: 'Magnifier',
|
|
34
35
|
onChange: onInputChange,
|
|
@@ -38,7 +39,7 @@ const SearchInput = (props: SearchInputProps) => {
|
|
|
38
39
|
value,
|
|
39
40
|
...rest,
|
|
40
41
|
};
|
|
41
|
-
return <Input {...inputProps} />;
|
|
42
|
+
return <Input {...inputProps} variant={variant} />;
|
|
42
43
|
};
|
|
43
44
|
|
|
44
45
|
export default SearchInput;
|
|
@@ -47,7 +47,7 @@ import ExpandableCard from './ExpandableCard/ExpandableCard.theme';
|
|
|
47
47
|
import FileInput from './Form/FileInput/FileInput.theme';
|
|
48
48
|
import Filter from './Filter/Filter.theme';
|
|
49
49
|
import Toggletip from './Toggletip/Toggletip.theme';
|
|
50
|
-
import FilterSwitch from './Filter/FilterSwitch/FilterSwitch.theme';
|
|
50
|
+
import FilterSwitch from './Filter/Desktop/FilterSwitch/FilterSwitch.theme';
|
|
51
51
|
import TagsInput from './Form/TagsInput/TagsInput.theme';
|
|
52
52
|
import DraggableCard from './DraggableCard/DraggableCard.theme';
|
|
53
53
|
import SelectableTag from './SelectableTag/SelectableTag.theme';
|
package/src/index.ts
CHANGED
|
@@ -323,10 +323,10 @@ export { default as FileInput } from './Components/Form/FileInput/FileInput';
|
|
|
323
323
|
export type { ToggletipProps } from './Components/Toggletip/Toggletip';
|
|
324
324
|
export { default as Toggletip } from './Components/Toggletip/Toggletip';
|
|
325
325
|
|
|
326
|
-
export type { FilterSwitchProps } from './Components/Filter/FilterSwitch/FilterSwitch';
|
|
327
|
-
export { default as FilterSwitch } from './Components/Filter/FilterSwitch/FilterSwitch';
|
|
326
|
+
export type { FilterSwitchProps } from './Components/Filter/Desktop/FilterSwitch/FilterSwitch';
|
|
327
|
+
export { default as FilterSwitch } from './Components/Filter/Desktop/FilterSwitch/FilterSwitch';
|
|
328
328
|
|
|
329
|
-
export { default as FilterSwitchGroup } from './Components/Filter/FilterSwitch/FilterSwitchGroup';
|
|
329
|
+
export { default as FilterSwitchGroup } from './Components/Filter/Desktop/FilterSwitch/FilterSwitchGroup';
|
|
330
330
|
|
|
331
331
|
export type { TablePaginationProps } from './Components/Table/TablePagination';
|
|
332
332
|
export { default as TablePagination } from './Components/Table/TablePagination';
|
|
@@ -337,7 +337,6 @@ export { default as Pagination } from './Components/Pagination/Pagination';
|
|
|
337
337
|
export type { ProgressIndicatorProps } from './Components/ProgressIndicator/ProgressIndicator';
|
|
338
338
|
export { default as ProgressIndicator } from './Components/ProgressIndicator/ProgressIndicator';
|
|
339
339
|
|
|
340
|
-
export type { FilterProps } from './Components/Filter/Filter';
|
|
341
340
|
export { default as Filter } from './Components/Filter/Filter';
|
|
342
341
|
export * from './Components/Filter/Filter.types';
|
|
343
342
|
|