@bitrise/bitkit 10.20.1 → 10.21.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
CHANGED
|
@@ -31,6 +31,13 @@ const TestComponent = forwardRef<
|
|
|
31
31
|
});
|
|
32
32
|
|
|
33
33
|
describe('Dropdown', () => {
|
|
34
|
+
it('sets ref to the button', async () => {
|
|
35
|
+
const handler = jest.fn();
|
|
36
|
+
render(<Dropdown ref={handler} />);
|
|
37
|
+
const button = await screen.findByRole('combobox');
|
|
38
|
+
expect(handler).toHaveBeenCalledWith(button);
|
|
39
|
+
});
|
|
40
|
+
|
|
34
41
|
it('shows option on button', async () => {
|
|
35
42
|
render(<TestComponent submit={() => {}} />);
|
|
36
43
|
const button = await screen.findByRole('combobox', { name: 'Test' });
|
|
@@ -1,14 +1,4 @@
|
|
|
1
|
-
import React, {
|
|
2
|
-
cloneElement,
|
|
3
|
-
forwardRef,
|
|
4
|
-
ReactNode,
|
|
5
|
-
useCallback,
|
|
6
|
-
useEffect,
|
|
7
|
-
useImperativeHandle,
|
|
8
|
-
useMemo,
|
|
9
|
-
useRef,
|
|
10
|
-
useState,
|
|
11
|
-
} from 'react';
|
|
1
|
+
import React, { cloneElement, forwardRef, ReactNode, useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
|
12
2
|
import {
|
|
13
3
|
chakra,
|
|
14
4
|
ChakraProps,
|
|
@@ -18,7 +8,7 @@ import {
|
|
|
18
8
|
useControllableState,
|
|
19
9
|
useMultiStyleConfig,
|
|
20
10
|
} from '@chakra-ui/react';
|
|
21
|
-
import { FloatingFocusManager } from '@floating-ui/react-dom-interactions';
|
|
11
|
+
import { FloatingFocusManager, UseFloatingProps } from '@floating-ui/react-dom-interactions';
|
|
22
12
|
import Icon, { TypeIconName } from '../Icon/Icon';
|
|
23
13
|
import { DropdownEventArgs, DropdownProvider, useDropdownContext, useDropdownStyles } from './Dropdown.context';
|
|
24
14
|
import { DropdownOption, DropdownGroup, DropdownDetailedOption, DropdownOptionProps } from './DropdownOption';
|
|
@@ -95,6 +85,8 @@ export interface DropdownProps<T> extends ChakraProps {
|
|
|
95
85
|
size?: 'small' | 'medium';
|
|
96
86
|
dropdownMaxHeight?: ChakraProps['maxH'];
|
|
97
87
|
dropdownMinHeight?: ChakraProps['minH'];
|
|
88
|
+
dropdownWidth?: ChakraProps['width'] | 'match';
|
|
89
|
+
placement?: UseFloatingProps['placement'];
|
|
98
90
|
readOnly?: boolean;
|
|
99
91
|
disabled?: boolean;
|
|
100
92
|
placeholder?: string;
|
|
@@ -102,7 +94,7 @@ export interface DropdownProps<T> extends ChakraProps {
|
|
|
102
94
|
search?: ReactNode;
|
|
103
95
|
children?: ReactNode;
|
|
104
96
|
iconName?: TypeIconName;
|
|
105
|
-
formLabel?:
|
|
97
|
+
formLabel?: ReactNode;
|
|
106
98
|
}
|
|
107
99
|
|
|
108
100
|
function useOptionListWithIndexes({ children }: { children: ReactNode }) {
|
|
@@ -132,8 +124,8 @@ function useOptionListWithIndexes({ children }: { children: ReactNode }) {
|
|
|
132
124
|
}, [children]);
|
|
133
125
|
}
|
|
134
126
|
|
|
135
|
-
type UseDropdownProps
|
|
136
|
-
ref: React.Ref<
|
|
127
|
+
type UseDropdownProps = {
|
|
128
|
+
ref: React.Ref<Element>;
|
|
137
129
|
optionsRef: React.RefObject<HTMLDivElement>;
|
|
138
130
|
};
|
|
139
131
|
|
|
@@ -162,11 +154,13 @@ function useDropdown<T>({
|
|
|
162
154
|
value,
|
|
163
155
|
optionsRef,
|
|
164
156
|
defaultValue,
|
|
157
|
+
dropdownWidth = 'match',
|
|
158
|
+
placement,
|
|
165
159
|
ref,
|
|
166
160
|
children,
|
|
167
161
|
readOnly,
|
|
168
162
|
...rest
|
|
169
|
-
}: DropdownProps<T> & UseDropdownProps
|
|
163
|
+
}: DropdownProps<T> & UseDropdownProps) {
|
|
170
164
|
const searchRef = useRef(null);
|
|
171
165
|
const {
|
|
172
166
|
close,
|
|
@@ -179,7 +173,7 @@ function useDropdown<T>({
|
|
|
179
173
|
setActiveIndex,
|
|
180
174
|
getItemProps,
|
|
181
175
|
listRef,
|
|
182
|
-
} = useFloatingDropdown({ enabled: !readOnly, optionsRef });
|
|
176
|
+
} = useFloatingDropdown({ enabled: !readOnly, optionsRef, dropdownWidth, placement });
|
|
183
177
|
const [formValue, setFormValue] = useControllableState<T>({
|
|
184
178
|
onChange: (newValue) => onChange?.({ target: { value: newValue, name } }),
|
|
185
179
|
defaultValue,
|
|
@@ -187,7 +181,6 @@ function useDropdown<T>({
|
|
|
187
181
|
});
|
|
188
182
|
|
|
189
183
|
const [formLabel, setFormLabel] = useState<ReactNode>();
|
|
190
|
-
useImperativeHandle(ref, () => ({ value: formValue, name }), [formValue, name]);
|
|
191
184
|
const refdChildren = useOptionListWithIndexes({ children });
|
|
192
185
|
|
|
193
186
|
const searchOnSubmit = useCallback(() => {
|
|
@@ -251,6 +244,7 @@ function useDropdown<T>({
|
|
|
251
244
|
return {
|
|
252
245
|
isOpen,
|
|
253
246
|
referenceProps: getReferenceProps({
|
|
247
|
+
ref,
|
|
254
248
|
onKeyDown: referenceKeyDown,
|
|
255
249
|
}),
|
|
256
250
|
floatingProps,
|
|
@@ -265,11 +259,12 @@ function useDropdown<T>({
|
|
|
265
259
|
};
|
|
266
260
|
}
|
|
267
261
|
|
|
268
|
-
const Dropdown = forwardRef<
|
|
262
|
+
const Dropdown = forwardRef<Element, DropdownProps<string | null>>(
|
|
269
263
|
(
|
|
270
264
|
{
|
|
271
265
|
dropdownMaxHeight,
|
|
272
266
|
dropdownMinHeight,
|
|
267
|
+
dropdownWidth,
|
|
273
268
|
readOnly,
|
|
274
269
|
onBlur,
|
|
275
270
|
placeholder,
|
|
@@ -297,6 +292,7 @@ const Dropdown = forwardRef<DropdownInstance<string | null>, DropdownProps<strin
|
|
|
297
292
|
name,
|
|
298
293
|
readOnly,
|
|
299
294
|
optionsRef,
|
|
295
|
+
dropdownWidth,
|
|
300
296
|
ref,
|
|
301
297
|
...props,
|
|
302
298
|
});
|
|
@@ -350,7 +346,7 @@ const Dropdown = forwardRef<DropdownInstance<string | null>, DropdownProps<strin
|
|
|
350
346
|
|
|
351
347
|
export function typedDropdown<T>() {
|
|
352
348
|
return {
|
|
353
|
-
Dropdown: Dropdown as React.ForwardRefExoticComponent<DropdownProps<T> & React.RefAttributes<
|
|
349
|
+
Dropdown: Dropdown as React.ForwardRefExoticComponent<DropdownProps<T> & React.RefAttributes<Element>>,
|
|
354
350
|
DropdownOption: DropdownOption as (p: DropdownOptionProps<T>) => JSX.Element,
|
|
355
351
|
};
|
|
356
352
|
}
|
|
@@ -9,10 +9,28 @@ import {
|
|
|
9
9
|
useRole,
|
|
10
10
|
useDismiss,
|
|
11
11
|
flip,
|
|
12
|
+
UseFloatingProps,
|
|
13
|
+
MiddlewareArguments,
|
|
12
14
|
} from '@floating-ui/react-dom-interactions';
|
|
15
|
+
import { ChakraProps } from '@chakra-ui/react';
|
|
16
|
+
import { mergeRefs } from '@chakra-ui/react-utils';
|
|
13
17
|
import useAutoScroll from './useAutoScroll';
|
|
14
18
|
|
|
15
|
-
|
|
19
|
+
type ApplyFnArgs = MiddlewareArguments & {
|
|
20
|
+
availableWidth: number;
|
|
21
|
+
availableHeight: number;
|
|
22
|
+
};
|
|
23
|
+
const useFloatingDropdown = ({
|
|
24
|
+
enabled,
|
|
25
|
+
optionsRef,
|
|
26
|
+
dropdownWidth,
|
|
27
|
+
placement,
|
|
28
|
+
}: {
|
|
29
|
+
enabled: boolean;
|
|
30
|
+
optionsRef: RefObject<HTMLDivElement>;
|
|
31
|
+
dropdownWidth: ChakraProps['width'] | 'match';
|
|
32
|
+
placement: UseFloatingProps['placement'] | undefined;
|
|
33
|
+
}) => {
|
|
16
34
|
const listRef = useRef<HTMLElement[]>([]);
|
|
17
35
|
const [isOpen, setOpen] = useState(false);
|
|
18
36
|
const [activeIndex, setActiveIndex] = useState<number | null>(null);
|
|
@@ -22,18 +40,21 @@ const useFloatingDropdown = ({ enabled, optionsRef }: { enabled: boolean; option
|
|
|
22
40
|
setKeyboardControlled(true);
|
|
23
41
|
}, [isOpen]);
|
|
24
42
|
|
|
25
|
-
const
|
|
43
|
+
const widthRef = useRef(dropdownWidth);
|
|
44
|
+
widthRef.current = dropdownWidth;
|
|
45
|
+
const { context, reference, floating, strategy, x, y } = useFloating<Element>({
|
|
26
46
|
open: enabled && isOpen,
|
|
27
47
|
onOpenChange: setOpen,
|
|
48
|
+
placement,
|
|
28
49
|
whileElementsMounted(aRef, aFloat, update) {
|
|
29
50
|
return autoUpdate(aRef, aFloat, update, { elementResize: false });
|
|
30
51
|
},
|
|
31
52
|
middleware: [
|
|
32
53
|
size({
|
|
33
54
|
padding: 5,
|
|
34
|
-
apply({ elements, availableHeight, rects }) {
|
|
55
|
+
apply: ({ elements, availableHeight, rects }: ApplyFnArgs) => {
|
|
35
56
|
Object.assign(elements.floating.style, {
|
|
36
|
-
width: `${rects.reference.width}px
|
|
57
|
+
width: widthRef.current === 'match' ? `${rects.reference.width}px` : widthRef.current,
|
|
37
58
|
});
|
|
38
59
|
elements.floating.style.setProperty('--floating-available-height', `${availableHeight}px`);
|
|
39
60
|
},
|
|
@@ -91,8 +112,9 @@ const useFloatingDropdown = ({ enabled, optionsRef }: { enabled: boolean; option
|
|
|
91
112
|
activeIndex,
|
|
92
113
|
setActiveIndex,
|
|
93
114
|
setSelectedIndex,
|
|
94
|
-
getReferenceProps(props: React.HTMLProps<Element>) {
|
|
95
|
-
|
|
115
|
+
getReferenceProps({ ref, ...props }: React.HTMLProps<Element>) {
|
|
116
|
+
const merged = mergeRefs(ref as any, reference);
|
|
117
|
+
return getReferenceProps({ ...props, ref: merged });
|
|
96
118
|
},
|
|
97
119
|
floatingProps: getFloatingProps({
|
|
98
120
|
ref: floating,
|