/** @license MIT | @cube-dev/ui-kit v0.0.0-canary-e694c50 | Cube Dev Team */
import { DisplayTransition } from "../DisplayTransition/DisplayTransition.js";
import { tasty } from "@tenphi/tasty";
import { isValidElement, useCallback, useLayoutEffect, useRef, useState } from "react";
import { Fragment as Fragment$1, jsx } from "react/jsx-runtime";

//#region src/components/helpers/IconSwitch/IconSwitch.tsx
function isNullishContent(node) {
	return node == null || node === false;
}
const typeIds = /* @__PURE__ */ new WeakMap();
let lastTypeId = 0;
function getTypeId(type) {
	const existing = typeIds.get(type);
	if (existing != null) return existing;
	const next = lastTypeId += 1;
	typeIds.set(type, next);
	return next;
}
/**
* Best-effort key derivation for icon switching when `contentKey` is not provided.
* The goal is to:
* - Transition when icon component type changes
* - Not transition when only props change for the same icon type (self-animating icons)
* - Transition when toggling to/from nullish content
*/
function deriveContentKey(children) {
	if (isNullishContent(children)) return "nullish";
	if (!isValidElement(children)) return `non-element:${typeof children}`;
	const { type, key } = children;
	const keyPart = key == null ? "" : `:${String(key)}`;
	if (typeof type === "string") return `host:${type}${keyPart}`;
	if (typeof type === "function") return `fn:${getTypeId(type)}${keyPart}`;
	if (typeof type === "object" && type != null) return `obj:${getTypeId(type)}${keyPart}`;
	if (typeof type === "symbol") return `sym:${String(type)}${keyPart}`;
	return `unknown${keyPart}`;
}
const IconSwitchElement = tasty({ styles: {
	display: "grid",
	placeItems: "center"
} });
const IconSlotElement = tasty({ styles: {
	gridArea: "1 / 1",
	display: "grid",
	placeItems: "center",
	opacity: {
		"": 0,
		entered: 1
	},
	transition: {
		"": "theme $transition ease-out",
		"exit | entered": "theme $transition ease-in"
	}
} });
/**
* A component that cross-fades between icons when children change.
* Useful for animated icon transitions in buttons, items, etc.
*
* When `contentKey` changes, a transition is triggered.
* When only `children` changes (same `contentKey`), content is updated in-place
* without transition, allowing self-animating icons (like DirectionIcon) to work.
*/
function IconSwitch(props) {
	const { children, contentKey, noWrapper, ...rest } = props;
	const keyCounterRef = useRef(0);
	const effectiveKey = contentKey ?? deriveContentKey(children);
	const prevEffectiveKeyRef = useRef(effectiveKey);
	const prevChildrenRef = useRef(children);
	const [icons, setIcons] = useState(() => [{
		key: keyCounterRef.current,
		content: children
	}]);
	useLayoutEffect(() => {
		const prevKey = prevEffectiveKeyRef.current;
		const prevChildren = prevChildrenRef.current;
		const hasKeyChanged = effectiveKey !== prevKey;
		const hasNullishToggled = isNullishContent(children) !== isNullishContent(prevChildren);
		if (hasKeyChanged || hasNullishToggled) {
			keyCounterRef.current += 1;
			const newEntry = {
				key: keyCounterRef.current,
				content: children
			};
			setIcons((prev) => [...prev, newEntry]);
		}
		prevEffectiveKeyRef.current = effectiveKey;
		prevChildrenRef.current = children;
	}, [children, effectiveKey]);
	const handleExitComplete = useCallback((exitedKey) => {
		setIcons((prev) => prev.filter((icon) => icon.key !== exitedKey));
	}, []);
	const latestKey = icons[icons.length - 1]?.key;
	const isKeyChangePending = effectiveKey !== prevEffectiveKeyRef.current;
	const isNullishChangePending = isNullishContent(children) !== isNullishContent(prevChildrenRef.current);
	const isTransitionPending = isKeyChangePending || isNullishChangePending;
	const content = icons.map((icon) => {
		const isActive = icon.key === latestKey;
		const displayContent = isActive && !isTransitionPending ? children : icon.content;
		return /* @__PURE__ */ jsx(DisplayTransition, {
			isShown: isActive,
			animateOnMount: icon.key !== 0,
			onRest: (transition) => {
				if (transition === "exit") handleExitComplete(icon.key);
			},
			children: ({ isShown, phase, ref }) => /* @__PURE__ */ jsx(IconSlotElement, {
				ref,
				mods: {
					entered: isShown,
					phase
				},
				children: displayContent
			})
		}, icon.key);
	});
	if (noWrapper) return /* @__PURE__ */ jsx(Fragment$1, { children: content });
	return /* @__PURE__ */ jsx(IconSwitchElement, {
		...rest,
		children: content
	});
}

//#endregion
export { IconSwitch };
//# sourceMappingURL=IconSwitch.js.map