@munchi_oy/native-ui 0.1.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/dist/index.d.mts +568 -0
- package/dist/index.d.ts +568 -0
- package/dist/index.js +1 -0
- package/dist/index.mjs +1 -0
- package/global.css +53 -0
- package/nativewind-env.d.ts +2 -0
- package/package.json +88 -0
- package/src/MAlert.tsx +38 -0
- package/src/MAnimation.tsx +55 -0
- package/src/MAvatar.tsx +111 -0
- package/src/MBadge.tsx +72 -0
- package/src/MButton.tsx +90 -0
- package/src/MCard.tsx +15 -0
- package/src/MChevron.tsx +47 -0
- package/src/MConfirmation.tsx +68 -0
- package/src/MCountDown.tsx +120 -0
- package/src/MDateTimePicker.tsx +124 -0
- package/src/MDivider.tsx +69 -0
- package/src/MDrawerRightPanel.tsx +187 -0
- package/src/MDropdown.tsx +277 -0
- package/src/MInput.tsx +162 -0
- package/src/MLabel.tsx +3 -0
- package/src/MLucideIcon.tsx +21 -0
- package/src/MModal.tsx +287 -0
- package/src/MNativeAlert.tsx +33 -0
- package/src/MNumpad.tsx +520 -0
- package/src/MPicker.tsx +150 -0
- package/src/MPinPadKeys.tsx +104 -0
- package/src/MPortal.tsx +4 -0
- package/src/MProgressBar.tsx +74 -0
- package/src/MRadioGroup.tsx +4 -0
- package/src/MRequiredLabel.tsx +21 -0
- package/src/MResponsiveContainer.tsx +74 -0
- package/src/MSearch.tsx +138 -0
- package/src/MSelector.tsx +48 -0
- package/src/MSkeleton.tsx +3 -0
- package/src/MSwitch.tsx +13 -0
- package/src/MTable.tsx +17 -0
- package/src/MTabs.tsx +198 -0
- package/src/MText.tsx +51 -0
- package/src/MTimerUp.tsx +88 -0
- package/src/MToggle.tsx +51 -0
- package/src/constants.ts +19 -0
- package/src/hooks/useColorScheme.tsx +12 -0
- package/src/hooks/useIconColors.ts +19 -0
- package/src/index.ts +124 -0
- package/src/primitives/accordion.tsx +143 -0
- package/src/primitives/alert-dialog.tsx +181 -0
- package/src/primitives/alert.tsx +94 -0
- package/src/primitives/aspect-ratio.tsx +5 -0
- package/src/primitives/avatar.tsx +47 -0
- package/src/primitives/badge.tsx +57 -0
- package/src/primitives/button.tsx +92 -0
- package/src/primitives/card.tsx +86 -0
- package/src/primitives/checkbox.tsx +35 -0
- package/src/primitives/collapsible.tsx +9 -0
- package/src/primitives/context-menu.tsx +255 -0
- package/src/primitives/dialog.tsx +166 -0
- package/src/primitives/dropdown-menu.tsx +264 -0
- package/src/primitives/hover-card.tsx +45 -0
- package/src/primitives/input.tsx +25 -0
- package/src/primitives/label.tsx +33 -0
- package/src/primitives/menubar.tsx +266 -0
- package/src/primitives/navigation-menu.tsx +192 -0
- package/src/primitives/popover.tsx +46 -0
- package/src/primitives/progress.tsx +82 -0
- package/src/primitives/radio-group.tsx +42 -0
- package/src/primitives/select.tsx +192 -0
- package/src/primitives/separator.tsx +28 -0
- package/src/primitives/skeleton.tsx +39 -0
- package/src/primitives/switch.tsx +102 -0
- package/src/primitives/table.tsx +107 -0
- package/src/primitives/tabs.tsx +66 -0
- package/src/primitives/text.tsx +28 -0
- package/src/primitives/textarea.tsx +39 -0
- package/src/primitives/toggle-group.tsx +89 -0
- package/src/primitives/toggle.tsx +91 -0
- package/src/primitives/tooltip.tsx +40 -0
- package/src/primitives/typography.tsx +214 -0
- package/src/theme.ts +43 -0
- package/src/tokens.ts +7 -0
- package/src/utils.ts +14 -0
- package/tailwind.config.ts +112 -0
package/src/MBadge.tsx
ADDED
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { type VariantProps, cva } from "class-variance-authority";
|
|
2
|
+
import type React from "react";
|
|
3
|
+
import { Text, type TextProps, View, type ViewProps } from "react-native";
|
|
4
|
+
import { cn } from "./utils";
|
|
5
|
+
|
|
6
|
+
const badgeVariants = cva("p-1 px-2 rounded-md border-0", {
|
|
7
|
+
variants: {
|
|
8
|
+
variant: {
|
|
9
|
+
default: "bg-secondary",
|
|
10
|
+
accent: "bg-accent",
|
|
11
|
+
muted: "bg-muted text-muted-foreground",
|
|
12
|
+
destructive: "bg-destructive",
|
|
13
|
+
primary: "bg-primary text-primary-foreground mx-1",
|
|
14
|
+
gray: "bg-muted text-muted-foreground",
|
|
15
|
+
custom: ""
|
|
16
|
+
}
|
|
17
|
+
},
|
|
18
|
+
defaultVariants: {
|
|
19
|
+
variant: "gray"
|
|
20
|
+
}
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
const badgeTextVariants = cva("text-xs font-munchi", {
|
|
24
|
+
variants: {
|
|
25
|
+
variant: {
|
|
26
|
+
default: "text-secondary-foreground",
|
|
27
|
+
accent: "text-accent-foreground",
|
|
28
|
+
muted: "text-muted-foreground",
|
|
29
|
+
destructive: "text-destructive-foreground",
|
|
30
|
+
primary: "text-primary-foreground",
|
|
31
|
+
gray: "text-muted-foreground",
|
|
32
|
+
custom: "text-foreground"
|
|
33
|
+
}
|
|
34
|
+
},
|
|
35
|
+
defaultVariants: {
|
|
36
|
+
variant: "gray"
|
|
37
|
+
}
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
export interface MBadgeProps
|
|
41
|
+
extends Pick<ViewProps, "className">,
|
|
42
|
+
VariantProps<typeof badgeVariants> {
|
|
43
|
+
text: string;
|
|
44
|
+
show?: boolean;
|
|
45
|
+
customBackgroundColor?: string;
|
|
46
|
+
textClassName?: TextProps["className"];
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export const MBadge: React.FC<MBadgeProps> = ({
|
|
50
|
+
variant = "gray",
|
|
51
|
+
text,
|
|
52
|
+
show = true,
|
|
53
|
+
customBackgroundColor,
|
|
54
|
+
className,
|
|
55
|
+
textClassName
|
|
56
|
+
}) => {
|
|
57
|
+
if (!show) return null;
|
|
58
|
+
const isCustom = variant === "custom";
|
|
59
|
+
|
|
60
|
+
return (
|
|
61
|
+
<View
|
|
62
|
+
className={cn(badgeVariants({ variant }), className)}
|
|
63
|
+
style={isCustom ? { backgroundColor: customBackgroundColor } : undefined}
|
|
64
|
+
>
|
|
65
|
+
<Text className={cn(badgeTextVariants({ variant }), textClassName)}>
|
|
66
|
+
{text}
|
|
67
|
+
</Text>
|
|
68
|
+
</View>
|
|
69
|
+
);
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
MBadge.displayName = "MBadge";
|
package/src/MButton.tsx
ADDED
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import { type VariantProps, cva } from "class-variance-authority";
|
|
2
|
+
import React from "react";
|
|
3
|
+
import { Pressable, type PressableProps, type View } from "react-native";
|
|
4
|
+
import { cn } from "./utils";
|
|
5
|
+
|
|
6
|
+
export const buttonVariants = cva(
|
|
7
|
+
"flex-row justify-center items-center rounded-full",
|
|
8
|
+
{
|
|
9
|
+
variants: {
|
|
10
|
+
variant: {
|
|
11
|
+
default: "bg-primary",
|
|
12
|
+
primary: "bg-primary",
|
|
13
|
+
white: "bg-card border border-border",
|
|
14
|
+
destructive: "bg-destructive",
|
|
15
|
+
outline: "bg-transparent border border-border",
|
|
16
|
+
secondary: "bg-secondary",
|
|
17
|
+
ghost: "bg-transparent",
|
|
18
|
+
link: "bg-transparent",
|
|
19
|
+
none: "none",
|
|
20
|
+
custom: ""
|
|
21
|
+
},
|
|
22
|
+
size: {
|
|
23
|
+
none: "",
|
|
24
|
+
default: "h-auto px-4 md:py-2",
|
|
25
|
+
sm: "h-8 px-3 py-1.5",
|
|
26
|
+
lg: "h-10 px-6 py-2.5",
|
|
27
|
+
icon: "h-9 w-9 p-2 justify-center items-center"
|
|
28
|
+
}
|
|
29
|
+
},
|
|
30
|
+
defaultVariants: {
|
|
31
|
+
variant: "default",
|
|
32
|
+
size: "default"
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
);
|
|
36
|
+
|
|
37
|
+
export interface MButtonProps
|
|
38
|
+
extends Omit<PressableProps, "children">,
|
|
39
|
+
VariantProps<typeof buttonVariants> {
|
|
40
|
+
onPress?: () => void;
|
|
41
|
+
disabled?: boolean;
|
|
42
|
+
children: React.ReactNode;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
const MButton = React.forwardRef<View, MButtonProps>((props, ref) => {
|
|
46
|
+
const {
|
|
47
|
+
onPress,
|
|
48
|
+
variant = "default",
|
|
49
|
+
size = "default",
|
|
50
|
+
disabled = false,
|
|
51
|
+
children,
|
|
52
|
+
className,
|
|
53
|
+
...rest
|
|
54
|
+
} = props;
|
|
55
|
+
|
|
56
|
+
if (variant === "custom") {
|
|
57
|
+
return (
|
|
58
|
+
<Pressable
|
|
59
|
+
ref={ref}
|
|
60
|
+
disabled={disabled}
|
|
61
|
+
className={cn(disabled && "opacity-50", className)}
|
|
62
|
+
onPress={onPress}
|
|
63
|
+
android_ripple={null}
|
|
64
|
+
{...rest}
|
|
65
|
+
>
|
|
66
|
+
{children}
|
|
67
|
+
</Pressable>
|
|
68
|
+
);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
return (
|
|
72
|
+
<Pressable
|
|
73
|
+
ref={ref}
|
|
74
|
+
disabled={disabled}
|
|
75
|
+
className={cn(
|
|
76
|
+
buttonVariants({ variant, size }),
|
|
77
|
+
disabled && "opacity-50",
|
|
78
|
+
className
|
|
79
|
+
)}
|
|
80
|
+
onPress={onPress}
|
|
81
|
+
{...rest}
|
|
82
|
+
>
|
|
83
|
+
{children}
|
|
84
|
+
</Pressable>
|
|
85
|
+
);
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
MButton.displayName = "MButton";
|
|
89
|
+
|
|
90
|
+
export { MButton };
|
package/src/MCard.tsx
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import {
|
|
2
|
+
Card,
|
|
3
|
+
CardContent,
|
|
4
|
+
CardDescription,
|
|
5
|
+
CardFooter,
|
|
6
|
+
CardHeader,
|
|
7
|
+
CardTitle
|
|
8
|
+
} from "./primitives/card";
|
|
9
|
+
|
|
10
|
+
export { Card as MCard };
|
|
11
|
+
export { CardContent as MCardContent };
|
|
12
|
+
export { CardDescription as MCardDescription };
|
|
13
|
+
export { CardFooter as MCardFooter };
|
|
14
|
+
export { CardHeader as MCardHeader };
|
|
15
|
+
export { CardTitle as MCardTitle };
|
package/src/MChevron.tsx
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { useEffect, useRef } from "react";
|
|
2
|
+
import { Animated } from "react-native";
|
|
3
|
+
import Svg, { Path } from "react-native-svg";
|
|
4
|
+
import { NAV_THEME } from "./constants";
|
|
5
|
+
import { useColorScheme } from "./hooks/useColorScheme";
|
|
6
|
+
|
|
7
|
+
export interface MChevronProps {
|
|
8
|
+
isOpen: boolean;
|
|
9
|
+
size?: number;
|
|
10
|
+
/** Override the chevron color. Defaults to the theme foreground color. */
|
|
11
|
+
color?: string;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export const MChevron = ({ isOpen, size = 11, color }: MChevronProps) => {
|
|
15
|
+
const { colorScheme } = useColorScheme();
|
|
16
|
+
const fillColor = color ?? NAV_THEME[colorScheme].text;
|
|
17
|
+
|
|
18
|
+
const rotateAnim = useRef(new Animated.Value(isOpen ? 90 : 0)).current;
|
|
19
|
+
|
|
20
|
+
useEffect(() => {
|
|
21
|
+
Animated.timing(rotateAnim, {
|
|
22
|
+
toValue: isOpen ? 90 : 0,
|
|
23
|
+
duration: 200,
|
|
24
|
+
useNativeDriver: true
|
|
25
|
+
}).start();
|
|
26
|
+
}, [isOpen, rotateAnim]);
|
|
27
|
+
|
|
28
|
+
const rotate = rotateAnim.interpolate({
|
|
29
|
+
inputRange: [0, 90],
|
|
30
|
+
outputRange: ["0deg", "90deg"]
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
return (
|
|
34
|
+
<Animated.View style={{ transform: [{ rotate }] }}>
|
|
35
|
+
<Svg width={size} height={size} viewBox="0 0 11 11" fill="none">
|
|
36
|
+
<Path
|
|
37
|
+
fillRule="evenodd"
|
|
38
|
+
clipRule="evenodd"
|
|
39
|
+
d="M3.80026 1.96823C3.97925 1.78924 4.26945 1.78924 4.44844 1.96823L7.65677 5.17656C7.83575 5.35554 7.83575 5.64576 7.65677 5.82474L4.44844 9.03307C4.26945 9.21205 3.97925 9.21205 3.80026 9.03307C3.62127 8.85409 3.62127 8.56388 3.80026 8.3849L6.68451 5.50065L3.80026 2.61641C3.62127 2.43742 3.62127 2.14722 3.80026 1.96823Z"
|
|
40
|
+
fill={fillColor}
|
|
41
|
+
/>
|
|
42
|
+
</Svg>
|
|
43
|
+
</Animated.View>
|
|
44
|
+
);
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
MChevron.displayName = "MChevron";
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import type React from "react";
|
|
2
|
+
import { ActivityIndicator, Pressable, Text, View } from "react-native";
|
|
3
|
+
import { useIconColors } from "./hooks/useIconColors";
|
|
4
|
+
import { cn } from "./utils";
|
|
5
|
+
|
|
6
|
+
export interface MConfirmationProps {
|
|
7
|
+
message: string;
|
|
8
|
+
onConfirm: () => void;
|
|
9
|
+
onCancel: () => void;
|
|
10
|
+
confirmText?: string;
|
|
11
|
+
cancelText?: string;
|
|
12
|
+
isLoading?: boolean;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export const MConfirmation: React.FC<MConfirmationProps> = ({
|
|
16
|
+
message,
|
|
17
|
+
onConfirm,
|
|
18
|
+
onCancel,
|
|
19
|
+
confirmText = "Confirm",
|
|
20
|
+
cancelText = "Cancel",
|
|
21
|
+
isLoading = false
|
|
22
|
+
}) => {
|
|
23
|
+
const { onPrimary } = useIconColors();
|
|
24
|
+
|
|
25
|
+
return (
|
|
26
|
+
<View className="p-4">
|
|
27
|
+
<Text className="font-munchi text-center mb-10 mt-4 text-foreground">
|
|
28
|
+
{message}
|
|
29
|
+
</Text>
|
|
30
|
+
|
|
31
|
+
<View className="flex-row justify-between">
|
|
32
|
+
<Pressable
|
|
33
|
+
className={cn(
|
|
34
|
+
"flex-1 mr-2 border border-border rounded-md py-3 bg-card",
|
|
35
|
+
isLoading && "opacity-50"
|
|
36
|
+
)}
|
|
37
|
+
onPress={onCancel}
|
|
38
|
+
disabled={isLoading}
|
|
39
|
+
>
|
|
40
|
+
<Text className="font-munchi text-center text-card-foreground">
|
|
41
|
+
{cancelText}
|
|
42
|
+
</Text>
|
|
43
|
+
</Pressable>
|
|
44
|
+
|
|
45
|
+
<Pressable
|
|
46
|
+
className={cn(
|
|
47
|
+
"flex-1 ml-2 bg-primary rounded-md py-3",
|
|
48
|
+
isLoading && "opacity-50"
|
|
49
|
+
)}
|
|
50
|
+
onPress={onConfirm}
|
|
51
|
+
disabled={isLoading}
|
|
52
|
+
>
|
|
53
|
+
{isLoading ? (
|
|
54
|
+
<ActivityIndicator color={onPrimary} />
|
|
55
|
+
) : (
|
|
56
|
+
<Text className="font-munchi text-center text-primary-foreground">
|
|
57
|
+
{confirmText}
|
|
58
|
+
</Text>
|
|
59
|
+
)}
|
|
60
|
+
</Pressable>
|
|
61
|
+
</View>
|
|
62
|
+
</View>
|
|
63
|
+
);
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
MConfirmation.displayName = "MConfirmation";
|
|
67
|
+
|
|
68
|
+
export default MConfirmation;
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
import type React from "react";
|
|
2
|
+
import { useMemo } from "react";
|
|
3
|
+
import Countdown, {
|
|
4
|
+
type CountdownProps,
|
|
5
|
+
type CountdownRenderProps
|
|
6
|
+
} from "react-countdown";
|
|
7
|
+
import { Text, type TextProps, View, type ViewProps } from "react-native";
|
|
8
|
+
import { cn, padNumber } from "./utils";
|
|
9
|
+
|
|
10
|
+
export interface MCountDownProps
|
|
11
|
+
extends Omit<CountdownProps, "renderer" | "className">,
|
|
12
|
+
Pick<ViewProps, "className"> {
|
|
13
|
+
warningThreshold?: number;
|
|
14
|
+
textClassName?: TextProps["className"];
|
|
15
|
+
showPrefix?: boolean;
|
|
16
|
+
countUp?: boolean;
|
|
17
|
+
renderer?: (props: CountdownRenderProps) => React.ReactNode;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export const MCountDown: React.FC<MCountDownProps> = ({
|
|
21
|
+
warningThreshold = 3,
|
|
22
|
+
className = "",
|
|
23
|
+
textClassName = "",
|
|
24
|
+
showPrefix = true,
|
|
25
|
+
countUp = false,
|
|
26
|
+
renderer: customRenderer,
|
|
27
|
+
onComplete,
|
|
28
|
+
date,
|
|
29
|
+
...countdownProps
|
|
30
|
+
}) => {
|
|
31
|
+
const defaultRenderer = useMemo(
|
|
32
|
+
() =>
|
|
33
|
+
({
|
|
34
|
+
minutes,
|
|
35
|
+
seconds,
|
|
36
|
+
completed
|
|
37
|
+
}: CountdownRenderProps): React.ReactNode => {
|
|
38
|
+
let displayMinutes: number;
|
|
39
|
+
let displaySeconds: number;
|
|
40
|
+
let timePrefix = "";
|
|
41
|
+
|
|
42
|
+
if (completed) {
|
|
43
|
+
if (countUp) {
|
|
44
|
+
const targetDate = new Date(date as number | string | Date);
|
|
45
|
+
const now = new Date();
|
|
46
|
+
const timeDiffMs: number = now.getTime() - targetDate.getTime();
|
|
47
|
+
|
|
48
|
+
displayMinutes = Math.floor(timeDiffMs / (1000 * 60));
|
|
49
|
+
displaySeconds = Math.floor((timeDiffMs % (1000 * 60)) / 1000);
|
|
50
|
+
|
|
51
|
+
if (showPrefix) {
|
|
52
|
+
timePrefix = "-";
|
|
53
|
+
}
|
|
54
|
+
} else {
|
|
55
|
+
displayMinutes = 0;
|
|
56
|
+
displaySeconds = 0;
|
|
57
|
+
}
|
|
58
|
+
} else {
|
|
59
|
+
displayMinutes = minutes;
|
|
60
|
+
displaySeconds = seconds;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
const formattedMinutes: string =
|
|
64
|
+
!completed || countUp ? padNumber(Math.abs(displayMinutes), 2) : "00";
|
|
65
|
+
|
|
66
|
+
const formattedSeconds: string =
|
|
67
|
+
!completed || countUp ? padNumber(Math.abs(displaySeconds), 2) : "00";
|
|
68
|
+
|
|
69
|
+
const isUnderThreshold: boolean =
|
|
70
|
+
!completed && minutes < warningThreshold;
|
|
71
|
+
const isExpired: boolean = completed;
|
|
72
|
+
|
|
73
|
+
const bgColorClass: string =
|
|
74
|
+
isUnderThreshold || isExpired
|
|
75
|
+
? "bg-destructive/15"
|
|
76
|
+
: "bg-green-500/15";
|
|
77
|
+
|
|
78
|
+
const textColorClass: string =
|
|
79
|
+
isUnderThreshold || isExpired ? "text-destructive" : "text-green-600";
|
|
80
|
+
|
|
81
|
+
return (
|
|
82
|
+
<View
|
|
83
|
+
className={cn(
|
|
84
|
+
"rounded-md flex items-center justify-center",
|
|
85
|
+
bgColorClass,
|
|
86
|
+
className
|
|
87
|
+
)}
|
|
88
|
+
>
|
|
89
|
+
<Text
|
|
90
|
+
className={cn(
|
|
91
|
+
"font-munchi-semibold text-center",
|
|
92
|
+
textColorClass,
|
|
93
|
+
textClassName
|
|
94
|
+
)}
|
|
95
|
+
>
|
|
96
|
+
{timePrefix}
|
|
97
|
+
{formattedMinutes}:{formattedSeconds}
|
|
98
|
+
</Text>
|
|
99
|
+
</View>
|
|
100
|
+
);
|
|
101
|
+
},
|
|
102
|
+
[warningThreshold, countUp, date, showPrefix, className, textClassName]
|
|
103
|
+
);
|
|
104
|
+
|
|
105
|
+
const renderer = customRenderer ?? defaultRenderer;
|
|
106
|
+
|
|
107
|
+
return (
|
|
108
|
+
<Countdown
|
|
109
|
+
renderer={renderer}
|
|
110
|
+
onComplete={onComplete}
|
|
111
|
+
overtime={countUp}
|
|
112
|
+
date={date}
|
|
113
|
+
{...countdownProps}
|
|
114
|
+
/>
|
|
115
|
+
);
|
|
116
|
+
};
|
|
117
|
+
|
|
118
|
+
MCountDown.displayName = "MCountDown";
|
|
119
|
+
|
|
120
|
+
export default MCountDown;
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
import type React from "react";
|
|
2
|
+
import { Text } from "react-native";
|
|
3
|
+
import DateTimePicker, {
|
|
4
|
+
useDefaultClassNames,
|
|
5
|
+
type CalendarComponents
|
|
6
|
+
} from "react-native-ui-datepicker";
|
|
7
|
+
import { cn } from "./utils";
|
|
8
|
+
|
|
9
|
+
export type CalendarProps = React.ComponentProps<typeof DateTimePicker>;
|
|
10
|
+
|
|
11
|
+
export const MDateTimePicker = ({
|
|
12
|
+
className,
|
|
13
|
+
classNames,
|
|
14
|
+
showOutsideDays = true,
|
|
15
|
+
containerHeight = 220,
|
|
16
|
+
components,
|
|
17
|
+
minDate,
|
|
18
|
+
maxDate,
|
|
19
|
+
...props
|
|
20
|
+
}: React.ComponentProps<typeof DateTimePicker>) => {
|
|
21
|
+
const defaultClassNames = useDefaultClassNames();
|
|
22
|
+
|
|
23
|
+
const defaultMinDate =
|
|
24
|
+
minDate ||
|
|
25
|
+
(() => {
|
|
26
|
+
const date = new Date();
|
|
27
|
+
date.setFullYear(date.getFullYear() - 1);
|
|
28
|
+
return date;
|
|
29
|
+
})();
|
|
30
|
+
|
|
31
|
+
const defaultMaxDate =
|
|
32
|
+
maxDate ||
|
|
33
|
+
(() => {
|
|
34
|
+
const date = new Date();
|
|
35
|
+
date.setDate(date.getDate());
|
|
36
|
+
return date;
|
|
37
|
+
})();
|
|
38
|
+
|
|
39
|
+
const defaultComponents: Partial<CalendarComponents> = {
|
|
40
|
+
IconPrev: (
|
|
41
|
+
<Text className="font-munchi text-lg text-foreground">{"<"}</Text>
|
|
42
|
+
),
|
|
43
|
+
IconNext: <Text className="font-munchi text-lg text-foreground">{">"}</Text>
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
return (
|
|
47
|
+
<DateTimePicker
|
|
48
|
+
showOutsideDays={showOutsideDays}
|
|
49
|
+
className={cn("bg-card w-full rounded-xl", className)}
|
|
50
|
+
containerHeight={containerHeight}
|
|
51
|
+
minDate={defaultMinDate}
|
|
52
|
+
maxDate={defaultMaxDate}
|
|
53
|
+
classNames={{
|
|
54
|
+
...defaultClassNames,
|
|
55
|
+
day_cell: "p-0.5",
|
|
56
|
+
day: cn(
|
|
57
|
+
defaultClassNames.day,
|
|
58
|
+
"font-munchi rounded-xl text-foreground w-10 h-10"
|
|
59
|
+
),
|
|
60
|
+
day_label: "font-munchi text-base text-foreground",
|
|
61
|
+
outside_label: "font-munchi text-base text-foreground opacity-40",
|
|
62
|
+
today_label: "text-destructive font-munchi-bold text-base",
|
|
63
|
+
month_selector_label: cn(
|
|
64
|
+
defaultClassNames.month_selector_label,
|
|
65
|
+
"text-base font-munchi-semibold text-foreground"
|
|
66
|
+
),
|
|
67
|
+
year_selector_label: cn(
|
|
68
|
+
defaultClassNames.year_selector_label,
|
|
69
|
+
"text-base font-munchi-semibold text-foreground"
|
|
70
|
+
),
|
|
71
|
+
time_selector_label: cn(
|
|
72
|
+
defaultClassNames.time_selector_label,
|
|
73
|
+
"text-base font-munchi text-foreground"
|
|
74
|
+
),
|
|
75
|
+
header: "font-munchi-semibold text-lg text-foreground pb-2",
|
|
76
|
+
weekday_label: "font-munchi-semibold text-sm text-muted-foreground",
|
|
77
|
+
selected: cn(
|
|
78
|
+
defaultClassNames.selected,
|
|
79
|
+
"font-munchi bg-primary rounded-xl"
|
|
80
|
+
),
|
|
81
|
+
selected_label:
|
|
82
|
+
"font-munchi-semibold text-primary-foreground text-base",
|
|
83
|
+
range_end: cn(
|
|
84
|
+
defaultClassNames.range_end,
|
|
85
|
+
"font-munchi bg-primary rounded-r-xl"
|
|
86
|
+
),
|
|
87
|
+
range_start: cn(
|
|
88
|
+
defaultClassNames.range_start,
|
|
89
|
+
"font-munchi bg-primary rounded-l-xl"
|
|
90
|
+
),
|
|
91
|
+
range_end_label: cn(
|
|
92
|
+
defaultClassNames.range_end_label,
|
|
93
|
+
"font-munchi-semibold text-primary-foreground text-base"
|
|
94
|
+
),
|
|
95
|
+
range_start_label: cn(
|
|
96
|
+
defaultClassNames.range_start_label,
|
|
97
|
+
"font-munchi-semibold text-primary-foreground text-base"
|
|
98
|
+
),
|
|
99
|
+
range_fill: "bg-primary/20 my-1",
|
|
100
|
+
range_fill_weekstart: "rounded-s-lg",
|
|
101
|
+
range_fill_weekend: "rounded-e-lg",
|
|
102
|
+
range_middle_label: "font-munchi text-base text-foreground",
|
|
103
|
+
month: cn(
|
|
104
|
+
defaultClassNames.month,
|
|
105
|
+
"font-munchi rounded-xl text-foreground"
|
|
106
|
+
),
|
|
107
|
+
month_label: "font-munchi text-base text-foreground",
|
|
108
|
+
year: cn(
|
|
109
|
+
defaultClassNames.year,
|
|
110
|
+
"font-munchi rounded-xl text-foreground"
|
|
111
|
+
),
|
|
112
|
+
year_label: "font-munchi text-base text-foreground",
|
|
113
|
+
time_label: "font-munchi text-2xl text-foreground",
|
|
114
|
+
...classNames
|
|
115
|
+
}}
|
|
116
|
+
components={{ ...defaultComponents, ...components }}
|
|
117
|
+
{...props}
|
|
118
|
+
/>
|
|
119
|
+
);
|
|
120
|
+
};
|
|
121
|
+
|
|
122
|
+
MDateTimePicker.displayName = "MDateTimePicker";
|
|
123
|
+
|
|
124
|
+
export default MDateTimePicker;
|
package/src/MDivider.tsx
ADDED
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { type VariantProps, cva } from "class-variance-authority";
|
|
2
|
+
import { View, type ViewProps } from "react-native";
|
|
3
|
+
import { cn } from "./utils";
|
|
4
|
+
|
|
5
|
+
const dividerVariants = cva("", {
|
|
6
|
+
variants: {
|
|
7
|
+
direction: {
|
|
8
|
+
horizontal: "my-2",
|
|
9
|
+
vertical: "mx-2"
|
|
10
|
+
},
|
|
11
|
+
variant: {
|
|
12
|
+
sm: "",
|
|
13
|
+
md: "",
|
|
14
|
+
lg: ""
|
|
15
|
+
}
|
|
16
|
+
},
|
|
17
|
+
defaultVariants: {
|
|
18
|
+
direction: "horizontal",
|
|
19
|
+
variant: "md"
|
|
20
|
+
}
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
const thicknessMap = {
|
|
24
|
+
sm: 1,
|
|
25
|
+
md: 2,
|
|
26
|
+
lg: 4
|
|
27
|
+
} as const;
|
|
28
|
+
|
|
29
|
+
export interface MDividerProps
|
|
30
|
+
extends Pick<ViewProps, "className" | "style">,
|
|
31
|
+
VariantProps<typeof dividerVariants> {
|
|
32
|
+
/** When set, overrides theme border color (e.g. legacy `#D3D3D3`). */
|
|
33
|
+
color?: string;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export const MDivider = ({
|
|
37
|
+
className,
|
|
38
|
+
direction = "horizontal",
|
|
39
|
+
variant = "md",
|
|
40
|
+
color,
|
|
41
|
+
style
|
|
42
|
+
}: MDividerProps) => {
|
|
43
|
+
const isHorizontal = direction === "horizontal";
|
|
44
|
+
const thickness = thicknessMap[variant ?? "md"];
|
|
45
|
+
|
|
46
|
+
const dynamicStyles = color
|
|
47
|
+
? {
|
|
48
|
+
backgroundColor: color,
|
|
49
|
+
[isHorizontal ? "height" : "width"]: thickness,
|
|
50
|
+
[isHorizontal ? "width" : "height"]: "100%"
|
|
51
|
+
}
|
|
52
|
+
: {
|
|
53
|
+
[isHorizontal ? "height" : "width"]: thickness,
|
|
54
|
+
[isHorizontal ? "width" : "height"]: "100%"
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
return (
|
|
58
|
+
<View
|
|
59
|
+
className={cn(
|
|
60
|
+
!color && "bg-border",
|
|
61
|
+
dividerVariants({ direction, variant }),
|
|
62
|
+
className
|
|
63
|
+
)}
|
|
64
|
+
style={[dynamicStyles, style]}
|
|
65
|
+
/>
|
|
66
|
+
);
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
MDivider.displayName = "MDivider";
|