@xqmsg/ui-core 0.24.2 → 0.24.3
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/README.md +8 -13
- package/dist/components/input/components/dropdown/index.d.ts +1 -0
- package/dist/ui-core.cjs.development.js +156 -100
- package/dist/ui-core.cjs.development.js.map +1 -1
- package/dist/ui-core.cjs.production.min.js +1 -1
- package/dist/ui-core.cjs.production.min.js.map +1 -1
- package/dist/ui-core.esm.js +157 -101
- package/dist/ui-core.esm.js.map +1 -1
- package/package.json +6 -2
- package/src/components/icons/checkmark/index.tsx +1 -1
- package/src/components/icons/chevron/down/index.tsx +7 -1
- package/src/components/icons/chevron/right/index.tsx +1 -1
- package/src/components/icons/clock/index.tsx +1 -1
- package/src/components/icons/dropdown/index.tsx +5 -1
- package/src/components/icons/error/index.tsx +1 -1
- package/src/components/icons/file/fill/index.tsx +1 -1
- package/src/components/icons/file/outline/index.tsx +1 -1
- package/src/components/icons/folder/add/fill/index.tsx +1 -1
- package/src/components/icons/folder/add/outline/index.tsx +1 -1
- package/src/components/icons/folder/outline/index.tsx +1 -1
- package/src/components/icons/group/index.tsx +1 -1
- package/src/components/icons/home/index.tsx +1 -1
- package/src/components/icons/image/index.tsx +1 -1
- package/src/components/icons/link/index.tsx +1 -1
- package/src/components/icons/menu/index.tsx +1 -1
- package/src/components/icons/microsoft/index.tsx +1 -1
- package/src/components/icons/neutral/index.tsx +3 -1
- package/src/components/icons/page/index.tsx +1 -1
- package/src/components/icons/positive/index.tsx +1 -1
- package/src/components/icons/question/index.tsx +1 -1
- package/src/components/icons/search/index.tsx +1 -1
- package/src/components/icons/services/index.tsx +1 -1
- package/src/components/icons/settings/index.tsx +3 -1
- package/src/components/icons/table/fill/index.tsx +1 -1
- package/src/components/icons/table/outline/index.tsx +1 -1
- package/src/components/icons/task/index.tsx +1 -1
- package/src/components/icons/trash/index.tsx +1 -1
- package/src/components/icons/video/index.tsx +1 -1
- package/src/components/icons/warning/index.tsx +1 -1
- package/src/components/input/StackedMultiSelect/index.tsx +34 -27
- package/src/components/input/StackedSelect/index.tsx +30 -25
- package/src/components/input/components/dropdown/index.tsx +39 -11
package/package.json
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"version": "0.24.
|
|
2
|
+
"version": "0.24.3",
|
|
3
3
|
"license": "MIT",
|
|
4
4
|
"main": "dist/index.js",
|
|
5
5
|
"typings": "dist/index.d.ts",
|
|
@@ -37,7 +37,11 @@
|
|
|
37
37
|
"trailingComma": "es5"
|
|
38
38
|
},
|
|
39
39
|
"name": "@xqmsg/ui-core",
|
|
40
|
-
"author":
|
|
40
|
+
"author": {
|
|
41
|
+
"name": "XQ",
|
|
42
|
+
"email": "ike@xqmsg.com",
|
|
43
|
+
"url": "https://xqmsg.co"
|
|
44
|
+
},
|
|
41
45
|
"module": "dist/ui-core.esm.js",
|
|
42
46
|
"size-limit": [
|
|
43
47
|
{
|
|
@@ -9,5 +9,5 @@ export interface CheckmarkProps {
|
|
|
9
9
|
* A functional React component utilized to render the `Checkmark` icon component
|
|
10
10
|
*/
|
|
11
11
|
export const Checkmark: React.FC<CheckmarkProps> = ({ boxSize }) => {
|
|
12
|
-
return <CheckmarkIcon boxSize={boxSize} />;
|
|
12
|
+
return <CheckmarkIcon width={boxSize} height={boxSize} />;
|
|
13
13
|
};
|
|
@@ -10,5 +10,11 @@ export interface ChevronDownProps {
|
|
|
10
10
|
* A functional React component utilized to render the `ChevronDown` icon component
|
|
11
11
|
*/
|
|
12
12
|
export const ChevronDown: React.FC<ChevronDownProps> = ({ boxSize }) => {
|
|
13
|
-
return
|
|
13
|
+
return (
|
|
14
|
+
<ChevronDownIcon
|
|
15
|
+
width={boxSize}
|
|
16
|
+
height={boxSize}
|
|
17
|
+
fill={colors.fill.action}
|
|
18
|
+
/>
|
|
19
|
+
);
|
|
14
20
|
};
|
|
@@ -9,5 +9,5 @@ export interface ChevronRightProps {
|
|
|
9
9
|
* A functional React component utilized to render the `ChevronRight` icon component
|
|
10
10
|
*/
|
|
11
11
|
export const ChevronRight: React.FC<ChevronRightProps> = ({ boxSize }) => {
|
|
12
|
-
return <ChevronRightIcon boxSize={boxSize} />;
|
|
12
|
+
return <ChevronRightIcon width={boxSize} height={boxSize} />;
|
|
13
13
|
};
|
|
@@ -9,5 +9,5 @@ export interface ClockProps {
|
|
|
9
9
|
* A functional React component utilized to render the `Clock` icon component
|
|
10
10
|
*/
|
|
11
11
|
export const Clock: React.FC<ClockProps> = ({ boxSize }) => {
|
|
12
|
-
return <ClockIcon boxSize={boxSize} />;
|
|
12
|
+
return <ClockIcon width={boxSize} height={boxSize} />;
|
|
13
13
|
};
|
|
@@ -11,6 +11,10 @@ export interface DropdownProps {
|
|
|
11
11
|
*/
|
|
12
12
|
export const Dropdown: React.FC<DropdownProps> = ({ boxSize, disabled }) => {
|
|
13
13
|
return (
|
|
14
|
-
<DropdownIcon
|
|
14
|
+
<DropdownIcon
|
|
15
|
+
width={boxSize}
|
|
16
|
+
height={boxSize}
|
|
17
|
+
fill={disabled ? '#3C3C4399' : '#0082FF'}
|
|
18
|
+
/>
|
|
15
19
|
);
|
|
16
20
|
};
|
|
@@ -9,5 +9,5 @@ export interface ErrorProps {
|
|
|
9
9
|
* A functional React component utilized to render the `Error` icon component
|
|
10
10
|
*/
|
|
11
11
|
export const Error: React.FC<ErrorProps> = ({ boxSize }) => {
|
|
12
|
-
return <ErrorIcon boxSize={boxSize} />;
|
|
12
|
+
return <ErrorIcon width={boxSize} height={boxSize} />;
|
|
13
13
|
};
|
|
@@ -9,5 +9,5 @@ export interface FileFillProps {
|
|
|
9
9
|
* A functional React component utilized to render the `FileFill` icon component
|
|
10
10
|
*/
|
|
11
11
|
export const FileFill: React.FC<FileFillProps> = ({ boxSize }) => {
|
|
12
|
-
return <FileFillIcon boxSize={boxSize} />;
|
|
12
|
+
return <FileFillIcon width={boxSize} height={boxSize} />;
|
|
13
13
|
};
|
|
@@ -9,5 +9,5 @@ export interface FileOutlineProps {
|
|
|
9
9
|
* A functional React component utilized to render the `FileOutline` icon component
|
|
10
10
|
*/
|
|
11
11
|
export const FileOutline: React.FC<FileOutlineProps> = ({ boxSize }) => {
|
|
12
|
-
return <FileOutlineIcon boxSize={boxSize} />;
|
|
12
|
+
return <FileOutlineIcon width={boxSize} height={boxSize} />;
|
|
13
13
|
};
|
|
@@ -9,5 +9,5 @@ export interface FolderAddFillProps {
|
|
|
9
9
|
* A functional React component utilized to render the `FolderAddFill` icon component
|
|
10
10
|
*/
|
|
11
11
|
export const FolderAddFill: React.FC<FolderAddFillProps> = ({ boxSize }) => {
|
|
12
|
-
return <FolderAddFillIcon boxSize={boxSize} />;
|
|
12
|
+
return <FolderAddFillIcon width={boxSize} height={boxSize} />;
|
|
13
13
|
};
|
|
@@ -9,5 +9,5 @@ export interface FolderOutlineProps {
|
|
|
9
9
|
* A functional React component utilized to render the `FolderOutline` icon component
|
|
10
10
|
*/
|
|
11
11
|
export const FolderOutline: React.FC<FolderOutlineProps> = ({ boxSize }) => {
|
|
12
|
-
return <FolderOutlineIcon boxSize={boxSize} />;
|
|
12
|
+
return <FolderOutlineIcon width={boxSize} height={boxSize} />;
|
|
13
13
|
};
|
|
@@ -9,5 +9,5 @@ export interface GroupProps {
|
|
|
9
9
|
* A functional React component utilized to render the `Group` icon component
|
|
10
10
|
*/
|
|
11
11
|
export const Group: React.FC<GroupProps> = ({ boxSize }) => {
|
|
12
|
-
return <GroupIcon boxSize={boxSize} />;
|
|
12
|
+
return <GroupIcon width={boxSize} height={boxSize} />;
|
|
13
13
|
};
|
|
@@ -9,5 +9,5 @@ export interface HomeProps {
|
|
|
9
9
|
* A functional React component utilized to render the `Home` icon component
|
|
10
10
|
*/
|
|
11
11
|
export const Home: React.FC<HomeProps> = ({ boxSize }) => {
|
|
12
|
-
return <HomeIcon boxSize={boxSize} />;
|
|
12
|
+
return <HomeIcon width={boxSize} height={boxSize} />;
|
|
13
13
|
};
|
|
@@ -9,5 +9,5 @@ export interface ImageProps {
|
|
|
9
9
|
* A functional React component utilized to render the `Image` icon component
|
|
10
10
|
*/
|
|
11
11
|
export const Image: React.FC<ImageProps> = ({ boxSize }) => {
|
|
12
|
-
return <ImageIcon boxSize={boxSize} />;
|
|
12
|
+
return <ImageIcon width={boxSize} height={boxSize} />;
|
|
13
13
|
};
|
|
@@ -9,5 +9,5 @@ export interface LinkProps {
|
|
|
9
9
|
* A functional React component utilized to render the `Link` icon component
|
|
10
10
|
*/
|
|
11
11
|
export const Link: React.FC<LinkProps> = ({ boxSize }) => {
|
|
12
|
-
return <LinkIcon boxSize={boxSize} />;
|
|
12
|
+
return <LinkIcon width={boxSize} height={boxSize} />;
|
|
13
13
|
};
|
|
@@ -9,5 +9,5 @@ export interface MenuProps {
|
|
|
9
9
|
* A functional React component utilized to render the `Menu` icon component
|
|
10
10
|
*/
|
|
11
11
|
export const Menu: React.FC<MenuProps> = ({ boxSize }) => {
|
|
12
|
-
return <MenuIcon boxSize={boxSize} />;
|
|
12
|
+
return <MenuIcon width={boxSize} height={boxSize} />;
|
|
13
13
|
};
|
|
@@ -9,5 +9,5 @@ export interface MicrosoftProps {
|
|
|
9
9
|
* A functional React component utilized to render the `Microsoft` icon component
|
|
10
10
|
*/
|
|
11
11
|
export const Microsoft: React.FC<MicrosoftProps> = ({ boxSize }) => {
|
|
12
|
-
return <MicrosoftLogo boxSize={boxSize} />;
|
|
12
|
+
return <MicrosoftLogo width={boxSize} height={boxSize} />;
|
|
13
13
|
};
|
|
@@ -10,5 +10,7 @@ export interface NeutralProps {
|
|
|
10
10
|
* A functional React component utilized to render the `Neutral` icon component
|
|
11
11
|
*/
|
|
12
12
|
export const Neutral: React.FC<NeutralProps> = ({ color, boxSize }) => {
|
|
13
|
-
return
|
|
13
|
+
return (
|
|
14
|
+
<NeutralIcon width={boxSize} height={boxSize} fill={color || '#3C3C43'} />
|
|
15
|
+
);
|
|
14
16
|
};
|
|
@@ -9,5 +9,5 @@ export interface PageProps {
|
|
|
9
9
|
* A functional React component utilized to render the `Page` icon component
|
|
10
10
|
*/
|
|
11
11
|
export const Page: React.FC<PageProps> = ({ boxSize }) => {
|
|
12
|
-
return <PageIcon boxSize={boxSize} />;
|
|
12
|
+
return <PageIcon width={boxSize} height={boxSize} />;
|
|
13
13
|
};
|
|
@@ -9,5 +9,5 @@ export interface PositiveProps {
|
|
|
9
9
|
* A functional React component utilized to render the `Positive` icon component
|
|
10
10
|
*/
|
|
11
11
|
export const Positive: React.FC<PositiveProps> = ({ boxSize }) => {
|
|
12
|
-
return <PositiveIcon boxSize={boxSize} />;
|
|
12
|
+
return <PositiveIcon width={boxSize} height={boxSize} />;
|
|
13
13
|
};
|
|
@@ -9,5 +9,5 @@ export interface QuestionProps {
|
|
|
9
9
|
* A functional React component utilized to render the `Question` icon component
|
|
10
10
|
*/
|
|
11
11
|
export const Question: React.FC<QuestionProps> = ({ boxSize }) => {
|
|
12
|
-
return <QuestionIcon boxSize={boxSize} />;
|
|
12
|
+
return <QuestionIcon width={boxSize} height={boxSize} />;
|
|
13
13
|
};
|
|
@@ -9,5 +9,5 @@ export interface SearchProps {
|
|
|
9
9
|
* A functional React component utilized to render the `Search` icon component
|
|
10
10
|
*/
|
|
11
11
|
export const Search: React.FC<SearchProps> = ({ boxSize }) => {
|
|
12
|
-
return <SearchIcon boxSize={boxSize} />;
|
|
12
|
+
return <SearchIcon width={boxSize} height={boxSize} />;
|
|
13
13
|
};
|
|
@@ -9,5 +9,5 @@ export interface ServicesProps {
|
|
|
9
9
|
* A functional React component utilized to render the `Services` icon component
|
|
10
10
|
*/
|
|
11
11
|
export const Services: React.FC<ServicesProps> = ({ boxSize }) => {
|
|
12
|
-
return <ServicesIcon boxSize={boxSize} />;
|
|
12
|
+
return <ServicesIcon width={boxSize} height={boxSize} />;
|
|
13
13
|
};
|
|
@@ -10,5 +10,7 @@ export interface SettingsProps {
|
|
|
10
10
|
* A functional React component utilized to render the `Settings` icon component
|
|
11
11
|
*/
|
|
12
12
|
export const Settings: React.FC<SettingsProps> = ({ boxSize }) => {
|
|
13
|
-
return
|
|
13
|
+
return (
|
|
14
|
+
<SettingsIcon width={boxSize} height={boxSize} fill={colors.fill.action} />
|
|
15
|
+
);
|
|
14
16
|
};
|
|
@@ -9,5 +9,5 @@ export interface TableFillProps {
|
|
|
9
9
|
* A functional React component utilized to render the `TableFill` icon component
|
|
10
10
|
*/
|
|
11
11
|
export const TableFill: React.FC<TableFillProps> = ({ boxSize }) => {
|
|
12
|
-
return <TableFillIcon boxSize={boxSize} />;
|
|
12
|
+
return <TableFillIcon width={boxSize} height={boxSize} />;
|
|
13
13
|
};
|
|
@@ -9,5 +9,5 @@ export interface TableOutlineProps {
|
|
|
9
9
|
* A functional React component utilized to render the `TableOutline` icon component
|
|
10
10
|
*/
|
|
11
11
|
export const TableOutline: React.FC<TableOutlineProps> = ({ boxSize }) => {
|
|
12
|
-
return <TableOutlineIcon boxSize={boxSize} />;
|
|
12
|
+
return <TableOutlineIcon width={boxSize} height={boxSize} />;
|
|
13
13
|
};
|
|
@@ -6,5 +6,5 @@ import { IconProps } from '..';
|
|
|
6
6
|
* A functional React component utilized to render the `Task` icon component
|
|
7
7
|
*/
|
|
8
8
|
export const Task: React.FC<IconProps> = ({ boxSize }) => {
|
|
9
|
-
return <TaskIcon boxSize={boxSize} />;
|
|
9
|
+
return <TaskIcon width={boxSize} height={boxSize} />;
|
|
10
10
|
};
|
|
@@ -9,5 +9,5 @@ export interface TrashProps {
|
|
|
9
9
|
* A functional React component utilized to render the `Trash` icon component
|
|
10
10
|
*/
|
|
11
11
|
export const Trash: React.FC<TrashProps> = ({ boxSize }) => {
|
|
12
|
-
return <TrashIcon boxSize={boxSize} />;
|
|
12
|
+
return <TrashIcon width={boxSize} height={boxSize} />;
|
|
13
13
|
};
|
|
@@ -9,5 +9,5 @@ export interface VideoProps {
|
|
|
9
9
|
* A functional React component utilized to render the `Video` icon component
|
|
10
10
|
*/
|
|
11
11
|
export const Video: React.FC<VideoProps> = ({ boxSize }) => {
|
|
12
|
-
return <VideoIcon boxSize={boxSize} />;
|
|
12
|
+
return <VideoIcon width={boxSize} height={boxSize} />;
|
|
13
13
|
};
|
|
@@ -9,5 +9,5 @@ export interface WarningProps {
|
|
|
9
9
|
* A functional React component utilized to render the `Warning` icon component
|
|
10
10
|
*/
|
|
11
11
|
export const Warning: React.FC<WarningProps> = ({ boxSize }) => {
|
|
12
|
-
return <WarningIcon boxSize={boxSize} />;
|
|
12
|
+
return <WarningIcon width={boxSize} height={boxSize} />;
|
|
13
13
|
};
|
|
@@ -1,12 +1,10 @@
|
|
|
1
1
|
import React, {
|
|
2
2
|
KeyboardEventHandler,
|
|
3
3
|
useEffect,
|
|
4
|
-
useMemo,
|
|
5
4
|
useRef,
|
|
6
5
|
useState,
|
|
7
6
|
} from 'react';
|
|
8
7
|
import { Box, Flex, Text, Input } from '@chakra-ui/react';
|
|
9
|
-
import { debounce } from 'lodash';
|
|
10
8
|
import {
|
|
11
9
|
FieldOption,
|
|
12
10
|
FieldOptions,
|
|
@@ -50,13 +48,16 @@ const StackedMultiSelect = React.forwardRef<
|
|
|
50
48
|
const [isInit, setIsInit] = useState(false);
|
|
51
49
|
const [localValues, setLocalValues] = useState<FieldOptions>([]);
|
|
52
50
|
const [localOptions, setLocalOptions] = useState<FieldOptions>(options);
|
|
51
|
+
const [filteredOptions, setFilteredOptions] = useState<FieldOptions>(
|
|
52
|
+
localOptions
|
|
53
|
+
);
|
|
53
54
|
const [isFocussed, setIsFocussed] = useState(false);
|
|
54
55
|
const [shouldSideScroll, setShouldSideScroll] = useState(false);
|
|
55
56
|
const [optionIndex, setOptionIndex] = useState<number | null>(null);
|
|
56
57
|
|
|
57
58
|
const [position, setPosition] = useState<'top' | 'bottom'>('top');
|
|
58
59
|
const [searchValue, setSearchValue] = useState('');
|
|
59
|
-
const [debouncedSearchValue, setDebouncedSearchValue] = useState('');
|
|
60
|
+
// const [debouncedSearchValue, setDebouncedSearchValue] = useState('');
|
|
60
61
|
|
|
61
62
|
const boundingClientRect = dropdownRef.current?.getBoundingClientRect() as DOMRect;
|
|
62
63
|
|
|
@@ -137,6 +138,9 @@ const StackedMultiSelect = React.forwardRef<
|
|
|
137
138
|
);
|
|
138
139
|
|
|
139
140
|
setLocalValues(prevLocalValues => [...prevLocalValues, option]);
|
|
141
|
+
|
|
142
|
+
// reset search on value select
|
|
143
|
+
setSearchValue('');
|
|
140
144
|
};
|
|
141
145
|
|
|
142
146
|
const handleDelete = (option: FieldOption) => {
|
|
@@ -180,8 +184,8 @@ const StackedMultiSelect = React.forwardRef<
|
|
|
180
184
|
|
|
181
185
|
if (e.key === 'ArrowUp' && optionIndex !== null && optionIndex > 0) {
|
|
182
186
|
const incrementValue =
|
|
183
|
-
|
|
184
|
-
|
|
187
|
+
filteredOptions[optionIndex - 1] &&
|
|
188
|
+
filteredOptions[optionIndex - 1].value === 'section_header'
|
|
185
189
|
? 2
|
|
186
190
|
: 1;
|
|
187
191
|
setOptionIndex(optionIndex - incrementValue);
|
|
@@ -195,11 +199,11 @@ const StackedMultiSelect = React.forwardRef<
|
|
|
195
199
|
if (
|
|
196
200
|
e.key === 'ArrowDown' &&
|
|
197
201
|
optionIndex !== null &&
|
|
198
|
-
optionIndex <
|
|
202
|
+
optionIndex < filteredOptions.length
|
|
199
203
|
) {
|
|
200
204
|
const incrementValue =
|
|
201
|
-
|
|
202
|
-
|
|
205
|
+
filteredOptions[optionIndex + 1] &&
|
|
206
|
+
filteredOptions[optionIndex + 1].value === 'section_header'
|
|
203
207
|
? 2
|
|
204
208
|
: 1;
|
|
205
209
|
setOptionIndex(optionIndex + incrementValue);
|
|
@@ -211,7 +215,7 @@ const StackedMultiSelect = React.forwardRef<
|
|
|
211
215
|
}
|
|
212
216
|
|
|
213
217
|
if (e.key === 'Enter' && optionIndex !== null) {
|
|
214
|
-
const option =
|
|
218
|
+
const option = filteredOptions.find((_, idx) => optionIndex === idx);
|
|
215
219
|
if (!option) return;
|
|
216
220
|
|
|
217
221
|
handleChange(option);
|
|
@@ -222,8 +226,6 @@ const StackedMultiSelect = React.forwardRef<
|
|
|
222
226
|
if (e.key === 'Tab') {
|
|
223
227
|
return setIsFocussed(false);
|
|
224
228
|
}
|
|
225
|
-
|
|
226
|
-
return update(debouncedSearchValue.concat(e.key));
|
|
227
229
|
}
|
|
228
230
|
};
|
|
229
231
|
|
|
@@ -236,24 +238,27 @@ const StackedMultiSelect = React.forwardRef<
|
|
|
236
238
|
);
|
|
237
239
|
|
|
238
240
|
dropdownMenuRef.current?.scrollTo({
|
|
239
|
-
top: idx *
|
|
241
|
+
top: idx * 27,
|
|
240
242
|
behavior: 'smooth',
|
|
241
243
|
});
|
|
242
|
-
|
|
243
|
-
setSearchValue('');
|
|
244
|
-
setDebouncedSearchValue('');
|
|
245
244
|
}
|
|
246
245
|
}, [options, searchValue]);
|
|
247
246
|
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
247
|
+
useEffect(() => {
|
|
248
|
+
setFilteredOptions(
|
|
249
|
+
localOptions.filter(element => {
|
|
250
|
+
return element.label.toLowerCase().includes(searchValue.toLowerCase());
|
|
251
|
+
})
|
|
252
|
+
);
|
|
253
|
+
}, [localOptions, searchValue]);
|
|
254
|
+
|
|
255
|
+
const handleInput = (e: React.ChangeEvent<HTMLInputElement>) => {
|
|
256
|
+
console.log(e);
|
|
257
|
+
const initialOptionIndex =
|
|
258
|
+
filteredOptions[0]?.value === 'section_header' ? 1 : 0;
|
|
259
|
+
setOptionIndex(initialOptionIndex);
|
|
260
|
+
const { value } = e.target;
|
|
261
|
+
setSearchValue(value);
|
|
257
262
|
};
|
|
258
263
|
|
|
259
264
|
return (
|
|
@@ -330,17 +335,19 @@ const StackedMultiSelect = React.forwardRef<
|
|
|
330
335
|
_focus={{ boxShadow: 'none !important' }}
|
|
331
336
|
/>
|
|
332
337
|
<Flex mr="4px" justifyContent="center" alignItems="center">
|
|
333
|
-
<DropdownIcon boxSize="
|
|
338
|
+
<DropdownIcon boxSize="12px" disabled={disabled} />
|
|
334
339
|
</Flex>
|
|
335
340
|
</Flex>
|
|
336
341
|
{isFocussed && (
|
|
337
342
|
<Dropdown
|
|
338
343
|
dropdownRef={dropdownMenuRef}
|
|
339
344
|
onSelectItem={option => handleChange(option)}
|
|
340
|
-
options={
|
|
345
|
+
options={filteredOptions}
|
|
341
346
|
position={position}
|
|
342
347
|
optionIndex={optionIndex}
|
|
343
|
-
|
|
348
|
+
>
|
|
349
|
+
<Input value={searchValue} onChange={handleInput} />
|
|
350
|
+
</Dropdown>
|
|
344
351
|
)}
|
|
345
352
|
</Box>
|
|
346
353
|
);
|
|
@@ -2,18 +2,15 @@ import React, {
|
|
|
2
2
|
KeyboardEventHandler,
|
|
3
3
|
useEffect,
|
|
4
4
|
useRef,
|
|
5
|
-
useMemo,
|
|
6
5
|
useState,
|
|
7
6
|
} from 'react';
|
|
8
7
|
import { Box, Input, InputGroup, InputRightElement } from '@chakra-ui/react';
|
|
9
8
|
import { FieldOptions } from '../InputTypes';
|
|
10
9
|
import { StackedInputProps } from '../StackedInput/StackedInput';
|
|
11
|
-
import colors from '../../../theme/foundations/colors';
|
|
12
10
|
import { UseFormSetValue, FieldValues, Control } from 'react-hook-form';
|
|
13
11
|
import { Dropdown } from '../components/dropdown';
|
|
14
12
|
import { useOnClickOutside } from '../../../hooks/useOnOutsideClick';
|
|
15
13
|
import { Dropdown as DropdownIcon } from '../../icons/dropdown';
|
|
16
|
-
import { debounce } from 'lodash';
|
|
17
14
|
|
|
18
15
|
export interface StackedSelectProps extends StackedInputProps {
|
|
19
16
|
options: FieldOptions;
|
|
@@ -51,7 +48,9 @@ const StackedSelect = React.forwardRef<HTMLInputElement, StackedSelectProps>(
|
|
|
51
48
|
const [optionIndex, setOptionIndex] = useState<number | null>(null);
|
|
52
49
|
const [position, setPosition] = useState<'top' | 'bottom'>('top');
|
|
53
50
|
const [searchValue, setSearchValue] = useState('');
|
|
54
|
-
const [
|
|
51
|
+
const [filteredOptions, setFilteredOptions] = useState<FieldOptions>(
|
|
52
|
+
options
|
|
53
|
+
);
|
|
55
54
|
|
|
56
55
|
const boundingClientRect = dropdownRef.current?.getBoundingClientRect() as DOMRect;
|
|
57
56
|
|
|
@@ -70,9 +69,12 @@ const StackedSelect = React.forwardRef<HTMLInputElement, StackedSelectProps>(
|
|
|
70
69
|
(fullOptions || options).find(option => option.value === value)
|
|
71
70
|
?.label ?? ''
|
|
72
71
|
);
|
|
73
|
-
}, [fullOptions, value]);
|
|
72
|
+
}, [fullOptions, options, value]);
|
|
74
73
|
|
|
75
|
-
useOnClickOutside(dropdownRef, () =>
|
|
74
|
+
useOnClickOutside(dropdownRef, () => {
|
|
75
|
+
setIsFocussed(false);
|
|
76
|
+
setSearchValue('');
|
|
77
|
+
});
|
|
76
78
|
|
|
77
79
|
const handleOnSelectItem = (option: {
|
|
78
80
|
label: string;
|
|
@@ -85,6 +87,7 @@ const StackedSelect = React.forwardRef<HTMLInputElement, StackedSelectProps>(
|
|
|
85
87
|
setValue(name as string, option.value);
|
|
86
88
|
setSelectedOption(option.label);
|
|
87
89
|
setIsFocussed(false);
|
|
90
|
+
setSearchValue('');
|
|
88
91
|
};
|
|
89
92
|
|
|
90
93
|
const handleOnKeyDown: KeyboardEventHandler<HTMLInputElement> = e => {
|
|
@@ -173,22 +176,27 @@ const StackedSelect = React.forwardRef<HTMLInputElement, StackedSelectProps>(
|
|
|
173
176
|
top: idx * 24,
|
|
174
177
|
behavior: 'smooth',
|
|
175
178
|
});
|
|
176
|
-
|
|
177
|
-
setSearchValue('');
|
|
178
|
-
setDebouncedSearchValue('');
|
|
179
179
|
}
|
|
180
180
|
}, [options, searchValue]);
|
|
181
181
|
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
182
|
+
useEffect(() => {
|
|
183
|
+
setFilteredOptions(
|
|
184
|
+
options.filter(element => {
|
|
185
|
+
return element.label
|
|
186
|
+
.toLowerCase()
|
|
187
|
+
.includes(searchValue.toLowerCase());
|
|
188
|
+
})
|
|
189
|
+
);
|
|
190
|
+
}, [options, searchValue]);
|
|
187
191
|
|
|
188
|
-
const
|
|
189
|
-
|
|
190
|
-
|
|
192
|
+
const handleInput = (e: React.ChangeEvent<HTMLInputElement>) => {
|
|
193
|
+
const initialOptionIndex =
|
|
194
|
+
filteredOptions[0]?.value === 'section_header' ? 1 : 0;
|
|
195
|
+
setOptionIndex(initialOptionIndex);
|
|
196
|
+
const { value } = e.target;
|
|
197
|
+
setSearchValue(value);
|
|
191
198
|
};
|
|
199
|
+
console.log(searchValue);
|
|
192
200
|
|
|
193
201
|
return (
|
|
194
202
|
<Box ref={dropdownRef} position="relative">
|
|
@@ -198,21 +206,18 @@ const StackedSelect = React.forwardRef<HTMLInputElement, StackedSelectProps>(
|
|
|
198
206
|
{...props}
|
|
199
207
|
ref={_ref}
|
|
200
208
|
onClick={() => setIsFocussed(!isFocussed)}
|
|
201
|
-
cursor=
|
|
202
|
-
color="transparent"
|
|
209
|
+
cursor={isFocussed ? 'select' : 'pointer'}
|
|
203
210
|
fontSize="13px"
|
|
204
|
-
|
|
205
|
-
value={selectedOption}
|
|
206
|
-
disabled={disabled}
|
|
211
|
+
value={isFocussed ? searchValue : selectedOption}
|
|
207
212
|
autoComplete="off"
|
|
208
|
-
onChange={
|
|
213
|
+
onChange={handleInput}
|
|
209
214
|
onKeyDown={handleOnKeyDown}
|
|
210
215
|
/>
|
|
211
216
|
<InputRightElement
|
|
212
217
|
cursor={disabled ? 'not-allowed' : 'pointer'}
|
|
213
218
|
onClick={() => !disabled && setIsFocussed(!isFocussed)}
|
|
214
219
|
>
|
|
215
|
-
<DropdownIcon boxSize="
|
|
220
|
+
<DropdownIcon boxSize="12px" disabled={disabled} />
|
|
216
221
|
</InputRightElement>
|
|
217
222
|
</InputGroup>
|
|
218
223
|
{isFocussed && (
|
|
@@ -220,7 +225,7 @@ const StackedSelect = React.forwardRef<HTMLInputElement, StackedSelectProps>(
|
|
|
220
225
|
position={position}
|
|
221
226
|
dropdownRef={dropdownMenuRef}
|
|
222
227
|
onSelectItem={handleOnSelectItem}
|
|
223
|
-
options={
|
|
228
|
+
options={filteredOptions}
|
|
224
229
|
optionIndex={optionIndex}
|
|
225
230
|
/>
|
|
226
231
|
)}
|
|
@@ -9,6 +9,7 @@ export interface DropdownProps {
|
|
|
9
9
|
dropdownRef: RefObject<HTMLDivElement>;
|
|
10
10
|
position: 'top' | 'bottom';
|
|
11
11
|
optionIndex?: number | null;
|
|
12
|
+
children?: React.ReactNode;
|
|
12
13
|
}
|
|
13
14
|
|
|
14
15
|
/**
|
|
@@ -20,8 +21,25 @@ export const Dropdown: React.FC<DropdownProps> = ({
|
|
|
20
21
|
dropdownRef,
|
|
21
22
|
position,
|
|
22
23
|
optionIndex,
|
|
24
|
+
children,
|
|
23
25
|
}) => {
|
|
24
26
|
const DropdownContent = useMemo(() => {
|
|
27
|
+
if (!options || options.length === 0) {
|
|
28
|
+
return (
|
|
29
|
+
<Box
|
|
30
|
+
borderRadius="inherit"
|
|
31
|
+
fontSize="13px"
|
|
32
|
+
px="8px"
|
|
33
|
+
py="4px"
|
|
34
|
+
width="100%"
|
|
35
|
+
color={colors.label.primary.light}
|
|
36
|
+
bg="inherit"
|
|
37
|
+
whiteSpace="nowrap"
|
|
38
|
+
>
|
|
39
|
+
No options
|
|
40
|
+
</Box>
|
|
41
|
+
);
|
|
42
|
+
}
|
|
25
43
|
return options.map((option, idx) => (
|
|
26
44
|
<Box key={idx} width="100%" role="combobox">
|
|
27
45
|
{option.value === 'section_header' &&
|
|
@@ -79,13 +97,8 @@ export const Dropdown: React.FC<DropdownProps> = ({
|
|
|
79
97
|
));
|
|
80
98
|
}, [onSelectItem, optionIndex, options]);
|
|
81
99
|
|
|
82
|
-
if (!options) return null;
|
|
83
|
-
|
|
84
100
|
return (
|
|
85
101
|
<Flex
|
|
86
|
-
flexDirection="column"
|
|
87
|
-
ref={dropdownRef}
|
|
88
|
-
scrollMargin="15px"
|
|
89
102
|
bg={colors.fill.light.quaternary}
|
|
90
103
|
backdropFilter="auto"
|
|
91
104
|
backdropBlur="64px"
|
|
@@ -94,18 +107,33 @@ export const Dropdown: React.FC<DropdownProps> = ({
|
|
|
94
107
|
borderColor={colors.fill.light.tertiary}
|
|
95
108
|
mt="3px"
|
|
96
109
|
maxH="240px"
|
|
97
|
-
|
|
110
|
+
position="absolute"
|
|
98
111
|
px="8px"
|
|
99
112
|
py="4px"
|
|
100
|
-
|
|
101
|
-
top={position === 'top' ? 26 : undefined}
|
|
102
|
-
bottom={position === 'bottom' ? 30 : undefined}
|
|
103
|
-
width="fit-content"
|
|
113
|
+
overflow="hidden"
|
|
104
114
|
minWidth="100%"
|
|
105
115
|
zIndex={100}
|
|
106
116
|
tabIndex={-2000}
|
|
117
|
+
alignItems="flex-start"
|
|
118
|
+
flexDirection="column"
|
|
119
|
+
top={position === 'top' ? 26 : undefined}
|
|
120
|
+
bottom={position === 'bottom' ? 30 : undefined}
|
|
107
121
|
>
|
|
108
|
-
{
|
|
122
|
+
{children && (
|
|
123
|
+
<Box width="100%" mb={2} mt={1}>
|
|
124
|
+
{children}
|
|
125
|
+
</Box>
|
|
126
|
+
)}
|
|
127
|
+
<Flex
|
|
128
|
+
width="fit-content"
|
|
129
|
+
overflowY="auto"
|
|
130
|
+
flexDirection="column"
|
|
131
|
+
ref={dropdownRef}
|
|
132
|
+
minWidth="100%"
|
|
133
|
+
scrollMargin="15px"
|
|
134
|
+
>
|
|
135
|
+
{DropdownContent}
|
|
136
|
+
</Flex>
|
|
109
137
|
</Flex>
|
|
110
138
|
);
|
|
111
139
|
};
|