@xqmsg/ui-core 0.14.4 → 0.15.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/StackedCheckbox/StackedCheckbox.d.ts +10 -0
- package/dist/components/input/StackedMultiSelect/index.d.ts +0 -1
- package/dist/components/input/StackedPilledInput/index.d.ts +0 -1
- package/dist/components/input/components/dropdown/index.d.ts +3 -1
- package/dist/theme/components/button.d.ts +10 -8
- package/dist/theme/components/input.d.ts +2 -0
- package/dist/theme/components/select.d.ts +2 -0
- package/dist/theme/components/table.d.ts +1 -0
- package/dist/theme/components/textarea.d.ts +3 -1
- package/dist/ui-core.cjs.development.js +336 -186
- 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 +337 -187
- package/dist/ui-core.esm.js.map +1 -1
- package/package.json +1 -1
- package/src/components/banner/index.tsx +7 -15
- package/src/components/button/Button.stories.tsx +15 -5
- package/src/components/button/index.tsx +2 -2
- package/src/components/input/Input.stories.tsx +95 -47
- package/src/components/input/StackedCheckbox/StackedCheckbox.tsx +27 -0
- package/src/components/input/StackedMultiSelect/index.tsx +187 -144
- package/src/components/input/StackedPilledInput/index.tsx +217 -225
- package/src/components/input/StackedSelect/StackedSelect.tsx +34 -2
- package/src/components/input/StackedSwitch/index.tsx +9 -1
- package/src/components/input/StackedTextarea/StackedTextarea.tsx +1 -1
- package/src/components/input/components/dropdown/index.tsx +23 -6
- package/src/components/input/components/token/index.tsx +11 -6
- package/src/components/input/index.tsx +5 -4
- package/src/components/table/index.tsx +2 -7
- package/src/theme/components/button.ts +10 -10
- package/src/theme/components/input.ts +1 -0
- package/src/theme/components/table.ts +1 -0
- package/src/theme/components/textarea.ts +4 -1
- package/dist/components/input/StackedCheckbox/StackedCheckboxGroup.d.ts +0 -10
- package/dist/components/input/StackedMultiSelect/components/MultiValue/index.d.ts +0 -10
- package/src/components/input/StackedCheckbox/StackedCheckboxGroup.tsx +0 -29
- package/src/components/input/StackedMultiSelect/components/MultiValue/index.tsx +0 -21
|
@@ -17,8 +17,6 @@ export interface StackedPilledInputProps extends InputFieldProps {
|
|
|
17
17
|
setError: UseFormSetError<FieldValues>;
|
|
18
18
|
clearErrors: UseFormClearErrors<FieldValues>;
|
|
19
19
|
control: Control<FieldValues, any>;
|
|
20
|
-
// Number of allowed options
|
|
21
|
-
maxLength?: number;
|
|
22
20
|
}
|
|
23
21
|
|
|
24
22
|
/**
|
|
@@ -27,87 +25,65 @@ export interface StackedPilledInputProps extends InputFieldProps {
|
|
|
27
25
|
const StackedPilledInput = React.forwardRef<
|
|
28
26
|
HTMLInputElement,
|
|
29
27
|
StackedPilledInputProps
|
|
30
|
-
>(
|
|
31
|
-
(
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
useEffect(() => {
|
|
59
|
-
if (watchedValue !== undefined && !watchedValue.length) {
|
|
60
|
-
setLatestFormValueToArray([]);
|
|
28
|
+
>(({ name, setValue, control, placeholder, disabled, clearErrors }, _ref) => {
|
|
29
|
+
const watchedValue = useWatch({ control, name: name as string });
|
|
30
|
+
const [lastestFormValueToArray, setLatestFormValueToArray] = useState<
|
|
31
|
+
string[]
|
|
32
|
+
>([]);
|
|
33
|
+
|
|
34
|
+
const inputRef = useRef<HTMLInputElement>(null);
|
|
35
|
+
const inputWrapperRef = useRef(null);
|
|
36
|
+
const scrollRef = useRef<HTMLDivElement>(null);
|
|
37
|
+
|
|
38
|
+
const [tokenIndex, setTokenIndex] = useState<number | null>(null);
|
|
39
|
+
const [isFocussed, setIsFocussed] = useState(false);
|
|
40
|
+
const [shouldSideScroll, setShouldSideScroll] = useState(false);
|
|
41
|
+
const [localValue, setLocalValue] = useState('');
|
|
42
|
+
|
|
43
|
+
// gets latest watched form value (common delimited) from RHF state and creates a list
|
|
44
|
+
useEffect(() => {
|
|
45
|
+
if (watchedValue !== undefined && !watchedValue.length) {
|
|
46
|
+
setLatestFormValueToArray([]);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
if (watchedValue !== undefined && watchedValue?.length) {
|
|
50
|
+
if (shouldSideScroll) {
|
|
51
|
+
(scrollRef.current as HTMLDivElement).scrollTo({
|
|
52
|
+
left: scrollRef.current?.scrollWidth,
|
|
53
|
+
behavior: 'smooth',
|
|
54
|
+
});
|
|
55
|
+
setShouldSideScroll(false);
|
|
61
56
|
}
|
|
62
57
|
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
)
|
|
82
|
-
setLocalValue(lastestFormValueToArray[tokenIndex]);
|
|
83
|
-
|
|
84
|
-
const filteredUniqueValues = Array.from(
|
|
85
|
-
new Set(
|
|
86
|
-
lastestFormValueToArray.filter(
|
|
87
|
-
value => value !== lastestFormValueToArray[tokenIndex]
|
|
88
|
-
)
|
|
89
|
-
)
|
|
90
|
-
);
|
|
91
|
-
|
|
92
|
-
setValue(
|
|
93
|
-
name as string,
|
|
94
|
-
filteredUniqueValues.toString().replace(/\s/g, ''),
|
|
95
|
-
{
|
|
96
|
-
shouldValidate: true,
|
|
97
|
-
shouldDirty: true,
|
|
98
|
-
}
|
|
99
|
-
);
|
|
100
|
-
|
|
101
|
-
return setTokenIndex(null);
|
|
102
|
-
}
|
|
58
|
+
setLatestFormValueToArray(watchedValue.split(',').filter(Boolean));
|
|
59
|
+
}
|
|
60
|
+
}, [watchedValue, shouldSideScroll]);
|
|
61
|
+
|
|
62
|
+
const onHandleKeyDown = (e: React.KeyboardEvent) => {
|
|
63
|
+
setShouldSideScroll(true);
|
|
64
|
+
|
|
65
|
+
if (
|
|
66
|
+
e.key === ' ' ||
|
|
67
|
+
e.key === 'Enter' ||
|
|
68
|
+
e.key === ',' ||
|
|
69
|
+
e.key === 'Tab'
|
|
70
|
+
) {
|
|
71
|
+
if (
|
|
72
|
+
e.key === 'Enter' &&
|
|
73
|
+
!localValue.trim().length &&
|
|
74
|
+
tokenIndex !== null
|
|
75
|
+
) {
|
|
76
|
+
setLocalValue(lastestFormValueToArray[tokenIndex]);
|
|
103
77
|
|
|
104
78
|
const filteredUniqueValues = Array.from(
|
|
105
|
-
new Set(
|
|
79
|
+
new Set(
|
|
80
|
+
lastestFormValueToArray.filter(
|
|
81
|
+
value => value !== lastestFormValueToArray[tokenIndex]
|
|
82
|
+
)
|
|
83
|
+
)
|
|
106
84
|
);
|
|
107
85
|
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
return setValue(
|
|
86
|
+
setValue(
|
|
111
87
|
name as string,
|
|
112
88
|
filteredUniqueValues.toString().replace(/\s/g, ''),
|
|
113
89
|
{
|
|
@@ -115,68 +91,15 @@ const StackedPilledInput = React.forwardRef<
|
|
|
115
91
|
shouldDirty: true,
|
|
116
92
|
}
|
|
117
93
|
);
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
if (!localValue.trim().length && lastestFormValueToArray.length) {
|
|
121
|
-
if (e.key === 'Backspace' && tokenIndex !== null) {
|
|
122
|
-
setLocalValue(
|
|
123
|
-
lastestFormValueToArray[tokenIndex].substring(
|
|
124
|
-
0,
|
|
125
|
-
lastestFormValueToArray[tokenIndex].length
|
|
126
|
-
)
|
|
127
|
-
);
|
|
128
|
-
|
|
129
|
-
const filteredUniqueValues = Array.from(
|
|
130
|
-
new Set(
|
|
131
|
-
[...lastestFormValueToArray].filter(
|
|
132
|
-
value => value !== lastestFormValueToArray[tokenIndex]
|
|
133
|
-
)
|
|
134
|
-
)
|
|
135
|
-
);
|
|
136
94
|
|
|
137
|
-
|
|
138
|
-
name as string,
|
|
139
|
-
filteredUniqueValues.toString().replace(/\s/g, ''),
|
|
140
|
-
{
|
|
141
|
-
shouldValidate: true,
|
|
142
|
-
shouldDirty: true,
|
|
143
|
-
}
|
|
144
|
-
);
|
|
145
|
-
|
|
146
|
-
return setTokenIndex(null);
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
if (e.key === 'ArrowLeft') {
|
|
150
|
-
if (tokenIndex === 0) return;
|
|
151
|
-
|
|
152
|
-
if (!tokenIndex) {
|
|
153
|
-
return setTokenIndex(lastestFormValueToArray.length - 1);
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
return setTokenIndex(
|
|
157
|
-
prevTokenIndex => (prevTokenIndex as number) - 1
|
|
158
|
-
);
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
if (e.key === 'ArrowRight') {
|
|
162
|
-
if (tokenIndex === null) return;
|
|
163
|
-
|
|
164
|
-
if (tokenIndex === lastestFormValueToArray.length - 1) {
|
|
165
|
-
return setTokenIndex(null);
|
|
166
|
-
}
|
|
167
|
-
return setTokenIndex(
|
|
168
|
-
prevTokenIndex => (prevTokenIndex as number) + 1
|
|
169
|
-
);
|
|
170
|
-
}
|
|
95
|
+
return setTokenIndex(null);
|
|
171
96
|
}
|
|
172
|
-
};
|
|
173
97
|
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
(_, i) => i !== index
|
|
98
|
+
const filteredUniqueValues = Array.from(
|
|
99
|
+
new Set([...lastestFormValueToArray, ...localValue.trim().split(',')])
|
|
177
100
|
);
|
|
178
101
|
|
|
179
|
-
|
|
102
|
+
setLocalValue('');
|
|
180
103
|
|
|
181
104
|
setValue(
|
|
182
105
|
name as string,
|
|
@@ -186,20 +109,25 @@ const StackedPilledInput = React.forwardRef<
|
|
|
186
109
|
shouldDirty: true,
|
|
187
110
|
}
|
|
188
111
|
);
|
|
189
|
-
};
|
|
190
112
|
|
|
191
|
-
|
|
192
|
-
|
|
113
|
+
return setIsFocussed(false);
|
|
114
|
+
}
|
|
193
115
|
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
116
|
+
if (!localValue.trim().length && lastestFormValueToArray.length) {
|
|
117
|
+
if (e.key === 'Backspace' && tokenIndex !== null) {
|
|
118
|
+
setLocalValue(
|
|
119
|
+
lastestFormValueToArray[tokenIndex].substring(
|
|
120
|
+
0,
|
|
121
|
+
lastestFormValueToArray[tokenIndex].length
|
|
122
|
+
)
|
|
123
|
+
);
|
|
200
124
|
|
|
201
125
|
const filteredUniqueValues = Array.from(
|
|
202
|
-
new Set(
|
|
126
|
+
new Set(
|
|
127
|
+
[...lastestFormValueToArray].filter(
|
|
128
|
+
value => value !== lastestFormValueToArray[tokenIndex]
|
|
129
|
+
)
|
|
130
|
+
)
|
|
203
131
|
);
|
|
204
132
|
|
|
205
133
|
setValue(
|
|
@@ -210,94 +138,158 @@ const StackedPilledInput = React.forwardRef<
|
|
|
210
138
|
shouldDirty: true,
|
|
211
139
|
}
|
|
212
140
|
);
|
|
213
|
-
|
|
141
|
+
|
|
142
|
+
return setTokenIndex(null);
|
|
214
143
|
}
|
|
215
|
-
setIsFocussed(false);
|
|
216
|
-
};
|
|
217
144
|
|
|
218
|
-
|
|
145
|
+
if (e.key === 'ArrowLeft') {
|
|
146
|
+
if (tokenIndex === 0) return;
|
|
219
147
|
|
|
220
|
-
|
|
221
|
-
|
|
148
|
+
if (!tokenIndex) {
|
|
149
|
+
return setTokenIndex(lastestFormValueToArray.length - 1);
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
return setTokenIndex(prevTokenIndex => (prevTokenIndex as number) - 1);
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
if (e.key === 'ArrowRight') {
|
|
156
|
+
if (tokenIndex === null) return;
|
|
157
|
+
|
|
158
|
+
if (tokenIndex === lastestFormValueToArray.length - 1) {
|
|
159
|
+
return setTokenIndex(null);
|
|
160
|
+
}
|
|
161
|
+
return setTokenIndex(prevTokenIndex => (prevTokenIndex as number) + 1);
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
};
|
|
165
|
+
|
|
166
|
+
const onRemoveTag = (index: number) => {
|
|
167
|
+
const filteredUniqueValues = lastestFormValueToArray.filter(
|
|
168
|
+
(_, i) => i !== index
|
|
169
|
+
);
|
|
170
|
+
|
|
171
|
+
setLatestFormValueToArray(filteredUniqueValues);
|
|
172
|
+
|
|
173
|
+
setValue(
|
|
174
|
+
name as string,
|
|
175
|
+
filteredUniqueValues.toString().replace(/\s/g, ''),
|
|
176
|
+
{
|
|
177
|
+
shouldValidate: true,
|
|
178
|
+
shouldDirty: true,
|
|
179
|
+
}
|
|
180
|
+
);
|
|
181
|
+
};
|
|
182
|
+
|
|
183
|
+
const onBlur = () => {
|
|
184
|
+
clearErrors(name);
|
|
185
|
+
|
|
186
|
+
if (localValue.trim()) {
|
|
187
|
+
const filteredUniqueValues = Array.from(
|
|
188
|
+
new Set([...lastestFormValueToArray, ...localValue.trim().split(',')])
|
|
189
|
+
);
|
|
190
|
+
|
|
191
|
+
setValue(
|
|
192
|
+
name as string,
|
|
193
|
+
filteredUniqueValues.toString().replace(/\s/g, ''),
|
|
194
|
+
{
|
|
195
|
+
shouldValidate: true,
|
|
196
|
+
shouldDirty: true,
|
|
197
|
+
}
|
|
198
|
+
);
|
|
199
|
+
setLocalValue('');
|
|
200
|
+
}
|
|
201
|
+
setIsFocussed(false);
|
|
202
|
+
};
|
|
203
|
+
|
|
204
|
+
useOutsideClick({ ref: inputWrapperRef, handler: onBlur });
|
|
205
|
+
|
|
206
|
+
return (
|
|
207
|
+
<Box position="relative">
|
|
208
|
+
<Flex
|
|
209
|
+
fontSize="13px"
|
|
210
|
+
border={isFocussed ? '2px solid' : '1px solid'}
|
|
211
|
+
borderColor={isFocussed ? colors.border.focus : colors.border.default}
|
|
212
|
+
py="5px"
|
|
213
|
+
pl="8px"
|
|
214
|
+
borderRadius="4px"
|
|
215
|
+
alignItems="center"
|
|
216
|
+
justifyContent="space-between"
|
|
217
|
+
onClick={() => {
|
|
218
|
+
if (!disabled) {
|
|
219
|
+
inputRef.current?.focus();
|
|
220
|
+
}
|
|
221
|
+
}}
|
|
222
|
+
bg={disabled ? colors.fill.light.quaternary : '#ffffff'}
|
|
223
|
+
cursor={disabled ? 'not-allowed' : 'pointer'}
|
|
224
|
+
ref={inputWrapperRef}
|
|
225
|
+
h="26px"
|
|
226
|
+
>
|
|
222
227
|
<Flex
|
|
223
|
-
|
|
224
|
-
border={isFocussed ? '2px solid' : '1px solid'}
|
|
225
|
-
borderColor={isFocussed ? colors.border.focus : colors.border.default}
|
|
226
|
-
py="5px"
|
|
227
|
-
pl="8px"
|
|
228
|
-
borderRadius="4px"
|
|
228
|
+
h="18px"
|
|
229
229
|
alignItems="center"
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
230
|
+
// width="fit-content"
|
|
231
|
+
// maxW="80%"
|
|
232
|
+
overflowX="scroll"
|
|
233
|
+
style={{
|
|
234
|
+
scrollbarWidth: 'none' /* Firefox */,
|
|
235
|
+
msOverflowStyle: 'none',
|
|
235
236
|
}}
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
237
|
+
sx={{
|
|
238
|
+
'::-webkit-scrollbar': {
|
|
239
|
+
display: 'none',
|
|
240
|
+
},
|
|
241
|
+
}}
|
|
242
|
+
ref={scrollRef}
|
|
239
243
|
>
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
onRemoveTag(index);
|
|
269
|
-
}}
|
|
270
|
-
/>
|
|
271
|
-
</Box>
|
|
272
|
-
))
|
|
273
|
-
) : (
|
|
274
|
-
<Text color={colors.label.secondary.light} fontSize="13px">
|
|
275
|
-
{placeholder}
|
|
276
|
-
</Text>
|
|
277
|
-
)}
|
|
278
|
-
</Flex>
|
|
279
|
-
<Flex flex={1}>
|
|
280
|
-
<Input
|
|
281
|
-
onKeyDown={onHandleKeyDown}
|
|
282
|
-
type="text"
|
|
283
|
-
padding={0}
|
|
284
|
-
width="100%"
|
|
285
|
-
border="none"
|
|
286
|
-
height="26px"
|
|
287
|
-
color={tokenIndex !== null ? 'transparent' : colors.label.primary}
|
|
288
|
-
_focus={{ boxShadow: 'none !important' }}
|
|
289
|
-
value={localValue}
|
|
290
|
-
onChange={e =>
|
|
291
|
-
tokenIndex === null && setLocalValue(e.target.value)
|
|
292
|
-
}
|
|
293
|
-
ref={inputRef}
|
|
294
|
-
onFocus={() => setIsFocussed(true)}
|
|
295
|
-
/>
|
|
296
|
-
</Flex>
|
|
244
|
+
{lastestFormValueToArray.length ? (
|
|
245
|
+
lastestFormValueToArray.map((label, index) => (
|
|
246
|
+
<Box
|
|
247
|
+
mr="4px"
|
|
248
|
+
border={
|
|
249
|
+
tokenIndex === index
|
|
250
|
+
? `1px solid ${colors.border.focus}`
|
|
251
|
+
: 'none'
|
|
252
|
+
}
|
|
253
|
+
borderRadius="full"
|
|
254
|
+
onClick={() => setTokenIndex(index)}
|
|
255
|
+
width="100%"
|
|
256
|
+
>
|
|
257
|
+
<Token
|
|
258
|
+
label={label}
|
|
259
|
+
onDelete={(e: any) => {
|
|
260
|
+
e.stopPropagation();
|
|
261
|
+
e.preventDefault();
|
|
262
|
+
onRemoveTag(index);
|
|
263
|
+
}}
|
|
264
|
+
/>
|
|
265
|
+
</Box>
|
|
266
|
+
))
|
|
267
|
+
) : (
|
|
268
|
+
<Text color={colors.label.secondary.light} fontSize="13px">
|
|
269
|
+
{placeholder}
|
|
270
|
+
</Text>
|
|
271
|
+
)}
|
|
297
272
|
</Flex>
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
273
|
+
<Flex flex={1}>
|
|
274
|
+
<Input
|
|
275
|
+
onKeyDown={onHandleKeyDown}
|
|
276
|
+
type="text"
|
|
277
|
+
padding={0}
|
|
278
|
+
width="100%"
|
|
279
|
+
border="none"
|
|
280
|
+
height="auto"
|
|
281
|
+
color={tokenIndex !== null ? 'transparent' : colors.label.primary}
|
|
282
|
+
_focus={{ boxShadow: 'none !important' }}
|
|
283
|
+
value={localValue}
|
|
284
|
+
onChange={e => tokenIndex === null && setLocalValue(e.target.value)}
|
|
285
|
+
ref={inputRef}
|
|
286
|
+
onFocus={() => setIsFocussed(true)}
|
|
287
|
+
onBlur={() => setIsFocussed(false)}
|
|
288
|
+
/>
|
|
289
|
+
</Flex>
|
|
290
|
+
</Flex>
|
|
291
|
+
</Box>
|
|
292
|
+
);
|
|
293
|
+
});
|
|
302
294
|
|
|
303
295
|
export default StackedPilledInput;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import React, { useRef, useState } from 'react';
|
|
1
|
+
import React, { useEffect, useRef, useState } from 'react';
|
|
2
2
|
import {
|
|
3
3
|
Box,
|
|
4
4
|
Image,
|
|
@@ -30,11 +30,24 @@ const StackedSelect = React.forwardRef<HTMLInputElement, StackedSelectProps>(
|
|
|
30
30
|
{ isRequired, options, name, setValue, handleOnChange, value, ...props },
|
|
31
31
|
_ref
|
|
32
32
|
) => {
|
|
33
|
-
const dropdownRef = useRef(null);
|
|
33
|
+
const dropdownRef = useRef<HTMLDivElement>(null);
|
|
34
|
+
const dropdownMenuRef = useRef<HTMLDivElement>(null);
|
|
35
|
+
|
|
34
36
|
const [isFocussed, setIsFocussed] = useState(false);
|
|
35
37
|
const [selectedOption, setSelectedOption] = useState(
|
|
36
38
|
options.find(option => option.value === value)?.label ?? ''
|
|
37
39
|
);
|
|
40
|
+
const [position, setPosition] = useState<'top' | 'bottom'>('top');
|
|
41
|
+
|
|
42
|
+
useEffect(() => {
|
|
43
|
+
const boundingClientRect = dropdownRef.current?.getBoundingClientRect() as DOMRect;
|
|
44
|
+
|
|
45
|
+
if (document.body.clientHeight - (boundingClientRect?.y + 240) >= 0) {
|
|
46
|
+
setPosition('top');
|
|
47
|
+
} else {
|
|
48
|
+
setPosition('bottom');
|
|
49
|
+
}
|
|
50
|
+
}, [dropdownRef]);
|
|
38
51
|
|
|
39
52
|
useDidMountEffect(() => {
|
|
40
53
|
setSelectedOption(
|
|
@@ -71,6 +84,23 @@ const StackedSelect = React.forwardRef<HTMLInputElement, StackedSelectProps>(
|
|
|
71
84
|
textShadow={`0 0 0 ${colors.label.primary.light}`}
|
|
72
85
|
value={selectedOption}
|
|
73
86
|
autoComplete="off"
|
|
87
|
+
onKeyDown={e => {
|
|
88
|
+
if (isFocussed) {
|
|
89
|
+
if (e.key === 'Tab') {
|
|
90
|
+
return setIsFocussed(false);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
const idx = options.findIndex(
|
|
94
|
+
option => option.label[0].toLocaleLowerCase() === e.key
|
|
95
|
+
);
|
|
96
|
+
console.log(idx);
|
|
97
|
+
|
|
98
|
+
dropdownMenuRef.current?.scrollTo({
|
|
99
|
+
top: idx * 27,
|
|
100
|
+
behavior: 'smooth',
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
}}
|
|
74
104
|
/>
|
|
75
105
|
<InputRightElement
|
|
76
106
|
cursor="pointer"
|
|
@@ -81,6 +111,8 @@ const StackedSelect = React.forwardRef<HTMLInputElement, StackedSelectProps>(
|
|
|
81
111
|
</InputGroup>
|
|
82
112
|
{isFocussed && (
|
|
83
113
|
<Dropdown
|
|
114
|
+
position={position}
|
|
115
|
+
dropdownRef={dropdownMenuRef}
|
|
84
116
|
onSelectItem={option => handleOnSelectItem(option)}
|
|
85
117
|
options={options}
|
|
86
118
|
/>
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import { Switch, SwitchProps } from '@chakra-ui/react';
|
|
3
|
+
import colors from '../../../theme/foundations/colors';
|
|
3
4
|
|
|
4
5
|
export interface StackedSwitchProps extends SwitchProps {}
|
|
5
6
|
|
|
@@ -8,9 +9,16 @@ export interface StackedSwitchProps extends SwitchProps {}
|
|
|
8
9
|
*/
|
|
9
10
|
const StackedSwitch = React.forwardRef<HTMLInputElement, StackedSwitchProps>(
|
|
10
11
|
({ isRequired, onChange, value }, _ref) => {
|
|
12
|
+
if (value === null) return null;
|
|
13
|
+
|
|
11
14
|
return (
|
|
12
15
|
<Switch
|
|
13
|
-
|
|
16
|
+
h="26px"
|
|
17
|
+
mx="4px"
|
|
18
|
+
_focus={{
|
|
19
|
+
border: '2px solid',
|
|
20
|
+
borderColor: colors.border.focus,
|
|
21
|
+
}}
|
|
14
22
|
ref={_ref}
|
|
15
23
|
isRequired={isRequired}
|
|
16
24
|
value={String(value)}
|
|
@@ -11,7 +11,7 @@ const StackedTextarea = React.forwardRef<
|
|
|
11
11
|
HTMLTextAreaElement,
|
|
12
12
|
StackedTextareaProps
|
|
13
13
|
>(({ ...props }, _ref) => {
|
|
14
|
-
return <Textarea ref={_ref} {...props} />;
|
|
14
|
+
return <Textarea ref={_ref} {...props} fontSize="13px" />;
|
|
15
15
|
});
|
|
16
16
|
|
|
17
17
|
export default StackedTextarea;
|
|
@@ -1,11 +1,13 @@
|
|
|
1
|
-
import React, { useMemo } from 'react';
|
|
2
|
-
import { Box } from '@chakra-ui/react';
|
|
1
|
+
import React, { RefObject, useMemo } from 'react';
|
|
2
|
+
import { Box, Flex } from '@chakra-ui/react';
|
|
3
3
|
import colors from '../../../../../src/theme/foundations/colors';
|
|
4
4
|
import { FieldOption, FieldOptions } from '../../InputTypes';
|
|
5
5
|
|
|
6
6
|
export interface DropdownProps {
|
|
7
7
|
onSelectItem: (option: FieldOption) => void;
|
|
8
8
|
options: FieldOptions;
|
|
9
|
+
dropdownRef: RefObject<HTMLDivElement>;
|
|
10
|
+
position: 'top' | 'bottom';
|
|
9
11
|
}
|
|
10
12
|
|
|
11
13
|
/**
|
|
@@ -14,6 +16,8 @@ export interface DropdownProps {
|
|
|
14
16
|
export const Dropdown: React.FC<DropdownProps> = ({
|
|
15
17
|
onSelectItem,
|
|
16
18
|
options,
|
|
19
|
+
dropdownRef,
|
|
20
|
+
position,
|
|
17
21
|
}) => {
|
|
18
22
|
const DropdownContent = useMemo(() => {
|
|
19
23
|
return options.map((option, idx) => (
|
|
@@ -24,12 +28,15 @@ export const Dropdown: React.FC<DropdownProps> = ({
|
|
|
24
28
|
<Box
|
|
25
29
|
color={colors.label.secondary.light}
|
|
26
30
|
fontSize="13px"
|
|
31
|
+
width="fit-content"
|
|
27
32
|
fontWeight="bold"
|
|
28
33
|
px="8px"
|
|
29
34
|
bg="inherit"
|
|
35
|
+
whiteSpace="nowrap"
|
|
30
36
|
>
|
|
31
37
|
{idx > 0 && (
|
|
32
38
|
<Box
|
|
39
|
+
width="100%"
|
|
33
40
|
my="3px"
|
|
34
41
|
borderTop="2px solid"
|
|
35
42
|
borderColor={colors.border.default}
|
|
@@ -47,13 +54,16 @@ export const Dropdown: React.FC<DropdownProps> = ({
|
|
|
47
54
|
fontSize="13px"
|
|
48
55
|
px="8px"
|
|
49
56
|
py="4px"
|
|
57
|
+
width="fit-content"
|
|
50
58
|
color={colors.label.primary.light}
|
|
51
59
|
_hover={{
|
|
52
60
|
color: colors.label.primary.dark,
|
|
53
61
|
bg: colors.fill.action,
|
|
54
62
|
borderRadius: '4px',
|
|
63
|
+
width: '100%',
|
|
55
64
|
}}
|
|
56
65
|
bg="inherit"
|
|
66
|
+
whiteSpace="nowrap"
|
|
57
67
|
>
|
|
58
68
|
{option.label}
|
|
59
69
|
</Box>
|
|
@@ -63,7 +73,10 @@ export const Dropdown: React.FC<DropdownProps> = ({
|
|
|
63
73
|
}, [onSelectItem, options]);
|
|
64
74
|
|
|
65
75
|
return (
|
|
66
|
-
<
|
|
76
|
+
<Flex
|
|
77
|
+
flexDirection="column"
|
|
78
|
+
ref={dropdownRef}
|
|
79
|
+
scrollMargin="15px"
|
|
67
80
|
bg={colors.fill.light.quaternary}
|
|
68
81
|
backdropFilter="auto"
|
|
69
82
|
backdropBlur="64px"
|
|
@@ -71,15 +84,19 @@ export const Dropdown: React.FC<DropdownProps> = ({
|
|
|
71
84
|
border="0.25px solid"
|
|
72
85
|
borderColor={colors.fill.light.tertiary}
|
|
73
86
|
mt="3px"
|
|
74
|
-
maxH="
|
|
87
|
+
maxH="240px"
|
|
75
88
|
overflowY="auto"
|
|
76
89
|
px="8px"
|
|
77
90
|
py="4px"
|
|
78
91
|
position="absolute"
|
|
79
|
-
|
|
92
|
+
top={position === 'top' ? 26 : undefined}
|
|
93
|
+
bottom={position === 'bottom' ? 30 : undefined}
|
|
94
|
+
width="fit-content"
|
|
95
|
+
minWidth="100%"
|
|
80
96
|
zIndex={100}
|
|
97
|
+
tabIndex={-2000}
|
|
81
98
|
>
|
|
82
99
|
{DropdownContent}
|
|
83
|
-
</
|
|
100
|
+
</Flex>
|
|
84
101
|
);
|
|
85
102
|
};
|