UNPKG

manuo

Version:

UI component library for React Native + NativeWind, mobile-first and platform-specific.

1,405 lines (1,361 loc) 111 kB
// src/nativeWindInterop.ts import { Text } from "react-native"; import { cssInterop } from "nativewind"; cssInterop(Text, { className: "style" }); // src/components/Button.tsx import { Platform } from "react-native"; // src/components/ios/ButtonIOS.tsx import { Text as RNText, View as RNView, ActivityIndicator, Pressable } from "react-native"; import { cssInterop as cssInterop2 } from "nativewind"; import { jsx, jsxs } from "react/jsx-runtime"; var Text2 = cssInterop2(RNText, { className: "style" }); var View = cssInterop2(RNView, { className: "style" }); var ButtonIOS = ({ title, icon, onPress, className, textClassName, variant = "primary", loading = false, loaderColor, ...rest }) => { const baseContainer = "px-4 py-2 min-w-[44px] min-h-[44px] rounded-xl flex-row items-center justify-center gap-2 active:opacity-70 transition"; const variants = { primary: "bg-blue-500", secondary: "bg-white border border-blue-500", tonal: "bg-blue-100", plain: "bg-transparent" }; const textStyles = { primary: "text-white text-xl font-semibold", // ⬅️ mai mare, bold secondary: "text-blue-500 text-xl font-medium", // ⬅️ mai mic, ca în poză tonal: "text-blue-700 text-base font-semibold", // ⬅️ ca primary, dar cu altă culoare plain: "text-blue-500 text-base font-medium" // ⬅️ subtil }; const defaultLoaderColor = loaderColor ?? (variant === "primary" ? "#ffffff" : "#007AFF"); return /* @__PURE__ */ jsx( Pressable, { onPress, disabled: loading, accessibilityRole: "button", accessibilityLabel: title, ...rest, children: /* @__PURE__ */ jsxs(View, { className: `${baseContainer} ${variants[variant]} ${className ?? ""}`, children: [ loading ? /* @__PURE__ */ jsx(ActivityIndicator, { size: "small", color: defaultLoaderColor }) : icon, !!title && /* @__PURE__ */ jsx( Text2, { className: `${textStyles[variant]} ${textClassName ?? ""}`, children: title } ) ] }) } ); }; // src/components/android/ButtonAndroid.tsx import { Text as RNText2, View as RNView2, ActivityIndicator as ActivityIndicator2, TouchableNativeFeedback } from "react-native"; import { cssInterop as cssInterop3 } from "nativewind"; import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime"; var Text3 = cssInterop3(RNText2, { className: "style" }); var View2 = cssInterop3(RNView2, { className: "style" }); var ButtonAndroid = ({ title, icon, onPress, className, textClassName, variant = "primary", loading = false, loaderColor }) => { const baseContainer = "px-4 py-2 min-w-[48px] min-h-[48px] rounded-full flex-row items-center justify-center gap-2 overflow-hidden"; const variants = { primary: "bg-blue-500", secondary: "bg-white border border-gray-400", tonal: "bg-blue-100", plain: "bg-transparent" }; const textStyles = { primary: "text-white text-lg font-semibold uppercase", secondary: "text-black text-lg font-medium uppercase", tonal: "text-blue-800 text-base font-semibold uppercase", plain: "text-black text-base font-medium uppercase" }; const defaultLoaderColor = loaderColor ?? (variant === "primary" ? "#fff" : "#2196F3"); return /* @__PURE__ */ jsx2( TouchableNativeFeedback, { onPress, disabled: loading, background: TouchableNativeFeedback.Ripple("#B0BEC5", false), children: /* @__PURE__ */ jsxs2(View2, { className: `${baseContainer} ${variants[variant]} ${className ?? ""}`, children: [ loading ? /* @__PURE__ */ jsx2(ActivityIndicator2, { size: "small", color: defaultLoaderColor }) : icon, !!title && /* @__PURE__ */ jsx2(Text3, { className: `${textStyles[variant]} ${textClassName ?? ""}`, children: title }) ] }) } ); }; // src/components/Button.tsx import { jsx as jsx3 } from "react/jsx-runtime"; var Button = (props) => { const isIOS2 = Platform.OS === "ios" || Platform.OS === "web"; return isIOS2 ? /* @__PURE__ */ jsx3(ButtonIOS, { ...props }) : /* @__PURE__ */ jsx3(ButtonAndroid, { ...props }); }; // src/components/TextDemo.tsx import { Text as RNText3 } from "react-native"; import { cssInterop as cssInterop4 } from "nativewind"; import { jsx as jsx4 } from "react/jsx-runtime"; var Text4 = cssInterop4(RNText3, { className: "style" }); var TextDemo = ({ children, className, ...props }) => { return /* @__PURE__ */ jsx4(Text4, { className: `text-base ${className ?? ""}`, ...props, children }); }; // src/utils/cn.ts function cn(...classes) { return classes.filter(Boolean).join(" "); } // src/components/Card.tsx import { Platform as Platform2 } from "react-native"; // src/components/ios/CardIOS.tsx import { View as RNView3, Text as RNText4, Image as RNImage, Pressable as RNPressable } from "react-native"; import { cssInterop as cssInterop5 } from "nativewind"; import { jsx as jsx5, jsxs as jsxs3 } from "react/jsx-runtime"; var View3 = cssInterop5(RNView3, { className: "style" }); var Text5 = cssInterop5(RNText4, { className: "style" }); var Image = cssInterop5(RNImage, { className: "style" }); var Pressable2 = cssInterop5(RNPressable, { className: "style" }); var CardIOS = ({ image, badge, title, subtitle, description, buttonLabel = "GET", icon, onPress, className, style, bodyClassName = "p-4", bodyStyle, imageContainerClassName, imageClassName, imageStyle, imageAspectRatio, imageResizeMode = "cover" }) => { return /* @__PURE__ */ jsxs3( Pressable2, { onPress, className: `rounded-2xl bg-white shadow-md overflow-hidden ${className ?? ""}`, style, children: [ !!image && /* @__PURE__ */ jsx5(View3, { className: imageContainerClassName, children: /* @__PURE__ */ jsx5( Image, { source: { uri: image }, className: imageClassName ?? "w-full h-48", style: imageAspectRatio ? [{ aspectRatio: imageAspectRatio }, imageStyle] : imageStyle, resizeMode: imageResizeMode } ) }), /* @__PURE__ */ jsxs3(View3, { className: bodyClassName, style: bodyStyle, children: [ !!badge && /* @__PURE__ */ jsx5(Text5, { className: "mb-2 self-start rounded-full bg-gray-100 px-2 py-0.5 text-xs font-semibold uppercase text-gray-500", children: badge }), /* @__PURE__ */ jsx5(Text5, { className: "text-3xl font-bold text-black", children: title }), !!subtitle && /* @__PURE__ */ jsx5(Text5, { className: "text-sm text-gray-500", children: subtitle }), !!description && /* @__PURE__ */ jsx5(Text5, { className: "mt-1 text-sm text-gray-600", children: description }), /* @__PURE__ */ jsxs3(View3, { className: "mt-4 flex-row items-center justify-between", children: [ /* @__PURE__ */ jsxs3(View3, { className: "flex-row items-center", children: [ icon, !!subtitle && /* @__PURE__ */ jsxs3(View3, { className: "ml-2", children: [ /* @__PURE__ */ jsx5(Text5, { className: "text-sm font-medium text-black", children: subtitle }), !!description && /* @__PURE__ */ jsx5(Text5, { className: "text-xs text-gray-400", children: description }) ] }) ] }), /* @__PURE__ */ jsx5(View3, { className: "rounded-full bg-blue-500 px-4 py-1.5", children: /* @__PURE__ */ jsx5(Text5, { className: "text-sm font-bold text-white", children: buttonLabel }) }) ] }) ] }) ] } ); }; // src/components/android/CardAndroid.tsx import { View as RNView4, Text as RNText5, Image as RNImage2, TouchableNativeFeedback as TouchableNativeFeedback2 } from "react-native"; import { cssInterop as cssInterop6 } from "nativewind"; import { jsx as jsx6, jsxs as jsxs4 } from "react/jsx-runtime"; var View4 = cssInterop6(RNView4, { className: "style" }); var Text6 = cssInterop6(RNText5, { className: "style" }); var Image2 = cssInterop6(RNImage2, { className: "style" }); var CardAndroid = ({ image, title, subtitle, description, buttonLabel = "Install", onPress, className, icon }) => { return /* @__PURE__ */ jsx6( TouchableNativeFeedback2, { onPress, background: TouchableNativeFeedback2.Ripple("#E0E0E0", false), children: /* @__PURE__ */ jsxs4(View4, { className: `bg-white rounded-xl shadow-sm p-4 ${className ?? ""}`, children: [ image && /* @__PURE__ */ jsx6( Image2, { source: { uri: image }, className: "mb-4 h-40 w-full rounded-lg", resizeMode: "cover" } ), /* @__PURE__ */ jsx6(Text6, { className: "text-3xl font-bold text-black", children: title }), !!subtitle && /* @__PURE__ */ jsx6(Text6, { className: "mt-0.5 text-xs uppercase text-gray-500 tracking-wider", children: subtitle }), !!description && /* @__PURE__ */ jsx6(Text6, { className: "mt-1 text-sm text-gray-600 leading-tight", children: description }), /* @__PURE__ */ jsxs4(View4, { className: "mt-4 flex-row items-center justify-between", children: [ /* @__PURE__ */ jsxs4(View4, { className: "flex-row items-center gap-2", children: [ icon, !!subtitle && /* @__PURE__ */ jsx6(Text6, { className: "text-xs text-gray-500", children: subtitle }) ] }), /* @__PURE__ */ jsx6(View4, { className: "rounded-full bg-gray-100 px-4 py-1", children: /* @__PURE__ */ jsx6(Text6, { className: "text-sm font-semibold text-blue-600", children: buttonLabel }) }) ] }) ] }) } ); }; // src/components/Card.tsx import { jsx as jsx7 } from "react/jsx-runtime"; var Card = (props) => { const isIOS2 = Platform2.OS === "ios" || Platform2.OS === "web"; return isIOS2 ? /* @__PURE__ */ jsx7(CardIOS, { ...props }) : /* @__PURE__ */ jsx7(CardAndroid, { ...props }); }; // src/components/ListItem.tsx import { SectionList, Platform as Platform3, Text as Text9 } from "react-native"; // src/components/ios/ListItemIOS.tsx import { Text as RNText6, View as RNView5, Pressable as Pressable3, Image as RNImage3 } from "react-native"; import { cssInterop as cssInterop7 } from "nativewind"; import { jsx as jsx8, jsxs as jsxs5 } from "react/jsx-runtime"; var View5 = cssInterop7(RNView5, { className: "style" }); var Text7 = cssInterop7(RNText6, { className: "style" }); var Image3 = cssInterop7(RNImage3, { className: "style" }); var ListItemIOS = ({ title, subtitle, rightText = "100+", icon, className, onPress }) => { return /* @__PURE__ */ jsx8(Pressable3, { onPress, children: /* @__PURE__ */ jsxs5(View5, { className: `flex-row items-center justify-between bg-white px-4 py-3 ${className ?? ""}`, children: [ /* @__PURE__ */ jsxs5(View5, { className: "flex-row items-center gap-3", children: [ icon ?? /* @__PURE__ */ jsx8(View5, { className: "h-10 w-10 rounded-xl bg-blue-500" }), /* @__PURE__ */ jsxs5(View5, { children: [ /* @__PURE__ */ jsx8(Text7, { className: "text-base font-semibold text-black", children: title }), /* @__PURE__ */ jsx8(Text7, { className: "text-sm text-gray-500", children: subtitle }) ] }) ] }), /* @__PURE__ */ jsx8(Text7, { className: "text-xs text-gray-500", children: rightText }) ] }) }); }; // src/components/android/ListItemAndroid.tsx import { Text as RNText7, View as RNView6, TouchableNativeFeedback as TouchableNativeFeedback3 } from "react-native"; import { cssInterop as cssInterop8 } from "nativewind"; import { jsx as jsx9, jsxs as jsxs6 } from "react/jsx-runtime"; var View6 = cssInterop8(RNView6, { className: "style" }); var Text8 = cssInterop8(RNText7, { className: "style" }); var ListItemAndroid = ({ title, subtitle, rightText = "100+", icon, className, onPress }) => { return /* @__PURE__ */ jsx9(TouchableNativeFeedback3, { onPress, background: TouchableNativeFeedback3.Ripple("#E0E0E0", false), children: /* @__PURE__ */ jsxs6(View6, { className: `flex-row items-center justify-between bg-white px-4 py-3 border-b border-gray-100 ${className ?? ""}`, children: [ /* @__PURE__ */ jsxs6(View6, { className: "flex-row items-center gap-3", children: [ icon ?? /* @__PURE__ */ jsx9(View6, { className: "h-10 w-10 rounded-md bg-blue-500" }), /* @__PURE__ */ jsxs6(View6, { children: [ /* @__PURE__ */ jsx9(Text8, { className: "text-sm font-semibold text-black", children: title }), /* @__PURE__ */ jsx9(Text8, { className: "text-xs text-gray-500", children: subtitle }) ] }) ] }), /* @__PURE__ */ jsx9(Text8, { className: "text-xs text-gray-500", children: rightText }) ] }) }); }; // src/components/ListItem.tsx import { jsx as jsx10 } from "react/jsx-runtime"; var ListSection = ({ sections, renderItem, sectionHeaderClassName }) => { const renderDefaultItem = ({ item }) => Platform3.OS === "ios" ? /* @__PURE__ */ jsx10(ListItemIOS, { ...item }) : /* @__PURE__ */ jsx10(ListItemAndroid, { ...item }); return /* @__PURE__ */ jsx10( SectionList, { sections, keyExtractor: (item, index) => `${item.title}-${index}`, renderItem: renderItem ?? renderDefaultItem, renderSectionHeader: ({ section }) => /* @__PURE__ */ jsx10( Text9, { className: `text-xs uppercase font-bold text-gray-400 px-4 py-2 ${sectionHeaderClassName ?? ""}`, children: section.title } ), stickySectionHeadersEnabled: true, contentContainerStyle: { paddingBottom: 24 } } ); }; // src/components/ProgressIndicator.tsx import { useEffect, useRef } from "react"; import { Animated, View as RNView7, Text as RNText8 } from "react-native"; import { cssInterop as cssInterop9 } from "nativewind"; import { jsx as jsx11, jsxs as jsxs7 } from "react/jsx-runtime"; var View8 = cssInterop9(RNView7, { className: "style" }); var Text10 = cssInterop9(RNText8, { className: "style" }); var AnimatedView = cssInterop9(Animated.View, { className: "style" }); var ProgressBar = ({ progress, label = "Progress Indicator", className = "", barClassName = "", trackClassName = "", thickness = 5 }) => { const animatedWidth = useRef(new Animated.Value(0)).current; useEffect(() => { Animated.timing(animatedWidth, { toValue: progress, duration: 300, useNativeDriver: false }).start(); }, [progress]); const widthInterpolation = animatedWidth.interpolate({ inputRange: [0, 1], outputRange: ["0%", "100%"] }); return /* @__PURE__ */ jsxs7(View8, { className: `w-full ${className}`, children: [ !!label && /* @__PURE__ */ jsx11(Text10, { className: "mb-2 text-center text-xs font-medium text-gray-600", children: label }), /* @__PURE__ */ jsx11( View8, { style: { height: thickness }, className: `w-full overflow-hidden rounded-full bg-gray-200 ${trackClassName}`, children: /* @__PURE__ */ jsx11( AnimatedView, { style: { width: widthInterpolation, height: thickness }, className: `rounded-full bg-blue-500 ${barClassName}` } ) } ) ] }); }; // src/components/SegmentControl.tsx import { Platform as Platform4 } from "react-native"; // src/components/ios/SegmentedControlIOS.tsx import { useEffect as useEffect2, useRef as useRef2, useState } from "react"; import { Animated as Animated2, Pressable as Pressable4, View as RNView8, Text as RNText9 } from "react-native"; import { cssInterop as cssInterop10 } from "nativewind"; import { jsx as jsx12, jsxs as jsxs8 } from "react/jsx-runtime"; var View9 = cssInterop10(RNView8, { className: "style" }); var Text11 = cssInterop10(RNText9, { className: "style" }); var AnimatedView2 = cssInterop10(Animated2.View, { className: "style" }); var SegmentedControlIOS = ({ options, selectedIndex = 0, onChange }) => { const [containerWidth, setContainerWidth] = useState(0); const [itemWidth, setItemWidth] = useState(0); const translateX = useRef2(new Animated2.Value(selectedIndex)).current; const [currentIndex, setCurrentIndex] = useState(selectedIndex); useEffect2(() => { if (itemWidth === 0) return; animateTo(selectedIndex); setCurrentIndex(selectedIndex); }, [selectedIndex, itemWidth]); const animateTo = (toIndex) => { Animated2.timing(translateX, { toValue: toIndex, duration: 400, useNativeDriver: false }).start(); }; const onLayout = (e) => { const width = e.nativeEvent.layout.width; const totalGap = 4; const adjustedItemWidth = (width - totalGap) / options.length; setContainerWidth(width); setItemWidth(adjustedItemWidth); }; const interpolatedX = translateX.interpolate({ inputRange: options.map((_, i) => i), outputRange: options.map((_, i) => 2 + i * itemWidth), extrapolate: "clamp" }); return /* @__PURE__ */ jsxs8( View9, { onLayout, className: "flex-row overflow-hidden rounded-[9px] bg-[#f0f0f5] p-[2px]", children: [ itemWidth > 0 && /* @__PURE__ */ jsx12( AnimatedView2, { style: { width: itemWidth, transform: [{ translateX: interpolatedX }] }, className: "absolute bottom-[2px] left-0 top-[2px] z-0 rounded-[7px] bg-white shadow-sm" } ), options.map((label, index) => { const isActive = index === currentIndex; const isBeforeActive = index === currentIndex + 1; const showDivider = index > 0 && !isActive && !isBeforeActive; return /* @__PURE__ */ jsxs8( Pressable4, { onPress: () => onChange?.(index), className: "relative z-10 flex-1 items-center justify-center px-3 py-[7px]", children: [ showDivider && /* @__PURE__ */ jsx12(View9, { className: "absolute bottom-[7px] left-0 top-[7px] w-[1px] bg-gray-300" }), /* @__PURE__ */ jsx12( Text11, { className: `text-base font-semibold ${isActive ? "text-black" : "text-gray-500"}`, children: label } ) ] }, index ); }) ] } ); }; // src/components/android/SegmentedControlAndroid.tsx import { Pressable as Pressable5, View as View10, Text as Text12 } from "react-native"; import { jsx as jsx13 } from "react/jsx-runtime"; var SegmentedControlAndroid = ({ options, selectedIndex = 0, onChange }) => { return /* @__PURE__ */ jsx13( View10, { style: { flexDirection: "row", borderWidth: 1, borderColor: "#D1D5DB", borderRadius: 24, overflow: "hidden" }, children: options.map((option, index) => { const isFirst = index === 0; const isLast = index === options.length - 1; const isSelected = selectedIndex === index; return /* @__PURE__ */ jsx13( Pressable5, { onPress: () => onChange?.(index), style: { flex: 1, backgroundColor: isSelected ? "#E0F2FE" : "#fff", paddingVertical: 10, alignItems: "center", borderRightWidth: index < options.length - 1 ? 1 : 0, borderRightColor: "#D1D5DB", borderTopLeftRadius: isFirst ? 999 : 0, borderBottomLeftRadius: isFirst ? 999 : 0, borderTopRightRadius: isLast ? 999 : 0, borderBottomRightRadius: isLast ? 999 : 0 }, children: /* @__PURE__ */ jsx13( Text12, { style: { fontSize: 14, fontWeight: isSelected ? "600" : "400", color: "#111827" }, children: option } ) }, index ); }) } ); }; // src/components/web/SegmentControlWeb.tsx import { useEffect as useEffect3, useRef as useRef3, useState as useState2 } from "react"; import { Animated as Animated3, Pressable as RNPressable2, View as RNView9, Text as RNText10 } from "react-native"; import { cssInterop as cssInterop11 } from "nativewind"; import { jsx as jsx14, jsxs as jsxs9 } from "react/jsx-runtime"; var View11 = cssInterop11(RNView9, { className: "style" }); var Text13 = cssInterop11(RNText10, { className: "style" }); var Pressable6 = cssInterop11(RNPressable2, { className: "style" }); var AnimatedView3 = cssInterop11(Animated3.View, { className: "style" }); function SegmentedControlWeb({ options, selectedIndex = 0, onChange }) { const [itemWidth, setItemWidth] = useState2(0); const [currentIndex, setCurrentIndex] = useState2(selectedIndex); const animIndex = useRef3(new Animated3.Value(selectedIndex)).current; useEffect3(() => { if (!itemWidth) return; Animated3.timing(animIndex, { toValue: selectedIndex, duration: 400, useNativeDriver: false }).start(() => setCurrentIndex(selectedIndex)); }, [selectedIndex, itemWidth]); const onLayout = (e) => { const width = e.nativeEvent.layout.width; const w = Math.floor((width - 4) / options.length); setItemWidth(w); }; const translateX = Animated3.add(new Animated3.Value(2), Animated3.multiply(animIndex, itemWidth)); return /* @__PURE__ */ jsxs9( View11, { onLayout, className: "flex-row items-stretch overflow-hidden rounded-[9px] bg-[#f0f0f5] p-[2px]", style: { willChange: "transform" }, children: [ itemWidth > 0 && /* @__PURE__ */ jsx14( AnimatedView3, { pointerEvents: "none", className: "absolute bottom-[2px] left-0 top-[2px] z-0 rounded-[7px] bg-white", style: { width: itemWidth, transform: [{ translateX }] } } ), options.map((label, index) => { const isActive = index === currentIndex; const isBeforeActive = index === currentIndex + 1; const showDivider = index > 0 && !isActive && !isBeforeActive; return /* @__PURE__ */ jsxs9( Pressable6, { onPress: () => onChange?.(index), className: "relative z-10 flex-1 basis-0 items-center justify-center px-3 py-[7px]", accessibilityRole: "button", accessibilityState: { selected: isActive }, children: [ showDivider && /* @__PURE__ */ jsx14(View11, { className: "absolute bottom-[7px] left-0 top-[7px] w-[1px] bg-gray-300 opacity-60" }), /* @__PURE__ */ jsx14(Text13, { className: `text-base font-semibold ${isActive ? "text-black" : "text-gray-500"}`, children: label }) ] }, index ); }) ] } ); } // src/components/SegmentControl.tsx import { jsx as jsx15 } from "react/jsx-runtime"; var SegmentedControl = (props) => { if (Platform4.OS === "web") return /* @__PURE__ */ jsx15(SegmentedControlWeb, { ...props }); if (Platform4.OS === "ios") return /* @__PURE__ */ jsx15(SegmentedControlIOS, { ...props }); return /* @__PURE__ */ jsx15(SegmentedControlAndroid, { ...props }); }; // src/components/Text.tsx import { Platform as Platform5 } from "react-native"; // src/components/ios/TextIOS.tsx import { Text as RNText11 } from "react-native"; import { cssInterop as cssInterop12 } from "nativewind"; import { jsx as jsx16 } from "react/jsx-runtime"; var Text14 = cssInterop12(RNText11, { className: "style" }); var iosVariants = { hero: "text-[34px] font-bold", pageTitle: "text-[28px] font-semibold", sectionTitle: "text-[22px] font-semibold", cardTitle: "text-[20px] font-semibold", header: "text-[17px] font-semibold", paragraph: "text-[16px] font-normal", hint: "text-[16px] font-normal", label: "text-[15px] font-normal", footnote: "text-[13px] font-normal", caption: "text-[12px] font-normal", captionSmall: "text-[11px] font-normal" }; var TextIOS = ({ variant = "paragraph", className = "", ...props }) => { return /* @__PURE__ */ jsx16(Text14, { className: `${iosVariants[variant]} ${className}`, ...props }); }; // src/components/android/TextAndroid.tsx import { Text as RNText12 } from "react-native"; import { cssInterop as cssInterop13 } from "nativewind"; import { jsx as jsx17 } from "react/jsx-runtime"; var Text15 = cssInterop13(RNText12, { className: "style" }); var androidVariants = { hero: "text-[34px] font-bold", pageTitle: "text-[28px] font-bold", sectionTitle: "text-[22px] font-semibold", cardTitle: "text-[20px] font-semibold", header: "text-[18px] font-medium", paragraph: "text-[16px] font-normal", hint: "text-[15px] font-normal", label: "text-[14px] font-normal", footnote: "text-[13px] font-normal", caption: "text-[12px] font-normal", captionSmall: "text-[11px] font-normal" }; var TextAndroid = ({ variant = "paragraph", className = "", ...props }) => { return /* @__PURE__ */ jsx17(Text15, { className: `${androidVariants[variant]} ${className}`, ...props }); }; // src/components/Text.tsx import { jsx as jsx18 } from "react/jsx-runtime"; var Text16 = (props) => { const isIOS2 = Platform5.OS === "ios" || Platform5.OS === "macos" || Platform5.OS === "web"; return isIOS2 ? /* @__PURE__ */ jsx18(TextIOS, { ...props }) : /* @__PURE__ */ jsx18(TextAndroid, { ...props }); }; // src/components/PlatformDrawer.tsx import { forwardRef as forwardRef2 } from "react"; import { Platform as Platform7 } from "react-native"; // src/components/ios/SimplePlatformDrawerIOS.tsx import { MaterialIcons } from "@expo/vector-icons"; import { forwardRef, useImperativeHandle, useRef as useRef4, useState as useState3 } from "react"; import { Animated as Animated4, Text as Text17, TouchableOpacity, View as View12 } from "react-native"; import { Fragment, jsx as jsx19, jsxs as jsxs10 } from "react/jsx-runtime"; var renderIcon = (icon, isSelected = false) => { const { library, name, size = 26 } = icon; const iconColor = isSelected ? "#FFFFFF" : "#007AFF"; return /* @__PURE__ */ jsx19(MaterialIcons, { name, size, color: iconColor }); }; var PlatformDrawerIOS = forwardRef((props, ref) => { const { title = "", sections = [], onOpen, onClose, className = "", drawerWidth = 320, backgroundColor = "#F8F9FA", activeColor = "#007AFF", inactiveColor = "#000000", activeBackgroundColor = "#007AFF", enableBackdropPress = true, animationDuration = 300, hasNavigationBar = true } = props; const [isOpen, setIsOpen] = useState3(false); const slideAnim = useRef4(new Animated4.Value(-drawerWidth)).current; useImperativeHandle(ref, () => ({ open: () => { setIsOpen(true); onOpen?.(); Animated4.timing(slideAnim, { toValue: 0, duration: animationDuration, useNativeDriver: true }).start(); }, close: () => { Animated4.timing(slideAnim, { toValue: -drawerWidth, duration: animationDuration, useNativeDriver: true }).start(() => { setIsOpen(false); onClose?.(); }); }, toggle: () => { if (isOpen) { ref?.current?.close(); } else { ref?.current?.open(); } } })); const handleBackdropPress = () => { if (enableBackdropPress && isOpen) { ref?.current?.close(); } }; if (!isOpen) return null; return /* @__PURE__ */ jsxs10(Fragment, { children: [ /* @__PURE__ */ jsx19( TouchableOpacity, { style: { position: "absolute", top: 0, left: 0, right: 0, bottom: 0, backgroundColor: "rgba(0, 0, 0, 0.4)", zIndex: 999 }, activeOpacity: 1, onPress: handleBackdropPress } ), /* @__PURE__ */ jsx19( Animated4.View, { style: { position: "absolute", top: 0, left: 0, width: drawerWidth, height: "100%", backgroundColor, transform: [{ translateX: slideAnim }], zIndex: hasNavigationBar ? 999 : 1e3, shadowColor: "#000", shadowOffset: { width: 1, height: 0 }, shadowOpacity: 0.15, shadowRadius: 10 }, children: /* @__PURE__ */ jsxs10(View12, { style: { flex: 1, paddingTop: 60 }, children: [ /* @__PURE__ */ jsx19(View12, { style: { paddingHorizontal: 24, paddingBottom: 30 }, children: /* @__PURE__ */ jsx19( Text17, { style: { fontSize: 38, fontWeight: "700", color: "#000000", letterSpacing: -1, lineHeight: 46 }, children: title } ) }), /* @__PURE__ */ jsx19(View12, { style: { flex: 1, paddingHorizontal: 20 }, children: sections.map((section, sectionIndex) => /* @__PURE__ */ jsxs10(View12, { style: { marginBottom: 30 }, children: [ section.title && /* @__PURE__ */ jsx19( Text17, { style: { fontSize: 22, fontWeight: "600", color: "#000000", marginBottom: 16, marginLeft: 4 }, children: section.title } ), section.items.map((item) => /* @__PURE__ */ jsxs10( TouchableOpacity, { style: { flexDirection: "row", alignItems: "center", paddingVertical: 15, paddingHorizontal: 16, marginBottom: 3, backgroundColor: item.isSelected ? "#007AFF" : "transparent", borderRadius: 12 }, onPress: item.onPress, activeOpacity: 0.8, children: [ item.icon && /* @__PURE__ */ jsx19(View12, { style: { marginRight: 15 }, children: renderIcon(item.icon, item.isSelected) }), /* @__PURE__ */ jsx19( Text17, { style: { flex: 1, fontSize: 17, fontWeight: item.isSelected ? "600" : "400", color: item.isSelected ? "#FFFFFF" : "#000000", letterSpacing: -0.3 }, children: item.label } ), item.badge && /* @__PURE__ */ jsx19( View12, { style: { backgroundColor: item.isSelected ? "rgba(255,255,255,0.25)" : "#FF3B30", borderRadius: 15, paddingHorizontal: 8, paddingVertical: 4, minWidth: 26, alignItems: "center", justifyContent: "center" }, children: /* @__PURE__ */ jsx19( Text17, { style: { fontSize: 13, fontWeight: "600", color: "#FFFFFF" }, children: item.badge } ) } ) ] }, item.id )) ] }, sectionIndex)) }) ] }) } ) ] }); }); PlatformDrawerIOS.displayName = "PlatformDrawer"; // src/components/PlatformDrawer.tsx import { jsx as jsx20 } from "react/jsx-runtime"; var PlatformDrawer = forwardRef2((props, ref) => { const isIOS2 = Platform7.OS === "ios" || Platform7.OS === "web"; return isIOS2 ? /* @__PURE__ */ jsx20(PlatformDrawerIOS, { ref, ...props }) : /* @__PURE__ */ jsx20(PlatformDrawer, { ref, ...props }); }); PlatformDrawer.displayName = ""; // src/components/Toggle.tsx import { Platform as Platform8 } from "react-native"; // src/components/ios/ToggleIOS.tsx import { Switch } from "react-native"; import { cssInterop as cssInterop14 } from "nativewind"; import { jsx as jsx21 } from "react/jsx-runtime"; var NativeSwitch = cssInterop14(Switch, { className: "style" }); var ToggleIOS = ({ className = "", ...props }) => { return /* @__PURE__ */ jsx21( NativeSwitch, { className: `ios-toggle-base ${className}`, ios_backgroundColor: "#E5E7EB", trackColor: { false: "#E5E7EB", true: "#007AFF" }, thumbColor: "#FFFFFF", ...props } ); }; // src/components/android/ToggleAndroid.tsx import { Switch as Switch2 } from "react-native"; import { cssInterop as cssInterop15 } from "nativewind"; import { jsx as jsx22 } from "react/jsx-runtime"; var NativeSwitch2 = cssInterop15(Switch2, { className: "style" }); var ToggleAndroid = ({ className = "", ...props }) => { return /* @__PURE__ */ jsx22( NativeSwitch2, { className: `android-toggle-base ${className}`, trackColor: { false: "#9CA3AF", true: "#2563EB" }, thumbColor: props.value ? "#FFFFFF" : "#F3F4F6", ...props } ); }; // src/components/Toggle.tsx import { jsx as jsx23 } from "react/jsx-runtime"; var Toggle = (props) => { const isIOS2 = Platform8.OS === "ios" || Platform8.OS === "web"; return isIOS2 ? /* @__PURE__ */ jsx23(ToggleIOS, { ...props }) : /* @__PURE__ */ jsx23(ToggleAndroid, { ...props }); }; // src/components/ActivityIndicator.tsx import { Platform as Platform9 } from "react-native"; // src/components/ios/ActivityIndicatorIOS.tsx import { ActivityIndicator as RNActivityIndicator } from "react-native"; import { jsx as jsx24 } from "react/jsx-runtime"; var ActivityIndicatorIOS = ({ size = "small", className = "" }) => { return /* @__PURE__ */ jsx24( RNActivityIndicator, { className, size, color: "#007AFF" } ); }; // src/components/android/ActivityIndicatorAndroid.tsx import { ActivityIndicator as RNActivityIndicator2 } from "react-native"; import { jsx as jsx25 } from "react/jsx-runtime"; var ActivityIndicatorAndroid = ({ size = "small", className = "" }) => { return /* @__PURE__ */ jsx25( RNActivityIndicator2, { className, size, color: "#2563EB" } ); }; // src/components/ActivityIndicator.tsx import { jsx as jsx26 } from "react/jsx-runtime"; var ActivityIndicator3 = (props) => { const isIOS2 = Platform9.OS === "ios" || Platform9.OS === "web"; return isIOS2 ? /* @__PURE__ */ jsx26(ActivityIndicatorIOS, { ...props }) : /* @__PURE__ */ jsx26(ActivityIndicatorAndroid, { ...props }); }; // src/components/Checkbox.tsx import { Platform as Platform10 } from "react-native"; // src/components/ios/CheckBoxIOS.tsx import { Pressable as Pressable7, View as View13 } from "react-native"; import { Ionicons } from "@expo/vector-icons"; import { jsx as jsx27 } from "react/jsx-runtime"; var CheckboxIOS = ({ value, onValueChange, className = "" }) => { return /* @__PURE__ */ jsx27(Pressable7, { onPress: () => onValueChange(!value), children: /* @__PURE__ */ jsx27( View13, { className: ` h-5 w-5 items-center justify-center rounded-full border ${value ? "border-[#007AFF] bg-[#007AFF]" : "border-gray-300 bg-white"} ${className} `, children: value && /* @__PURE__ */ jsx27(Ionicons, { name: "checkmark", size: 12, color: "white" }) } ) }); }; // src/components/android/CheckBoxAndroid.tsx import { Pressable as Pressable8, View as View14 } from "react-native"; import { Ionicons as Ionicons2 } from "@expo/vector-icons"; import { jsx as jsx28 } from "react/jsx-runtime"; var CheckboxAndroid = ({ value, onValueChange, className = "" }) => { return /* @__PURE__ */ jsx28(Pressable8, { onPress: () => onValueChange(!value), children: /* @__PURE__ */ jsx28( View14, { className: ` h-5 w-5 items-center justify-center rounded-sm border ${value ? "border-[#2563EB] bg-[#2563EB]" : "border-gray-400 bg-white"} ${className} `, children: value && /* @__PURE__ */ jsx28(Ionicons2, { name: "checkmark", size: 14, color: "white" }) } ) }); }; // src/components/Checkbox.tsx import { jsx as jsx29 } from "react/jsx-runtime"; var Checkbox = (props) => { const isIOS2 = Platform10.OS === "ios" || Platform10.OS === "web"; return isIOS2 ? /* @__PURE__ */ jsx29(CheckboxIOS, { ...props }) : /* @__PURE__ */ jsx29(CheckboxAndroid, { ...props }); }; // src/components/DateTimeField.tsx import { useMemo, useState as useState4 } from "react"; import { Pressable as RNPressable3, View as RNView10, Text as RNText13, Platform as Platform11 } from "react-native"; import DateTimePicker from "@react-native-community/datetimepicker"; import { cssInterop as cssInterop16 } from "nativewind"; import { jsx as jsx30, jsxs as jsxs11 } from "react/jsx-runtime"; var View15 = cssInterop16(RNView10, { className: "style" }); var Text18 = cssInterop16(RNText13, { className: "style" }); var Pressable9 = cssInterop16(RNPressable3, { className: "style" }); var VALID_MINUTE_INTERVALS = [1, 2, 3, 4, 5, 6, 10, 12, 15, 20, 30]; var DateTimeField = ({ value, onChange, label, helperText, errorText, className = "", triggerClassName = "", showInlineOnIOS = true, locale, format = { dateStyle: "medium", timeStyle: "short" }, mode = "date", minimumDate, maximumDate, // iOS/web minuteInterval, themeVariant, accentColor, textColor, // Android is24Hour, positiveButtonLabel, negativeButtonLabel, neutralButtonLabel, // nou pickerBackgroundColor, pickerContainerClassName }) => { const [open, setOpen] = useState4(false); const formatted = useMemo(() => { try { return new Intl.DateTimeFormat(locale || void 0, format).format(value); } catch { return value.toLocaleString(); } }, [value, locale, format]); const handleChange = (e, selected) => { if (Platform11.OS === "android") { setOpen(false); if (e.type === "set" && selected) onChange(selected); if (e.type === "neutralButtonPressed") onChange(null); } else { if (selected) onChange(selected); } }; const safeMinuteInterval = minuteInterval && VALID_MINUTE_INTERVALS.includes(minuteInterval) ? minuteInterval : void 0; const isCupertino = Platform11.OS === "ios" || Platform11.OS === "web"; const cupertinoDisplay = showInlineOnIOS ? "inline" : "compact"; const resolvedPickerBg = isCupertino ? pickerBackgroundColor ?? "#ffffff" : void 0; return /* @__PURE__ */ jsxs11(View15, { className: `w-full ${className}`, children: [ !!label && /* @__PURE__ */ jsx30(Text18, { className: "mb-1 text-sm text-gray-500", children: label }), /* @__PURE__ */ jsx30( Pressable9, { onPress: () => setOpen(true), accessibilityRole: "button", accessibilityLabel: label || "Open date time picker", className: `rounded-xl border border-gray-200 bg-white px-3 py-2 ${triggerClassName}`, children: /* @__PURE__ */ jsx30(Text18, { className: "text-base text-gray-900", children: formatted }) } ), !!helperText && !errorText && /* @__PURE__ */ jsx30(Text18, { className: "mt-1 text-xs text-gray-500", children: helperText }), !!errorText && /* @__PURE__ */ jsx30(Text18, { className: "mt-1 text-xs text-red-600", children: errorText }), open && (isCupertino ? ( // iOS și WEB cupertinoDisplay === "inline" ? ( // placă albă cu colțuri ca în iOS /* @__PURE__ */ jsx30( View15, { className: `mt-2 rounded-2xl border border-black/5 shadow-sm p-2 ${pickerContainerClassName || ""}`, style: { backgroundColor: resolvedPickerBg }, children: /* @__PURE__ */ jsx30(View15, { className: "overflow-hidden rounded-xl", children: /* @__PURE__ */ jsx30( DateTimePicker, { value, mode, display: "inline", onChange: handleChange, minimumDate, maximumDate, minuteInterval: safeMinuteInterval, themeVariant, accentColor, textColor } ) }) } ) ) : ( // compact: lăsăm nativ (arată ca field-ul iOS) /* @__PURE__ */ jsx30(View15, { className: "mt-2", children: /* @__PURE__ */ jsx30( DateTimePicker, { value, mode, display: "compact", onChange: handleChange, minimumDate, maximumDate, minuteInterval: safeMinuteInterval, themeVariant, accentColor, textColor } ) }) ) ) : ( // ANDROID (dialog nativ) /* @__PURE__ */ jsx30( DateTimePicker, { value, mode, display: "default", onChange: handleChange, minimumDate, maximumDate, is24Hour, positiveButton: { label: positiveButtonLabel }, negativeButton: { label: negativeButtonLabel }, neutralButton: neutralButtonLabel ? { label: neutralButtonLabel } : void 0 } ) )) ] }); }; // src/components/Stepper.tsx import { Platform as Platform12 } from "react-native"; // src/components/ios/StepperIOS.tsx import { useEffect as useEffect4, useMemo as useMemo2, useRef as useRef5 } from "react"; import { View as View16, Text as Text19, Pressable as Pressable10 } from "react-native"; import { Ionicons as Ionicons3 } from "@expo/vector-icons"; import { jsx as jsx31, jsxs as jsxs12 } from "react/jsx-runtime"; var StepperIOS = ({ value, onChange, min = Number.NEGATIVE_INFINITY, max = Number.POSITIVE_INFINITY, step = 1, disabled = false, allowDecimals = false, className = "", buttonClassName = "", valueClassName = "", accentColor = "#007AFF", neutralColor = "#F2F3F5", longPressIntervalMs = 100, valueSlotWidth = 56 }) => { const timerRef = useRef5(null); const clamped = Math.min(max, Math.max(min, value)); const canDec = !disabled && clamped > min; const canInc = !disabled && clamped < max; const displayText = useMemo2(() => { if (allowDecimals) return clamped.toFixed(1); return String(Math.round(clamped)); }, [clamped, allowDecimals]); const clamp = (v) => Math.min(max, Math.max(min, v)); const inc = () => canInc && onChange(clamp(clamped + step)); const dec = () => canDec && onChange(clamp(clamped - step)); const clearHold = () => { if (timerRef.current) { clearInterval(timerRef.current); timerRef.current = null; } }; const startHold = (fn) => { clearHold(); timerRef.current = setInterval(fn, longPressIntervalMs); }; useEffect4(() => { return () => clearHold(); }, []); const onAccessibilityAction = (e) => { if (e.nativeEvent.actionName === "increment") inc(); if (e.nativeEvent.actionName === "decrement") dec(); }; return /* @__PURE__ */ jsxs12( View16, { className: `flex-row items-center rounded-full border border-gray-200 bg-white px-1 py-1 ${disabled ? "opacity-50" : ""} ${className}`, accessibilityRole: "adjustable", accessibilityActions: [{ name: "increment" }, { name: "decrement" }], onAccessibilityAction, children: [ /* @__PURE__ */ jsx31( Pressable10, { accessibilityRole: "button", accessibilityLabel: "Decrement", disabled: !canDec, onPress: dec, onPressIn: () => startHold(dec), onPressOut: clearHold, hitSlop: 8, className: `h-8 w-8 items-center justify-center rounded-full ${buttonClassName}`, style: { backgroundColor: canDec ? neutralColor : "#F5F6F7", opacity: canDec ? 1 : 0.6 }, children: /* @__PURE__ */ jsx31(Ionicons3, { name: "remove", size: 16, color: canDec ? "#111827" : "#9CA3AF" }) } ), /* @__PURE__ */ jsx31(View16, { className: "items-center justify-center px-3", style: { minWidth: valueSlotWidth }, children: /* @__PURE__ */ jsx31( Text19, { className: `text-base font-semibold text-gray-900 ${valueClassName}`, style: { fontVariant: ["tabular-nums"] }, children: displayText } ) }), /* @__PURE__ */ jsx31( Pressable10, { accessibilityRole: "button", accessibilityLabel: "Increment", disabled: !canInc, onPress: inc, onPressIn: () => startHold(inc), onPressOut: clearHold, hitSlop: 8, className: `h-8 w-8 items-center justify-center rounded-full ${buttonClassName}`, style: { backgroundColor: canInc ? accentColor : "#C7D7FE", opacity: canInc ? 1 : 0.7 }, children: /* @__PURE__ */ jsx31(Ionicons3, { name: "add", size: 16, color: "white" }) } ) ] } ); }; // src/components/android/StepperAndroid.tsx import { useEffect as useEffect5, useMemo as useMemo3, useRef as useRef6 } from "react"; import { View as RNView11, Text as RNText14, Pressable as RNPressable4 } from "react-native"; import { Ionicons as Ionicons4 } from "@expo/vector-icons"; import { cssInterop as cssInterop17 } from "nativewind"; import { jsx as jsx32, jsxs as jsxs13 } from "react/jsx-runtime"; var View17 = cssInterop17(RNView11, { className: "style" }); var Text20 = cssInterop17(RNText14, { className: "style" }); var Pressable11 = cssInterop17(RNPressable4, { className: "style" }); var StepperAndroid = ({ value, onChange, min = Number.NEGATIVE_INFINITY, max = Number.POSITIVE_INFINITY, step = 1, disabled = false, allowDecimals = false, className = "", buttonClassName = "", valueClassName = "", accentColor = "#2563EB", // Material Blue 600 neutralColor = "#EEF2FF", longPressIntervalMs = 100, valueSlotWidth = 64 }) => { const timerRef = useRef6(null); const clamped = useMemo3(() => Math.min(max, Math.max(min, value)), [value, min, max]); const canDec = !disabled && clamped > min; const canInc = !disabled && clamped < max; const displayText = useMemo3(() => { if (allowDecimals) return clamped.toFixed(1); return String(Math.round(clamped)); }, [clamped, allowDecimals]); const clamp = (v) => Math.min(max, Math.max(min, v)); const inc = () => canInc && onChange(clamp(clamped + step)); const dec = () => canDec && onChange(clamp(clamped - step)); const clearHold = () => { if (timerRef.current) { clearInterval(timerRef.current); timerRef.current = null; } }; const startHold = (fn) => { clearHold(); timerRef.current = setInterval(fn, longPressIntervalMs); }; useEffect5(() => { return () => clearHold(); }, []); const onAccessibilityAction = (e) => { if (e.nativeEvent.actionName === "increment") inc(); if (e.nativeEvent.actionName === "decrement") dec(); }; return /* @__PURE__ */ jsxs13( View17, { className: `flex-row items-center overflow-hidden rounded-xl border border-gray-200 bg-white ${disabled ? "opacity-50" : ""} ${className}`, accessibilityRole: "adjustable", accessibilityActions: [{ name: "increment" }, { name: "decrement" }], onAccessibilityAction, children: [ /* @__PURE__ */ jsx32( Pressable11, { android_ripple: { color: "#E5E7EB", borderless: false }, accessibilityRole: "button", accessibilityLabel: "Decrement", disabled: !canDec, onPress: dec, onPressIn: () => startHold(dec), onPressOut: clearHold, hitSlop: 8, className: `h-10 w-10 items-center justify-center ${buttonClassName}`, style: { backgroundColor: canDec ? neutralColor : "#F3F4F6", opacity: canDec ? 1 : 0.6 }, children: /* @__PURE__ */ jsx32(Ionicons4, { name: "remove", size: 18, color: canDec ? accentColor : "#9CA3AF" }) } ), /* @__PURE__ */ jsx32(View17, { className: "items-center justify-center px-3", style: { minWidth: valueSlotWidth }, children: /* @__PURE__ */ jsx32( Text20, { className: `text-base font-medium text-gray-900 ${valueClassName}`, style: { fontVariant: ["tabular-nums"] }, children: displayText } ) }), /* @__PURE__ */ jsx32( Pressable11, { android_ripple: { color: "#E5E7EB", borderless: false }, accessibilityRole: "button", accessibilityLabel: "Increment", disabled: !canInc, onPress: inc, onPressIn: () => startHold(inc), onPressOut: clearHold, hitSlop: 8, className: `h-10 w-10 items-center justify-center ${buttonClassName}`, style: { backgroundColor: canInc ? accentColor : "#C7D7FE", opacity: canInc ? 1 : 0.7 }, children: /* @__PURE__ */ jsx32(Ionicons4, { name: "add", size: 18, color: "white" }) } ) ] } ); }; // src/components/Stepper.tsx import { jsx as jsx33 } from "react/jsx-runtime"; var Stepper = (props) => { const isIO