'use client';

import { cn } from "../../utils/cn.mjs";
import { Button } from "../Button/Button.mjs";
import { createContext, useContext, useEffect, useRef, useState } from "react";
import { MinusIcon } from "lucide-react";
import { cva } from "class-variance-authority";
import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";

//#region src/components/Input/OTPInput.tsx
/**
* This component is a fork of https://github.com/guilhermerodz/input-otp
*/
const syncTimeouts = (cb) => {
	return [
		setTimeout(cb, 0),
		setTimeout(cb, 10),
		setTimeout(cb, 50)
	];
};
const safeInsertRule = (sheet, rule) => {
	try {
		sheet.insertRule(rule);
	} catch {
		console.error("input-otp could not insert CSS rule:", rule);
	}
};
const NOSCRIPT_CSS_FALLBACK = `
[data-input-otp] {
  --nojs-bg: white !important;
  --nojs-fg: black !important;

  background-color: var(--nojs-bg) !important;
  color: var(--nojs-fg) !important;
  caret-color: var(--nojs-fg) !important;
  letter-spacing: .25em !important;
  text-align: center !important;
  border: 1px solid var(--nojs-fg) !important;
  border-radius: 4px !important;
  width: 100% !important;
}
@media (prefers-color-scheme: dark) {
  [data-input-otp] {
    --nojs-bg: black !important;
    --nojs-fg: white !important;
  }
}`;
const PWM_BADGE_MARGIN_RIGHT = 18;
const PWM_BADGE_SPACE_WIDTH_PX = 40;
const PWM_BADGE_SPACE_WIDTH = `${PWM_BADGE_SPACE_WIDTH_PX}px`;
const PASSWORD_MANAGERS_SELECTORS = [
	"[data-lastpass-icon-root]",
	"com-1password-button",
	"[data-dashlanecreated]",
	"[style$=\"2147483647 !important;\"]"
].join(",");
const usePasswordManagerBadge = ({ containerRef, inputRef, pushPasswordManagerStrategy, isFocused }) => {
	/** Password managers have a badge
	*  and I'll use this state to push them
	*  outside the input */
	const [hasPWMBadge, setHasPWMBadge] = useState(false);
	const [hasPWMBadgeSpace, setHasPWMBadgeSpace] = useState(false);
	const [done, setDone] = useState(false);
	const willPushPWMBadge = pushPasswordManagerStrategy === "none" ? false : (pushPasswordManagerStrategy === "increase-width" || pushPasswordManagerStrategy === "experimental-no-flickering") && hasPWMBadge && hasPWMBadgeSpace;
	const trackPWMBadge = () => {
		const container = containerRef.current;
		const input = inputRef.current;
		if (!container || !input || done || pushPasswordManagerStrategy === "none") return;
		const elementToCompare = container;
		const rightCornerX = elementToCompare.getBoundingClientRect().left + elementToCompare.offsetWidth;
		const centereredY = elementToCompare.getBoundingClientRect().top + elementToCompare.offsetHeight / 2;
		const x = rightCornerX - PWM_BADGE_MARGIN_RIGHT;
		const y = centereredY;
		if (document.querySelectorAll(PASSWORD_MANAGERS_SELECTORS).length === 0) {
			if (document.elementFromPoint(x, y) === container) return;
		}
		setHasPWMBadge(true);
		setDone(true);
	};
	useEffect(() => {
		const container = containerRef.current;
		if (!container || pushPasswordManagerStrategy === "none") return;
		const checkHasSpace = () => {
			setHasPWMBadgeSpace(window.innerWidth - container.getBoundingClientRect().right >= PWM_BADGE_SPACE_WIDTH_PX);
		};
		checkHasSpace();
		const interval = setInterval(checkHasSpace, 1e3);
		return () => {
			clearInterval(interval);
		};
	}, [containerRef, pushPasswordManagerStrategy]);
	useEffect(() => {
		const _isFocused = isFocused || document.activeElement === inputRef.current;
		if (pushPasswordManagerStrategy === "none" || !_isFocused) return;
		const t1 = setTimeout(trackPWMBadge, 0);
		const t2 = setTimeout(trackPWMBadge, 2e3);
		const t3 = setTimeout(trackPWMBadge, 5e3);
		const t4 = setTimeout(() => {
			setDone(true);
		}, 6e3);
		return () => {
			clearTimeout(t1);
			clearTimeout(t2);
			clearTimeout(t3);
			clearTimeout(t4);
		};
	}, [
		inputRef,
		isFocused,
		pushPasswordManagerStrategy
	]);
	return {
		hasPWMBadge,
		willPushPWMBadge,
		PWM_BADGE_SPACE_WIDTH
	};
};
const usePrevious = (value) => {
	const ref = useRef(void 0);
	useEffect(() => {
		ref.current = value;
	});
	return ref.current;
};
const OTPInputContext = createContext({});
const OTPInput = ({ value: uncheckedValue, onChange: uncheckedOnChange, maxLength, pattern, placeholder, inputMode = "numeric", onComplete, onActiveSlotChange, pushPasswordManagerStrategy = "increase-width", pasteTransformer, containerClassName, noScriptCSSFallback = NOSCRIPT_CSS_FALLBACK, render, children, ...props }) => {
	const [internalValue, setInternalValue] = useState(typeof props.defaultValue === "string" ? props.defaultValue : "");
	const value = uncheckedValue ?? internalValue;
	const previousValue = usePrevious(value);
	const onChange = (newValue) => {
		uncheckedOnChange?.(newValue);
		setInternalValue(newValue);
	};
	const regexp = pattern !== void 0 ? typeof pattern === "string" ? new RegExp(pattern) : pattern : null;
	/** useRef */
	const inputRef = useRef(null);
	const containerRef = useRef(null);
	const initialLoadRef = useRef({
		value,
		onChange,
		isIOS: typeof window !== "undefined" && window?.CSS?.supports?.("-webkit-touch-callout", "none")
	});
	const inputMetadataRef = useRef({ prev: [
		inputRef.current?.selectionStart ?? null,
		inputRef.current?.selectionEnd ?? null,
		inputRef.current?.selectionDirection ?? "none"
	] });
	useEffect(() => {
		const input = inputRef.current;
		const container = containerRef.current;
		if (!input || !container) return;
		if (initialLoadRef.current.value !== input.value) initialLoadRef.current.onChange(input.value);
		inputMetadataRef.current.prev = [
			input.selectionStart,
			input.selectionEnd,
			input.selectionDirection ?? "none"
		];
		const onDocumentSelectionChange = () => {
			if (document.activeElement !== input) {
				setMirrorSelectionStart(null);
				setMirrorSelectionEnd(null);
				setActualCaretPosition(null);
				return;
			}
			const selectionStart = input.selectionStart;
			const selectionEnd = input.selectionEnd;
			const selectionDirection = input.selectionDirection;
			const maxLength = input.maxLength;
			const value = input.value;
			const previousSelection = inputMetadataRef.current.prev;
			let calculatedStart = -1;
			let calculatedEnd = -1;
			let calculatedDirection = selectionDirection ?? "none";
			if (value.length !== 0 && selectionStart !== null && selectionEnd !== null) {
				const isSingleCaret = selectionStart === selectionEnd;
				const isInsertMode = selectionStart === value.length && value.length < maxLength;
				if (isSingleCaret && !isInsertMode) {
					const caretPosition = selectionStart;
					if (caretPosition === 0) {
						calculatedStart = 0;
						calculatedEnd = 1;
						calculatedDirection = "forward";
					} else if (caretPosition === maxLength) {
						calculatedStart = caretPosition - 1;
						calculatedEnd = caretPosition;
						calculatedDirection = "backward";
					} else if (maxLength > 1 && value.length > 1) {
						let offset = 0;
						if (previousSelection[0] !== null && previousSelection[1] !== null) {
							calculatedDirection = caretPosition < previousSelection[1] ? "backward" : "forward";
							const wasPreviouslyInserting = previousSelection[0] === previousSelection[1] && previousSelection[0] < maxLength;
							if (calculatedDirection === "backward" && !wasPreviouslyInserting) offset = -1;
						}
						calculatedStart = offset + caretPosition;
						calculatedEnd = offset + caretPosition + 1;
					}
				}
				if (calculatedStart !== -1 && calculatedEnd !== -1 && calculatedStart !== calculatedEnd) inputRef.current?.setSelectionRange(calculatedStart, calculatedEnd, calculatedDirection);
			}
			const finalSelectionStart = calculatedStart !== -1 ? calculatedStart : selectionStart;
			const finalSelectionEnd = calculatedEnd !== -1 ? calculatedEnd : selectionEnd;
			const finalDirection = calculatedDirection;
			if (selectionStart !== null && selectionEnd !== null) if (selectionStart === selectionEnd) setActualCaretPosition(selectionStart);
			else setActualCaretPosition(finalSelectionStart);
			else setActualCaretPosition(null);
			setMirrorSelectionStart(finalSelectionStart);
			setMirrorSelectionEnd(finalSelectionEnd);
			inputMetadataRef.current.prev = [
				finalSelectionStart,
				finalSelectionEnd,
				finalDirection
			];
		};
		document.addEventListener("selectionchange", onDocumentSelectionChange, { capture: true });
		onDocumentSelectionChange();
		if (document.activeElement === input) setIsFocused(true);
		if (!document.getElementById("input-otp-style")) {
			const styleEl = document.createElement("style");
			styleEl.id = "input-otp-style";
			document.head.appendChild(styleEl);
			if (styleEl.sheet) {
				const autofillStyles = "background: transparent !important; color: transparent !important; border-color: transparent !important; opacity: 0 !important; box-shadow: none !important; -webkit-box-shadow: none !important; -webkit-text-fill-color: transparent !important;";
				safeInsertRule(styleEl.sheet, "[data-input-otp]::selection { background: transparent !important; color: transparent !important; }");
				safeInsertRule(styleEl.sheet, `[data-input-otp]:autofill { ${autofillStyles} }`);
				safeInsertRule(styleEl.sheet, `[data-input-otp]:-webkit-autofill { ${autofillStyles} }`);
				safeInsertRule(styleEl.sheet, `@supports (-webkit-touch-callout: none) { [data-input-otp] { letter-spacing: -.6em !important; font-weight: 100 !important; font-stretch: ultra-condensed; font-optical-sizing: none !important; left: -1px !important; right: 1px !important; } }`);
				safeInsertRule(styleEl.sheet, `[data-input-otp] + * { pointer-events: all !important; }`);
			}
		}
		const updateRootHeight = () => {
			if (container) container.style.setProperty("--root-height", `${input.clientHeight}px`);
		};
		updateRootHeight();
		const resizeObserver = new ResizeObserver(updateRootHeight);
		resizeObserver.observe(input);
		return () => {
			document.removeEventListener("selectionchange", onDocumentSelectionChange, { capture: true });
			resizeObserver.disconnect();
		};
	}, []);
	/** Mirrors for UI rendering purpose only */
	const [isHoveringInput, setIsHoveringInput] = useState(false);
	const [isFocused, setIsFocused] = useState(false);
	const [mirrorSelectionStart, setMirrorSelectionStart] = useState(null);
	const [mirrorSelectionEnd, setMirrorSelectionEnd] = useState(null);
	const [actualCaretPosition, setActualCaretPosition] = useState(null);
	/** Effects */
	useEffect(() => {
		syncTimeouts(() => {
			inputRef.current?.dispatchEvent(new Event("input"));
			const s = inputRef.current?.selectionStart ?? null;
			const e = inputRef.current?.selectionEnd ?? null;
			const dir = inputRef.current?.selectionDirection ?? "none";
			if (s !== null && e !== null) {
				setMirrorSelectionStart(s);
				setMirrorSelectionEnd(e);
				setActualCaretPosition(s);
				inputMetadataRef.current.prev = [
					s,
					e,
					dir
				];
			}
		});
	}, [value, isFocused]);
	useEffect(() => {
		if (previousValue === void 0) return;
		if (value !== previousValue && previousValue.length < maxLength && value.length === maxLength) onComplete?.(value);
	}, [
		maxLength,
		onComplete,
		previousValue,
		value
	]);
	const previousActiveSlot = useRef(null);
	useEffect(() => {
		const activeSlotIndex = isFocused && actualCaretPosition !== null ? actualCaretPosition : null;
		if (activeSlotIndex !== previousActiveSlot.current) {
			previousActiveSlot.current = activeSlotIndex;
			onActiveSlotChange?.(activeSlotIndex);
		}
	}, [
		isFocused,
		actualCaretPosition,
		onActiveSlotChange
	]);
	const pwmb = usePasswordManagerBadge({
		containerRef,
		inputRef,
		pushPasswordManagerStrategy,
		isFocused
	});
	/** Event handlers */
	const _changeListener = (e) => {
		const newValue = e.currentTarget.value.slice(0, maxLength);
		if (newValue.length > 0 && regexp && !regexp.test(newValue)) {
			e.preventDefault();
			return;
		}
		if (typeof previousValue === "string" && newValue.length < previousValue.length) document.dispatchEvent(new Event("selectionchange"));
		onChange(newValue);
	};
	const _focusListener = () => {
		if (inputRef.current) {
			const start = Math.min(inputRef.current.value.length, maxLength - 1);
			const end = inputRef.current.value.length;
			inputRef.current?.setSelectionRange(start, end);
			setMirrorSelectionStart(start);
			setMirrorSelectionEnd(end);
		}
		setIsFocused(true);
	};
	const _pasteListener = (e) => {
		const input = inputRef.current;
		if (!pasteTransformer && (!initialLoadRef.current.isIOS || !e.clipboardData || !input)) return;
		const _content = e.clipboardData.getData("text/plain");
		const content = pasteTransformer ? pasteTransformer(_content) : _content;
		e.preventDefault();
		const start = inputRef.current?.selectionStart;
		const end = inputRef.current?.selectionEnd;
		const newValue = (start !== end ? value.slice(0, start ?? 0) + content + value.slice(end ?? 0) : value.slice(0, start ?? 0) + content + value.slice(start ?? 0)).slice(0, maxLength);
		if (newValue.length > 0 && regexp && !regexp.test(newValue)) return;
		if (input) {
			input.value = newValue;
			onChange(newValue);
			const _start = Math.min(newValue.length, maxLength - 1);
			const _end = newValue.length;
			input.setSelectionRange(_start, _end);
			setMirrorSelectionStart(_start);
			setMirrorSelectionEnd(_end);
		}
	};
	/** Styles - dynamic styles that can't be converted to Tailwind */
	const dynamicInputStyle = {
		width: pwmb.willPushPWMBadge ? `calc(100% + ${pwmb.PWM_BADGE_SPACE_WIDTH})` : "100%",
		clipPath: pwmb.willPushPWMBadge ? `inset(0 ${pwmb.PWM_BADGE_SPACE_WIDTH} 0 0)` : void 0,
		fontSize: "var(--root-height)"
	};
	/** Rendering */
	const renderedInput = /* @__PURE__ */ jsx("input", {
		autoComplete: props.autoComplete || "one-time-code",
		...props,
		"data-input-otp": true,
		"data-input-otp-placeholder-shown": value.length === 0 || void 0,
		"data-input-otp-mss": mirrorSelectionStart,
		"data-input-otp-mse": mirrorSelectionEnd,
		inputMode,
		pattern: regexp?.source,
		"aria-placeholder": placeholder,
		className: "pointer-events-auto absolute inset-0 -z-10 flex h-full border-0 border-transparent bg-transparent text-center font-mono text-transparent tabular-nums leading-none tracking-[-.5em] caret-transparent opacity-100 shadow-none outline-none",
		style: dynamicInputStyle,
		maxLength,
		value,
		ref: inputRef,
		onPaste: (e) => {
			_pasteListener(e);
			props.onPaste?.(e);
		},
		onChange: _changeListener,
		onMouseOver: (e) => {
			setIsHoveringInput(true);
			props.onMouseOver?.(e);
		},
		onMouseLeave: (e) => {
			setIsHoveringInput(false);
			props.onMouseLeave?.(e);
		},
		onKeyDown: (e) => {
			if (e.key === "ArrowLeft" || e.key === "ArrowRight") requestAnimationFrame(() => {
				const input = inputRef.current;
				if (input && document.activeElement === input) {
					const s = input.selectionStart;
					const end = input.selectionEnd;
					if (s !== null && end !== null) setActualCaretPosition(s);
				}
			});
			props.onKeyDown?.(e);
		},
		onFocus: (e) => {
			_focusListener();
			props.onFocus?.(e);
		},
		onBlur: (e) => {
			setIsFocused(false);
			props.onBlur?.(e);
		}
	});
	const setSelection = (index) => {
		const input = inputRef.current;
		if (!input || props.disabled) return;
		const clampedIndex = Math.max(0, Math.min(index, maxLength - 1));
		if (document.activeElement !== input) input.focus();
		const hasChar = value[clampedIndex] !== void 0;
		const start = clampedIndex;
		const end = hasChar ? clampedIndex + 1 : clampedIndex;
		input.setSelectionRange(start, end);
		setMirrorSelectionStart(start);
		setMirrorSelectionEnd(end);
		setIsFocused(true);
	};
	const contextValue = {
		slots: Array.from({ length: maxLength }).map((_, slotIdx) => {
			const isActive = isFocused && mirrorSelectionStart !== null && mirrorSelectionEnd !== null && (mirrorSelectionStart === mirrorSelectionEnd && slotIdx === mirrorSelectionStart || slotIdx >= mirrorSelectionStart && slotIdx < mirrorSelectionEnd);
			const char = value[slotIdx] !== void 0 ? value[slotIdx] : null;
			return {
				char,
				placeholderChar: value[0] !== void 0 ? null : placeholder?.[slotIdx] ?? null,
				isActive,
				hasFakeCaret: isActive && char === null
			};
		}),
		isFocused,
		isHovering: !props.disabled && isHoveringInput,
		setSelection
	};
	const renderedChildren = render !== void 0 ? render(contextValue) : /* @__PURE__ */ jsx(OTPInputContext.Provider, {
		value: contextValue,
		children
	});
	return /* @__PURE__ */ jsxs(Fragment$1, { children: [noScriptCSSFallback !== null && /* @__PURE__ */ jsx("noscript", { children: /* @__PURE__ */ jsx("style", { children: noScriptCSSFallback }) }), /* @__PURE__ */ jsxs("div", {
		ref: containerRef,
		className: cn("relative", props.disabled ? "cursor-default" : "cursor-text", containerClassName),
		children: [renderedChildren, /* @__PURE__ */ jsx("div", {
			className: "absolute inset-0",
			children: renderedInput
		})]
	})] });
};
const inputSlotVariants = cva("block text-center", {
	variants: { size: {
		sm: "h-4 w-3 text-sm",
		md: "h-5 w-4 text-base",
		lg: "h-6 w-5 text-lg",
		xl: "h-7 w-6 text-xl"
	} },
	defaultVariants: { size: "md" }
});
const InputOTP = ({ className, render, ...props }) => /* @__PURE__ */ jsx(OTPInput, {
	containerClassName: "relative flex items-center gap-2 has-disabled:opacity-50",
	className: cn("disabled:cursor-not-allowed", className),
	render,
	...props
});
const InputOTPGroup = ({ className, ...props }) => /* @__PURE__ */ jsx("div", {
	className: cn("z-10 flex items-center gap-3", className),
	...props
});
const InputOTPSlot = ({ index, className, onClick, onKeyDown, ...props }) => {
	const inputOTPContext = useContext(OTPInputContext);
	const { char, isActive } = inputOTPContext?.slots[index] ?? {};
	const { setSelection } = inputOTPContext ?? {};
	const handleClick = (e) => {
		setSelection?.(index);
		onClick?.(e);
	};
	const handleKeyDown = (e) => {
		if (e.key === "Enter" || e.key === " ") {
			e.preventDefault();
			setSelection?.(index);
		}
		onKeyDown?.(e);
	};
	return /* @__PURE__ */ jsx(Button, {
		isSelected: isActive,
		variant: "input",
		color: "custom",
		tabIndex: -1,
		className: cn("relative z-10 px-2!", isActive && "ring-4!", className),
		onClick: handleClick,
		onKeyDown: handleKeyDown,
		label: null,
		...props,
		children: /* @__PURE__ */ jsx("span", {
			className: "relative z-10 flex h-6 w-4 items-center justify-center",
			children: char
		})
	});
};
const InputOTPSeparator = (props) => /* @__PURE__ */ jsx("div", {
	"aria-hidden": true,
	className: "z-0 table h-0.5 w-3 rounded-full bg-border text-text/50",
	...props,
	children: /* @__PURE__ */ jsx(MinusIcon, {})
});
const InputIndicator = (props) => /* @__PURE__ */ jsx("div", {
	"data-indicator": true,
	className: "absolute top-0 z-0 h-full w-auto rounded-xl bg-text/20 ring-4 ring-text/20 transition-[left,width] duration-300 ease-in-out [corner-shape:squircle] supports-[corner-shape:squircle]:rounded-2xl motion-reduce:transition-none",
	...props
});

//#endregion
export { InputIndicator, InputOTP, InputOTPGroup, InputOTPSeparator, InputOTPSlot, OTPInput, OTPInputContext, inputSlotVariants, usePasswordManagerBadge, usePrevious };
//# sourceMappingURL=OTPInput.mjs.map