@gooddata/sdk-ui-kit 11.14.0-alpha.2 → 11.14.0-alpha.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/esm/@ui/UiDropdown/UiDropdown.d.ts +19 -0
- package/esm/@ui/UiDropdown/UiDropdown.d.ts.map +1 -0
- package/esm/@ui/UiDropdown/UiDropdown.js +125 -0
- package/esm/@ui/UiDropdown/UiDropdown.js.map +1 -0
- package/esm/@ui/UiDropdown/types.d.ts +167 -0
- package/esm/@ui/UiDropdown/types.d.ts.map +1 -0
- package/esm/@ui/UiDropdown/types.js +3 -0
- package/esm/@ui/UiDropdown/types.js.map +1 -0
- package/esm/@ui/UiFloatingElement/UiFloatingElement.d.ts +20 -0
- package/esm/@ui/UiFloatingElement/UiFloatingElement.d.ts.map +1 -0
- package/esm/@ui/UiFloatingElement/UiFloatingElement.js +92 -0
- package/esm/@ui/UiFloatingElement/UiFloatingElement.js.map +1 -0
- package/esm/@ui/UiFloatingElement/types.d.ts +96 -0
- package/esm/@ui/UiFloatingElement/types.d.ts.map +1 -0
- package/esm/@ui/UiFloatingElement/types.js +3 -0
- package/esm/@ui/UiFloatingElement/types.js.map +1 -0
- package/esm/@ui/UiFloatingElement/useFloatingPosition.d.ts +8 -0
- package/esm/@ui/UiFloatingElement/useFloatingPosition.d.ts.map +1 -0
- package/esm/@ui/UiFloatingElement/useFloatingPosition.js +105 -0
- package/esm/@ui/UiFloatingElement/useFloatingPosition.js.map +1 -0
- package/esm/@ui/UiFloatingElement/utils.d.ts +42 -0
- package/esm/@ui/UiFloatingElement/utils.d.ts.map +1 -0
- package/esm/@ui/UiFloatingElement/utils.js +124 -0
- package/esm/@ui/UiFloatingElement/utils.js.map +1 -0
- package/esm/@ui/UiFocusManager/UiReturnFocusOnUnmount.d.ts.map +1 -1
- package/esm/@ui/UiFocusManager/UiReturnFocusOnUnmount.js +7 -3
- package/esm/@ui/UiFocusManager/UiReturnFocusOnUnmount.js.map +1 -1
- package/esm/@ui/UiSearchResultsAnnouncement/UiSearchResultsAnnouncement.d.ts.map +1 -1
- package/esm/@ui/UiSearchResultsAnnouncement/UiSearchResultsAnnouncement.js +3 -1
- package/esm/@ui/UiSearchResultsAnnouncement/UiSearchResultsAnnouncement.js.map +1 -1
- package/esm/@ui/UiTabs/defaultComponents/DefaultUiTabsAllTabs.d.ts.map +1 -1
- package/esm/@ui/UiTabs/defaultComponents/DefaultUiTabsAllTabs.js +14 -9
- package/esm/@ui/UiTabs/defaultComponents/DefaultUiTabsAllTabs.js.map +1 -1
- package/esm/@ui/UiTabs/defaultComponents/DefaultUiTabsContainer.js.map +1 -1
- package/esm/@ui/UiTabs/defaultComponents/DefaultUiTabsTabActions.d.ts.map +1 -1
- package/esm/@ui/UiTabs/defaultComponents/DefaultUiTabsTabActions.js +16 -12
- package/esm/@ui/UiTabs/defaultComponents/DefaultUiTabsTabActions.js.map +1 -1
- package/esm/@ui/UiTabs/messages.d.ts.map +1 -1
- package/esm/@ui/UiTabs/messages.js +2 -0
- package/esm/@ui/UiTabs/messages.js.map +1 -1
- package/esm/@ui/UiTooltip/UiTooltip.d.ts.map +1 -1
- package/esm/@ui/UiTooltip/UiTooltip.js +40 -34
- package/esm/@ui/UiTooltip/UiTooltip.js.map +1 -1
- package/esm/@ui/UiTooltip/utils.d.ts +1 -1
- package/esm/@ui/UiTooltip/utils.d.ts.map +1 -1
- package/esm/@ui/UiTooltip/utils.js +5 -1
- package/esm/@ui/UiTooltip/utils.js.map +1 -1
- package/esm/@ui/hooks/useCloseOnEscape.d.ts +7 -0
- package/esm/@ui/hooks/useCloseOnEscape.d.ts.map +1 -0
- package/esm/@ui/hooks/useCloseOnEscape.js +22 -0
- package/esm/@ui/hooks/useCloseOnEscape.js.map +1 -0
- package/esm/@ui/hooks/useCloseOnMouseDrag.d.ts +8 -0
- package/esm/@ui/hooks/useCloseOnMouseDrag.d.ts.map +1 -0
- package/esm/@ui/hooks/useCloseOnMouseDrag.js +19 -0
- package/esm/@ui/hooks/useCloseOnMouseDrag.js.map +1 -0
- package/esm/@ui/hooks/useCloseOnOutsideClick.d.ts +24 -0
- package/esm/@ui/hooks/useCloseOnOutsideClick.d.ts.map +1 -0
- package/esm/@ui/hooks/useCloseOnOutsideClick.js +46 -0
- package/esm/@ui/hooks/useCloseOnOutsideClick.js.map +1 -0
- package/esm/@ui/hooks/useCloseOnParentScroll.d.ts +10 -0
- package/esm/@ui/hooks/useCloseOnParentScroll.d.ts.map +1 -0
- package/esm/@ui/hooks/useCloseOnParentScroll.js +25 -0
- package/esm/@ui/hooks/useCloseOnParentScroll.js.map +1 -0
- package/esm/@ui/hooks/useScopedId.d.ts +8 -4
- package/esm/@ui/hooks/useScopedId.d.ts.map +1 -1
- package/esm/@ui/hooks/useScopedId.js.map +1 -1
- package/esm/List/InvertableSelect/InvertableSelectVirtualised.js.map +1 -1
- package/esm/Overlay/Overlay.d.ts.map +1 -1
- package/esm/Overlay/Overlay.js +4 -2
- package/esm/Overlay/Overlay.js.map +1 -1
- package/esm/index.d.ts +13 -0
- package/esm/index.d.ts.map +1 -1
- package/esm/index.js +9 -0
- package/esm/index.js.map +1 -1
- package/esm/sdk-ui-kit.d.ts +407 -8
- package/esm/utils/drag.d.ts +6 -0
- package/esm/utils/drag.d.ts.map +1 -1
- package/esm/utils/drag.js +8 -2
- package/esm/utils/drag.js.map +1 -1
- package/esm/utils/scroll.d.ts +6 -0
- package/esm/utils/scroll.d.ts.map +1 -1
- package/esm/utils/scroll.js +8 -2
- package/esm/utils/scroll.js.map +1 -1
- package/package.json +9 -9
- package/src/@ui/UiDropdown/UiDropdown.scss +20 -0
- package/src/@ui/index.scss +1 -0
- package/styles/css/main.css +18 -0
- package/styles/css/main.css.map +1 -1
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { type IUiDropdownProps } from "./types.js";
|
|
2
|
+
/**
|
|
3
|
+
* A dropdown component that combines a trigger button with a floating body.
|
|
4
|
+
* Built on top of UiFloatingElement for positioning.
|
|
5
|
+
*
|
|
6
|
+
* @remarks
|
|
7
|
+
* This component provides a similar API to the legacy Dropdown component
|
|
8
|
+
* but uses floating-ui for positioning instead of the custom Overlay component.
|
|
9
|
+
*
|
|
10
|
+
* Key features:
|
|
11
|
+
* - Render prop pattern for flexible button and body rendering
|
|
12
|
+
* - Full accessibility support with ARIA attributes
|
|
13
|
+
* - Focus management with trapping and return focus
|
|
14
|
+
* - Support for legacy align points
|
|
15
|
+
*
|
|
16
|
+
* @internal
|
|
17
|
+
*/
|
|
18
|
+
export declare function UiDropdown({ renderButton, renderBody, isOpen: isOpenProp, onOpenChange, openOnInit, placement, offset, alignPoints, closeOnOutsideClick, closeOnEscape, closeOnParentScroll, closeOnMouseDrag, ignoreClicksOnByClass, zIndex, width, enableFocusTrap, autofocusOnOpen, initialFocus, returnFocusTo, onOpen, onClose, accessibilityConfig, }: IUiDropdownProps): import("react/jsx-runtime").JSX.Element;
|
|
19
|
+
//# sourceMappingURL=UiDropdown.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"UiDropdown.d.ts","sourceRoot":"","sources":["../../../src/@ui/UiDropdown/UiDropdown.tsx"],"names":[],"mappings":"AAMA,OAAO,EAGH,KAAK,gBAAgB,EACxB,MAAM,YAAY,CAAC;AAapB;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,UAAU,CAAC,EACvB,YAAY,EACZ,UAAU,EACV,MAAM,EAAE,UAAU,EAClB,YAAY,EACZ,UAAkB,EAClB,SAA0B,EAC1B,MAAM,EACN,WAAW,EACX,mBAA0B,EAC1B,aAAqB,EACrB,mBAA2B,EAC3B,gBAAwB,EACxB,qBAA8C,EAC9C,MAAM,EACN,KAAK,EACL,eAAsB,EACtB,eAAuB,EACvB,YAAY,EACZ,aAAa,EACb,MAAM,EACN,OAAO,EACP,mBAAmB,GACtB,EAAE,gBAAgB,2CA4IlB"}
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
// (C) 2025 GoodData Corporation
|
|
3
|
+
import { useCallback, useMemo, useRef } from "react";
|
|
4
|
+
import { usePropState } from "@gooddata/sdk-ui";
|
|
5
|
+
import { isElementTextInput } from "../../utils/domUtilities.js";
|
|
6
|
+
import { useId } from "../../utils/useId.js";
|
|
7
|
+
import { bem } from "../@utils/bem.js";
|
|
8
|
+
import { UiFloatingElement } from "../UiFloatingElement/UiFloatingElement.js";
|
|
9
|
+
import { UiFocusManager } from "../UiFocusManager/UiFocusManager.js";
|
|
10
|
+
import { resolveRef } from "../UiFocusManager/utils.js";
|
|
11
|
+
const { e } = bem("gd-ui-kit-dropdown");
|
|
12
|
+
// Stable empty array to avoid re-creating on every render
|
|
13
|
+
const EMPTY_IGNORE_CLICKS_ON = [];
|
|
14
|
+
/**
|
|
15
|
+
* A dropdown component that combines a trigger button with a floating body.
|
|
16
|
+
* Built on top of UiFloatingElement for positioning.
|
|
17
|
+
*
|
|
18
|
+
* @remarks
|
|
19
|
+
* This component provides a similar API to the legacy Dropdown component
|
|
20
|
+
* but uses floating-ui for positioning instead of the custom Overlay component.
|
|
21
|
+
*
|
|
22
|
+
* Key features:
|
|
23
|
+
* - Render prop pattern for flexible button and body rendering
|
|
24
|
+
* - Full accessibility support with ARIA attributes
|
|
25
|
+
* - Focus management with trapping and return focus
|
|
26
|
+
* - Support for legacy align points
|
|
27
|
+
*
|
|
28
|
+
* @internal
|
|
29
|
+
*/
|
|
30
|
+
export function UiDropdown({ renderButton, renderBody, isOpen: isOpenProp, onOpenChange, openOnInit = false, placement = "bottom-start", offset, alignPoints, closeOnOutsideClick = true, closeOnEscape = false, closeOnParentScroll = false, closeOnMouseDrag = false, ignoreClicksOnByClass = EMPTY_IGNORE_CLICKS_ON, zIndex, width, enableFocusTrap = true, autofocusOnOpen = false, initialFocus, returnFocusTo, onOpen, onClose, accessibilityConfig, }) {
|
|
31
|
+
const [isOpen, setIsOpen] = usePropState(isOpenProp ?? openOnInit);
|
|
32
|
+
const buttonWrapperRef = useRef(null);
|
|
33
|
+
const buttonRef = useRef(null);
|
|
34
|
+
const id = useId();
|
|
35
|
+
const dropdownId = `dropdown-${id}`;
|
|
36
|
+
const buttonId = `dropdown-button-${id}`;
|
|
37
|
+
const openDropdown = useCallback(() => {
|
|
38
|
+
if (onOpenChange) {
|
|
39
|
+
onOpenChange(true);
|
|
40
|
+
}
|
|
41
|
+
else {
|
|
42
|
+
setIsOpen(true);
|
|
43
|
+
}
|
|
44
|
+
onOpen?.();
|
|
45
|
+
}, [onOpenChange, setIsOpen, onOpen]);
|
|
46
|
+
const closeDropdown = useCallback(() => {
|
|
47
|
+
if (onOpenChange) {
|
|
48
|
+
onOpenChange(false);
|
|
49
|
+
}
|
|
50
|
+
else {
|
|
51
|
+
setIsOpen(false);
|
|
52
|
+
}
|
|
53
|
+
onClose?.();
|
|
54
|
+
}, [onOpenChange, setIsOpen, onClose]);
|
|
55
|
+
const toggleDropdown = useCallback(() => {
|
|
56
|
+
if (isOpen) {
|
|
57
|
+
closeDropdown();
|
|
58
|
+
}
|
|
59
|
+
else {
|
|
60
|
+
openDropdown();
|
|
61
|
+
}
|
|
62
|
+
}, [isOpen, openDropdown, closeDropdown]);
|
|
63
|
+
const handleTabOut = useCallback(() => {
|
|
64
|
+
closeDropdown();
|
|
65
|
+
resolveRef(returnFocusTo)?.focus();
|
|
66
|
+
}, [closeDropdown, returnFocusTo]);
|
|
67
|
+
// Keyboard handler for the button wrapper
|
|
68
|
+
const handleKeyDown = useCallback((event) => {
|
|
69
|
+
const isInputFocused = isElementTextInput(document.activeElement);
|
|
70
|
+
if (event.code === "Enter" || (event.code === "Space" && !isInputFocused)) {
|
|
71
|
+
toggleDropdown();
|
|
72
|
+
event.preventDefault();
|
|
73
|
+
event.stopPropagation();
|
|
74
|
+
}
|
|
75
|
+
if (event.code === "ArrowUp" && isOpen) {
|
|
76
|
+
closeDropdown();
|
|
77
|
+
event.preventDefault();
|
|
78
|
+
event.stopPropagation();
|
|
79
|
+
}
|
|
80
|
+
if (event.code === "ArrowDown" && !isOpen) {
|
|
81
|
+
openDropdown();
|
|
82
|
+
event.preventDefault();
|
|
83
|
+
event.stopPropagation();
|
|
84
|
+
}
|
|
85
|
+
}, [isOpen, toggleDropdown, closeDropdown, openDropdown]);
|
|
86
|
+
// Button render props
|
|
87
|
+
const buttonRenderProps = useMemo(() => {
|
|
88
|
+
const triggerRole = accessibilityConfig?.triggerRole ?? "button";
|
|
89
|
+
const popupRole = accessibilityConfig?.popupRole ?? "dialog";
|
|
90
|
+
return {
|
|
91
|
+
ref: buttonRef,
|
|
92
|
+
isOpen,
|
|
93
|
+
dropdownId,
|
|
94
|
+
openDropdown,
|
|
95
|
+
closeDropdown,
|
|
96
|
+
toggleDropdown,
|
|
97
|
+
ariaAttributes: {
|
|
98
|
+
role: triggerRole,
|
|
99
|
+
"aria-haspopup": popupRole,
|
|
100
|
+
"aria-expanded": isOpen,
|
|
101
|
+
"aria-controls": isOpen ? dropdownId : undefined,
|
|
102
|
+
},
|
|
103
|
+
};
|
|
104
|
+
}, [
|
|
105
|
+
isOpen,
|
|
106
|
+
dropdownId,
|
|
107
|
+
openDropdown,
|
|
108
|
+
closeDropdown,
|
|
109
|
+
toggleDropdown,
|
|
110
|
+
accessibilityConfig?.triggerRole,
|
|
111
|
+
accessibilityConfig?.popupRole,
|
|
112
|
+
]);
|
|
113
|
+
// Body render props
|
|
114
|
+
const bodyRenderProps = useMemo(() => ({
|
|
115
|
+
closeDropdown,
|
|
116
|
+
ariaAttributes: {
|
|
117
|
+
id: dropdownId,
|
|
118
|
+
},
|
|
119
|
+
}), [closeDropdown, dropdownId]);
|
|
120
|
+
return (_jsxs(_Fragment, { children: [_jsx("div", { ref: buttonWrapperRef, id: buttonId, className: e("button"), onKeyDown: handleKeyDown, children: renderButton(buttonRenderProps) }), _jsx(UiFloatingElement, { anchor: buttonWrapperRef, isOpen: isOpen, onClose: closeDropdown, placement: placement, offset: offset, alignPoints: alignPoints, closeOnOutsideClick: closeOnOutsideClick, closeOnEscape: closeOnEscape, closeOnParentScroll: closeOnParentScroll, closeOnMouseDrag: closeOnMouseDrag, ignoreClicksOn: ignoreClicksOnByClass, zIndex: zIndex, width: width, accessibilityConfig: {
|
|
121
|
+
role: accessibilityConfig?.popupRole ?? "dialog",
|
|
122
|
+
ariaLabelledBy: buttonId,
|
|
123
|
+
}, children: _jsx(UiFocusManager, { tabOutHandler: enableFocusTrap ? undefined : handleTabOut, enableFocusTrap: enableFocusTrap, enableAutofocus: autofocusOnOpen ? { initialFocus } : false, enableReturnFocusOnUnmount: { returnFocusTo: returnFocusTo ?? buttonRef }, children: _jsx("div", { className: e("body"), children: renderBody(bodyRenderProps) }) }) })] }));
|
|
124
|
+
}
|
|
125
|
+
//# sourceMappingURL=UiDropdown.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"UiDropdown.js","sourceRoot":"","sources":["../../../src/@ui/UiDropdown/UiDropdown.tsx"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
import { type ReactNode, type RefObject } from "react";
|
|
2
|
+
import { type OffsetOptions, type Placement } from "@floating-ui/react";
|
|
3
|
+
import { type ILegacyAlignPoint } from "../UiFloatingElement/types.js";
|
|
4
|
+
/**
|
|
5
|
+
* Props for the UiDropdown component.
|
|
6
|
+
*
|
|
7
|
+
* @internal
|
|
8
|
+
*/
|
|
9
|
+
export interface IUiDropdownProps {
|
|
10
|
+
/**
|
|
11
|
+
* Render function for the dropdown button/trigger.
|
|
12
|
+
*/
|
|
13
|
+
renderButton: (props: IUiDropdownButtonRenderProps) => ReactNode;
|
|
14
|
+
/**
|
|
15
|
+
* Render function for the dropdown body/content.
|
|
16
|
+
*/
|
|
17
|
+
renderBody: (props: IUiDropdownBodyRenderProps) => ReactNode;
|
|
18
|
+
/**
|
|
19
|
+
* Controlled open state.
|
|
20
|
+
*/
|
|
21
|
+
isOpen?: boolean;
|
|
22
|
+
/**
|
|
23
|
+
* Callback when open state changes.
|
|
24
|
+
*/
|
|
25
|
+
onOpenChange?: (isOpen: boolean) => void;
|
|
26
|
+
/**
|
|
27
|
+
* Callback when dropdown opens.
|
|
28
|
+
*/
|
|
29
|
+
onOpen?: () => void;
|
|
30
|
+
/**
|
|
31
|
+
* Callback when dropdown closes.
|
|
32
|
+
*/
|
|
33
|
+
onClose?: () => void;
|
|
34
|
+
/**
|
|
35
|
+
* Whether the dropdown starts open.
|
|
36
|
+
* @defaultValue false
|
|
37
|
+
*/
|
|
38
|
+
openOnInit?: boolean;
|
|
39
|
+
/**
|
|
40
|
+
* Placement of the dropdown relative to the button.
|
|
41
|
+
* @defaultValue "bottom-start"
|
|
42
|
+
*/
|
|
43
|
+
placement?: Placement;
|
|
44
|
+
/**
|
|
45
|
+
* Offset of the dropdown from the button.
|
|
46
|
+
*/
|
|
47
|
+
offset?: OffsetOptions;
|
|
48
|
+
/**
|
|
49
|
+
* Legacy align points for backwards compatibility.
|
|
50
|
+
*/
|
|
51
|
+
alignPoints?: ILegacyAlignPoint[];
|
|
52
|
+
/**
|
|
53
|
+
* Whether to close when clicking outside.
|
|
54
|
+
* @defaultValue true
|
|
55
|
+
*/
|
|
56
|
+
closeOnOutsideClick?: boolean;
|
|
57
|
+
/**
|
|
58
|
+
* Whether to close when pressing Escape.
|
|
59
|
+
* @defaultValue false
|
|
60
|
+
*/
|
|
61
|
+
closeOnEscape?: boolean;
|
|
62
|
+
/**
|
|
63
|
+
* Whether to close when parent scrolls.
|
|
64
|
+
* @defaultValue false
|
|
65
|
+
*/
|
|
66
|
+
closeOnParentScroll?: boolean;
|
|
67
|
+
/**
|
|
68
|
+
* Whether to close on mouse drag.
|
|
69
|
+
* @defaultValue false
|
|
70
|
+
*/
|
|
71
|
+
closeOnMouseDrag?: boolean;
|
|
72
|
+
/**
|
|
73
|
+
* CSS selectors to ignore for outside click detection.
|
|
74
|
+
*/
|
|
75
|
+
ignoreClicksOnByClass?: string[];
|
|
76
|
+
/**
|
|
77
|
+
* Custom z-index.
|
|
78
|
+
*/
|
|
79
|
+
zIndex?: number;
|
|
80
|
+
/**
|
|
81
|
+
* Width of the dropdown body.
|
|
82
|
+
*/
|
|
83
|
+
width?: number | "same-as-anchor" | "auto";
|
|
84
|
+
/**
|
|
85
|
+
* Whether to enable focus trap.
|
|
86
|
+
* @defaultValue true
|
|
87
|
+
*/
|
|
88
|
+
enableFocusTrap?: boolean;
|
|
89
|
+
/**
|
|
90
|
+
* Whether to autofocus when opened.
|
|
91
|
+
* @defaultValue false
|
|
92
|
+
*/
|
|
93
|
+
autofocusOnOpen?: boolean;
|
|
94
|
+
/**
|
|
95
|
+
* Element to focus initially when opened.
|
|
96
|
+
*/
|
|
97
|
+
initialFocus?: RefObject<HTMLElement> | string;
|
|
98
|
+
/**
|
|
99
|
+
* Element to return focus to when closed.
|
|
100
|
+
*/
|
|
101
|
+
returnFocusTo?: RefObject<HTMLElement> | string;
|
|
102
|
+
/**
|
|
103
|
+
* Accessibility configuration for trigger and body roles.
|
|
104
|
+
*/
|
|
105
|
+
accessibilityConfig?: {
|
|
106
|
+
triggerRole?: "button" | "combobox";
|
|
107
|
+
popupRole?: "listbox" | "tree" | "grid" | "dialog" | "menu";
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* Props passed to the button render function.
|
|
112
|
+
*
|
|
113
|
+
* @internal
|
|
114
|
+
*/
|
|
115
|
+
export interface IUiDropdownButtonRenderProps {
|
|
116
|
+
/**
|
|
117
|
+
* Ref to attach to the button element.
|
|
118
|
+
*/
|
|
119
|
+
ref: RefObject<HTMLElement>;
|
|
120
|
+
/**
|
|
121
|
+
* Whether the dropdown is currently open.
|
|
122
|
+
*/
|
|
123
|
+
isOpen: boolean;
|
|
124
|
+
/**
|
|
125
|
+
* ID of the dropdown content (for aria-controls).
|
|
126
|
+
*/
|
|
127
|
+
dropdownId: string;
|
|
128
|
+
/**
|
|
129
|
+
* Open the dropdown.
|
|
130
|
+
*/
|
|
131
|
+
openDropdown: () => void;
|
|
132
|
+
/**
|
|
133
|
+
* Close the dropdown.
|
|
134
|
+
*/
|
|
135
|
+
closeDropdown: () => void;
|
|
136
|
+
/**
|
|
137
|
+
* Toggle the dropdown state.
|
|
138
|
+
*/
|
|
139
|
+
toggleDropdown: () => void;
|
|
140
|
+
/**
|
|
141
|
+
* ARIA attributes to spread on the button element.
|
|
142
|
+
*/
|
|
143
|
+
ariaAttributes: {
|
|
144
|
+
role: "button" | "combobox";
|
|
145
|
+
"aria-haspopup": "listbox" | "tree" | "grid" | "dialog" | "menu" | true;
|
|
146
|
+
"aria-expanded": boolean;
|
|
147
|
+
"aria-controls"?: string;
|
|
148
|
+
};
|
|
149
|
+
}
|
|
150
|
+
/**
|
|
151
|
+
* Props passed to the body render function.
|
|
152
|
+
*
|
|
153
|
+
* @internal
|
|
154
|
+
*/
|
|
155
|
+
export interface IUiDropdownBodyRenderProps {
|
|
156
|
+
/**
|
|
157
|
+
* Close the dropdown.
|
|
158
|
+
*/
|
|
159
|
+
closeDropdown: () => void;
|
|
160
|
+
/**
|
|
161
|
+
* ARIA attributes to spread on the body element.
|
|
162
|
+
*/
|
|
163
|
+
ariaAttributes: {
|
|
164
|
+
id: string;
|
|
165
|
+
};
|
|
166
|
+
}
|
|
167
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/@ui/UiDropdown/types.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/@ui/UiDropdown/types.ts"],"names":[],"mappings":"AAAA,gCAAgC"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { type IUiFloatingElementProps } from "./types.js";
|
|
2
|
+
/**
|
|
3
|
+
* A low-level component for rendering floating elements (dropdowns, popovers, tooltips, etc.)
|
|
4
|
+
* using floating-ui for positioning.
|
|
5
|
+
*
|
|
6
|
+
* @remarks
|
|
7
|
+
* This component is designed as a modern replacement for the Overlay component,
|
|
8
|
+
* providing similar functionality with a simpler API and better performance.
|
|
9
|
+
*
|
|
10
|
+
* Features:
|
|
11
|
+
* - Automatic positioning with floating-ui
|
|
12
|
+
* - Portal rendering to avoid overflow issues
|
|
13
|
+
* - Close on outside click, escape, parent scroll, mouse drag
|
|
14
|
+
* - Legacy align point format support for easier migration
|
|
15
|
+
* - Z-index management via OverlayController
|
|
16
|
+
*
|
|
17
|
+
* @internal
|
|
18
|
+
*/
|
|
19
|
+
export declare function UiFloatingElement({ children, anchor, isOpen, onClose, placement, alignPoints, strategy, offset, autoFlip, closeOnOutsideClick, closeOnEscape, closeOnParentScroll, closeOnMouseDrag, ignoreClicksOn, shouldCloseOnClick, zIndex: zIndexProp, className, contentClassName, style, width, maxWidth, maxHeight, accessibilityConfig, onPlacementChange, }: IUiFloatingElementProps): import("react/jsx-runtime").JSX.Element | null;
|
|
20
|
+
//# sourceMappingURL=UiFloatingElement.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"UiFloatingElement.d.ts","sourceRoot":"","sources":["../../../src/@ui/UiFloatingElement/UiFloatingElement.tsx"],"names":[],"mappings":"AASA,OAAO,EAAE,KAAK,uBAAuB,EAAE,MAAM,YAAY,CAAC;AAc1D;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,iBAAiB,CAAC,EAC9B,QAAQ,EACR,MAAM,EACN,MAAM,EACN,OAAO,EACP,SAA0B,EAC1B,WAAW,EACX,QAAqB,EACrB,MAAM,EACN,QAAe,EACf,mBAA0B,EAC1B,aAAqB,EACrB,mBAA2B,EAC3B,gBAAwB,EACxB,cAAuC,EACvC,kBAAkB,EAClB,MAAM,EAAE,UAAU,EAClB,SAAS,EACT,gBAAgB,EAChB,KAAK,EACL,KAAc,EACd,QAAQ,EACR,SAAS,EACT,mBAAmB,EACnB,iBAAiB,GACpB,EAAE,uBAAuB,kDA0FzB"}
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
// (C) 2025 GoodData Corporation
|
|
3
|
+
import { useCallback, useEffect, useState } from "react";
|
|
4
|
+
import { FloatingPortal } from "@floating-ui/react";
|
|
5
|
+
import cx from "classnames";
|
|
6
|
+
import { ConditionalScopedThemeProvider } from "@gooddata/sdk-ui-theme-provider";
|
|
7
|
+
import { useFloatingPosition } from "./useFloatingPosition.js";
|
|
8
|
+
import { getDimensionsFromRef, resolveAnchor } from "./utils.js";
|
|
9
|
+
import { bem } from "../@utils/bem.js";
|
|
10
|
+
import { useCloseOnEscape } from "../hooks/useCloseOnEscape.js";
|
|
11
|
+
import { useCloseOnMouseDrag } from "../hooks/useCloseOnMouseDrag.js";
|
|
12
|
+
import { FLOATING_ELEMENT_DATA_ATTR, useCloseOnOutsideClick } from "../hooks/useCloseOnOutsideClick.js";
|
|
13
|
+
import { useCloseOnParentScroll } from "../hooks/useCloseOnParentScroll.js";
|
|
14
|
+
const { b, e } = bem("gd-ui-kit-floating-element");
|
|
15
|
+
// Stable empty array to avoid re-creating on every render
|
|
16
|
+
const EMPTY_IGNORE_CLICKS_ON = [];
|
|
17
|
+
/**
|
|
18
|
+
* A low-level component for rendering floating elements (dropdowns, popovers, tooltips, etc.)
|
|
19
|
+
* using floating-ui for positioning.
|
|
20
|
+
*
|
|
21
|
+
* @remarks
|
|
22
|
+
* This component is designed as a modern replacement for the Overlay component,
|
|
23
|
+
* providing similar functionality with a simpler API and better performance.
|
|
24
|
+
*
|
|
25
|
+
* Features:
|
|
26
|
+
* - Automatic positioning with floating-ui
|
|
27
|
+
* - Portal rendering to avoid overflow issues
|
|
28
|
+
* - Close on outside click, escape, parent scroll, mouse drag
|
|
29
|
+
* - Legacy align point format support for easier migration
|
|
30
|
+
* - Z-index management via OverlayController
|
|
31
|
+
*
|
|
32
|
+
* @internal
|
|
33
|
+
*/
|
|
34
|
+
export function UiFloatingElement({ children, anchor, isOpen, onClose, placement = "bottom-start", alignPoints, strategy = "absolute", offset, autoFlip = true, closeOnOutsideClick = true, closeOnEscape = false, closeOnParentScroll = false, closeOnMouseDrag = false, ignoreClicksOn = EMPTY_IGNORE_CLICKS_ON, shouldCloseOnClick, zIndex: zIndexProp, className, contentClassName, style, width = "auto", maxWidth, maxHeight, accessibilityConfig, onPlacementChange, }) {
|
|
35
|
+
const [resolvedAnchor, setResolvedAnchor] = useState(() => resolveAnchor(anchor));
|
|
36
|
+
// Core positioning
|
|
37
|
+
const { refs, floatingStyles, placement: actualPlacement, zIndex, } = useFloatingPosition({
|
|
38
|
+
isOpen,
|
|
39
|
+
placement,
|
|
40
|
+
alignPoints,
|
|
41
|
+
strategy,
|
|
42
|
+
offset,
|
|
43
|
+
autoFlip,
|
|
44
|
+
maxWidth,
|
|
45
|
+
maxHeight,
|
|
46
|
+
zIndex: zIndexProp,
|
|
47
|
+
});
|
|
48
|
+
// Close behaviors - each hook is independent and composable
|
|
49
|
+
const handleClose = useCallback(() => {
|
|
50
|
+
onClose?.();
|
|
51
|
+
}, [onClose]);
|
|
52
|
+
useCloseOnOutsideClick(isOpen && closeOnOutsideClick, handleClose, {
|
|
53
|
+
floatingRef: refs.floating,
|
|
54
|
+
anchorRef: refs.reference,
|
|
55
|
+
ignoreClicksOn,
|
|
56
|
+
shouldCloseOnClick,
|
|
57
|
+
});
|
|
58
|
+
useCloseOnEscape(isOpen && closeOnEscape, handleClose);
|
|
59
|
+
useCloseOnParentScroll(isOpen && closeOnParentScroll, handleClose, refs.reference);
|
|
60
|
+
useCloseOnMouseDrag(isOpen && closeOnMouseDrag, handleClose);
|
|
61
|
+
// Update anchor reference when it changes
|
|
62
|
+
useEffect(() => {
|
|
63
|
+
const resolved = resolveAnchor(anchor);
|
|
64
|
+
setResolvedAnchor(resolved);
|
|
65
|
+
refs.setReference(resolved);
|
|
66
|
+
}, [anchor, refs]);
|
|
67
|
+
// Notify when placement changes
|
|
68
|
+
useEffect(() => {
|
|
69
|
+
onPlacementChange?.(actualPlacement);
|
|
70
|
+
}, [actualPlacement, onPlacementChange]);
|
|
71
|
+
// Compute width style
|
|
72
|
+
const getWidthStyle = useCallback(() => {
|
|
73
|
+
if (width === "same-as-anchor") {
|
|
74
|
+
const dimensions = getDimensionsFromRef(resolvedAnchor);
|
|
75
|
+
return { width: dimensions.width };
|
|
76
|
+
}
|
|
77
|
+
if (typeof width === "number") {
|
|
78
|
+
return { width };
|
|
79
|
+
}
|
|
80
|
+
return {};
|
|
81
|
+
}, [width, resolvedAnchor]);
|
|
82
|
+
if (!isOpen) {
|
|
83
|
+
return null;
|
|
84
|
+
}
|
|
85
|
+
return (_jsx(FloatingPortal, { children: _jsx(ConditionalScopedThemeProvider, { children: _jsx("div", { ref: refs.setFloating, className: cx(b(), className), style: {
|
|
86
|
+
...floatingStyles,
|
|
87
|
+
...getWidthStyle(),
|
|
88
|
+
...style,
|
|
89
|
+
zIndex,
|
|
90
|
+
}, [FLOATING_ELEMENT_DATA_ATTR]: true, role: accessibilityConfig?.role, "aria-label": accessibilityConfig?.ariaLabel, "aria-labelledby": accessibilityConfig?.ariaLabelledBy, "aria-describedby": accessibilityConfig?.ariaDescribedBy, children: _jsx("div", { className: cx(e("content"), contentClassName), children: children }) }) }) }));
|
|
91
|
+
}
|
|
92
|
+
//# sourceMappingURL=UiFloatingElement.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"UiFloatingElement.js","sourceRoot":"","sources":["../../../src/@ui/UiFloatingElement/UiFloatingElement.tsx"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import { type CSSProperties, type MutableRefObject, type ReactNode, type RefObject } from "react";
|
|
2
|
+
import { type FloatingContext, type Middleware, type OffsetOptions, type Placement, type Strategy, type VirtualElement } from "@floating-ui/react";
|
|
3
|
+
import { type IAccessibilityConfigBase } from "../../typings/accessibility.js";
|
|
4
|
+
/**
|
|
5
|
+
* Align point specification using the legacy "bl tl" format.
|
|
6
|
+
* First part is anchor point, second is floating element point.
|
|
7
|
+
* Letters: t=top, b=bottom, l=left, r=right, c=center
|
|
8
|
+
*
|
|
9
|
+
* @example "bl tl" - anchor bottom-left to floating top-left (dropdown below)
|
|
10
|
+
* @example "tl bl" - anchor top-left to floating bottom-left (dropdown above)
|
|
11
|
+
*
|
|
12
|
+
* @internal
|
|
13
|
+
*/
|
|
14
|
+
export interface ILegacyAlignPoint {
|
|
15
|
+
align: string;
|
|
16
|
+
offset?: {
|
|
17
|
+
x?: number;
|
|
18
|
+
y?: number;
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Anchor element for the floating element - can be an element, ref, selector, or virtual element.
|
|
23
|
+
*
|
|
24
|
+
* @internal
|
|
25
|
+
*/
|
|
26
|
+
export type IFloatingAnchor = HTMLElement | RefObject<HTMLElement | null> | VirtualElement | string | null;
|
|
27
|
+
/**
|
|
28
|
+
* Props for the UiFloatingElement component.
|
|
29
|
+
*
|
|
30
|
+
* @internal
|
|
31
|
+
*/
|
|
32
|
+
export interface IUiFloatingElementProps {
|
|
33
|
+
children: ReactNode;
|
|
34
|
+
anchor: IFloatingAnchor;
|
|
35
|
+
isOpen: boolean;
|
|
36
|
+
onClose?: () => void;
|
|
37
|
+
placement?: Placement;
|
|
38
|
+
alignPoints?: ILegacyAlignPoint[];
|
|
39
|
+
strategy?: Strategy;
|
|
40
|
+
offset?: OffsetOptions;
|
|
41
|
+
autoFlip?: boolean;
|
|
42
|
+
closeOnOutsideClick?: boolean;
|
|
43
|
+
closeOnEscape?: boolean;
|
|
44
|
+
closeOnParentScroll?: boolean;
|
|
45
|
+
closeOnMouseDrag?: boolean;
|
|
46
|
+
ignoreClicksOn?: Array<string | HTMLElement>;
|
|
47
|
+
shouldCloseOnClick?: (event: Event) => boolean;
|
|
48
|
+
zIndex?: number;
|
|
49
|
+
className?: string;
|
|
50
|
+
contentClassName?: string;
|
|
51
|
+
style?: CSSProperties;
|
|
52
|
+
width?: number | "same-as-anchor" | "auto";
|
|
53
|
+
maxWidth?: number | string;
|
|
54
|
+
maxHeight?: number | string;
|
|
55
|
+
accessibilityConfig?: IAccessibilityConfigBase;
|
|
56
|
+
onPlacementChange?: (placement: Placement) => void;
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* @internal
|
|
60
|
+
*/
|
|
61
|
+
export interface IUseFloatingPositionOptions {
|
|
62
|
+
isOpen: boolean;
|
|
63
|
+
onOpenChange?: (open: boolean) => void;
|
|
64
|
+
placement?: Placement;
|
|
65
|
+
alignPoints?: ILegacyAlignPoint[];
|
|
66
|
+
strategy?: Strategy;
|
|
67
|
+
offset?: OffsetOptions;
|
|
68
|
+
autoFlip?: boolean;
|
|
69
|
+
fallbackPlacements?: Placement[];
|
|
70
|
+
arrowRef?: RefObject<SVGSVGElement | null>;
|
|
71
|
+
customMiddleware?: Middleware[];
|
|
72
|
+
maxWidth?: number | string;
|
|
73
|
+
maxHeight?: number | string;
|
|
74
|
+
zIndex?: number;
|
|
75
|
+
/**
|
|
76
|
+
* Padding for the shift middleware to keep the floating element away from viewport edges.
|
|
77
|
+
*/
|
|
78
|
+
shiftPadding?: number;
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* @internal
|
|
82
|
+
*/
|
|
83
|
+
export interface IUseFloatingPositionResult {
|
|
84
|
+
refs: {
|
|
85
|
+
setReference: (node: any) => void;
|
|
86
|
+
setFloating: (node: HTMLElement | null) => void;
|
|
87
|
+
reference: MutableRefObject<any>;
|
|
88
|
+
floating: MutableRefObject<HTMLElement | null>;
|
|
89
|
+
};
|
|
90
|
+
floatingStyles: CSSProperties;
|
|
91
|
+
placement: Placement;
|
|
92
|
+
zIndex: number | undefined;
|
|
93
|
+
context: FloatingContext;
|
|
94
|
+
middlewareData: Record<string, any>;
|
|
95
|
+
}
|
|
96
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/@ui/UiFloatingElement/types.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/@ui/UiFloatingElement/types.ts"],"names":[],"mappings":"AAAA,gCAAgC"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { type IUseFloatingPositionOptions, type IUseFloatingPositionResult } from "./types.js";
|
|
2
|
+
/**
|
|
3
|
+
* Hook for floating element positioning using floating-ui.
|
|
4
|
+
*
|
|
5
|
+
* @internal
|
|
6
|
+
*/
|
|
7
|
+
export declare function useFloatingPosition({ isOpen, onOpenChange, placement: placementProp, alignPoints, strategy, offset: offsetProp, autoFlip, fallbackPlacements: fallbackPlacementsProp, arrowRef, customMiddleware, maxWidth, maxHeight, zIndex: zIndexProp, shiftPadding, }: IUseFloatingPositionOptions): IUseFloatingPositionResult;
|
|
8
|
+
//# sourceMappingURL=useFloatingPosition.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useFloatingPosition.d.ts","sourceRoot":"","sources":["../../../src/@ui/UiFloatingElement/useFloatingPosition.ts"],"names":[],"mappings":"AAiBA,OAAO,EAAE,KAAK,2BAA2B,EAAE,KAAK,0BAA0B,EAAE,MAAM,YAAY,CAAC;AAO/F;;;;GAIG;AACH,wBAAgB,mBAAmB,CAAC,EAChC,MAAM,EACN,YAAY,EACZ,SAAS,EAAE,aAA8B,EACzC,WAAW,EACX,QAAqB,EACrB,MAAM,EAAE,UAAU,EAClB,QAAe,EACf,kBAAkB,EAAE,sBAAsB,EAC1C,QAAQ,EACR,gBAAmC,EACnC,QAAQ,EACR,SAAS,EACT,MAAM,EAAE,UAAU,EAClB,YAAgB,GACnB,EAAE,2BAA2B,GAAG,0BAA0B,CAyH1D"}
|