@xqmsg/ui-core 0.9.3 → 0.10.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/dist/components/input/InputTypes.d.ts +5 -3
- package/dist/components/input/StackedInput/StackedInput.d.ts +0 -3
- package/dist/components/input/StackedMultiSelect/index.d.ts +1 -1
- package/dist/components/input/StackedSelect/StackedSelect.d.ts +7 -3
- package/dist/components/input/components/dropdown/index.d.ts +10 -0
- package/dist/components/input/components/label/index.d.ts +9 -0
- package/dist/components/input/components/token/Token.stories.d.ts +5 -0
- package/dist/components/input/components/token/index.d.ts +7 -0
- package/dist/components/input/index.d.ts +1 -3
- package/dist/theme/components/form-error.d.ts +3 -3
- package/dist/theme/components/form-label.d.ts +4 -6
- package/dist/theme/components/form.d.ts +3 -3
- package/dist/theme/components/input.d.ts +32 -161
- package/dist/theme/components/select.d.ts +27 -153
- package/dist/theme/components/textarea.d.ts +10 -117
- package/dist/theme/foundations/colors.d.ts +30 -0
- package/dist/ui-core.cjs.development.js +455 -490
- 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 +459 -494
- package/dist/ui-core.esm.js.map +1 -1
- package/package.json +1 -1
- package/src/components/input/Input.stories.tsx +28 -12
- package/src/components/input/InputTypes.ts +7 -1
- package/src/components/input/StackedInput/StackedInput.tsx +3 -15
- package/src/components/input/StackedMultiSelect/components/MultiValue/index.tsx +2 -2
- package/src/components/input/StackedMultiSelect/index.tsx +89 -93
- package/src/components/input/StackedPilledInput/index.tsx +145 -56
- package/src/components/input/StackedSelect/StackedSelect.tsx +63 -20
- package/src/components/input/StackedSelect/assets/svg/subtract.svg +3 -0
- package/src/components/input/components/dropdown/index.tsx +79 -0
- package/src/components/input/components/label/index.tsx +24 -0
- package/src/components/input/components/token/Token.stories.tsx +22 -0
- package/src/components/input/components/token/assets/svg/close.svg +3 -0
- package/src/components/input/components/token/index.tsx +37 -0
- package/src/components/input/index.tsx +8 -20
- package/src/theme/components/alert.ts +4 -4
- package/src/theme/components/form-error.ts +11 -14
- package/src/theme/components/form-label.ts +8 -8
- package/src/theme/components/form.ts +10 -13
- package/src/theme/components/input.ts +17 -191
- package/src/theme/components/select.ts +5 -10
- package/src/theme/components/textarea.ts +2 -38
- package/src/theme/foundations/colors.ts +17 -1
- package/dist/components/input/components/InputTag/index.d.ts +0 -7
- package/src/components/input/components/InputTag/index.tsx +0 -24
package/package.json
CHANGED
|
@@ -7,6 +7,7 @@ import * as Yup from 'yup';
|
|
|
7
7
|
import { Form } from '../form';
|
|
8
8
|
import ipRegex from 'ip-regex';
|
|
9
9
|
import { useEffect, useMemo } from '@storybook/addons';
|
|
10
|
+
import { Box } from '@chakra-ui/react';
|
|
10
11
|
|
|
11
12
|
const meta: Meta<InputProps<StoryFormSchema>> = {
|
|
12
13
|
title: 'Input example',
|
|
@@ -85,7 +86,7 @@ const storyFormSchema: Yup.SchemaOf<StoryFormSchema> = Yup.object().shape({
|
|
|
85
86
|
(value, testContext) => {
|
|
86
87
|
if (value) {
|
|
87
88
|
const ipStringsToArray = value.split(',');
|
|
88
|
-
const isIPValidArray = ipStringsToArray.map(ip => {
|
|
89
|
+
const isIPValidArray = ipStringsToArray.map((ip) => {
|
|
89
90
|
return ipRegex({ exact: true }).test(ip as string);
|
|
90
91
|
});
|
|
91
92
|
|
|
@@ -99,7 +100,7 @@ const storyFormSchema: Yup.SchemaOf<StoryFormSchema> = Yup.object().shape({
|
|
|
99
100
|
return malformedIP.trim();
|
|
100
101
|
}
|
|
101
102
|
})
|
|
102
|
-
.filter(invalidIP => invalidIP !== undefined);
|
|
103
|
+
.filter((invalidIP) => invalidIP !== undefined);
|
|
103
104
|
|
|
104
105
|
const errorMessage = `Malformed IPs: ${malformedIPList.join(', ')}`;
|
|
105
106
|
return testContext.createError({
|
|
@@ -114,7 +115,7 @@ const storyFormSchema: Yup.SchemaOf<StoryFormSchema> = Yup.object().shape({
|
|
|
114
115
|
});
|
|
115
116
|
|
|
116
117
|
export default meta;
|
|
117
|
-
const Template: Story<InputProps<StoryFormSchema>> = args => {
|
|
118
|
+
const Template: Story<InputProps<StoryFormSchema>> = (args) => {
|
|
118
119
|
const formHandler = useFormHandler<StoryFormSchema>(
|
|
119
120
|
onStubbedSubmit,
|
|
120
121
|
storyFormDefaultValues,
|
|
@@ -129,20 +130,15 @@ const Template: Story<InputProps<StoryFormSchema>> = args => {
|
|
|
129
130
|
if (form.formState.errors) return form.formState.errors.prop?.message;
|
|
130
131
|
}, [form.formState.errors]);
|
|
131
132
|
|
|
132
|
-
console.log(form.watch('prop'));
|
|
133
|
-
|
|
134
133
|
useEffect(() => {
|
|
135
134
|
form.resetField('prop');
|
|
136
|
-
}, [args.inputType]);
|
|
135
|
+
}, [args.inputType, form]);
|
|
137
136
|
|
|
138
137
|
return (
|
|
139
138
|
<Form formHandler={formHandler}>
|
|
140
|
-
<Input
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
errorText={valueErrorMessage}
|
|
144
|
-
isInvalid={!!valueErrorMessage}
|
|
145
|
-
/>
|
|
139
|
+
<Input {...args} setValue={form.setValue} errorText={valueErrorMessage} />
|
|
140
|
+
<Box mb={10}>Hi</Box> <Box mb={10}>there</Box> <Box mb={10}>Hi</Box>{' '}
|
|
141
|
+
<Box mb={10}>hey</Box> hello
|
|
146
142
|
</Form>
|
|
147
143
|
);
|
|
148
144
|
};
|
|
@@ -153,17 +149,37 @@ Default.args = {
|
|
|
153
149
|
inputType: 'text',
|
|
154
150
|
name: 'prop',
|
|
155
151
|
options: [
|
|
152
|
+
{ value: 'section_header', label: 'Section 1', sortValue: 0 },
|
|
156
153
|
{
|
|
157
154
|
value: 'value1',
|
|
158
155
|
label: 'Value 1',
|
|
156
|
+
sortValue: 1,
|
|
159
157
|
},
|
|
160
158
|
{
|
|
161
159
|
value: 'value2',
|
|
162
160
|
label: 'Value 2',
|
|
161
|
+
sortValue: 2,
|
|
163
162
|
},
|
|
164
163
|
{
|
|
165
164
|
value: 'value3',
|
|
166
165
|
label: 'Value 3',
|
|
166
|
+
sortValue: 3,
|
|
167
|
+
},
|
|
168
|
+
{
|
|
169
|
+
value: 'value4',
|
|
170
|
+
label: 'Value 4',
|
|
171
|
+
sortValue: 4,
|
|
172
|
+
},
|
|
173
|
+
{ value: 'section_header', label: 'Section 2', sortValue: 5 },
|
|
174
|
+
{
|
|
175
|
+
value: 'value5',
|
|
176
|
+
label: 'Value 5',
|
|
177
|
+
sortValue: 6,
|
|
178
|
+
},
|
|
179
|
+
{
|
|
180
|
+
value: 'value6',
|
|
181
|
+
label: 'Value 6',
|
|
182
|
+
sortValue: 7,
|
|
167
183
|
},
|
|
168
184
|
],
|
|
169
185
|
isRequired: true,
|
|
@@ -18,7 +18,13 @@ export type InputType =
|
|
|
18
18
|
| 'checkbox'
|
|
19
19
|
| 'switch';
|
|
20
20
|
|
|
21
|
-
export type
|
|
21
|
+
export type FieldOption = {
|
|
22
|
+
label: string;
|
|
23
|
+
value: string | 'section_header';
|
|
24
|
+
sortValue: number;
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
export type FieldOptions = FieldOption[];
|
|
22
28
|
|
|
23
29
|
export interface ValidationProps {
|
|
24
30
|
isRequired: boolean;
|
|
@@ -1,29 +1,17 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
-
import { Input
|
|
2
|
+
import { Input } from '@chakra-ui/react';
|
|
3
3
|
import { InputFieldProps } from '../InputTypes';
|
|
4
4
|
|
|
5
5
|
export interface StackedInputProps extends InputFieldProps {
|
|
6
|
-
label?: string;
|
|
7
6
|
isRequired?: boolean;
|
|
8
|
-
leftElement?: React.ReactNode;
|
|
9
|
-
rightElement?: React.ReactNode;
|
|
10
7
|
}
|
|
11
8
|
|
|
12
9
|
/**
|
|
13
10
|
* A functional React component utilized to render the `StackedInput` component.
|
|
14
11
|
*/
|
|
15
12
|
const StackedInput = React.forwardRef<HTMLInputElement, StackedInputProps>(
|
|
16
|
-
(
|
|
17
|
-
{ type
|
|
18
|
-
_ref
|
|
19
|
-
) => {
|
|
20
|
-
return (
|
|
21
|
-
<InputGroup>
|
|
22
|
-
{leftElement && leftElement}
|
|
23
|
-
<Input ref={_ref} type={type} isRequired={isRequired} {...props} />
|
|
24
|
-
{rightElement && rightElement}
|
|
25
|
-
</InputGroup>
|
|
26
|
-
);
|
|
13
|
+
({ type = 'text', isRequired, ...props }, _ref) => {
|
|
14
|
+
return <Input ref={_ref} type={type} isRequired={isRequired} {...props} />;
|
|
27
15
|
}
|
|
28
16
|
);
|
|
29
17
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Box } from '@chakra-ui/react';
|
|
2
2
|
import React, { PropsWithChildren } from 'react';
|
|
3
|
-
import InputTag from '../../../components/
|
|
3
|
+
import InputTag from '../../../components/token';
|
|
4
4
|
|
|
5
5
|
interface MultiValueProps extends PropsWithChildren {
|
|
6
6
|
clearValue: () => void;
|
|
@@ -13,7 +13,7 @@ interface MultiValueProps extends PropsWithChildren {
|
|
|
13
13
|
const MultiValue: React.FC<MultiValueProps> = ({ children, clearValue }) => {
|
|
14
14
|
return (
|
|
15
15
|
<Box marginRight="5px">
|
|
16
|
-
<InputTag
|
|
16
|
+
<InputTag label={children} onDelete={clearValue} />
|
|
17
17
|
</Box>
|
|
18
18
|
);
|
|
19
19
|
};
|
|
@@ -1,15 +1,20 @@
|
|
|
1
|
-
import React, { useEffect, useState } from 'react';
|
|
2
|
-
import { Flex } from '@chakra-ui/react';
|
|
3
|
-
import {
|
|
4
|
-
|
|
1
|
+
import React, { useEffect, useRef, useState } from 'react';
|
|
2
|
+
import { Box, Flex, Text, Image, useOutsideClick } from '@chakra-ui/react';
|
|
3
|
+
import {
|
|
4
|
+
FieldOption,
|
|
5
|
+
FieldOptions,
|
|
6
|
+
ReactSelectFieldProps,
|
|
7
|
+
} from '../InputTypes';
|
|
5
8
|
import colors from '../../../theme/foundations/colors';
|
|
6
|
-
import MultiValue from './components/MultiValue';
|
|
7
9
|
import {
|
|
8
10
|
Control,
|
|
9
11
|
FieldValues,
|
|
10
12
|
UseFormSetValue,
|
|
11
13
|
useWatch,
|
|
12
14
|
} from 'react-hook-form';
|
|
15
|
+
import SubtractIcon from '../StackedSelect/assets/svg/subtract.svg';
|
|
16
|
+
import { Dropdown } from '../components/dropdown';
|
|
17
|
+
import Token from '../components/token';
|
|
13
18
|
|
|
14
19
|
export interface StackedMultiSelectProps extends ReactSelectFieldProps {
|
|
15
20
|
options: FieldOptions;
|
|
@@ -21,124 +26,115 @@ export interface StackedMultiSelectProps extends ReactSelectFieldProps {
|
|
|
21
26
|
* A functional React component utilized to render the `StackedMultiSelect` component.
|
|
22
27
|
*/
|
|
23
28
|
const StackedMultiSelect = React.forwardRef<
|
|
24
|
-
|
|
29
|
+
HTMLInputElement,
|
|
25
30
|
StackedMultiSelectProps
|
|
26
|
-
>(({ options, setValue, control, name }, _ref) => {
|
|
31
|
+
>(({ options, setValue, control, name, placeholder, disabled }, _ref) => {
|
|
27
32
|
const watchedValue = useWatch({ control, name: name as string });
|
|
33
|
+
const dropdownRef = useRef(null);
|
|
34
|
+
|
|
35
|
+
const [localValues, setLocalValues] = useState<FieldOptions>([]);
|
|
36
|
+
const [localOptions, setLocalOptions] = useState<FieldOptions>(options);
|
|
37
|
+
const [isFocussed, setIsFocussed] = useState(false);
|
|
28
38
|
|
|
29
|
-
|
|
30
|
-
const [localValue, setLocalValue] = useState([]);
|
|
39
|
+
useOutsideClick({ ref: dropdownRef, handler: () => setIsFocussed(false) });
|
|
31
40
|
|
|
32
41
|
// gets latest watched form value (common delimited) from RHF state and creates a list
|
|
33
42
|
useEffect(() => {
|
|
34
43
|
if (watchedValue !== undefined && !watchedValue.length) {
|
|
35
|
-
|
|
44
|
+
setLocalValues([]);
|
|
36
45
|
}
|
|
37
46
|
|
|
38
47
|
if (watchedValue !== undefined && watchedValue?.length) {
|
|
39
|
-
|
|
48
|
+
setLocalValues(
|
|
40
49
|
watchedValue
|
|
41
50
|
.split(',')
|
|
42
51
|
.filter(Boolean)
|
|
43
52
|
.map((value: string) =>
|
|
44
|
-
options.find(option => option.value === value)
|
|
53
|
+
options.find((option) => option.value === value)
|
|
45
54
|
)
|
|
46
55
|
);
|
|
47
56
|
}
|
|
48
57
|
}, [options, watchedValue]);
|
|
49
58
|
|
|
50
|
-
const
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
clearValue={() => {
|
|
55
|
-
const arrayValue = watchedValue
|
|
56
|
-
.split(',')
|
|
57
|
-
.filter((_: string, index: number) => index !== props.index);
|
|
58
|
-
|
|
59
|
-
setLocalValue(
|
|
60
|
-
arrayValue.map((value: string) =>
|
|
61
|
-
options.find(option => option.value === value)
|
|
62
|
-
)
|
|
63
|
-
);
|
|
64
|
-
|
|
65
|
-
setValue(name as string, arrayValue.join(','), {
|
|
66
|
-
shouldValidate: true,
|
|
67
|
-
shouldDirty: true,
|
|
68
|
-
});
|
|
69
|
-
}}
|
|
70
|
-
>
|
|
71
|
-
{props.children}
|
|
72
|
-
</MultiValue>
|
|
73
|
-
),
|
|
74
|
-
};
|
|
59
|
+
const handleChange = (option: FieldOption) => {
|
|
60
|
+
const newValue = [...localValues, option]
|
|
61
|
+
.map(({ value }) => value)
|
|
62
|
+
.join(',');
|
|
75
63
|
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
}
|
|
64
|
+
setValue(name as string, newValue, {
|
|
65
|
+
shouldValidate: true,
|
|
66
|
+
shouldDirty: true,
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
setLocalOptions((prevLocalOptions) =>
|
|
70
|
+
prevLocalOptions.filter((prevLocalOption) => prevLocalOption !== option)
|
|
84
71
|
);
|
|
72
|
+
|
|
73
|
+
setLocalValues((prevLocalValues) => [...prevLocalValues, option]);
|
|
85
74
|
};
|
|
86
75
|
|
|
87
|
-
const
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
76
|
+
const handleDelete = (option: FieldOption) => {
|
|
77
|
+
const newValue = localValues
|
|
78
|
+
.filter((localValue) => localValue !== option)
|
|
79
|
+
.map(({ value }) => value)
|
|
80
|
+
.join(',');
|
|
91
81
|
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
82
|
+
setValue(name as string, newValue, {
|
|
83
|
+
shouldValidate: true,
|
|
84
|
+
shouldDirty: true,
|
|
85
|
+
});
|
|
95
86
|
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
<Flex alignItems="center" justifyContent="space-between">
|
|
99
|
-
<span>{data.label}</span>
|
|
100
|
-
</Flex>
|
|
87
|
+
setLocalOptions((prevLocalOptions) =>
|
|
88
|
+
[...prevLocalOptions, option].sort((a, b) => a.sortValue - b.sortValue)
|
|
101
89
|
);
|
|
102
|
-
};
|
|
103
90
|
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
fontSize: '16px',
|
|
108
|
-
color: '#202020',
|
|
109
|
-
backgroundColor: '#FFFFFF',
|
|
110
|
-
border: '1px solid',
|
|
111
|
-
borderColor: colors.gray[200],
|
|
112
|
-
minHeight: '48px',
|
|
113
|
-
display: 'flex',
|
|
114
|
-
padding: '2px 6px',
|
|
115
|
-
}),
|
|
116
|
-
menu: () => ({
|
|
117
|
-
boxShadow: '0 5px 5px 0 rgba(16, 27, 79, 0.15)',
|
|
118
|
-
borderRadius: '6px',
|
|
119
|
-
backgroundColor: 'white',
|
|
120
|
-
}),
|
|
121
|
-
indicatorsContainer: () => ({ display: 'none' }),
|
|
122
|
-
placeholder: () => ({ color: '#CBCDCF', fontSize: '16px' }),
|
|
91
|
+
setLocalValues((prevLocalValues) =>
|
|
92
|
+
prevLocalValues.filter((prevLocalValue) => prevLocalValue !== option)
|
|
93
|
+
);
|
|
123
94
|
};
|
|
124
95
|
|
|
125
96
|
return (
|
|
126
|
-
<
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
97
|
+
<Box ref={dropdownRef} position="relative">
|
|
98
|
+
<Flex
|
|
99
|
+
fontSize="13px"
|
|
100
|
+
border={isFocussed ? '2px solid' : '1px solid'}
|
|
101
|
+
borderColor={isFocussed ? colors.border.focus : colors.border.default}
|
|
102
|
+
py="5px"
|
|
103
|
+
pl="8px"
|
|
104
|
+
borderRadius="4px"
|
|
105
|
+
alignItems="center"
|
|
106
|
+
justifyContent="space-between"
|
|
107
|
+
onClick={() => !disabled && setIsFocussed(true)}
|
|
108
|
+
bg={disabled ? colors.fill.light : '#ffffff'}
|
|
109
|
+
cursor={disabled ? 'not-allowed' : 'pointer'}
|
|
110
|
+
>
|
|
111
|
+
<Flex height="28px" alignItems="center">
|
|
112
|
+
{localValues.length ? (
|
|
113
|
+
localValues.map((option) => (
|
|
114
|
+
<Box mr="4px">
|
|
115
|
+
<Token
|
|
116
|
+
label={option.label}
|
|
117
|
+
onDelete={() => handleDelete(option)}
|
|
118
|
+
/>
|
|
119
|
+
</Box>
|
|
120
|
+
))
|
|
121
|
+
) : (
|
|
122
|
+
<Text color={colors.label.secondary.light} fontSize="13px">
|
|
123
|
+
{placeholder}
|
|
124
|
+
</Text>
|
|
125
|
+
)}
|
|
126
|
+
</Flex>
|
|
127
|
+
<Flex width="39px" justifyContent="center" alignItems="center">
|
|
128
|
+
<Image src={SubtractIcon} alt="subtract" boxSize="16px" />
|
|
129
|
+
</Flex>
|
|
130
|
+
</Flex>
|
|
131
|
+
{isFocussed && (
|
|
132
|
+
<Dropdown
|
|
133
|
+
onSelectItem={(option) => handleChange(option)}
|
|
134
|
+
options={localOptions}
|
|
135
|
+
/>
|
|
136
|
+
)}
|
|
137
|
+
</Box>
|
|
142
138
|
);
|
|
143
139
|
});
|
|
144
140
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import React, { useEffect, useRef, useState } from 'react';
|
|
2
|
-
import { Box, Flex, Input } from '@chakra-ui/react';
|
|
2
|
+
import { Box, Flex, Input, Text, useOutsideClick } from '@chakra-ui/react';
|
|
3
3
|
import { InputFieldProps } from '../InputTypes';
|
|
4
4
|
import {
|
|
5
5
|
Control,
|
|
@@ -8,7 +8,7 @@ import {
|
|
|
8
8
|
useWatch,
|
|
9
9
|
} from 'react-hook-form';
|
|
10
10
|
import colors from '../../../theme/foundations/colors';
|
|
11
|
-
import
|
|
11
|
+
import Token from '../components/token';
|
|
12
12
|
|
|
13
13
|
export interface StackedPilledInputProps extends InputFieldProps {
|
|
14
14
|
setValue: UseFormSetValue<FieldValues>;
|
|
@@ -21,15 +21,17 @@ export interface StackedPilledInputProps extends InputFieldProps {
|
|
|
21
21
|
const StackedPilledInput = React.forwardRef<
|
|
22
22
|
HTMLInputElement,
|
|
23
23
|
StackedPilledInputProps
|
|
24
|
-
>(({ name, setValue, control }, _ref) => {
|
|
24
|
+
>(({ name, setValue, control, placeholder, disabled }, _ref) => {
|
|
25
25
|
const watchedValue = useWatch({ control, name: name as string });
|
|
26
26
|
const [lastestFormValueToArray, setLatestFormValueToArray] = useState<
|
|
27
27
|
string[]
|
|
28
28
|
>([]);
|
|
29
29
|
|
|
30
30
|
const inputRef = useRef<HTMLInputElement>(null);
|
|
31
|
+
const inputWrapperRef = useRef(null);
|
|
31
32
|
|
|
32
|
-
const [
|
|
33
|
+
const [tokenIndex, setTokenIndex] = useState<number | null>(null);
|
|
34
|
+
const [isFocussed, setIsFocussed] = useState(false);
|
|
33
35
|
|
|
34
36
|
const [localValue, setLocalValue] = useState('');
|
|
35
37
|
|
|
@@ -44,17 +46,34 @@ const StackedPilledInput = React.forwardRef<
|
|
|
44
46
|
}
|
|
45
47
|
}, [watchedValue]);
|
|
46
48
|
|
|
47
|
-
// ensures after value addition that the input field is wiped
|
|
48
|
-
useEffect(() => {
|
|
49
|
-
if (localValue === ' ' || localValue.trim() === ',') {
|
|
50
|
-
setLocalValue('');
|
|
51
|
-
}
|
|
52
|
-
}, [localValue]);
|
|
53
|
-
|
|
54
49
|
const onHandleKeyDown = (e: React.KeyboardEvent) => {
|
|
55
50
|
if (e.key === ' ' || e.key === 'Enter' || e.key === ',') {
|
|
56
|
-
if (
|
|
57
|
-
|
|
51
|
+
if (
|
|
52
|
+
e.key === 'Enter' &&
|
|
53
|
+
!localValue.trim().length &&
|
|
54
|
+
tokenIndex !== null
|
|
55
|
+
) {
|
|
56
|
+
setLocalValue(lastestFormValueToArray[tokenIndex]);
|
|
57
|
+
|
|
58
|
+
const filteredUniqueValues = Array.from(
|
|
59
|
+
new Set(
|
|
60
|
+
lastestFormValueToArray.filter(
|
|
61
|
+
(value) => value !== lastestFormValueToArray[tokenIndex]
|
|
62
|
+
)
|
|
63
|
+
)
|
|
64
|
+
);
|
|
65
|
+
|
|
66
|
+
setValue(
|
|
67
|
+
name as string,
|
|
68
|
+
filteredUniqueValues.toString().replace(/\s/g, ''),
|
|
69
|
+
{
|
|
70
|
+
shouldValidate: true,
|
|
71
|
+
shouldDirty: true,
|
|
72
|
+
}
|
|
73
|
+
);
|
|
74
|
+
|
|
75
|
+
return setTokenIndex(null);
|
|
76
|
+
}
|
|
58
77
|
|
|
59
78
|
const filteredUniqueValues = Array.from(
|
|
60
79
|
new Set([...lastestFormValueToArray, ...localValue.trim().split(',')])
|
|
@@ -71,6 +90,59 @@ const StackedPilledInput = React.forwardRef<
|
|
|
71
90
|
}
|
|
72
91
|
);
|
|
73
92
|
}
|
|
93
|
+
|
|
94
|
+
if (!localValue.trim().length && lastestFormValueToArray.length) {
|
|
95
|
+
if (e.key === 'Backspace' && tokenIndex !== null) {
|
|
96
|
+
setLocalValue(
|
|
97
|
+
lastestFormValueToArray[tokenIndex].substring(
|
|
98
|
+
0,
|
|
99
|
+
lastestFormValueToArray[tokenIndex].length
|
|
100
|
+
)
|
|
101
|
+
);
|
|
102
|
+
|
|
103
|
+
const filteredUniqueValues = Array.from(
|
|
104
|
+
new Set(
|
|
105
|
+
[...lastestFormValueToArray].filter(
|
|
106
|
+
(value) => value !== lastestFormValueToArray[tokenIndex]
|
|
107
|
+
)
|
|
108
|
+
)
|
|
109
|
+
);
|
|
110
|
+
|
|
111
|
+
setValue(
|
|
112
|
+
name as string,
|
|
113
|
+
filteredUniqueValues.toString().replace(/\s/g, ''),
|
|
114
|
+
{
|
|
115
|
+
shouldValidate: true,
|
|
116
|
+
shouldDirty: true,
|
|
117
|
+
}
|
|
118
|
+
);
|
|
119
|
+
|
|
120
|
+
return setTokenIndex(null);
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
if (e.key === 'ArrowLeft') {
|
|
124
|
+
if (tokenIndex === 0) return;
|
|
125
|
+
|
|
126
|
+
if (!tokenIndex) {
|
|
127
|
+
return setTokenIndex(lastestFormValueToArray.length - 1);
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
return setTokenIndex(
|
|
131
|
+
(prevTokenIndex) => (prevTokenIndex as number) - 1
|
|
132
|
+
);
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
if (e.key === 'ArrowRight') {
|
|
136
|
+
if (tokenIndex === null) return;
|
|
137
|
+
|
|
138
|
+
if (tokenIndex === lastestFormValueToArray.length - 1) {
|
|
139
|
+
return setTokenIndex(null);
|
|
140
|
+
}
|
|
141
|
+
return setTokenIndex(
|
|
142
|
+
(prevTokenIndex) => (prevTokenIndex as number) + 1
|
|
143
|
+
);
|
|
144
|
+
}
|
|
145
|
+
}
|
|
74
146
|
};
|
|
75
147
|
|
|
76
148
|
const onRemoveTag = (index: number) => {
|
|
@@ -106,63 +178,80 @@ const StackedPilledInput = React.forwardRef<
|
|
|
106
178
|
);
|
|
107
179
|
setLocalValue('');
|
|
108
180
|
}
|
|
109
|
-
|
|
181
|
+
setIsFocussed(false);
|
|
110
182
|
};
|
|
111
183
|
|
|
184
|
+
useOutsideClick({ ref: inputWrapperRef, handler: onBlur });
|
|
185
|
+
|
|
112
186
|
return (
|
|
113
|
-
<
|
|
114
|
-
<
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
187
|
+
<Box position="relative">
|
|
188
|
+
<Flex
|
|
189
|
+
fontSize="13px"
|
|
190
|
+
border={isFocussed ? '2px solid' : '1px solid'}
|
|
191
|
+
borderColor={isFocussed ? colors.border.focus : colors.border.default}
|
|
192
|
+
py="5px"
|
|
193
|
+
pl="8px"
|
|
194
|
+
borderRadius="4px"
|
|
195
|
+
alignItems="center"
|
|
196
|
+
justifyContent="space-between"
|
|
197
|
+
onClick={() => {
|
|
198
|
+
if (!disabled) {
|
|
199
|
+
inputRef.current?.focus();
|
|
200
|
+
}
|
|
201
|
+
}}
|
|
202
|
+
bg={disabled ? colors.fill.light : '#ffffff'}
|
|
203
|
+
cursor={disabled ? 'not-allowed' : 'pointer'}
|
|
204
|
+
ref={inputWrapperRef}
|
|
118
205
|
>
|
|
119
|
-
<Flex
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
206
|
+
<Flex height="28px" alignItems="center" width="fit-content">
|
|
207
|
+
{lastestFormValueToArray.length ? (
|
|
208
|
+
lastestFormValueToArray.map((label, index) => (
|
|
209
|
+
<Box
|
|
210
|
+
mr="4px"
|
|
211
|
+
border={
|
|
212
|
+
tokenIndex === index
|
|
213
|
+
? `2px solid ${colors.border.focus}`
|
|
214
|
+
: 'none'
|
|
215
|
+
}
|
|
216
|
+
borderRadius="full"
|
|
217
|
+
onClick={() => setTokenIndex(index)}
|
|
218
|
+
>
|
|
219
|
+
<Token
|
|
220
|
+
label={label}
|
|
221
|
+
onDelete={(e: any) => {
|
|
222
|
+
e.stopPropagation();
|
|
223
|
+
e.preventDefault();
|
|
224
|
+
onRemoveTag(index);
|
|
225
|
+
}}
|
|
226
|
+
/>
|
|
227
|
+
</Box>
|
|
228
|
+
))
|
|
229
|
+
) : (
|
|
230
|
+
<Text color={colors.label.secondary.light} fontSize="13px">
|
|
231
|
+
{placeholder}
|
|
232
|
+
</Text>
|
|
233
|
+
)}
|
|
234
|
+
</Flex>
|
|
235
|
+
<Flex flex={1}>
|
|
149
236
|
<Input
|
|
150
237
|
onKeyDown={onHandleKeyDown}
|
|
151
238
|
type="text"
|
|
152
|
-
padding={
|
|
153
|
-
height={isInputFocused ? '46px' : '0px'}
|
|
239
|
+
padding={0}
|
|
154
240
|
width="100%"
|
|
155
241
|
border="none"
|
|
242
|
+
height="26px"
|
|
243
|
+
color={tokenIndex !== null ? 'transparent' : colors.label.primary}
|
|
156
244
|
_focus={{ boxShadow: 'none !important' }}
|
|
157
245
|
value={localValue}
|
|
158
|
-
|
|
159
|
-
|
|
246
|
+
onChange={(e) =>
|
|
247
|
+
tokenIndex === null && setLocalValue(e.target.value)
|
|
248
|
+
}
|
|
160
249
|
ref={inputRef}
|
|
161
|
-
onFocus={() =>
|
|
250
|
+
onFocus={() => setIsFocussed(true)}
|
|
162
251
|
/>
|
|
163
252
|
</Flex>
|
|
164
|
-
</
|
|
165
|
-
</
|
|
253
|
+
</Flex>
|
|
254
|
+
</Box>
|
|
166
255
|
);
|
|
167
256
|
});
|
|
168
257
|
|