import { Text, useTheme, zero } from "@streamplace/components"; import { motion, spacing } from "@streamplace/components/src/lib/theme/tokens"; import React, { ReactNode, useState } from "react"; import { GestureResponderEvent, Platform, Pressable, View } from "react-native"; /** 24px icons in a 40px row — YouTube's proportions, which give the rail a * confident anchor against the 14px labels. Also the exact icon width the * collapsed 64px rail leaves room for (64 - 8·2 sidebar - 12·2 row = 24). */ const ICON_SIZE = 24; /** * Sidebar navigation row, Linear-style: quiet at rest (text2), surface pill * on hover, filled pill + text1 when active. 40px tall, 24px icons. */ export default function SidebarItem({ icon, label, collapsed, active, onPress, href, }: { icon: | React.ComponentType | React.ReactElement | (() => React.ReactElement); label: string | ReactNode; collapsed: boolean; active: boolean; onPress: (event: GestureResponderEvent) => void; href: string; }) { const [hover, setHover] = useState(false); const { theme } = useTheme(); const iconColor = active || hover ? theme.colors.text1 : theme.colors.text2; const renderIcon = () => { if (!icon) return null; if (React.isValidElement(icon)) { return React.cloneElement(icon as any, { color: iconColor, size: ICON_SIZE, }); } if (typeof icon === "function") { const IconComponent = icon; return ; } if ((icon as any).$$typeof === Symbol.for("react.memo")) { const MemoizedIcon = (icon as any).type; return ; } // forwardRef components (e.g. lucide icons) are objects, not functions if (typeof icon === "object") { const IconComponent = icon as any; return ; } return null; }; const webTransition = Platform.OS === "web" ? ({ transitionDuration: `${motion.fast}ms`, transitionTimingFunction: motion.easingCss, transitionProperty: "background-color, color", } as any) : null; return ( setHover(true)} onHoverOut={() => setHover(false)} role="link" accessibilityLabel={typeof label === "string" ? label : "Link to " + href} // @ts-ignore This makes it render as on web! href={href} > {renderIcon()} {!collapsed && ( {typeof label === "string" ? ( {label} ) : ( label )} )} ); }