/** @license MIT | @cube-dev/ui-kit v0.0.0-canary-e694c50 | Cube Dev Team */
import { extractStyles } from "../../../utils/styles.js";
import { forwardRefWithGenerics } from "../../../utils/react/forwardRefWithGenerics.js";
import { useLayoutEffect as useLayoutEffect$1 } from "../../../utils/react/useLayoutEffect.js";
import { mergeProps as mergeProps$1 } from "../../../utils/react/mergeProps.js";
import { useCombinedRefs } from "../../../utils/react/useCombinedRefs.js";
import { useEventBus } from "../../../utils/react/useEventBus.js";
import { useEvent } from "../../../_internal/hooks/use-event.js";
import { _Text } from "../../content/Text.js";
import { useFocus as useFocus$1 } from "../../../utils/react/interactions.js";
import { DisplayTransition } from "../../helpers/DisplayTransition/DisplayTransition.js";
import { Portal } from "../../portal/Portal.js";
import { LoadingIcon } from "../../../icons/LoadingIcon.js";
import { useProviderProps } from "../../../provider.js";
import { ItemAction } from "../../actions/ItemAction/ItemAction.js";
import { _CollectionItem, filterCollectionItemProps } from "../../CollectionItem.js";
import { _Item } from "../../content/Item/Item.js";
import { CloseIcon } from "../../../icons/CloseIcon.js";
import { DirectionIcon } from "../../../icons/DirectionIcon.js";
import { StyledDivider, StyledSection, StyledSectionHeading } from "../../actions/Menu/styled.js";
import { generateRandomId } from "../../../utils/random.js";
import { useFormProps } from "../../form/Form/Form.js";
import { useFieldProps } from "../../form/Form/use-field/use-field-props.js";
import { wrapWithField } from "../../form/wrapper.js";
import { chainRaf } from "../../../utils/raf.js";
import { InvalidIcon } from "../../shared/InvalidIcon.js";
import { ValidIcon } from "../../shared/ValidIcon.js";
import { BASE_STYLES, COLOR_STYLES, OUTER_STYLES, tasty } from "@tenphi/tasty";
import React, { cloneElement, useEffect, useMemo, useRef } from "react";
import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
import { DismissButton, FocusScope, HiddenSelect, useButton, useHover, useListBox, useListBoxSection, useOption, useOverlay, useOverlayPosition, useSelect } from "react-aria";
import { Section, useSelectState } from "react-stately";

