UNPKG

gebeya-whatsapp-otp

Version:

React WhatsApp OTP verification component with Supabase integration

102 lines (101 loc) 5.58 kB
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime"; import React, { useState, useRef, useEffect } from "react"; import { cn } from "../../utils/cn"; export const Select = ({ value, onValueChange, children, searchable = false, placeholder, }) => { const [isOpen, setIsOpen] = useState(false); const [searchValue, setSearchValue] = useState(""); const selectRef = useRef(null); const searchInputRef = useRef(null); useEffect(() => { const handleClickOutside = (event) => { if (selectRef.current && !selectRef.current.contains(event.target)) { setIsOpen(false); setSearchValue(""); } }; document.addEventListener("mousedown", handleClickOutside); return () => { document.removeEventListener("mousedown", handleClickOutside); }; }, []); useEffect(() => { if (isOpen && searchable && searchInputRef.current) { // Focus search input when dropdown opens setTimeout(() => { searchInputRef.current?.focus(); }, 100); } }, [isOpen, searchable]); const handleToggle = () => { setIsOpen(!isOpen); if (!isOpen) { setSearchValue(""); } }; const handleSelect = (selectedValue) => { onValueChange?.(selectedValue); setIsOpen(false); setSearchValue(""); }; const handleSearchChange = (newSearchValue) => { setSearchValue(newSearchValue); }; return (_jsx("div", { className: "relative", ref: selectRef, children: React.Children.map(children, (child) => { if (React.isValidElement(child)) { if (child.type === SelectTrigger) { return React.cloneElement(child, { onClick: handleToggle }); } if (child.type === SelectContent) { return React.cloneElement(child, { isOpen, onSelect: handleSelect, searchable, searchValue, onSearchChange: handleSearchChange, searchInputRef, }); } if (child.type === SelectValue) { return React.cloneElement(child, { value, placeholder }); } } return child; }) })); }; export const SelectTrigger = ({ children, className, onClick, }) => { return (_jsxs("div", { className: cn("flex h-10 w-full items-center justify-between rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background placeholder:text-muted-foreground focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 cursor-pointer", className), onClick: onClick, children: [children, _jsx("svg", { className: "h-4 w-4 opacity-50", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", xmlns: "http://www.w3.org/2000/svg", children: _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M19 9l-7 7-7-7" }) })] })); }; export const SelectValue = ({ children, placeholder = "", value, }) => { return _jsx("span", { children: children || value || placeholder }); }; export const SelectContent = ({ children, isOpen, onSelect, searchable, searchValue, onSearchChange, searchInputRef, }) => { if (!isOpen) return null; // Filter children based on search value const filteredChildren = React.Children.toArray(children).filter((child) => { if (!searchable || !searchValue || !React.isValidElement(child)) { return true; } // Extract search text from child props const childProps = child.props; const searchText = childProps.searchText || childProps.value || ""; return searchText.toLowerCase().includes(searchValue.toLowerCase()); }); return (_jsxs("div", { className: "absolute top-full left-0 right-0 z-50 mt-1 w-full rounded-md border bg-white shadow-lg", children: [searchable && (_jsx("div", { className: "p-2 border-b bg-white sticky top-0 z-10", children: _jsx("input", { ref: searchInputRef, type: "text", placeholder: "", value: searchValue, onChange: (e) => onSearchChange?.(e.target.value), className: "w-full px-3 py-2 text-sm border rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent", onClick: (e) => e.stopPropagation() }) })), _jsx("div", { className: "overflow-y-auto", style: { maxHeight: "200px", scrollbarWidth: "thin", scrollbarColor: "#cbd5e0 #f7fafc", }, children: filteredChildren.length > 0 ? (React.Children.map(filteredChildren, (child) => { if (React.isValidElement(child) && child.type === SelectItem) { return React.cloneElement(child, { onSelect }); } return child; })) : (_jsx("div", { className: "px-3 py-2 text-sm text-gray-500 text-center", children: "No countries found" })) })] })); }; export const SelectItem = ({ value, children, onSelect, }) => { const handleClick = () => { onSelect?.(value); }; return (_jsx("div", { className: "relative flex w-full cursor-pointer select-none items-center rounded-sm py-1.5 pl-2 pr-2 text-sm outline-none hover:bg-accent hover:text-accent-foreground", onClick: handleClick, children: children })); };