"use client";
import { useProps } from "../../core/MantineProvider/use-props/use-props.mjs";
import { useResolvedStylesApi } from "../../core/styles-api/use-resolved-styles-api/use-resolved-styles-api.mjs";
import { useStyles } from "../../core/styles-api/use-styles/use-styles.mjs";
import { extractStyleProps } from "../../core/Box/style-props/extract-style-props/extract-style-props.mjs";
import { genericFactory } from "../../core/factory/factory.mjs";
import { ScrollArea } from "../ScrollArea/ScrollArea.mjs";
import { InputBase } from "../InputBase/InputBase.mjs";
import { useCombobox } from "../Combobox/use-combobox/use-combobox.mjs";
import { Combobox } from "../Combobox/Combobox.mjs";
import { Pill } from "../Pill/Pill.mjs";
import { PillsInput } from "../PillsInput/PillsInput.mjs";
import { findTreeNode, getChildrenNodesValues } from "../Tree/get-children-nodes-values/get-children-nodes-values.mjs";
import { isNodeChecked } from "../Tree/is-node-checked/is-node-checked.mjs";
import { isNodeIndeterminate } from "../Tree/is-node-indeterminate/is-node-indeterminate.mjs";
import { getTreeExpandedState } from "../Tree/use-tree.mjs";
import { filterTreeData } from "../Tree/filter-tree-data/filter-tree-data.mjs";
import { flattenTreeSelectData } from "./flatten-tree-select-data.mjs";
import { checkedToValue, expandToLeafChecked } from "./get-checked-values-by-strategy.mjs";
import TreeSelect_module_default from "./TreeSelect.module.mjs";
import { TreeSelectOption } from "./TreeSelectOption.mjs";
import { useCallback, useEffect, useMemo, useRef } from "react";
import { useId as useId$1, useUncontrolled } from "@mantine/hooks";
import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
//#region packages/@mantine/core/src/components/TreeSelect/TreeSelect.tsx
const defaultProps = {
	mode: "single",
	allowDeselect: true,
	checkedStrategy: "child",
	maxValues: Infinity,
	hiddenInputValuesDivider: ",",
	clearSearchOnChange: true,
	openOnFocus: true,
	size: "sm",
	withLines: true
};
const clearSectionOffset = {
	xs: 41,
	sm: 50,
	md: 60,
	lg: 72,
	xl: 89
};
function getAncestorsToNode(value, nodes) {
	for (const node of nodes) {
		if (node.value === value) return [];
		if (Array.isArray(node.children)) {
			const path = getAncestorsToNode(value, node.children);
			if (path !== null) return [node.value, ...path];
		}
	}
	return null;
}
const TreeSelect = genericFactory((_props) => {
	const props = useProps([
		"Input",
		"InputWrapper",
		"TreeSelect"
	], defaultProps, _props);
	const { classNames, className, style, styles, unstyled, vars, size, data, mode, value, defaultValue, onChange, checkStrictly, checkedStrategy, defaultExpandedValues, defaultExpandAll, expandedValues, onExpandedChange, expandOnClick, searchable, searchValue, defaultSearchValue, onSearchChange, filter, nothingFoundMessage, allowDeselect, clearable, clearSectionMode, clearButtonProps, maxValues, maxDisplayedValues, maxDisplayedValuesContent, onRemove, onClear, renderNode, withLines, hiddenInputProps, hiddenInputValuesDivider, scrollAreaProps, chevronColor, maxDropdownHeight, dropdownOpened, defaultDropdownOpened, onDropdownOpen, onDropdownClose, comboboxProps, clearSearchOnChange, openOnFocus, chevronAriaLabels, variant, onKeyDown, onFocus, onBlur, onClick, readOnly, disabled, radius, rightSection, rightSectionWidth, rightSectionPointerEvents, rightSectionProps, leftSection, leftSectionWidth, leftSectionPointerEvents, leftSectionProps, inputContainer, inputWrapperOrder, withAsterisk, labelProps, descriptionProps, errorProps, wrapperProps, description, label, error, withErrorStyles, name, form, id, placeholder, required, mod, attributes, ...others } = props;
	const isMulti = mode === "multiple" || mode === "checkbox";
	const isCheckbox = mode === "checkbox";
	const _id = useId$1(id);
	const combobox = useCombobox({
		opened: dropdownOpened,
		defaultOpened: defaultDropdownOpened,
		onDropdownOpen: () => {
			onDropdownOpen?.();
			combobox.updateSelectedOptionIndex("active", { scrollIntoView: true });
		},
		onDropdownClose: () => {
			onDropdownClose?.();
			combobox.resetSelectedOption();
		}
	});
	const initialExpanded = useMemo(() => {
		if (defaultExpandAll) return getTreeExpandedState(data, "*");
		if (defaultExpandedValues) return getTreeExpandedState(data, defaultExpandedValues);
		return getTreeExpandedState(data, []);
	}, []);
	const [_expandedState, setExpandedState] = useUncontrolled({
		value: useCallback((values) => {
			if (!values) return;
			return getTreeExpandedState(data, values);
		}, [data])(expandedValues),
		defaultValue: initialExpanded,
		finalValue: {},
		onChange: (val) => {
			if (onExpandedChange) onExpandedChange(Object.entries(val).filter(([, v]) => v).map(([k]) => k));
		}
	});
	const toggleExpand = useCallback((nodeValue) => {
		setExpandedState({
			..._expandedState,
			[nodeValue]: !_expandedState[nodeValue]
		});
	}, [_expandedState]);
	const [_searchValue, setSearchValue] = useUncontrolled({
		value: searchValue,
		defaultValue: defaultSearchValue,
		finalValue: useMemo(() => {
			if (mode !== "single" || !defaultValue) return "";
			const node = findTreeNode(defaultValue, data);
			return node ? typeof node.label === "string" ? node.label : "" : "";
		}, []),
		onChange: onSearchChange
	});
	const handleSearchChange = (val) => {
		setSearchValue(val);
		combobox.resetSelectedOption();
	};
	const [_value, setValue] = useUncontrolled({
		value,
		defaultValue,
		finalValue: isMulti ? [] : null,
		onChange
	});
	const internalChecked = useMemo(() => {
		if (!isCheckbox || !_value || !Array.isArray(_value)) return [];
		if (checkStrictly) return _value;
		return expandToLeafChecked(_value, data);
	}, [
		isCheckbox,
		_value,
		data,
		checkStrictly
	]);
	const filteredData = useMemo(() => {
		if (!searchable || !_searchValue) return data;
		if (mode === "single" && _value) {
			const node = findTreeNode(_value, data);
			if (node && _searchValue === (typeof node.label === "string" ? node.label : "")) return data;
		}
		return filterTreeData(data, _searchValue, filter);
	}, [
		data,
		_searchValue,
		filter,
		searchable,
		mode,
		_value
	]);
	const expandedForRender = useMemo(() => {
		if (_searchValue && filteredData !== data) {
			const expanded = { ..._expandedState };
			const expandFilteredParents = (nodes) => {
				for (const node of nodes) if (Array.isArray(node.children) && node.children.length > 0) {
					expanded[node.value] = true;
					expandFilteredParents(node.children);
				}
			};
			expandFilteredParents(filteredData);
			return expanded;
		}
		return _expandedState;
	}, [
		filteredData,
		_expandedState,
		_searchValue,
		data
	]);
	const flatNodes = useMemo(() => flattenTreeSelectData(filteredData, expandedForRender), [filteredData, expandedForRender]);
	const flatNodesRef = useRef(flatNodes);
	flatNodesRef.current = flatNodes;
	const nodeLookup = useMemo(() => {
		const lookup = {};
		const walk = (nodes) => {
			for (const node of nodes) {
				lookup[node.value] = node;
				if (Array.isArray(node.children)) walk(node.children);
			}
		};
		walk(data);
		return lookup;
	}, [data]);
	const getNodeLabel = (nodeValue) => {
		const node = nodeLookup[nodeValue];
		if (!node) return nodeValue;
		return typeof node.label === "string" ? node.label : nodeValue;
	};
	const getStyles = useStyles({
		name: "TreeSelect",
		classes: {},
		props,
		classNames,
		styles,
		unstyled,
		attributes
	});
	const { resolvedClassNames, resolvedStyles } = useResolvedStylesApi({
		props,
		styles,
		classNames
	});
	const { styleProps, rest: { type, autoComplete, ...rest } } = extractStyleProps(others);
	const handleOptionSubmit = (val) => {
		if (mode === "single") {
			if (expandOnClick) {
				const node = findTreeNode(val, data);
				if (node && Array.isArray(node.children) && node.children.length > 0) {
					toggleExpand(val);
					return;
				}
			}
			const nextValue = allowDeselect && val === _value ? null : val;
			setValue(nextValue);
			combobox.closeDropdown();
			if (clearSearchOnChange) handleSearchChange(nextValue ? getNodeLabel(nextValue) : "");
		} else if (mode === "multiple") {
			if (expandOnClick) {
				const node = findTreeNode(val, data);
				if (node && Array.isArray(node.children) && node.children.length > 0) {
					toggleExpand(val);
					return;
				}
			}
			const arr = _value || [];
			if (arr.includes(val)) {
				setValue(arr.filter((v) => v !== val));
				onRemove?.(val);
			} else if (arr.length < (maxValues ?? Infinity)) setValue([...arr, val]);
			else return;
			if (clearSearchOnChange) setSearchValue("");
		} else if (mode === "checkbox") {
			const nodeChecked = checkStrictly ? internalChecked.includes(val) : isNodeChecked(val, data, internalChecked);
			let newInternalChecked;
			if (checkStrictly) newInternalChecked = nodeChecked ? internalChecked.filter((v) => v !== val) : [...internalChecked, val];
			else {
				const childLeaves = getChildrenNodesValues(val, data);
				if (nodeChecked) newInternalChecked = internalChecked.filter((v) => !childLeaves.includes(v));
				else newInternalChecked = [...new Set([...internalChecked, ...childLeaves])];
			}
			const newValue = checkedToValue(newInternalChecked, data, checkedStrategy);
			if (!nodeChecked && newValue.length > (maxValues ?? Infinity)) return;
			setValue(newValue);
			if (clearSearchOnChange) setSearchValue("");
			if (expandOnClick) {
				const node = findTreeNode(val, data);
				if (node && Array.isArray(node.children) && node.children.length > 0) {
					if (!_expandedState[val]) toggleExpand(val);
				}
			}
		}
	};
	const handleKeyDown = (event) => {
		onKeyDown?.(event);
		if (event.key === " " && !searchable && isMulti) {
			event.preventDefault();
			combobox.toggleDropdown();
		}
		if (event.key === "Backspace" && _searchValue.length === 0 && isMulti) {
			const arr = _value || [];
			if (arr.length > 0) {
				const removed = arr[arr.length - 1];
				onRemove?.(removed);
				setValue(arr.slice(0, -1));
			}
		}
		if (!combobox.dropdownOpened) return;
		const index = combobox.getSelectedOptionIndex();
		if (index < 0 || index >= flatNodesRef.current.length) return;
		const currentNode = flatNodesRef.current[index];
		if (event.key === "ArrowRight") {
			if (currentNode.hasChildren && !currentNode.expanded) {
				event.preventDefault();
				toggleExpand(currentNode.node.value);
			}
		}
		if (event.key === "ArrowLeft") {
			if (currentNode.hasChildren && currentNode.expanded) {
				event.preventDefault();
				toggleExpand(currentNode.node.value);
			} else if (currentNode.parent) {
				event.preventDefault();
				const parentIndex = flatNodesRef.current.findIndex((n) => n.node.value === currentNode.parent);
				if (parentIndex >= 0) combobox.selectOption(parentIndex);
			}
		}
	};
	useEffect(() => {
		if (mode !== "single" || !searchable) return;
		if (value === null) handleSearchChange("");
		else if (typeof value === "string") handleSearchChange(getNodeLabel(value));
	}, [value]);
	const prevDropdownOpenedRef = useRef(false);
	useEffect(() => {
		if (combobox.dropdownOpened && !prevDropdownOpenedRef.current && searchable && _value) {
			const targets = Array.isArray(_value) ? _value : [_value];
			const newExpanded = { ..._expandedState };
			let changed = false;
			for (const target of targets) {
				const ancestors = getAncestorsToNode(target, data);
				if (ancestors) {
					for (const a of ancestors) if (!newExpanded[a]) {
						newExpanded[a] = true;
						changed = true;
					}
				}
			}
			if (changed) {
				setExpandedState(newExpanded);
				requestAnimationFrame(() => {
					combobox.updateSelectedOptionIndex("active", { scrollIntoView: true });
				});
			}
		}
		prevDropdownOpenedRef.current = combobox.dropdownOpened;
	});
	const clearButton = /* @__PURE__ */ jsx(Combobox.ClearButton, {
		...clearButtonProps,
		onClear: () => {
			onClear?.();
			setValue(isMulti ? [] : null);
			handleSearchChange("");
			combobox.focusTarget();
		}
	});
	const hasValue = isMulti ? Array.isArray(_value) && _value.length > 0 : _value != null && _value !== "";
	const _clearable = clearable && hasValue && !disabled && !readOnly;
	const singleDisplayLabel = useMemo(() => {
		if (mode !== "single" || !_value) return "";
		return getNodeLabel(_value);
	}, [
		mode,
		_value,
		nodeLookup
	]);
	const displayValues = useMemo(() => {
		if (!isMulti || !Array.isArray(_value)) return [];
		return _value;
	}, [isMulti, _value]);
	const pillsListStyle = _clearable && isMulti ? { paddingInlineEnd: clearSectionOffset[size] ?? clearSectionOffset.sm } : void 0;
	const visiblePills = maxDisplayedValues != null ? displayValues.slice(0, maxDisplayedValues) : displayValues;
	const overflowCount = maxDisplayedValues != null ? Math.max(0, displayValues.length - maxDisplayedValues) : 0;
	const pills = visiblePills.map((item, index) => /* @__PURE__ */ jsx(Pill, {
		withRemoveButton: !readOnly,
		onRemove: () => {
			if (isCheckbox) {
				const childLeaves = checkStrictly ? [item] : getChildrenNodesValues(item, data);
				setValue(checkedToValue(internalChecked.filter((v) => !childLeaves.includes(v)), data, checkedStrategy));
			} else setValue(_value.filter((v) => v !== item));
			onRemove?.(item);
		},
		unstyled,
		disabled,
		...getStyles("pill"),
		children: getNodeLabel(item)
	}, `${item}-${index}`));
	if (overflowCount > 0) {
		const overflowContent = typeof maxDisplayedValuesContent === "function" ? maxDisplayedValuesContent(overflowCount) : maxDisplayedValuesContent || `+${overflowCount} more`;
		pills.push(/* @__PURE__ */ jsx(Pill, {
			unstyled,
			disabled,
			...getStyles("pill"),
			children: overflowContent
		}, "__overflow"));
	}
	const isEmpty = flatNodes.length === 0;
	const options = flatNodes.map((flatNode) => {
		const isSelected = mode === "single" ? _value === flatNode.node.value : mode === "multiple" ? (_value || []).includes(flatNode.node.value) : false;
		const nodeChecked = isCheckbox ? checkStrictly ? internalChecked.includes(flatNode.node.value) : isNodeChecked(flatNode.node.value, data, internalChecked) : false;
		const nodeIndeterminate = isCheckbox && !checkStrictly ? isNodeIndeterminate(flatNode.node.value, data, internalChecked) : false;
		return /* @__PURE__ */ jsx(TreeSelectOption, {
			node: flatNode.node,
			level: flatNode.level,
			expanded: flatNode.expanded,
			hasChildren: flatNode.hasChildren,
			selected: isSelected,
			checked: nodeChecked,
			indeterminate: nodeIndeterminate,
			showCheckbox: isCheckbox,
			isLastChild: flatNode.isLastChild,
			lineGuides: flatNode.lineGuides,
			withLines: !!withLines,
			onToggleExpand: toggleExpand,
			renderNode,
			chevronAriaLabels
		}, flatNode.node.value);
	});
	const dropdown = /* @__PURE__ */ jsx(Combobox.Dropdown, {
		hidden: readOnly || disabled,
		children: /* @__PURE__ */ jsxs(Combobox.Options, {
			className: TreeSelect_module_default.optionsWrapper,
			"aria-multiselectable": isMulti || void 0,
			children: [/* @__PURE__ */ jsx(ScrollArea.Autosize, {
				mah: maxDropdownHeight ?? 220,
				type: "scroll",
				scrollbarSize: "var(--combobox-padding)",
				offsetScrollbars: "y",
				...scrollAreaProps,
				children: options
			}), isEmpty && nothingFoundMessage && /* @__PURE__ */ jsx(Combobox.Empty, { children: nothingFoundMessage })]
		})
	});
	if (isMulti) return /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsxs(Combobox, {
		store: combobox,
		classNames: resolvedClassNames,
		styles: resolvedStyles,
		unstyled,
		size,
		readOnly,
		__staticSelector: "TreeSelect",
		attributes,
		onOptionSubmit: handleOptionSubmit,
		...comboboxProps,
		children: [/* @__PURE__ */ jsx(Combobox.DropdownTarget, { children: /* @__PURE__ */ jsx(PillsInput, {
			...styleProps,
			__staticSelector: "TreeSelect",
			classNames: resolvedClassNames,
			styles: resolvedStyles,
			unstyled,
			size,
			className,
			style,
			variant,
			disabled,
			radius,
			__defaultRightSection: /* @__PURE__ */ jsx(Combobox.Chevron, {
				size,
				error,
				unstyled,
				color: chevronColor
			}),
			__clearSection: clearButton,
			__clearable: _clearable,
			__clearSectionMode: clearSectionMode,
			rightSection,
			rightSectionPointerEvents: rightSectionPointerEvents || "none",
			rightSectionWidth,
			rightSectionProps,
			leftSection,
			leftSectionWidth,
			leftSectionPointerEvents,
			leftSectionProps,
			inputContainer,
			inputWrapperOrder,
			withAsterisk,
			labelProps,
			descriptionProps,
			errorProps,
			wrapperProps,
			description,
			label,
			error,
			withErrorStyles,
			__stylesApiProps: {
				...props,
				rightSectionPointerEvents: rightSectionPointerEvents || "none",
				multiline: true
			},
			pointer: !searchable,
			onClick: () => searchable ? combobox.openDropdown() : combobox.toggleDropdown(),
			"data-expanded": combobox.dropdownOpened || void 0,
			id: _id,
			required,
			mod,
			attributes,
			children: /* @__PURE__ */ jsxs(Pill.Group, {
				attributes,
				disabled,
				unstyled,
				...getStyles("pillsList", { style: pillsListStyle }),
				children: [pills, /* @__PURE__ */ jsx(Combobox.EventsTarget, {
					autoComplete,
					children: /* @__PURE__ */ jsx(PillsInput.Field, {
						...rest,
						id: _id,
						placeholder,
						type: !searchable && !placeholder ? "hidden" : "visible",
						...getStyles("inputField"),
						unstyled,
						onFocus: (event) => {
							onFocus?.(event);
							if (openOnFocus && searchable) combobox.openDropdown();
						},
						onBlur: (event) => {
							onBlur?.(event);
							combobox.closeDropdown();
							handleSearchChange("");
						},
						onKeyDown: handleKeyDown,
						value: _searchValue,
						onChange: (event) => {
							handleSearchChange(event.currentTarget.value);
							if (searchable) combobox.openDropdown();
						},
						disabled,
						readOnly: readOnly || !searchable,
						pointer: !searchable
					})
				})]
			})
		}) }), dropdown]
	}), /* @__PURE__ */ jsx(Combobox.HiddenInput, {
		name,
		valuesDivider: hiddenInputValuesDivider,
		value: _value,
		form,
		disabled,
		...hiddenInputProps
	})] });
	return /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsxs(Combobox, {
		store: combobox,
		__staticSelector: "TreeSelect",
		classNames: resolvedClassNames,
		styles: resolvedStyles,
		unstyled,
		readOnly,
		size,
		attributes,
		onOptionSubmit: handleOptionSubmit,
		...comboboxProps,
		children: [/* @__PURE__ */ jsx(Combobox.Target, {
			targetType: searchable ? "input" : "button",
			autoComplete,
			children: /* @__PURE__ */ jsx(InputBase, {
				id: _id,
				__defaultRightSection: /* @__PURE__ */ jsx(Combobox.Chevron, {
					size,
					error,
					unstyled,
					color: chevronColor
				}),
				__clearSection: clearButton,
				__clearable: _clearable,
				__clearSectionMode: clearSectionMode,
				rightSection,
				rightSectionPointerEvents: rightSectionPointerEvents || "none",
				...rest,
				...styleProps,
				size,
				__staticSelector: "TreeSelect",
				disabled,
				readOnly: readOnly || !searchable,
				value: searchable ? _searchValue : singleDisplayLabel,
				onChange: (event) => {
					handleSearchChange(event.currentTarget.value);
					combobox.openDropdown();
				},
				onFocus: (event) => {
					if (openOnFocus && searchable) combobox.openDropdown();
					onFocus?.(event);
				},
				onBlur: (event) => {
					if (searchable) combobox.closeDropdown();
					handleSearchChange(_value ? getNodeLabel(_value) : "");
					onBlur?.(event);
				},
				onClick: (event) => {
					searchable ? combobox.openDropdown() : combobox.toggleDropdown();
					onClick?.(event);
				},
				onKeyDown: handleKeyDown,
				classNames: resolvedClassNames,
				styles: resolvedStyles,
				unstyled,
				pointer: !searchable,
				error,
				attributes,
				className,
				style,
				variant,
				radius,
				leftSection,
				leftSectionWidth,
				leftSectionPointerEvents,
				leftSectionProps,
				rightSectionWidth,
				rightSectionProps,
				inputContainer,
				inputWrapperOrder,
				withAsterisk,
				labelProps,
				descriptionProps,
				errorProps,
				wrapperProps,
				description,
				label,
				withErrorStyles,
				placeholder,
				required,
				mod
			})
		}), dropdown]
	}), /* @__PURE__ */ jsx(Combobox.HiddenInput, {
		value: _value,
		name,
		form,
		disabled,
		...hiddenInputProps
	})] });
});
TreeSelect.classes = {
	...InputBase.classes,
	...Combobox.classes
};
TreeSelect.displayName = "@mantine/core/TreeSelect";
//#endregion
export { TreeSelect };

//# sourceMappingURL=TreeSelect.mjs.map