@gooddata/sdk-ui-kit 11.42.0-alpha.1 → 11.42.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/UiAutocomplete/UiAutocomplete.d.ts +9 -0
- package/esm/@ui/UiAutocomplete/UiAutocomplete.d.ts.map +1 -0
- package/esm/@ui/UiAutocomplete/UiAutocomplete.js +230 -0
- package/esm/@ui/UiAutocomplete/types.d.ts +61 -0
- package/esm/@ui/UiAutocomplete/types.d.ts.map +1 -0
- package/esm/@ui/UiAutocomplete/types.js +2 -0
- package/esm/@ui/UiAutocomplete/useAsyncListSource.d.ts +42 -0
- package/esm/@ui/UiAutocomplete/useAsyncListSource.d.ts.map +1 -0
- package/esm/@ui/UiAutocomplete/useAsyncListSource.js +112 -0
- package/esm/@ui/UiCombobox/UiComboboxInput.d.ts +27 -4
- package/esm/@ui/UiCombobox/UiComboboxInput.d.ts.map +1 -1
- package/esm/@ui/UiCombobox/UiComboboxInput.js +38 -31
- package/esm/@ui/UiCombobox/UiComboboxList.js +2 -2
- package/esm/@ui/UiCombobox/UiComboboxListItem.d.ts +3 -13
- package/esm/@ui/UiCombobox/UiComboboxListItem.d.ts.map +1 -1
- package/esm/@ui/UiCombobox/UiComboboxListItem.js +13 -23
- package/esm/@ui/UiCombobox/UiComboboxPopup.d.ts +6 -3
- package/esm/@ui/UiCombobox/UiComboboxPopup.d.ts.map +1 -1
- package/esm/@ui/UiCombobox/UiComboboxPopup.js +5 -7
- package/esm/@ui/UiCombobox/types.d.ts +17 -9
- package/esm/@ui/UiCombobox/types.d.ts.map +1 -1
- package/esm/@ui/UiCombobox/useCombobox.d.ts.map +1 -1
- package/esm/@ui/UiCombobox/useCombobox.js +66 -161
- package/esm/@ui/UiCombobox/useComboboxChrome.d.ts +20 -0
- package/esm/@ui/UiCombobox/useComboboxChrome.d.ts.map +1 -0
- package/esm/@ui/UiCombobox/useComboboxChrome.js +89 -0
- package/esm/@ui/UiCombobox/useComboboxSelection.d.ts +23 -0
- package/esm/@ui/UiCombobox/useComboboxSelection.d.ts.map +1 -0
- package/esm/@ui/UiCombobox/useComboboxSelection.js +78 -0
- package/esm/@ui/UiDropdown/UiDropdown.js +3 -3
- package/esm/@ui/UiFloatingElement/UiFloatingElement.d.ts.map +1 -1
- package/esm/@ui/UiFloatingElement/UiFloatingElement.js +3 -2
- package/esm/@ui/UiFloatingPanel/UiFloatingPanel.d.ts +28 -0
- package/esm/@ui/UiFloatingPanel/UiFloatingPanel.d.ts.map +1 -0
- package/esm/@ui/UiFloatingPanel/UiFloatingPanel.js +14 -0
- package/esm/@ui/UiTags/UiTags.d.ts.map +1 -1
- package/esm/@ui/UiTags/UiTags.js +2 -2
- package/esm/@ui/UiTextInput/UiTextInput.d.ts +13 -2
- package/esm/@ui/UiTextInput/UiTextInput.d.ts.map +1 -1
- package/esm/@ui/UiTextInput/UiTextInput.js +2 -2
- package/esm/@ui/UiTooltip/UiTooltip.d.ts.map +1 -1
- package/esm/@ui/UiTooltip/UiTooltip.js +10 -4
- package/esm/@ui/hooks/useCloseOnOutsideClick.d.ts +31 -0
- package/esm/@ui/hooks/useCloseOnOutsideClick.d.ts.map +1 -1
- package/esm/@ui/hooks/useCloseOnOutsideClick.js +73 -6
- package/esm/Tabs/Tabs.d.ts +2 -1
- package/esm/Tabs/Tabs.d.ts.map +1 -1
- package/esm/Tabs/Tabs.js +1 -1
- package/esm/WidgetNotice/WidgetNotice.d.ts.map +1 -1
- package/esm/WidgetNotice/WidgetNotice.js +1 -1
- package/esm/index.d.ts +5 -2
- package/esm/index.d.ts.map +1 -1
- package/esm/index.js +2 -0
- package/esm/locales.d.ts +17 -0
- package/esm/locales.d.ts.map +1 -1
- package/esm/locales.js +7 -0
- package/esm/sdk-ui-kit.d.ts +166 -31
- package/package.json +11 -11
- package/src/@ui/UiAutocomplete/UiAutocomplete.scss +53 -0
- package/src/@ui/UiCombobox/UiCombobox.scss +0 -16
- package/src/@ui/UiDropdown/UiDropdown.scss +1 -20
- package/src/@ui/UiFloatingPanel/UiFloatingPanel.scss +27 -0
- package/src/@ui/UiPopover/UiPopover.scss +8 -0
- package/src/@ui/UiTags/UiTags.scss +0 -4
- package/src/@ui/UiTextInput/UiTextInput.scss +6 -2
- package/src/@ui/index.scss +2 -0
- package/styles/css/main.css +64 -28
- package/styles/css/main.css.map +1 -1
|
@@ -7,20 +7,14 @@ import { useComboboxState } from "./UiComboboxContext.js";
|
|
|
7
7
|
/** @internal */
|
|
8
8
|
export function UiComboboxListItem(props) {
|
|
9
9
|
const { option } = props;
|
|
10
|
-
const { registerItemRef,
|
|
10
|
+
const { registerItemRef, setActiveIndex, selectOption, activeOption, selectedOption } = useComboboxState();
|
|
11
11
|
const isDisabled = Boolean(option.disabled);
|
|
12
12
|
const isActive = activeOption?.id === option.id;
|
|
13
13
|
const isSelected = selectedOption?.id === option.id;
|
|
14
|
-
return (_jsx(UiComboboxListItemImpl, { ...props, isActive: isActive, isSelected: isSelected, isDisabled: isDisabled,
|
|
14
|
+
return (_jsx(UiComboboxListItemImpl, { ...props, isActive: isActive, isSelected: isSelected, isDisabled: isDisabled, registerItemRef: registerItemRef, setActiveIndex: setActiveIndex, selectOption: selectOption }));
|
|
15
15
|
}
|
|
16
16
|
export const UiComboboxListItemImpl = memo(function UiComboboxListItemImpl(props) {
|
|
17
|
-
const { option, index, className, children, onClick, isActive, isSelected, isDisabled,
|
|
18
|
-
// https://floating-ui.com/docs/useRole#component-roles
|
|
19
|
-
const itemProps = getItemProps({
|
|
20
|
-
...htmlProps,
|
|
21
|
-
active: isActive,
|
|
22
|
-
selected: isSelected,
|
|
23
|
-
});
|
|
17
|
+
const { option, index, className, children, onClick, onMouseMove, isActive, isSelected, isDisabled, registerItemRef, setActiveIndex, selectOption, ...htmlProps } = props;
|
|
24
18
|
function handleClick(event) {
|
|
25
19
|
if (isDisabled) {
|
|
26
20
|
event.preventDefault();
|
|
@@ -29,27 +23,23 @@ export const UiComboboxListItemImpl = memo(function UiComboboxListItemImpl(props
|
|
|
29
23
|
selectOption(option, index);
|
|
30
24
|
onClick?.(event);
|
|
31
25
|
}
|
|
32
|
-
|
|
26
|
+
function handleMouseMove(event) {
|
|
27
|
+
if (!isActive) {
|
|
28
|
+
setActiveIndex(index);
|
|
29
|
+
}
|
|
30
|
+
onMouseMove?.(event);
|
|
31
|
+
}
|
|
32
|
+
return (_jsx("li", { ...htmlProps, ref: (node) => {
|
|
33
33
|
registerItemRef(node, index);
|
|
34
|
-
}, id: option.id, role: "option", "aria-selected": isSelected, "aria-disabled": isDisabled, className: cx(e("item", { isActive, isSelected, isDisabled }), className), onClick: handleClick, children: children ?? (_jsxs(_Fragment, { children: [
|
|
34
|
+
}, id: option.id, role: "option", "aria-selected": isSelected, "aria-disabled": isDisabled, className: cx(e("item", { isActive, isSelected, isDisabled }), className), onClick: handleClick, onMouseMove: handleMouseMove, children: children ?? (_jsxs(_Fragment, { children: [
|
|
35
35
|
_jsx(UiComboboxListItemLabel, { children: option.label }), option.creatable ? _jsx(UiComboboxListItemCreatableLabel, {}) : null] })) }));
|
|
36
36
|
});
|
|
37
|
-
/**
|
|
38
|
-
* Renders the primary label content within a combobox list item.
|
|
39
|
-
* Use this component for composable customization of list item content.
|
|
40
|
-
*
|
|
41
|
-
* @internal
|
|
42
|
-
*/
|
|
37
|
+
/** @internal */
|
|
43
38
|
export function UiComboboxListItemLabel(props) {
|
|
44
39
|
const { children, className, ...htmlProps } = props;
|
|
45
40
|
return (_jsx("span", { ...htmlProps, className: cx(e("item-label"), className), children: children }));
|
|
46
41
|
}
|
|
47
|
-
/**
|
|
48
|
-
* Renders the "creatable" label suffix within a combobox list item.
|
|
49
|
-
* Use this component for composable customization of list item content.
|
|
50
|
-
*
|
|
51
|
-
* @internal
|
|
52
|
-
*/
|
|
42
|
+
/** @internal */
|
|
53
43
|
export function UiComboboxListItemCreatableLabel(props) {
|
|
54
44
|
const { children = "(create new)", className, ...htmlProps } = props;
|
|
55
45
|
return (_jsx("span", { ...htmlProps, className: cx(e("item-creatable"), className), children: children }));
|
|
@@ -1,6 +1,9 @@
|
|
|
1
|
-
import type
|
|
1
|
+
import { type CSSProperties, type ReactNode } from "react";
|
|
2
2
|
/** @internal */
|
|
3
|
-
export
|
|
3
|
+
export interface IUiComboboxPopupProps {
|
|
4
|
+
children?: ReactNode;
|
|
5
|
+
style?: CSSProperties;
|
|
6
|
+
}
|
|
4
7
|
/** @internal */
|
|
5
|
-
export declare function UiComboboxPopup({
|
|
8
|
+
export declare function UiComboboxPopup({ children, style }: IUiComboboxPopupProps): import("react/jsx-runtime").JSX.Element | null;
|
|
6
9
|
//# sourceMappingURL=UiComboboxPopup.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"UiComboboxPopup.d.ts","sourceRoot":"","sources":["../../../src/@ui/UiCombobox/UiComboboxPopup.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"UiComboboxPopup.d.ts","sourceRoot":"","sources":["../../../src/@ui/UiCombobox/UiComboboxPopup.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,aAAa,EAAE,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAM3D,gBAAgB;AAChB,MAAM,WAAW,qBAAqB;IAClC,QAAQ,CAAC,EAAE,SAAS,CAAC;IACrB,KAAK,CAAC,EAAE,aAAa,CAAC;CACzB;AAED,gBAAgB;AAChB,wBAAgB,eAAe,CAAC,EAAE,QAAQ,EAAE,KAAK,EAAE,EAAE,qBAAqB,kDAwBzE"}
|
|
@@ -1,13 +1,11 @@
|
|
|
1
1
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
-
|
|
3
|
-
import cx from "classnames";
|
|
4
|
-
import { e } from "./comboboxBem.js";
|
|
2
|
+
import { UiFloatingPanel } from "../UiFloatingPanel/UiFloatingPanel.js";
|
|
5
3
|
import { useComboboxState } from "./UiComboboxContext.js";
|
|
6
4
|
/** @internal */
|
|
7
|
-
export function UiComboboxPopup({
|
|
8
|
-
const { isOpen,
|
|
9
|
-
if (!
|
|
5
|
+
export function UiComboboxPopup({ children, style }) {
|
|
6
|
+
const { isOpen, setIsOpen, anchorRef, shouldRenderPopup } = useComboboxState();
|
|
7
|
+
if (!shouldRenderPopup) {
|
|
10
8
|
return null;
|
|
11
9
|
}
|
|
12
|
-
return (_jsx(
|
|
10
|
+
return (_jsx(UiFloatingPanel, { anchor: anchorRef, isOpen: isOpen, onClose: () => setIsOpen(false), placement: "bottom-start", width: "same-as-anchor", padding: "listbox", closeOnOutsideClick: true, accessibilityConfig: { role: undefined }, style: style, children: _jsx("div", { onMouseDown: (event) => event.preventDefault(), children: children }) }));
|
|
13
11
|
}
|
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
import type { CSSProperties, KeyboardEvent } from "react";
|
|
1
|
+
import type { KeyboardEvent, RefObject } from "react";
|
|
3
2
|
/** @internal */
|
|
4
3
|
export interface IUiComboboxOption {
|
|
5
4
|
id: string;
|
|
@@ -22,7 +21,10 @@ export interface IUiComboboxParams {
|
|
|
22
21
|
*/
|
|
23
22
|
defaultValue?: string;
|
|
24
23
|
/**
|
|
25
|
-
*
|
|
24
|
+
* Called whenever the input value changes — on typing, on Escape reset,
|
|
25
|
+
* and when an option is selected. The combobox is fully controlled when
|
|
26
|
+
* paired with `value`; consumers that need to distinguish selection from
|
|
27
|
+
* typing should inspect the current `selectedOption` state.
|
|
26
28
|
*/
|
|
27
29
|
onValueChange?: (value: string) => void;
|
|
28
30
|
/**
|
|
@@ -45,13 +47,19 @@ export interface IUiComboboxState {
|
|
|
45
47
|
selectOption: (option: IUiComboboxOption, index?: number) => void;
|
|
46
48
|
isOpen: boolean;
|
|
47
49
|
setIsOpen: (isOpen: boolean) => void;
|
|
48
|
-
|
|
49
|
-
|
|
50
|
+
/**
|
|
51
|
+
* Drives popup visibility. Sync combobox sets it to `availableOptions.length > 0`;
|
|
52
|
+
* async sources keep it `true` so status rows (loading / error / no-match) can show.
|
|
53
|
+
*/
|
|
54
|
+
shouldRenderPopup: boolean;
|
|
55
|
+
/** Anchor for the popup — typically the input's outer wrapper, so the popup matches the visible field width. */
|
|
56
|
+
anchorRef: RefObject<HTMLElement | null>;
|
|
50
57
|
registerItemRef: (node: HTMLElement | null, index: number) => void;
|
|
51
|
-
getReferenceProps: UseInteractionsReturn["getReferenceProps"];
|
|
52
|
-
getFloatingProps: UseInteractionsReturn["getFloatingProps"];
|
|
53
|
-
getItemProps: UseInteractionsReturn["getItemProps"];
|
|
54
|
-
floatingStyles: CSSProperties;
|
|
55
58
|
creatable: boolean;
|
|
59
|
+
/**
|
|
60
|
+
* Stable id of the `<ul role="listbox">`. The input advertises it via
|
|
61
|
+
* `aria-controls`; the listbox sets it as its `id`.
|
|
62
|
+
*/
|
|
63
|
+
listboxId: string;
|
|
56
64
|
}
|
|
57
65
|
//# sourceMappingURL=types.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/@ui/UiCombobox/types.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,aAAa,EAAE,
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/@ui/UiCombobox/types.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAEtD,gBAAgB;AAChB,MAAM,WAAW,iBAAiB;IAC9B,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,SAAS,CAAC,EAAE,OAAO,CAAC;CACvB;AAED,gBAAgB;AAChB,MAAM,WAAW,iBAAiB;IAC9B;;OAEG;IACH,OAAO,EAAE,iBAAiB,EAAE,CAAC;IAC7B;;OAEG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IACf;;OAEG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB;;;;;OAKG;IACH,aAAa,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACxC;;;OAGG;IACH,SAAS,CAAC,EAAE,OAAO,CAAC;CACvB;AAED,gBAAgB;AAChB,MAAM,WAAW,gBAAgB;IAC7B,UAAU,EAAE,MAAM,CAAC;IACnB,aAAa,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACvC,cAAc,EAAE,CAAC,KAAK,EAAE,aAAa,CAAC,gBAAgB,CAAC,KAAK,IAAI,CAAC;IACjE,WAAW,EAAE,MAAM,IAAI,CAAC;IAExB,gBAAgB,EAAE,iBAAiB,EAAE,CAAC;IACtC,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,cAAc,EAAE,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,KAAK,IAAI,CAAC;IAC/C,YAAY,EAAE,iBAAiB,GAAG,SAAS,CAAC;IAC5C,cAAc,EAAE,iBAAiB,GAAG,SAAS,CAAC;IAC9C,YAAY,EAAE,CAAC,MAAM,EAAE,iBAAiB,EAAE,KAAK,CAAC,EAAE,MAAM,KAAK,IAAI,CAAC;IAElE,MAAM,EAAE,OAAO,CAAC;IAChB,SAAS,EAAE,CAAC,MAAM,EAAE,OAAO,KAAK,IAAI,CAAC;IACrC;;;OAGG;IACH,iBAAiB,EAAE,OAAO,CAAC;IAC3B,kHAAgH;IAChH,SAAS,EAAE,SAAS,CAAC,WAAW,GAAG,IAAI,CAAC,CAAC;IACzC,eAAe,EAAE,CAAC,IAAI,EAAE,WAAW,GAAG,IAAI,EAAE,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAEnE,SAAS,EAAE,OAAO,CAAC;IACnB;;;OAGG;IACH,SAAS,EAAE,MAAM,CAAC;CACrB"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useCombobox.d.ts","sourceRoot":"","sources":["../../../src/@ui/UiCombobox/useCombobox.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"useCombobox.d.ts","sourceRoot":"","sources":["../../../src/@ui/UiCombobox/useCombobox.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAkBtE,gBAAgB;AAChB,wBAAgB,WAAW,CAAC,MAAM,EAAE,iBAAiB,GAAG,gBAAgB,CAuEvE"}
|
|
@@ -1,169 +1,74 @@
|
|
|
1
1
|
// (C) 2025-2026 GoodData Corporation
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
2
|
+
import { useId, useMemo } from "react";
|
|
3
|
+
import { makeKeyboardNavigation } from "../@utils/keyboardNavigation.js";
|
|
4
|
+
import { useComboboxChrome } from "./useComboboxChrome.js";
|
|
5
|
+
import { useComboboxSelection } from "./useComboboxSelection.js";
|
|
6
|
+
// Omit handlers where we want default behavior to fall through —
|
|
7
|
+
// `makeKeyboardNavigation` preventDefaults every registered action.
|
|
8
|
+
const comboboxKeys = makeKeyboardNavigation({
|
|
9
|
+
onArrowDown: [{ code: "ArrowDown" }],
|
|
10
|
+
onArrowUp: [{ code: "ArrowUp" }],
|
|
11
|
+
onEnter: [{ code: ["Enter", "NumpadEnter"] }],
|
|
12
|
+
onEscape: [{ code: "Escape" }],
|
|
13
|
+
});
|
|
5
14
|
/** @internal */
|
|
6
15
|
export function useCombobox(params) {
|
|
7
16
|
const { value, defaultValue = "", onValueChange, options, creatable = false } = params;
|
|
8
|
-
const
|
|
9
|
-
const
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
setInputValue(defaultValue);
|
|
15
|
-
setActiveIndex(null);
|
|
16
|
-
setSelectedOption(undefined);
|
|
17
|
-
}, [defaultValue, setInputValue]);
|
|
18
|
-
const availableOptions = useMemo(() => {
|
|
19
|
-
const value = normalizeValue(inputValue);
|
|
20
|
-
const selectedValue = selectedOption ? normalizeValue(selectedOption.label) : undefined;
|
|
21
|
-
// Show all options when there is no value or the value is the same as the selected value
|
|
22
|
-
if (!value || value === selectedValue) {
|
|
23
|
-
return options;
|
|
24
|
-
}
|
|
25
|
-
const matchedOptions = options.filter((option) => normalizeValue(option.label).includes(value));
|
|
26
|
-
const hasExactMatch = matchedOptions.some((option) => normalizeValue(option.label) === value);
|
|
27
|
-
// Add a creatable option if there are multiple matches and none matches the input exactly
|
|
28
|
-
if (creatable && !hasExactMatch) {
|
|
29
|
-
matchedOptions.push({
|
|
30
|
-
id: `creatable/${inputValue}`,
|
|
31
|
-
label: inputValue,
|
|
32
|
-
creatable: true,
|
|
33
|
-
});
|
|
34
|
-
}
|
|
35
|
-
return matchedOptions;
|
|
36
|
-
}, [options, inputValue, selectedOption, creatable]);
|
|
37
|
-
const activeOption = activeIndex == null ? undefined : availableOptions[activeIndex];
|
|
38
|
-
const { setReferenceRef, setFloatingRef, floatingStyles, getReferenceProps, getFloatingProps, getItemProps, registerItemRef, } = useComboboxFloating({ isOpen, setIsOpen, activeIndex, setActiveIndex });
|
|
39
|
-
const handleSelectOption = useCallback((option, index) => {
|
|
40
|
-
if (index !== undefined) {
|
|
41
|
-
setActiveIndex(index);
|
|
42
|
-
}
|
|
43
|
-
setSelectedOption(option);
|
|
44
|
-
setIsOpen(false);
|
|
45
|
-
setInputValue(option.label);
|
|
46
|
-
}, [setInputValue]);
|
|
47
|
-
const handleInputChange = useCallback((inputValue) => {
|
|
48
|
-
setInputValue(inputValue);
|
|
49
|
-
setIsOpen(true);
|
|
50
|
-
}, [setInputValue]);
|
|
51
|
-
const handleInputKeyDown = useCallback((event) => {
|
|
52
|
-
if (event.key === "Escape" && !isOpen && !isInputValueEmpty) {
|
|
53
|
-
event.stopPropagation();
|
|
54
|
-
resetState();
|
|
55
|
-
}
|
|
56
|
-
if (event.key === "Enter" && activeOption) {
|
|
57
|
-
event.preventDefault();
|
|
58
|
-
handleSelectOption(activeOption);
|
|
59
|
-
}
|
|
60
|
-
}, [activeOption, isInputValueEmpty, isOpen, handleSelectOption, resetState]);
|
|
61
|
-
const handleInputBlur = useCallback(() => {
|
|
62
|
-
if (inputValue && selectedOption && inputValue !== selectedOption.label && !creatable) {
|
|
63
|
-
setInputValue(selectedOption.label);
|
|
64
|
-
}
|
|
65
|
-
setIsOpen(false);
|
|
66
|
-
}, [inputValue, selectedOption, setInputValue, creatable]);
|
|
67
|
-
return useMemo(() => ({
|
|
68
|
-
availableOptions,
|
|
69
|
-
inputValue,
|
|
70
|
-
isOpen,
|
|
71
|
-
setIsOpen,
|
|
72
|
-
onInputChange: handleInputChange,
|
|
73
|
-
onInputKeyDown: handleInputKeyDown,
|
|
74
|
-
onInputBlur: handleInputBlur,
|
|
75
|
-
activeIndex,
|
|
76
|
-
setActiveIndex,
|
|
77
|
-
activeOption,
|
|
78
|
-
selectedOption,
|
|
79
|
-
selectOption: handleSelectOption,
|
|
80
|
-
setReferenceRef,
|
|
81
|
-
setFloatingRef,
|
|
82
|
-
registerItemRef,
|
|
83
|
-
getReferenceProps,
|
|
84
|
-
getFloatingProps,
|
|
85
|
-
getItemProps,
|
|
86
|
-
floatingStyles,
|
|
17
|
+
const listboxId = useId();
|
|
18
|
+
const selection = useComboboxSelection({
|
|
19
|
+
options,
|
|
20
|
+
value,
|
|
21
|
+
defaultValue,
|
|
22
|
+
onValueChange,
|
|
87
23
|
creatable,
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
24
|
+
setIsOpen: (open) => chrome.setIsOpen(open),
|
|
25
|
+
});
|
|
26
|
+
const chrome = useComboboxChrome(selection.availableOptions);
|
|
27
|
+
const activeOption = chrome.activeOption;
|
|
28
|
+
const onInputKeyDown = useMemo(() => {
|
|
29
|
+
// Leave Enter unhandled when there's no selectable target so creatable
|
|
30
|
+
// flows like UiTags (add tag on unhandled Enter) can react to it.
|
|
31
|
+
const onEnter = chrome.isOpen && activeOption
|
|
32
|
+
? activeOption.disabled
|
|
33
|
+
? () => undefined
|
|
34
|
+
: () => selection.selectOption(activeOption)
|
|
35
|
+
: undefined;
|
|
36
|
+
// Leave Escape unhandled when idle so the enclosing modal can dismiss.
|
|
37
|
+
const hasSomethingToClose = chrome.isOpen || selection.inputValue.length > 0;
|
|
38
|
+
const onEscape = hasSomethingToClose
|
|
39
|
+
? (event) => {
|
|
40
|
+
event.nativeEvent.stopPropagation();
|
|
41
|
+
if (chrome.isOpen) {
|
|
42
|
+
chrome.setIsOpen(false);
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
selection.resetState();
|
|
46
|
+
}
|
|
47
|
+
: undefined;
|
|
48
|
+
return comboboxKeys({
|
|
49
|
+
onArrowDown: () => chrome.focusByDelta(1),
|
|
50
|
+
onArrowUp: () => chrome.focusByDelta(-1),
|
|
51
|
+
onEnter,
|
|
52
|
+
onEscape,
|
|
53
|
+
});
|
|
54
|
+
}, [chrome, selection, activeOption]);
|
|
55
|
+
return useMemo(() => ({
|
|
56
|
+
availableOptions: selection.availableOptions,
|
|
57
|
+
inputValue: selection.inputValue,
|
|
58
|
+
isOpen: chrome.isOpen,
|
|
59
|
+
setIsOpen: chrome.setIsOpen,
|
|
60
|
+
onInputChange: selection.onInputChange,
|
|
61
|
+
onInputKeyDown,
|
|
62
|
+
onInputBlur: selection.onInputBlur,
|
|
63
|
+
activeIndex: chrome.activeIndex,
|
|
64
|
+
setActiveIndex: chrome.setActiveIndex,
|
|
96
65
|
activeOption,
|
|
97
|
-
selectedOption,
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
getReferenceProps,
|
|
103
|
-
getFloatingProps,
|
|
104
|
-
getItemProps,
|
|
105
|
-
floatingStyles,
|
|
66
|
+
selectedOption: selection.selectedOption,
|
|
67
|
+
selectOption: selection.selectOption,
|
|
68
|
+
anchorRef: chrome.anchorRef,
|
|
69
|
+
registerItemRef: chrome.registerItemRef,
|
|
70
|
+
shouldRenderPopup: selection.availableOptions.length > 0,
|
|
106
71
|
creatable,
|
|
107
|
-
|
|
108
|
-
}
|
|
109
|
-
function useControlledValue(params) {
|
|
110
|
-
const { value, defaultValue, onValueChange } = params;
|
|
111
|
-
const [uncontrolledValue, setUncontrolledValue] = useState(defaultValue);
|
|
112
|
-
const isControlled = value !== undefined;
|
|
113
|
-
const controlledValue = isControlled ? value : uncontrolledValue;
|
|
114
|
-
const setControlledValue = useCallback((newValue) => {
|
|
115
|
-
if (isControlled) {
|
|
116
|
-
onValueChange?.(newValue);
|
|
117
|
-
}
|
|
118
|
-
else {
|
|
119
|
-
setUncontrolledValue(newValue);
|
|
120
|
-
}
|
|
121
|
-
}, [isControlled, onValueChange]);
|
|
122
|
-
return [controlledValue, setControlledValue];
|
|
123
|
-
}
|
|
124
|
-
function useComboboxFloating(params) {
|
|
125
|
-
const { isOpen, setIsOpen, activeIndex, setActiveIndex } = params;
|
|
126
|
-
const listRef = useRef([]);
|
|
127
|
-
const { refs, floatingStyles, context } = useFloating({
|
|
128
|
-
placement: "bottom-start",
|
|
129
|
-
open: isOpen,
|
|
130
|
-
onOpenChange: setIsOpen,
|
|
131
|
-
whileElementsMounted: autoUpdate,
|
|
132
|
-
middleware: [
|
|
133
|
-
flip(),
|
|
134
|
-
size({
|
|
135
|
-
apply({ rects, elements }) {
|
|
136
|
-
elements.floating.style.width = `${rects.reference.width}px`;
|
|
137
|
-
},
|
|
138
|
-
}),
|
|
139
|
-
],
|
|
140
|
-
});
|
|
141
|
-
const listNav = useListNavigation(context, {
|
|
142
|
-
listRef,
|
|
143
|
-
activeIndex,
|
|
144
|
-
onNavigate: setActiveIndex,
|
|
145
|
-
virtual: true,
|
|
146
|
-
loop: true,
|
|
147
|
-
});
|
|
148
|
-
const click = useClick(context);
|
|
149
|
-
const dismiss = useDismiss(context);
|
|
150
|
-
const role = useRole(context, { role: "combobox" });
|
|
151
|
-
const { getReferenceProps, getFloatingProps, getItemProps } = useInteractions([
|
|
152
|
-
listNav,
|
|
153
|
-
click,
|
|
154
|
-
dismiss,
|
|
155
|
-
role,
|
|
156
|
-
]);
|
|
157
|
-
const registerItemRef = useCallback((node, index) => {
|
|
158
|
-
listRef.current[index] = node;
|
|
159
|
-
}, []);
|
|
160
|
-
return {
|
|
161
|
-
setReferenceRef: refs.setReference,
|
|
162
|
-
setFloatingRef: refs.setFloating,
|
|
163
|
-
floatingStyles,
|
|
164
|
-
getReferenceProps,
|
|
165
|
-
getFloatingProps,
|
|
166
|
-
getItemProps,
|
|
167
|
-
registerItemRef,
|
|
168
|
-
};
|
|
72
|
+
listboxId,
|
|
73
|
+
}), [chrome, selection, onInputKeyDown, activeOption, creatable, listboxId]);
|
|
169
74
|
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { IUiComboboxOption, IUiComboboxState } from "./types.js";
|
|
2
|
+
type IUseComboboxChromeReturn = Pick<IUiComboboxState, "isOpen" | "setIsOpen" | "activeIndex" | "setActiveIndex" | "anchorRef" | "registerItemRef"> & {
|
|
3
|
+
/** The currently highlighted option, or undefined. */
|
|
4
|
+
activeOption: IUiComboboxOption | undefined;
|
|
5
|
+
/** Open the popup if needed and move the highlight by `delta`, wrapping around. */
|
|
6
|
+
focusByDelta: (delta: 1 | -1) => void;
|
|
7
|
+
};
|
|
8
|
+
/**
|
|
9
|
+
* Owns popup open/close, highlight, and scroll. The highlight is tracked by
|
|
10
|
+
* option **id**, not index: when the option list changes (async results arrive,
|
|
11
|
+
* a row is filtered out) a highlighted row that's gone simply resolves to no
|
|
12
|
+
* index, so the highlight can never point at a different row than the user
|
|
13
|
+
* navigated to. Callers pass the current `options` so the id ⇄ index mapping
|
|
14
|
+
* and `focusByDelta` wrapping stay in sync with what's rendered.
|
|
15
|
+
*
|
|
16
|
+
* @internal
|
|
17
|
+
*/
|
|
18
|
+
export declare function useComboboxChrome(options: IUiComboboxOption[]): IUseComboboxChromeReturn;
|
|
19
|
+
export {};
|
|
20
|
+
//# sourceMappingURL=useComboboxChrome.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useComboboxChrome.d.ts","sourceRoot":"","sources":["../../../src/@ui/UiCombobox/useComboboxChrome.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAEtE,KAAK,wBAAwB,GAAG,IAAI,CAChC,gBAAgB,EAChB,QAAQ,GAAG,WAAW,GAAG,aAAa,GAAG,gBAAgB,GAAG,WAAW,GAAG,iBAAiB,CAC9F,GAAG;IACA,sDAAsD;IACtD,YAAY,EAAE,iBAAiB,GAAG,SAAS,CAAC;IAC5C,mFAAmF;IACnF,YAAY,EAAE,CAAC,KAAK,EAAE,CAAC,GAAG,CAAC,CAAC,KAAK,IAAI,CAAC;CACzC,CAAC;AAEF;;;;;;;;;GASG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,iBAAiB,EAAE,GAAG,wBAAwB,CA6FxF"}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
// (C) 2026 GoodData Corporation
|
|
2
|
+
import { useCallback, useMemo, useRef, useState } from "react";
|
|
3
|
+
/**
|
|
4
|
+
* Owns popup open/close, highlight, and scroll. The highlight is tracked by
|
|
5
|
+
* option **id**, not index: when the option list changes (async results arrive,
|
|
6
|
+
* a row is filtered out) a highlighted row that's gone simply resolves to no
|
|
7
|
+
* index, so the highlight can never point at a different row than the user
|
|
8
|
+
* navigated to. Callers pass the current `options` so the id ⇄ index mapping
|
|
9
|
+
* and `focusByDelta` wrapping stay in sync with what's rendered.
|
|
10
|
+
*
|
|
11
|
+
* @internal
|
|
12
|
+
*/
|
|
13
|
+
export function useComboboxChrome(options) {
|
|
14
|
+
const [isOpen, setIsOpenState] = useState(false);
|
|
15
|
+
const [activeId, setActiveId] = useState(null);
|
|
16
|
+
// A highlight only has meaning while the popup is open, so closing always
|
|
17
|
+
// drops it — reopening then starts fresh. This is the single point that
|
|
18
|
+
// keeps a stale highlight from surviving Escape / blur / reset and being
|
|
19
|
+
// Enter-selected on the next open.
|
|
20
|
+
const setIsOpen = useCallback((open) => {
|
|
21
|
+
setIsOpenState(open);
|
|
22
|
+
if (!open) {
|
|
23
|
+
setActiveId(null);
|
|
24
|
+
}
|
|
25
|
+
}, []);
|
|
26
|
+
const anchorRef = useRef(null);
|
|
27
|
+
const itemRefs = useRef([]);
|
|
28
|
+
// Target index for when the scroll request runs before the item mounts.
|
|
29
|
+
const pendingScrollIndexRef = useRef(null);
|
|
30
|
+
const activeIndex = activeId == null ? null : options.findIndex((o) => o.id === activeId);
|
|
31
|
+
// findIndex returns -1 for a vanished row; surface that as "no highlight".
|
|
32
|
+
const safeActiveIndex = activeIndex != null && activeIndex >= 0 ? activeIndex : null;
|
|
33
|
+
const activeOption = safeActiveIndex == null ? undefined : options[safeActiveIndex];
|
|
34
|
+
const scrollIndexIntoView = useCallback((index) => {
|
|
35
|
+
const node = itemRefs.current[index];
|
|
36
|
+
if (node) {
|
|
37
|
+
pendingScrollIndexRef.current = null;
|
|
38
|
+
node.scrollIntoView({ block: "nearest" });
|
|
39
|
+
}
|
|
40
|
+
else {
|
|
41
|
+
pendingScrollIndexRef.current = index;
|
|
42
|
+
}
|
|
43
|
+
}, []);
|
|
44
|
+
const registerItemRef = useCallback((node, index) => {
|
|
45
|
+
itemRefs.current[index] = node;
|
|
46
|
+
if (node != null && pendingScrollIndexRef.current === index) {
|
|
47
|
+
pendingScrollIndexRef.current = null;
|
|
48
|
+
node.scrollIntoView({ block: "nearest" });
|
|
49
|
+
}
|
|
50
|
+
}, []);
|
|
51
|
+
const setActiveIndex = useCallback((index) => setActiveId(index == null ? null : (options[index]?.id ?? null)), [options]);
|
|
52
|
+
const focusByDelta = useCallback((delta) => {
|
|
53
|
+
const total = options.length;
|
|
54
|
+
if (total === 0) {
|
|
55
|
+
setIsOpen(true);
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
// Resolve against the current list so a stale/removed highlight still
|
|
59
|
+
// produces a sensible next target.
|
|
60
|
+
const current = safeActiveIndex;
|
|
61
|
+
const next = !isOpen || current == null
|
|
62
|
+
? delta === 1
|
|
63
|
+
? 0
|
|
64
|
+
: total - 1
|
|
65
|
+
: (current + delta + total) % total;
|
|
66
|
+
setIsOpen(true);
|
|
67
|
+
setActiveId(options[next]?.id ?? null);
|
|
68
|
+
scrollIndexIntoView(next);
|
|
69
|
+
}, [isOpen, options, safeActiveIndex, scrollIndexIntoView, setIsOpen]);
|
|
70
|
+
return useMemo(() => ({
|
|
71
|
+
isOpen,
|
|
72
|
+
setIsOpen,
|
|
73
|
+
activeIndex: safeActiveIndex,
|
|
74
|
+
activeOption,
|
|
75
|
+
setActiveIndex,
|
|
76
|
+
anchorRef,
|
|
77
|
+
registerItemRef,
|
|
78
|
+
focusByDelta,
|
|
79
|
+
}), [
|
|
80
|
+
isOpen,
|
|
81
|
+
setIsOpen,
|
|
82
|
+
safeActiveIndex,
|
|
83
|
+
activeOption,
|
|
84
|
+
setActiveIndex,
|
|
85
|
+
anchorRef,
|
|
86
|
+
registerItemRef,
|
|
87
|
+
focusByDelta,
|
|
88
|
+
]);
|
|
89
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { IUiComboboxOption } from "./types.js";
|
|
2
|
+
/** @internal */
|
|
3
|
+
export interface IUseComboboxSelectionParams {
|
|
4
|
+
options: IUiComboboxOption[];
|
|
5
|
+
value?: string;
|
|
6
|
+
defaultValue?: string;
|
|
7
|
+
onValueChange?: (value: string) => void;
|
|
8
|
+
creatable?: boolean;
|
|
9
|
+
setIsOpen: (open: boolean) => void;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* @internal
|
|
13
|
+
*/
|
|
14
|
+
export declare function useComboboxSelection({ options, value, defaultValue, onValueChange, creatable, setIsOpen }: IUseComboboxSelectionParams): {
|
|
15
|
+
availableOptions: IUiComboboxOption[];
|
|
16
|
+
inputValue: string;
|
|
17
|
+
onInputChange: (next: string) => void;
|
|
18
|
+
onInputBlur: () => void;
|
|
19
|
+
selectedOption: IUiComboboxOption | undefined;
|
|
20
|
+
selectOption: (option: IUiComboboxOption) => void;
|
|
21
|
+
resetState: () => void;
|
|
22
|
+
};
|
|
23
|
+
//# sourceMappingURL=useComboboxSelection.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useComboboxSelection.d.ts","sourceRoot":"","sources":["../../../src/@ui/UiCombobox/useComboboxSelection.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAGpD,gBAAgB;AAChB,MAAM,WAAW,2BAA2B;IACxC,OAAO,EAAE,iBAAiB,EAAE,CAAC;IAC7B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,aAAa,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACxC,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,SAAS,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAC;CACtC;AAED;;GAEG;AACH,wBAAgB,oBAAoB,CAAC,EACjC,OAAO,EACP,KAAK,EACL,YAAiB,EACjB,aAAa,EACb,SAAiB,EACjB,SAAS,EACZ,EAAE,2BAA2B;;;;;;;;EA4E7B"}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
// (C) 2026 GoodData Corporation
|
|
2
|
+
import { useCallback, useMemo, useState } from "react";
|
|
3
|
+
import { normalizeValue } from "./utils.js";
|
|
4
|
+
/**
|
|
5
|
+
* @internal
|
|
6
|
+
*/
|
|
7
|
+
export function useComboboxSelection({ options, value, defaultValue = "", onValueChange, creatable = false, setIsOpen, }) {
|
|
8
|
+
const [inputValue, setInputValue] = useControlledValue({ value, defaultValue, onValueChange });
|
|
9
|
+
const [selectedOption, setSelectedOption] = useState(undefined);
|
|
10
|
+
const resetState = useCallback(() => {
|
|
11
|
+
setInputValue(defaultValue);
|
|
12
|
+
setSelectedOption(undefined);
|
|
13
|
+
}, [defaultValue, setInputValue]);
|
|
14
|
+
const availableOptions = useMemo(() => {
|
|
15
|
+
const value = normalizeValue(inputValue);
|
|
16
|
+
const selectedValue = selectedOption ? normalizeValue(selectedOption.label) : undefined;
|
|
17
|
+
// Show all options when there is no value or the value is the same as the selected value
|
|
18
|
+
if (!value || value === selectedValue) {
|
|
19
|
+
return options;
|
|
20
|
+
}
|
|
21
|
+
const matchedOptions = options.filter((option) => normalizeValue(option.label).includes(value));
|
|
22
|
+
const hasExactMatch = matchedOptions.some((option) => normalizeValue(option.label) === value);
|
|
23
|
+
// Add a creatable option if there are multiple matches and none matches the input exactly
|
|
24
|
+
if (creatable && !hasExactMatch) {
|
|
25
|
+
matchedOptions.push({
|
|
26
|
+
id: `creatable/${inputValue}`,
|
|
27
|
+
label: inputValue,
|
|
28
|
+
creatable: true,
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
return matchedOptions;
|
|
32
|
+
}, [options, inputValue, selectedOption, creatable]);
|
|
33
|
+
const selectOption = useCallback((option) => {
|
|
34
|
+
// Hover sets the highlight without checking `disabled`, so without
|
|
35
|
+
// this guard a disabled row could be Enter-confirmed even though
|
|
36
|
+
// clicking it is blocked in the list item.
|
|
37
|
+
if (option.disabled) {
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
setSelectedOption(option);
|
|
41
|
+
setIsOpen(false);
|
|
42
|
+
setInputValue(option.label);
|
|
43
|
+
}, [setIsOpen, setInputValue]);
|
|
44
|
+
const onInputChange = useCallback((next) => {
|
|
45
|
+
setInputValue(next);
|
|
46
|
+
setIsOpen(true);
|
|
47
|
+
}, [setInputValue, setIsOpen]);
|
|
48
|
+
const onInputBlur = useCallback(() => {
|
|
49
|
+
if (inputValue && selectedOption && inputValue !== selectedOption.label && !creatable) {
|
|
50
|
+
setInputValue(selectedOption.label);
|
|
51
|
+
}
|
|
52
|
+
setIsOpen(false);
|
|
53
|
+
}, [inputValue, selectedOption, setInputValue, creatable, setIsOpen]);
|
|
54
|
+
return useMemo(() => ({
|
|
55
|
+
availableOptions,
|
|
56
|
+
inputValue,
|
|
57
|
+
onInputChange,
|
|
58
|
+
onInputBlur,
|
|
59
|
+
selectedOption,
|
|
60
|
+
selectOption,
|
|
61
|
+
resetState,
|
|
62
|
+
}), [availableOptions, inputValue, onInputChange, onInputBlur, selectedOption, selectOption, resetState]);
|
|
63
|
+
}
|
|
64
|
+
function useControlledValue(params) {
|
|
65
|
+
const { value, defaultValue, onValueChange } = params;
|
|
66
|
+
const [uncontrolledValue, setUncontrolledValue] = useState(defaultValue);
|
|
67
|
+
const isControlled = value !== undefined;
|
|
68
|
+
const controlledValue = isControlled ? value : uncontrolledValue;
|
|
69
|
+
const setControlledValue = useCallback((newValue) => {
|
|
70
|
+
if (isControlled) {
|
|
71
|
+
onValueChange?.(newValue);
|
|
72
|
+
}
|
|
73
|
+
else {
|
|
74
|
+
setUncontrolledValue(newValue);
|
|
75
|
+
}
|
|
76
|
+
}, [isControlled, onValueChange]);
|
|
77
|
+
return [controlledValue, setControlledValue];
|
|
78
|
+
}
|
|
@@ -5,7 +5,7 @@ import { usePropState } from "@gooddata/sdk-ui";
|
|
|
5
5
|
import { isElementTextInput } from "../../utils/domUtilities.js";
|
|
6
6
|
import { useId } from "../../utils/useId.js";
|
|
7
7
|
import { bem } from "../@utils/bem.js";
|
|
8
|
-
import {
|
|
8
|
+
import { UiFloatingPanel } from "../UiFloatingPanel/UiFloatingPanel.js";
|
|
9
9
|
import { UiFocusManager } from "../UiFocusManager/UiFocusManager.js";
|
|
10
10
|
import { resolveRef } from "../UiFocusManager/utils.js";
|
|
11
11
|
const { e } = bem("gd-ui-kit-dropdown");
|
|
@@ -118,9 +118,9 @@ export function UiDropdown({ renderButton, renderBody, isOpen: isOpenProp, onOpe
|
|
|
118
118
|
},
|
|
119
119
|
}), [closeDropdown, dropdownId]);
|
|
120
120
|
return (_jsxs(_Fragment, { children: [
|
|
121
|
-
_jsx("div", { ref: buttonWrapperRef, id: buttonId, className: e("button", { fullWidth: !!fullWidthButton }), onKeyDown: handleKeyDown, children: renderButton(buttonRenderProps) }), _jsx(
|
|
121
|
+
_jsx("div", { ref: buttonWrapperRef, id: buttonId, className: e("button", { fullWidth: !!fullWidthButton }), onKeyDown: handleKeyDown, children: renderButton(buttonRenderProps) }), _jsx(UiFloatingPanel, { 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: {
|
|
122
122
|
role: accessibilityConfig?.popupRole ?? "dialog",
|
|
123
123
|
ariaLabelledBy: buttonId,
|
|
124
|
-
}, children: _jsx(UiFocusManager, { tabOutHandler: enableFocusTrap ? undefined : handleTabOut, enableFocusTrap: enableFocusTrap, enableAutofocus: autofocusOnOpen ? { initialFocus } : false, enableReturnFocusOnUnmount: { returnFocusTo: returnFocusTo ?? buttonRef }, children:
|
|
124
|
+
}, children: _jsx(UiFocusManager, { tabOutHandler: enableFocusTrap ? undefined : handleTabOut, enableFocusTrap: enableFocusTrap, enableAutofocus: autofocusOnOpen ? { initialFocus } : false, enableReturnFocusOnUnmount: { returnFocusTo: returnFocusTo ?? buttonRef }, children: renderBody(bodyRenderProps) }) })
|
|
125
125
|
] }));
|
|
126
126
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"UiFloatingElement.d.ts","sourceRoot":"","sources":["../../../src/@ui/UiFloatingElement/UiFloatingElement.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"UiFloatingElement.d.ts","sourceRoot":"","sources":["../../../src/@ui/UiFloatingElement/UiFloatingElement.tsx"],"names":[],"mappings":"AAmBA,OAAO,EAAE,KAAK,uBAAuB,EAAE,MAAM,YAAY,CAAC;AAS1D;;;;;;;;;;;;;;;;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,EACpB,EAAE,uBAAuB,kDA+FzB"}
|