//#region src/components/fields/Select/Select.tsx
const SelectWrapperElement = tasty({
	qa: "SelectWrapper",
	styles: {
		display: "grid",
		position: "relative",
		radius: true,
		fill: {
			"": "#white",
			disabled: "#dark.04",
			"theme=special": "#clear"
		},
		color: {
			"": "#dark.85",
			focused: "#dark.85",
			invalid: "#danger-text",
			disabled: "#dark.30"
		}
	}
});
const ListBoxElement = tasty({
	qa: "ListBox",
	as: "ul",
	styles: {
		display: "flex",
		gap: "1bw",
		flow: "column",
		margin: "0",
		padding: "0",
		listStyle: "none",
		scrollbar: "styled"
	}
});
const OptionItem = tasty(_Item, {
	as: "li",
	disableActionsFocus: true,
	qa: "Option",
	styles: { "$inline-compensation": "0px" }
});
const SelectOverlayWrapper = tasty({
	qa: "SelectOverlayWrapper",
	styles: {
		position: "absolute",
		zIndex: 1e3
	}
});
const OverlayElement = tasty({
	qa: "SelectOverlay",
	styles: {
		width: "min $overlay-min-width",
		display: "grid",
		gridRows: "1sf",
		height: "initial max-content (50vh - 5x)",
		overflow: "auto",
		background: "#white",
		radius: "1cr",
		shadow: true,
		padding: ".5x",
		border: true,
		boxSizing: "border-box",
		transition: "translate $transition ease-out, scale $transition ease-out, theme $transition ease-out",
		translate: {
			"": "0 0",
			"open & [data-placement=\"top\"]": "0 0",
			"!open & [data-placement=\"top\"]": "0 1x",
			"open & ([data-placement=\"bottom\"] | ![data-placement])": "0 0",
			"!open & ([data-placement=\"bottom\"] | ![data-placement])": "0 -1x"
		},
		transformOrigin: {
			"": "top center",
			"[data-placement=\"top\"]": "bottom center"
		},
		scale: {
			"": "1 1",
			"!open": "1 .9"
		},
		opacity: {
			"": 1,
			"!open": .001
		}
	}
});
const PROP_STYLES = [
	...BASE_STYLES,
	...OUTER_STYLES,
	...COLOR_STYLES
];
function Select(props, ref) {
	props = useProviderProps(props);
	props = useFormProps(props);
	props = useFieldProps(props, {
		defaultValidationTrigger: "onChange",
		valuePropsMapper: ({ value, onChange }) => ({
			selectedKey: value ?? null,
			onSelectionChange: onChange
		})
	});
	let { qa, label, extra, icon, rightIcon, labelStyles, isRequired, necessityIndicator, validationState, prefix, isDisabled = props.isLoading || false, autoFocus, inputProps, triggerRef, popoverRef, listBoxRef, isLoading, loadingIndicator, overlayOffset = 8, inputStyles, triggerStyles, optionStyles, listBoxStyles, overlayStyles, suffix, message, triggerDescription, descriptionPlacement, hotkeys, direction = "bottom", shouldFlip = true, containerPadding = 8, placeholder, tooltip, size = "medium", shape, styles, type = "outline", theme = "default", labelSuffix, suffixPosition = "before", isClearable, onOpenChange, form, ...otherProps } = props;
	let state = useSelectState(props);
	const selectId = useMemo(() => generateRandomId(), []);
	const { emit, on } = useEventBus();
	useEffect(() => {
		return on("popover:open", (data) => {
			if (data.menuId !== selectId && state.isOpen) state.close();
		});
	}, [
		on,
		selectId,
		state
	]);
	useEffect(() => {
		if (state.isOpen) emit("popover:open", { menuId: selectId });
	}, [
		state.isOpen,
		emit,
		selectId
	]);
	useEffect(() => {
		onOpenChange?.(state.isOpen);
	}, [state.isOpen]);
	styles = extractStyles(otherProps, PROP_STYLES, styles);
	ref = useCombinedRefs(ref);
	triggerRef = useCombinedRefs(triggerRef);
	popoverRef = useCombinedRefs(popoverRef);
	listBoxRef = useCombinedRefs(listBoxRef);
	let { labelProps, triggerProps, valueProps, menuProps } = useSelect(props, state, triggerRef);
	let { overlayProps, placement, updatePosition } = useOverlayPosition({
		targetRef: triggerRef,
		overlayRef: popoverRef,
		scrollRef: listBoxRef,
		placement: `${direction} end`,
		shouldFlip,
		isOpen: state.isOpen,
		onClose: state.close,
		offset: overlayOffset,
		containerPadding
	});
	let { isFocused, focusProps } = useFocus$1({ isDisabled }, true);
	let { hoverProps, isHovered } = useHover({ isDisabled });
	let { buttonProps } = useButton(triggerProps, triggerRef);
	let isInvalid = validationState === "invalid";
	let validation = cloneElement(isInvalid ? InvalidIcon : ValidIcon);
	let hasSelection = state.selectedItem != null;
	let showClearButton = isClearable && hasSelection && !isDisabled && !props.isReadOnly;
	let clearValue = useEvent(() => {
		props.onSelectionChange?.(null);
		state.setSelectedKey(null);
		if (state.isOpen) state.close();
		triggerRef.current?.focus?.();
		props.onClear?.();
	});
	let triggerWidth = triggerRef?.current?.offsetWidth;
	const showPlaceholder = !!placeholder?.trim() && !state.selectedItem;
	const modifiers = useMemo(() => ({
		invalid: isInvalid,
		valid: validationState === "valid",
		disabled: isDisabled,
		loading: isLoading,
		hovered: isHovered,
		focused: isFocused,
		placeholder: showPlaceholder,
		prefix: !!prefix,
		suffix: true
	}), [
		validationState,
		isDisabled,
		isLoading,
		isHovered,
		isFocused,
		showPlaceholder,
		prefix
	]);
	suffix = useMemo(() => {
		if (!suffix && !validationState) return null;
		return /* @__PURE__ */ jsxs(Fragment$1, { children: [suffix, validationState ? validation : null] });
	}, [
		suffix,
		validationState,
		validation
	]);
	return wrapWithField(/* @__PURE__ */ jsxs(SelectWrapperElement, {
		mods: modifiers,
		styles,
		"data-size": size,
		"data-type": type,
		"data-theme": theme,
		children: [
			/* @__PURE__ */ jsx(HiddenSelect, {
				state,
				triggerRef,
				label: props.label,
				name: props.name
			}),
			/* @__PURE__ */ jsx(_Item, {
				as: "button",
				qa: qa || "Select",
				"data-input-type": "select",
				...mergeProps$1(buttonProps, hoverProps, focusProps),
				ref: triggerRef,
				"data-popover-trigger": true,
				styles: {
					...inputStyles,
					...triggerStyles
				},
				theme,
				size,
				shape,
				htmlType: "button",
				type,
				mods: modifiers,
				prefix,
				suffix,
				icon,
				rightIcon: rightIcon !== void 0 ? rightIcon : showClearButton ? /* @__PURE__ */ jsx(ItemAction, {
					icon: /* @__PURE__ */ jsx(CloseIcon, {}),
					theme: validationState === "invalid" ? "danger" : void 0,
					qa: "SelectClearButton",
					mods: { pressed: false },
					onPress: clearValue
				}) : isLoading ? /* @__PURE__ */ jsx(LoadingIcon, {}) : /* @__PURE__ */ jsx(DirectionIcon, { to: state.isOpen ? "up" : "down" }),
				description: triggerDescription,
				descriptionPlacement,
				hotkeys,
				tooltip,
				labelProps: valueProps,
				children: state.selectedItem ? state.selectedItem.rendered : placeholder ? /* @__PURE__ */ jsx(_Text.Placeholder, { children: placeholder }) : null
			}),
			/* @__PURE__ */ jsx(ListBoxPopup, {
				...menuProps,
				popoverRef,
				listBoxRef,
				overlayProps,
				placement,
				updatePosition,
				state,
				listBoxStyles,
				overlayStyles,
				optionStyles,
				minWidth: triggerWidth,
				triggerRef,
				isDisabled
			})
		]
	}), ref, mergeProps$1({ ...props }, { labelProps }));
}
function ListBoxPopup({ state, popoverRef, listBoxRef, listBoxStyles, overlayStyles, optionStyles, overlayProps: parentOverlayProps, shouldUseVirtualFocus = false, placement, updatePosition, minWidth, size = "small", triggerRef, isDisabled, ...otherProps }) {
	const listItemSize = size === "small" ? "medium" : size;
	useLayoutEffect$1(() => {
		if (state.isOpen && updatePosition) return chainRaf(() => {
			updatePosition();
		}, 3);
	}, [state.isOpen]);
	let { listBoxProps } = useListBox({
		autoFocus: state.focusStrategy || true,
		shouldUseVirtualFocus,
		...otherProps
	}, state, listBoxRef);
	let { overlayProps } = useOverlay({
		onClose: () => state.close(),
		shouldCloseOnBlur: true,
		isOpen: state.isOpen,
		isDismissable: true,
		shouldCloseOnInteractOutside: (el) => {
			const menuTriggerEl = el.closest("[data-popover-trigger]");
			if (!menuTriggerEl) return true;
			if (menuTriggerEl === triggerRef?.current) return true;
			return false;
		}
	}, popoverRef);
	const placementDirection = placement?.split(" ")[0] || "bottom";
	return /* @__PURE__ */ jsx(Portal, { children: /* @__PURE__ */ jsx(DisplayTransition, {
		isShown: state.isOpen && !isDisabled,
		children: ({ phase, isShown, ref: transitionRef }) => /* @__PURE__ */ jsx(SelectOverlayWrapper, {
			...overlayProps,
			...parentOverlayProps,
			ref: popoverRef,
			style: parentOverlayProps?.style,
			children: /* @__PURE__ */ jsx(OverlayElement, {
				ref: transitionRef,
				"data-placement": placementDirection,
				"data-phase": phase,
				mods: { open: isShown },
				styles: overlayStyles,
				style: { "--overlay-min-width": minWidth ? `${minWidth}px` : "initial" },
				children: /* @__PURE__ */ jsxs(FocusScope, {
					restoreFocus: true,
					children: [
						/* @__PURE__ */ jsx(DismissButton, { onDismiss: () => state.close() }),
						(() => {
							const renderedItems = [];
							let isFirstSection = true;
							for (const item of state.collection) if (item.type === "section") {
								if (!isFirstSection) renderedItems.push(/* @__PURE__ */ jsx(StyledDivider, {
									as: "li",
									role: "separator",
									"aria-orientation": "horizontal"
								}, `divider-${String(item.key)}`));
								renderedItems.push(/* @__PURE__ */ jsx(SelectSection, {
									item,
									state,
									optionStyles,
									sectionStyles: void 0,
									shouldUseVirtualFocus,
									size: listItemSize
								}, item.key));
								isFirstSection = false;
							} else renderedItems.push(/* @__PURE__ */ jsx(Option, {
								item,
								state,
								styles: optionStyles,
								shouldUseVirtualFocus,
								size: listItemSize
							}, item.key));
							return /* @__PURE__ */ jsx(ListBoxElement, {
								styles: listBoxStyles,
								...listBoxProps,
								ref: listBoxRef,
								children: renderedItems
							});
						})(),
						/* @__PURE__ */ jsx(DismissButton, { onDismiss: () => state.close() })
					]
				})
			})
		})
	}) });
}
function Option({ item, state, styles, shouldUseVirtualFocus, size }) {
	let ref = useRef(null);
	let isDisabled = state.disabledKeys.has(item.key);
	let isSelected = state.selectionManager.isSelected(item.key);
	let isVirtualFocused = state.selectionManager.focusedKey === item.key;
	let { optionProps, isPressed, labelProps, descriptionProps } = useOption({
		key: item.key,
		isDisabled,
		isSelected,
		shouldSelectOnPressUp: true,
		shouldFocusOnHover: true,
		shouldUseVirtualFocus
	}, state, ref);
	let { isFocused, focusProps } = useFocus$1({ isDisabled });
	const filteredItemProps = filterCollectionItemProps(item.props);
	return /* @__PURE__ */ jsx(OptionItem, {
		...mergeProps$1(optionProps, focusProps, filteredItemProps),
		ref,
		mods: {
			listboxitem: true,
			selected: isSelected,
			focused: shouldUseVirtualFocus ? isVirtualFocused : isFocused,
			disabled: isDisabled,
			pressed: isPressed
		},
		"data-size": size,
		styles: {
			...styles,
			...filteredItemProps.styles
		},
		labelProps,
		descriptionProps,
		defaultTooltipPlacement: "right",
		children: item.rendered
	});
}
function SelectSection(props) {
	const { item, state, optionStyles, headingStyles, sectionStyles, shouldUseVirtualFocus, size } = props;
	const heading = item.rendered;
	const { itemProps, headingProps, groupProps } = useListBoxSection({
		heading,
		"aria-label": item["aria-label"]
	});
	return /* @__PURE__ */ jsxs(StyledSection, {
		...itemProps,
		styles: sectionStyles,
		children: [heading && /* @__PURE__ */ jsx(StyledSectionHeading, {
			...headingProps,
			size,
			styles: {
				...headingStyles,
				"$inline-compensation": "0px"
			},
			children: heading
		}), /* @__PURE__ */ jsx(ListBoxElement, {
			...groupProps,
			mods: { section: true },
			children: [...item.childNodes].filter((node) => state.collection.getItem(node.key)).map((node) => /* @__PURE__ */ jsx(Option, {
				item: node,
				state,
				styles: optionStyles,
				shouldUseVirtualFocus,
				size
			}, node.key))
		})]
	});
}
const _Select = forwardRefWithGenerics(Select);
_Select.cubeInputType = "Select";
const SelectSectionComponent = Object.assign(Section, { displayName: "Section" });
const __Select = Object.assign(_Select, {
	Item: _CollectionItem,
	Section: SelectSectionComponent
});
__Select.displayName = "Select";

//#endregion
export { ListBoxElement, ListBoxPopup, __Select, useSelectState };
//# sourceMappingURL=Select.js.map