@vvedantb/native-ui 0.0.0-stage → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +89 -2
- package/package.json +72 -3
- package/src/AmbientBackground.tsx +29 -0
- package/src/BottomSheetContainer.tsx +92 -0
- package/src/Button.tsx +111 -0
- package/src/Card.tsx +64 -0
- package/src/Chip.tsx +49 -0
- package/src/DateTimeField.tsx +78 -0
- package/src/EmptyState.tsx +51 -0
- package/src/FloatingFAB.tsx +62 -0
- package/src/FloatingSurface.tsx +114 -0
- package/src/FloatingTabBar.tsx +107 -0
- package/src/HeaderIconButton.tsx +29 -0
- package/src/Input.tsx +32 -0
- package/src/LiquidGlass.tsx +14 -0
- package/src/ListRow.tsx +85 -0
- package/src/PillTabs.tsx +51 -0
- package/src/SafeAreaContainer.tsx +26 -0
- package/src/ScreenContainer.tsx +36 -0
- package/src/Select.tsx +132 -0
- package/src/Skeleton.tsx +37 -0
- package/src/Switch.tsx +45 -0
- package/src/cn.ts +6 -0
- package/src/colors.ts +17 -0
- package/src/floating.ts +40 -0
- package/src/haptics.ts +9 -0
- package/src/index.ts +58 -0
- package/src/primitives/button.tsx +101 -0
- package/src/primitives/card.tsx +102 -0
- package/src/primitives/icon.tsx +14 -0
- package/src/primitives/input.tsx +37 -0
- package/src/primitives/native-only-animated-view.tsx +33 -0
- package/src/primitives/select.tsx +265 -0
- package/src/primitives/switch.tsx +77 -0
- package/src/primitives/text.tsx +95 -0
- package/src/settings/SettingsField.tsx +33 -0
- package/src/settings/SettingsSection.tsx +75 -0
- package/src/settings/SettingsStack.tsx +5 -0
- package/src/settings/SettingsToggleRow.tsx +58 -0
- package/src/theme.tsx +44 -0
- package/src/tokens.ts +43 -0
- package/src/useReduceTransparency.ts +24 -0
package/src/Skeleton.tsx
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { View } from "react-native";
|
|
2
|
+
import Animated, {
|
|
3
|
+
useAnimatedStyle,
|
|
4
|
+
useSharedValue,
|
|
5
|
+
withRepeat,
|
|
6
|
+
withTiming,
|
|
7
|
+
} from "react-native-reanimated";
|
|
8
|
+
import { useEffect } from "react";
|
|
9
|
+
import { cn } from "./cn";
|
|
10
|
+
|
|
11
|
+
export function Skeleton({ className }: { className?: string }) {
|
|
12
|
+
const opacity = useSharedValue(0.4);
|
|
13
|
+
|
|
14
|
+
useEffect(() => {
|
|
15
|
+
opacity.value = withRepeat(withTiming(1, { duration: 800 }), -1, true);
|
|
16
|
+
}, [opacity]);
|
|
17
|
+
|
|
18
|
+
const animatedStyle = useAnimatedStyle(() => ({
|
|
19
|
+
opacity: opacity.value,
|
|
20
|
+
}));
|
|
21
|
+
|
|
22
|
+
return (
|
|
23
|
+
<Animated.View
|
|
24
|
+
style={animatedStyle}
|
|
25
|
+
className={cn("bg-neutral-200 dark:bg-neutral-700 rounded-lg", className)}
|
|
26
|
+
/>
|
|
27
|
+
);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export function CardSkeleton() {
|
|
31
|
+
return (
|
|
32
|
+
<View className="rounded-lg bg-surface p-5 gap-3">
|
|
33
|
+
<Skeleton className="h-4 w-32" />
|
|
34
|
+
<Skeleton className="h-16 w-full" />
|
|
35
|
+
</View>
|
|
36
|
+
);
|
|
37
|
+
}
|
package/src/Switch.tsx
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
import { Switch as PrimitiveSwitch } from "./primitives/switch";
|
|
3
|
+
import { cn } from "./cn";
|
|
4
|
+
|
|
5
|
+
type SwitchProps = Omit<
|
|
6
|
+
React.ComponentPropsWithoutRef<typeof PrimitiveSwitch>,
|
|
7
|
+
"checked" | "onCheckedChange"
|
|
8
|
+
> & {
|
|
9
|
+
value?: boolean;
|
|
10
|
+
checked?: boolean;
|
|
11
|
+
onValueChange?: (value: boolean) => void;
|
|
12
|
+
onCheckedChange?: (value: boolean) => void;
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
const Switch = React.forwardRef<
|
|
16
|
+
React.ElementRef<typeof PrimitiveSwitch>,
|
|
17
|
+
SwitchProps
|
|
18
|
+
>(({ value, checked, onValueChange, onCheckedChange, ...props }, ref) => {
|
|
19
|
+
const resolvedValue = checked ?? value ?? false;
|
|
20
|
+
|
|
21
|
+
const handleCheckedChange = (nextValue: boolean) => {
|
|
22
|
+
onCheckedChange?.(nextValue);
|
|
23
|
+
onValueChange?.(nextValue);
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
return (
|
|
27
|
+
<PrimitiveSwitch
|
|
28
|
+
ref={ref}
|
|
29
|
+
checked={resolvedValue}
|
|
30
|
+
onCheckedChange={handleCheckedChange}
|
|
31
|
+
hitSlop={12}
|
|
32
|
+
className="h-8 w-14"
|
|
33
|
+
thumbClassName={cn(
|
|
34
|
+
"h-7 w-7",
|
|
35
|
+
resolvedValue ? "translate-x-6" : "translate-x-0",
|
|
36
|
+
)}
|
|
37
|
+
{...props}
|
|
38
|
+
/>
|
|
39
|
+
);
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
Switch.displayName = "Switch";
|
|
43
|
+
|
|
44
|
+
export { Switch };
|
|
45
|
+
export type { SwitchProps };
|
package/src/cn.ts
ADDED
package/src/colors.ts
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { tokens } from "./tokens";
|
|
2
|
+
|
|
3
|
+
export const NEUTRAL_100 = "#f5f5f5";
|
|
4
|
+
export const NEUTRAL_500 = tokens.color.muted.light;
|
|
5
|
+
export const NEUTRAL_900 = "#171717";
|
|
6
|
+
export const PINK_50 = "#fdf2f8";
|
|
7
|
+
export const PINK_100 = "#fce7f3";
|
|
8
|
+
export const PINK_600 = "#db2777";
|
|
9
|
+
export const PINK_700 = "#be185d";
|
|
10
|
+
|
|
11
|
+
export const Colors = {
|
|
12
|
+
white: tokens.color.white,
|
|
13
|
+
black: tokens.color.black,
|
|
14
|
+
neutral: {
|
|
15
|
+
800: "#262626",
|
|
16
|
+
},
|
|
17
|
+
} as const;
|
package/src/floating.ts
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { Platform, type ViewStyle } from "react-native";
|
|
2
|
+
import { tokens } from "./tokens";
|
|
3
|
+
|
|
4
|
+
export const FLOATING_INSET = tokens.spacing.unit;
|
|
5
|
+
export const FLOATING_TAB_BAR_HEIGHT = 64;
|
|
6
|
+
export const FLOATING_TAB_BAR_HEIGHT_LARGE = 72;
|
|
7
|
+
export const FLOATING_RADIUS = tokens.radius.card;
|
|
8
|
+
export const FLOATING_ROW_RADIUS = tokens.radius.field;
|
|
9
|
+
export const FLOATING_PILL_RADIUS = tokens.radius.pill;
|
|
10
|
+
|
|
11
|
+
const FLOATING_BOX_SHADOW = "0px 8px 24px rgba(10, 10, 10, 0.12)";
|
|
12
|
+
|
|
13
|
+
export const floatingShadow: ViewStyle =
|
|
14
|
+
Platform.select({
|
|
15
|
+
ios: {
|
|
16
|
+
shadowColor: "#0a0a0a",
|
|
17
|
+
shadowOffset: { width: 0, height: 8 },
|
|
18
|
+
shadowOpacity: 0.12,
|
|
19
|
+
shadowRadius: 20,
|
|
20
|
+
},
|
|
21
|
+
default: {
|
|
22
|
+
boxShadow: FLOATING_BOX_SHADOW,
|
|
23
|
+
},
|
|
24
|
+
}) ?? {};
|
|
25
|
+
|
|
26
|
+
export const floatingHairline = tokens.color.hairline;
|
|
27
|
+
|
|
28
|
+
export const floatingFill = tokens.color.fill;
|
|
29
|
+
|
|
30
|
+
export const floatingSolidFill = {
|
|
31
|
+
light: tokens.color.surface.light,
|
|
32
|
+
dark: tokens.color.surface.dark,
|
|
33
|
+
} as const;
|
|
34
|
+
|
|
35
|
+
export function tabBarReserve(largerText: boolean, bottomInset: number) {
|
|
36
|
+
const bar = largerText
|
|
37
|
+
? FLOATING_TAB_BAR_HEIGHT_LARGE
|
|
38
|
+
: FLOATING_TAB_BAR_HEIGHT;
|
|
39
|
+
return bar + FLOATING_INSET + Math.max(bottomInset, 8) + 28;
|
|
40
|
+
}
|
package/src/haptics.ts
ADDED
package/src/index.ts
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
export { cn } from "./cn";
|
|
2
|
+
export {
|
|
3
|
+
tokens,
|
|
4
|
+
NativeUiProvider,
|
|
5
|
+
useNativeUi,
|
|
6
|
+
useLargerText,
|
|
7
|
+
useAccentColor,
|
|
8
|
+
DEFAULT_ACCENT,
|
|
9
|
+
} from "./theme";
|
|
10
|
+
export type { NativeUiTheme } from "./theme";
|
|
11
|
+
export {
|
|
12
|
+
FLOATING_INSET,
|
|
13
|
+
FLOATING_TAB_BAR_HEIGHT,
|
|
14
|
+
FLOATING_TAB_BAR_HEIGHT_LARGE,
|
|
15
|
+
FLOATING_RADIUS,
|
|
16
|
+
FLOATING_ROW_RADIUS,
|
|
17
|
+
FLOATING_PILL_RADIUS,
|
|
18
|
+
floatingShadow,
|
|
19
|
+
floatingHairline,
|
|
20
|
+
floatingFill,
|
|
21
|
+
floatingSolidFill,
|
|
22
|
+
tabBarReserve,
|
|
23
|
+
} from "./floating";
|
|
24
|
+
export { selectionHaptic } from "./haptics";
|
|
25
|
+
export { useReduceTransparency } from "./useReduceTransparency";
|
|
26
|
+
export { FloatingSurface, GlassSheetBackground } from "./FloatingSurface";
|
|
27
|
+
export {
|
|
28
|
+
LiquidGlass,
|
|
29
|
+
GlassBlurProvider,
|
|
30
|
+
GlassBlurTarget,
|
|
31
|
+
} from "./LiquidGlass";
|
|
32
|
+
export { AmbientBackground } from "./AmbientBackground";
|
|
33
|
+
export { FloatingTabBar } from "./FloatingTabBar";
|
|
34
|
+
export { FloatingFAB } from "./FloatingFAB";
|
|
35
|
+
export { Button } from "./Button";
|
|
36
|
+
export type { ButtonProps } from "./Button";
|
|
37
|
+
export { Input } from "./Input";
|
|
38
|
+
export type { InputProps } from "./Input";
|
|
39
|
+
export { Select } from "./Select";
|
|
40
|
+
export type { SelectOption, SelectProps } from "./Select";
|
|
41
|
+
export { Switch } from "./Switch";
|
|
42
|
+
export type { SwitchProps } from "./Switch";
|
|
43
|
+
export { Chip } from "./Chip";
|
|
44
|
+
export { PillTabs } from "./PillTabs";
|
|
45
|
+
export { ListRow } from "./ListRow";
|
|
46
|
+
export { HeaderIconButton } from "./HeaderIconButton";
|
|
47
|
+
export { Card } from "./Card";
|
|
48
|
+
export { Skeleton, CardSkeleton } from "./Skeleton";
|
|
49
|
+
export { EmptyState } from "./EmptyState";
|
|
50
|
+
export { DateTimeField } from "./DateTimeField";
|
|
51
|
+
export { BottomSheetContainer } from "./BottomSheetContainer";
|
|
52
|
+
export { SafeAreaContainer } from "./SafeAreaContainer";
|
|
53
|
+
export { ScreenContainer } from "./ScreenContainer";
|
|
54
|
+
export { SettingsSection } from "./settings/SettingsSection";
|
|
55
|
+
export { SettingsField } from "./settings/SettingsField";
|
|
56
|
+
export { SettingsToggleRow } from "./settings/SettingsToggleRow";
|
|
57
|
+
export { SettingsStack } from "./settings/SettingsStack";
|
|
58
|
+
export { PINK_50, PINK_100, PINK_600, PINK_700, NEUTRAL_100, NEUTRAL_500, NEUTRAL_900, Colors } from "./colors";
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import { TextClassContext } from "./text";
|
|
2
|
+
import { cn } from "../cn";
|
|
3
|
+
import { cva, type VariantProps } from "class-variance-authority";
|
|
4
|
+
import * as React from "react";
|
|
5
|
+
import { Platform, Pressable } from "react-native";
|
|
6
|
+
|
|
7
|
+
const buttonVariants = cva(
|
|
8
|
+
cn(
|
|
9
|
+
"group flex-row items-center justify-center gap-2 rounded-lg shadow-none active:opacity-80",
|
|
10
|
+
Platform.select({
|
|
11
|
+
web: "outline-none transition-all",
|
|
12
|
+
}),
|
|
13
|
+
),
|
|
14
|
+
{
|
|
15
|
+
variants: {
|
|
16
|
+
variant: {
|
|
17
|
+
default: cn(
|
|
18
|
+
"bg-primary",
|
|
19
|
+
Platform.select({ web: "hover:bg-primary/90" }),
|
|
20
|
+
),
|
|
21
|
+
destructive: cn(
|
|
22
|
+
"bg-destructive",
|
|
23
|
+
Platform.select({ web: "hover:bg-destructive/90" }),
|
|
24
|
+
),
|
|
25
|
+
outline: cn(
|
|
26
|
+
"border border-border bg-background",
|
|
27
|
+
Platform.select({ web: "hover:bg-accent" }),
|
|
28
|
+
),
|
|
29
|
+
secondary: cn(
|
|
30
|
+
"bg-secondary",
|
|
31
|
+
Platform.select({ web: "hover:bg-secondary/80" }),
|
|
32
|
+
),
|
|
33
|
+
ghost: cn(Platform.select({ web: "hover:bg-accent" })),
|
|
34
|
+
link: "",
|
|
35
|
+
},
|
|
36
|
+
size: {
|
|
37
|
+
default: "h-10 px-4 py-2",
|
|
38
|
+
sm: "h-8 px-3",
|
|
39
|
+
lg: "h-11 px-6",
|
|
40
|
+
icon: "h-10 w-10",
|
|
41
|
+
},
|
|
42
|
+
},
|
|
43
|
+
defaultVariants: {
|
|
44
|
+
variant: "default",
|
|
45
|
+
size: "default",
|
|
46
|
+
},
|
|
47
|
+
},
|
|
48
|
+
);
|
|
49
|
+
|
|
50
|
+
const buttonTextVariants = cva("text-sm font-medium text-foreground", {
|
|
51
|
+
variants: {
|
|
52
|
+
variant: {
|
|
53
|
+
default: "text-primary-foreground",
|
|
54
|
+
destructive: "text-white",
|
|
55
|
+
outline: "text-accent-foreground",
|
|
56
|
+
secondary: "text-secondary-foreground",
|
|
57
|
+
ghost: "text-accent-foreground",
|
|
58
|
+
link: "text-primary underline",
|
|
59
|
+
},
|
|
60
|
+
size: {
|
|
61
|
+
default: "",
|
|
62
|
+
sm: "",
|
|
63
|
+
lg: "",
|
|
64
|
+
icon: "",
|
|
65
|
+
},
|
|
66
|
+
},
|
|
67
|
+
defaultVariants: {
|
|
68
|
+
variant: "default",
|
|
69
|
+
size: "default",
|
|
70
|
+
},
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
type ButtonProps = React.ComponentPropsWithoutRef<typeof Pressable> &
|
|
74
|
+
VariantProps<typeof buttonVariants> & {
|
|
75
|
+
className?: string;
|
|
76
|
+
};
|
|
77
|
+
|
|
78
|
+
const Button = React.forwardRef<
|
|
79
|
+
React.ElementRef<typeof Pressable>,
|
|
80
|
+
ButtonProps
|
|
81
|
+
>(({ className, variant, size, ...props }, ref) => {
|
|
82
|
+
return (
|
|
83
|
+
<TextClassContext.Provider value={buttonTextVariants({ variant, size })}>
|
|
84
|
+
<Pressable
|
|
85
|
+
ref={ref}
|
|
86
|
+
className={cn(
|
|
87
|
+
buttonVariants({ variant, size }),
|
|
88
|
+
props.disabled && "opacity-45",
|
|
89
|
+
className,
|
|
90
|
+
)}
|
|
91
|
+
role="button"
|
|
92
|
+
{...props}
|
|
93
|
+
/>
|
|
94
|
+
</TextClassContext.Provider>
|
|
95
|
+
);
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
Button.displayName = "Button";
|
|
99
|
+
|
|
100
|
+
export { Button, buttonTextVariants, buttonVariants };
|
|
101
|
+
export type { ButtonProps };
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
import { View } from "react-native";
|
|
3
|
+
import { Text, TextClassContext } from "./text";
|
|
4
|
+
import { cn } from "../cn";
|
|
5
|
+
|
|
6
|
+
type CardViewProps = React.ComponentPropsWithoutRef<typeof View> & {
|
|
7
|
+
className?: string;
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
const Card = React.forwardRef<React.ElementRef<typeof View>, CardViewProps>(
|
|
11
|
+
({ className, ...props }, ref) => {
|
|
12
|
+
return (
|
|
13
|
+
<TextClassContext.Provider value="text-card-foreground">
|
|
14
|
+
<View
|
|
15
|
+
ref={ref}
|
|
16
|
+
className={cn(
|
|
17
|
+
"flex flex-col gap-6 rounded-lg bg-surface py-6",
|
|
18
|
+
className,
|
|
19
|
+
)}
|
|
20
|
+
{...props}
|
|
21
|
+
/>
|
|
22
|
+
</TextClassContext.Provider>
|
|
23
|
+
);
|
|
24
|
+
},
|
|
25
|
+
);
|
|
26
|
+
|
|
27
|
+
const CardHeader = React.forwardRef<
|
|
28
|
+
React.ElementRef<typeof View>,
|
|
29
|
+
CardViewProps
|
|
30
|
+
>(({ className, ...props }, ref) => {
|
|
31
|
+
return (
|
|
32
|
+
<View
|
|
33
|
+
ref={ref}
|
|
34
|
+
className={cn("flex flex-col gap-1.5 px-6", className)}
|
|
35
|
+
{...props}
|
|
36
|
+
/>
|
|
37
|
+
);
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
const CardTitle = React.forwardRef<
|
|
41
|
+
React.ElementRef<typeof Text>,
|
|
42
|
+
React.ComponentPropsWithoutRef<typeof Text> & { className?: string }
|
|
43
|
+
>(({ className, ...props }, ref) => {
|
|
44
|
+
return (
|
|
45
|
+
<Text
|
|
46
|
+
ref={ref}
|
|
47
|
+
role="heading"
|
|
48
|
+
aria-level={3}
|
|
49
|
+
className={cn("font-semibold leading-none", className)}
|
|
50
|
+
{...props}
|
|
51
|
+
/>
|
|
52
|
+
);
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
const CardDescription = React.forwardRef<
|
|
56
|
+
React.ElementRef<typeof Text>,
|
|
57
|
+
React.ComponentPropsWithoutRef<typeof Text> & { className?: string }
|
|
58
|
+
>(({ className, ...props }, ref) => {
|
|
59
|
+
return (
|
|
60
|
+
<Text
|
|
61
|
+
ref={ref}
|
|
62
|
+
className={cn("text-sm text-muted-foreground", className)}
|
|
63
|
+
{...props}
|
|
64
|
+
/>
|
|
65
|
+
);
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
const CardContent = React.forwardRef<
|
|
69
|
+
React.ElementRef<typeof View>,
|
|
70
|
+
CardViewProps
|
|
71
|
+
>(({ className, ...props }, ref) => {
|
|
72
|
+
return <View ref={ref} className={cn("px-6", className)} {...props} />;
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
const CardFooter = React.forwardRef<
|
|
76
|
+
React.ElementRef<typeof View>,
|
|
77
|
+
CardViewProps
|
|
78
|
+
>(({ className, ...props }, ref) => {
|
|
79
|
+
return (
|
|
80
|
+
<View
|
|
81
|
+
ref={ref}
|
|
82
|
+
className={cn("flex flex-row items-center px-6", className)}
|
|
83
|
+
{...props}
|
|
84
|
+
/>
|
|
85
|
+
);
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
Card.displayName = "Card";
|
|
89
|
+
CardHeader.displayName = "CardHeader";
|
|
90
|
+
CardTitle.displayName = "CardTitle";
|
|
91
|
+
CardDescription.displayName = "CardDescription";
|
|
92
|
+
CardContent.displayName = "CardContent";
|
|
93
|
+
CardFooter.displayName = "CardFooter";
|
|
94
|
+
|
|
95
|
+
export {
|
|
96
|
+
Card,
|
|
97
|
+
CardContent,
|
|
98
|
+
CardDescription,
|
|
99
|
+
CardFooter,
|
|
100
|
+
CardHeader,
|
|
101
|
+
CardTitle,
|
|
102
|
+
};
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
import type { LucideIcon, LucideProps } from "lucide-react-native";
|
|
3
|
+
|
|
4
|
+
type IconProps = LucideProps & {
|
|
5
|
+
as: LucideIcon;
|
|
6
|
+
className?: string;
|
|
7
|
+
};
|
|
8
|
+
|
|
9
|
+
function Icon({ as: Component, className: _className, ...props }: IconProps) {
|
|
10
|
+
return <Component {...props} />;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export { Icon };
|
|
14
|
+
export type { IconProps };
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
import { Platform, TextInput } from "react-native";
|
|
3
|
+
import { cn } from "../cn";
|
|
4
|
+
|
|
5
|
+
type InputProps = React.ComponentPropsWithoutRef<typeof TextInput> & {
|
|
6
|
+
className?: string;
|
|
7
|
+
};
|
|
8
|
+
|
|
9
|
+
const Input = React.forwardRef<React.ElementRef<typeof TextInput>, InputProps>(
|
|
10
|
+
({ className, ...props }, ref) => {
|
|
11
|
+
return (
|
|
12
|
+
<TextInput
|
|
13
|
+
ref={ref}
|
|
14
|
+
className={cn(
|
|
15
|
+
"flex w-full flex-row items-center rounded-lg border-0 bg-secondary px-3 py-2 text-base text-foreground",
|
|
16
|
+
props.editable === false &&
|
|
17
|
+
cn(
|
|
18
|
+
"opacity-50",
|
|
19
|
+
Platform.select({
|
|
20
|
+
web: "cursor-not-allowed pointer-events-none",
|
|
21
|
+
}),
|
|
22
|
+
),
|
|
23
|
+
Platform.select({
|
|
24
|
+
web: "outline-none transition-[color,box-shadow] md:text-sm",
|
|
25
|
+
native: "placeholder:text-muted-foreground/50",
|
|
26
|
+
}),
|
|
27
|
+
className,
|
|
28
|
+
)}
|
|
29
|
+
{...props}
|
|
30
|
+
/>
|
|
31
|
+
);
|
|
32
|
+
},
|
|
33
|
+
);
|
|
34
|
+
|
|
35
|
+
Input.displayName = "Input";
|
|
36
|
+
|
|
37
|
+
export { Input };
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { Platform, View, type ViewProps } from "react-native";
|
|
2
|
+
import Animated, { type AnimatedProps } from "react-native-reanimated";
|
|
3
|
+
|
|
4
|
+
type NativeOnlyAnimatedViewProps = ViewProps & {
|
|
5
|
+
entering?: AnimatedProps<ViewProps>["entering"];
|
|
6
|
+
exiting?: AnimatedProps<ViewProps>["exiting"];
|
|
7
|
+
layout?: AnimatedProps<ViewProps>["layout"];
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
function NativeOnlyAnimatedView({
|
|
11
|
+
children,
|
|
12
|
+
entering,
|
|
13
|
+
exiting,
|
|
14
|
+
layout,
|
|
15
|
+
...props
|
|
16
|
+
}: NativeOnlyAnimatedViewProps) {
|
|
17
|
+
if (Platform.OS === "web") {
|
|
18
|
+
return <View {...props}>{children}</View>;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
return (
|
|
22
|
+
<Animated.View
|
|
23
|
+
entering={entering}
|
|
24
|
+
exiting={exiting}
|
|
25
|
+
layout={layout}
|
|
26
|
+
{...props}
|
|
27
|
+
>
|
|
28
|
+
{children}
|
|
29
|
+
</Animated.View>
|
|
30
|
+
);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export { NativeOnlyAnimatedView };
|