@pushwoosh/dumb-components 2.9.14 → 2.9.16
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/Combobox/types.d.ts +1 -1
- package/ComboboxMulti/types.d.ts +1 -1
- package/package.json +1 -1
- package/shared/dropdownField/SuggestionsDropdown.js +37 -2
- package/shared/dropdownField/constants.d.ts +1 -1
- package/shared/dropdownField/constants.js +1 -1
- package/shared/dropdownField/useDropdownPosition.d.ts +1 -1
- package/shared/dropdownField/useDropdownPosition.js +2 -2
package/Combobox/types.d.ts
CHANGED
|
@@ -54,7 +54,7 @@ type CommonProps<T> = {
|
|
|
54
54
|
width?: string;
|
|
55
55
|
/** Minimum CSS width, useful together with `autosize`. */
|
|
56
56
|
minWidth?: string;
|
|
57
|
-
/**
|
|
57
|
+
/** Make the dropdown exactly as wide as the field instead of capping at the default width. */
|
|
58
58
|
fullWidth?: boolean;
|
|
59
59
|
};
|
|
60
60
|
/**
|
package/ComboboxMulti/types.d.ts
CHANGED
|
@@ -57,7 +57,7 @@ export type ComboboxMultiProps<T> = ItemsSource<T> & GetKeyProp<T> & CreatablePr
|
|
|
57
57
|
width?: string;
|
|
58
58
|
/** Minimum CSS width, useful together with `autosize`. */
|
|
59
59
|
minWidth?: string;
|
|
60
|
-
/**
|
|
60
|
+
/** Make the dropdown exactly as wide as the field instead of capping at the default width. */
|
|
61
61
|
fullWidth?: boolean;
|
|
62
62
|
};
|
|
63
63
|
export {};
|
package/package.json
CHANGED
|
@@ -5,6 +5,7 @@ import { CreateItemLabel, Dropdown, DropdownEmpty, DropdownItem, DropdownLoading
|
|
|
5
5
|
import { Spinner } from '../../Spinner';
|
|
6
6
|
const LOAD_MORE_THRESHOLD = 24;
|
|
7
7
|
const CREATE_KEY = '__create__';
|
|
8
|
+
const TOUCH_SCROLL_THRESHOLD = 8;
|
|
8
9
|
/**
|
|
9
10
|
* Internal floating option list shared by the Combobox family: renders the rows,
|
|
10
11
|
* empty/loading text, an optional "create" row and load-more support.
|
|
@@ -34,10 +35,44 @@ export function SuggestionsDropdown({
|
|
|
34
35
|
const activeItem = items.find(item => item.active);
|
|
35
36
|
const activeKey = createActive ? CREATE_KEY : activeItem?.key ?? null;
|
|
36
37
|
useEffect(() => {
|
|
37
|
-
if (activeKey === null) return;
|
|
38
|
-
activeItemRef.current?.scrollIntoView({
|
|
38
|
+
if (activeKey === null) return undefined;
|
|
39
|
+
const scrollToActive = () => activeItemRef.current?.scrollIntoView({
|
|
39
40
|
block: 'nearest'
|
|
40
41
|
});
|
|
42
|
+
scrollToActive();
|
|
43
|
+
const list = activeItemRef.current?.parentElement;
|
|
44
|
+
if (!list || typeof ResizeObserver === 'undefined') return undefined;
|
|
45
|
+
const observer = new ResizeObserver(scrollToActive);
|
|
46
|
+
const stopFollowing = () => observer.disconnect();
|
|
47
|
+
const onScrollbarPointerDown = event => {
|
|
48
|
+
if (event.target === list) stopFollowing();
|
|
49
|
+
};
|
|
50
|
+
let touchStartY = null;
|
|
51
|
+
const onTouchStart = event => {
|
|
52
|
+
touchStartY = event.touches[0]?.clientY ?? null;
|
|
53
|
+
};
|
|
54
|
+
const onTouchMove = event => {
|
|
55
|
+
const y = event.touches[0]?.clientY;
|
|
56
|
+
if (touchStartY !== null && y !== undefined && Math.abs(y - touchStartY) > TOUCH_SCROLL_THRESHOLD) stopFollowing();
|
|
57
|
+
};
|
|
58
|
+
observer.observe(list);
|
|
59
|
+
list.addEventListener('wheel', stopFollowing, {
|
|
60
|
+
passive: true
|
|
61
|
+
});
|
|
62
|
+
list.addEventListener('touchstart', onTouchStart, {
|
|
63
|
+
passive: true
|
|
64
|
+
});
|
|
65
|
+
list.addEventListener('touchmove', onTouchMove, {
|
|
66
|
+
passive: true
|
|
67
|
+
});
|
|
68
|
+
list.addEventListener('pointerdown', onScrollbarPointerDown);
|
|
69
|
+
return () => {
|
|
70
|
+
observer.disconnect();
|
|
71
|
+
list.removeEventListener('wheel', stopFollowing);
|
|
72
|
+
list.removeEventListener('touchstart', onTouchStart);
|
|
73
|
+
list.removeEventListener('touchmove', onTouchMove);
|
|
74
|
+
list.removeEventListener('pointerdown', onScrollbarPointerDown);
|
|
75
|
+
};
|
|
41
76
|
}, [activeKey]);
|
|
42
77
|
if (typeof document === 'undefined') return null;
|
|
43
78
|
const isEmpty = !loading && items.length === 0 && !createLabel;
|
|
@@ -2,7 +2,7 @@ import { Color } from '@pushwoosh/kit-constants';
|
|
|
2
2
|
export declare const LOADING_BORDER_COLORS: readonly [Color.PRIMARY, Color.BRIGHT, Color.BRAND_GREEN, Color.EXCEPTIONAL];
|
|
3
3
|
export declare const LOADING_BORDER_ANIMATION_MS = 3000;
|
|
4
4
|
export declare const DROPDOWN_MAX_HEIGHT = 300;
|
|
5
|
-
/** Default dropdown width cap.
|
|
5
|
+
/** Default dropdown width cap. With `fullWidth` the dropdown matches the field width instead. */
|
|
6
6
|
export declare const DROPDOWN_DEFAULT_WIDTH = 320;
|
|
7
7
|
/** Default debounce (ms) before an async `loadItems` call fires after the query changes. */
|
|
8
8
|
export declare const DEFAULT_DEBOUNCE_MS = 250;
|
|
@@ -2,7 +2,7 @@ import { Color } from '@pushwoosh/kit-constants';
|
|
|
2
2
|
export const LOADING_BORDER_COLORS = [Color.PRIMARY, Color.BRIGHT, Color.BRAND_GREEN, Color.EXCEPTIONAL];
|
|
3
3
|
export const LOADING_BORDER_ANIMATION_MS = 3000;
|
|
4
4
|
export const DROPDOWN_MAX_HEIGHT = 300;
|
|
5
|
-
/** Default dropdown width cap.
|
|
5
|
+
/** Default dropdown width cap. With `fullWidth` the dropdown matches the field width instead. */
|
|
6
6
|
export const DROPDOWN_DEFAULT_WIDTH = 320;
|
|
7
7
|
/** Default debounce (ms) before an async `loadItems` call fires after the query changes. */
|
|
8
8
|
export const DEFAULT_DEBOUNCE_MS = 250;
|
|
@@ -6,7 +6,7 @@ type Args = {
|
|
|
6
6
|
/**
|
|
7
7
|
* Positions the dropdown relative to the field via floating-ui (flip, offset,
|
|
8
8
|
* width/height sizing) and wires click-outside to `onClickOutside`. With
|
|
9
|
-
* `fullWidth` the dropdown
|
|
9
|
+
* `fullWidth` the dropdown is exactly as wide as the field instead of capping at
|
|
10
10
|
* `DROPDOWN_DEFAULT_WIDTH`.
|
|
11
11
|
*/
|
|
12
12
|
export declare function useDropdownPosition({ isOpen, onClickOutside, fullWidth }: Args): {
|
|
@@ -4,7 +4,7 @@ import { useOnClickOutside } from '../../hooks';
|
|
|
4
4
|
/**
|
|
5
5
|
* Positions the dropdown relative to the field via floating-ui (flip, offset,
|
|
6
6
|
* width/height sizing) and wires click-outside to `onClickOutside`. With
|
|
7
|
-
* `fullWidth` the dropdown
|
|
7
|
+
* `fullWidth` the dropdown is exactly as wide as the field instead of capping at
|
|
8
8
|
* `DROPDOWN_DEFAULT_WIDTH`.
|
|
9
9
|
*/
|
|
10
10
|
export function useDropdownPosition({
|
|
@@ -27,7 +27,7 @@ export function useDropdownPosition({
|
|
|
27
27
|
availableHeight
|
|
28
28
|
}) {
|
|
29
29
|
const fieldWidth = rects.reference.width;
|
|
30
|
-
const maxWidth =
|
|
30
|
+
const maxWidth = Math.min(fullWidth ? fieldWidth : DROPDOWN_DEFAULT_WIDTH, availableWidth);
|
|
31
31
|
const minWidth = Math.min(fieldWidth, maxWidth);
|
|
32
32
|
Object.assign(elements.floating.style, {
|
|
33
33
|
minWidth: `${minWidth}px`,
|