@medway-ui/native 1.0.4 → 1.1.2
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/README.md +283 -77
- package/lib/commonjs/components/Alert.js +6 -3
- package/lib/commonjs/components/Alert.js.map +1 -1
- package/lib/commonjs/components/AlertDialog.js +38 -15
- package/lib/commonjs/components/AlertDialog.js.map +1 -1
- package/lib/commonjs/components/Avatar.js +101 -0
- package/lib/commonjs/components/Avatar.js.map +1 -0
- package/lib/commonjs/components/CardNews.js +319 -0
- package/lib/commonjs/components/CardNews.js.map +1 -0
- package/lib/commonjs/components/Checkbox.js +36 -13
- package/lib/commonjs/components/Checkbox.js.map +1 -1
- package/lib/commonjs/components/Dialog.js +15 -10
- package/lib/commonjs/components/Dialog.js.map +1 -1
- package/lib/commonjs/components/EmptyState.js +42 -0
- package/lib/commonjs/components/EmptyState.js.map +1 -0
- package/lib/commonjs/components/FallbackImage.js +55 -0
- package/lib/commonjs/components/FallbackImage.js.map +1 -0
- package/lib/commonjs/components/Input.js +55 -16
- package/lib/commonjs/components/Input.js.map +1 -1
- package/lib/commonjs/components/Label.js +43 -14
- package/lib/commonjs/components/Label.js.map +1 -1
- package/lib/commonjs/components/Loading.js +7 -3
- package/lib/commonjs/components/Loading.js.map +1 -1
- package/lib/commonjs/components/PageHeader.js +39 -0
- package/lib/commonjs/components/PageHeader.js.map +1 -0
- package/lib/commonjs/components/Select.js +32 -13
- package/lib/commonjs/components/Select.js.map +1 -1
- package/lib/commonjs/components/Sheet.js +14 -9
- package/lib/commonjs/components/Sheet.js.map +1 -1
- package/lib/commonjs/components/Skeleton.js +34 -0
- package/lib/commonjs/components/Skeleton.js.map +1 -0
- package/lib/commonjs/components/Switch.js +43 -14
- package/lib/commonjs/components/Switch.js.map +1 -1
- package/lib/commonjs/components/ThemedIcon.js +29 -0
- package/lib/commonjs/components/ThemedIcon.js.map +1 -0
- package/lib/commonjs/components/Toast.js +24 -12
- package/lib/commonjs/components/Toast.js.map +1 -1
- package/lib/commonjs/components/Tooltip.js +5 -3
- package/lib/commonjs/components/Tooltip.js.map +1 -1
- package/lib/commonjs/hooks/useThemeColor.js +71 -0
- package/lib/commonjs/hooks/useThemeColor.js.map +1 -0
- package/lib/commonjs/index.js +152 -0
- package/lib/commonjs/index.js.map +1 -1
- package/lib/module/components/Alert.js +6 -3
- package/lib/module/components/Alert.js.map +1 -1
- package/lib/module/components/AlertDialog.js +38 -15
- package/lib/module/components/AlertDialog.js.map +1 -1
- package/lib/module/components/Avatar.js +94 -0
- package/lib/module/components/Avatar.js.map +1 -0
- package/lib/module/components/CardNews.js +303 -0
- package/lib/module/components/CardNews.js.map +1 -0
- package/lib/module/components/Checkbox.js +37 -14
- package/lib/module/components/Checkbox.js.map +1 -1
- package/lib/module/components/Dialog.js +15 -10
- package/lib/module/components/Dialog.js.map +1 -1
- package/lib/module/components/EmptyState.js +39 -0
- package/lib/module/components/EmptyState.js.map +1 -0
- package/lib/module/components/FallbackImage.js +51 -0
- package/lib/module/components/FallbackImage.js.map +1 -0
- package/lib/module/components/Input.js +55 -16
- package/lib/module/components/Input.js.map +1 -1
- package/lib/module/components/Label.js +44 -15
- package/lib/module/components/Label.js.map +1 -1
- package/lib/module/components/Loading.js +7 -3
- package/lib/module/components/Loading.js.map +1 -1
- package/lib/module/components/PageHeader.js +36 -0
- package/lib/module/components/PageHeader.js.map +1 -0
- package/lib/module/components/Select.js +32 -13
- package/lib/module/components/Select.js.map +1 -1
- package/lib/module/components/Sheet.js +14 -9
- package/lib/module/components/Sheet.js.map +1 -1
- package/lib/module/components/Skeleton.js +30 -0
- package/lib/module/components/Skeleton.js.map +1 -0
- package/lib/module/components/Switch.js +44 -15
- package/lib/module/components/Switch.js.map +1 -1
- package/lib/module/components/ThemedIcon.js +26 -0
- package/lib/module/components/ThemedIcon.js.map +1 -0
- package/lib/module/components/Toast.js +24 -12
- package/lib/module/components/Toast.js.map +1 -1
- package/lib/module/components/Tooltip.js +6 -4
- package/lib/module/components/Tooltip.js.map +1 -1
- package/lib/module/hooks/useThemeColor.js +68 -0
- package/lib/module/hooks/useThemeColor.js.map +1 -0
- package/lib/module/index.js +15 -0
- package/lib/module/index.js.map +1 -1
- package/lib/typescript/components/Alert.d.ts.map +1 -1
- package/lib/typescript/components/AlertDialog.d.ts +2 -2
- package/lib/typescript/components/AlertDialog.d.ts.map +1 -1
- package/lib/typescript/components/Avatar.d.ts +28 -0
- package/lib/typescript/components/Avatar.d.ts.map +1 -0
- package/lib/typescript/components/CardNews.d.ts +54 -0
- package/lib/typescript/components/CardNews.d.ts.map +1 -0
- package/lib/typescript/components/Checkbox.d.ts +5 -5
- package/lib/typescript/components/Checkbox.d.ts.map +1 -1
- package/lib/typescript/components/Dialog.d.ts.map +1 -1
- package/lib/typescript/components/EmptyState.d.ts +13 -0
- package/lib/typescript/components/EmptyState.d.ts.map +1 -0
- package/lib/typescript/components/FallbackImage.d.ts +9 -0
- package/lib/typescript/components/FallbackImage.d.ts.map +1 -0
- package/lib/typescript/components/Input.d.ts +4 -5
- package/lib/typescript/components/Input.d.ts.map +1 -1
- package/lib/typescript/components/Label.d.ts.map +1 -1
- package/lib/typescript/components/Loading.d.ts +5 -1
- package/lib/typescript/components/Loading.d.ts.map +1 -1
- package/lib/typescript/components/PageHeader.d.ts +12 -0
- package/lib/typescript/components/PageHeader.d.ts.map +1 -0
- package/lib/typescript/components/Select.d.ts +3 -1
- package/lib/typescript/components/Select.d.ts.map +1 -1
- package/lib/typescript/components/Sheet.d.ts.map +1 -1
- package/lib/typescript/components/Skeleton.d.ts +8 -0
- package/lib/typescript/components/Skeleton.d.ts.map +1 -0
- package/lib/typescript/components/Switch.d.ts +2 -2
- package/lib/typescript/components/Switch.d.ts.map +1 -1
- package/lib/typescript/components/ThemedIcon.d.ts +24 -0
- package/lib/typescript/components/ThemedIcon.d.ts.map +1 -0
- package/lib/typescript/components/Toast.d.ts +1 -1
- package/lib/typescript/components/Toast.d.ts.map +1 -1
- package/lib/typescript/components/Tooltip.d.ts.map +1 -1
- package/lib/typescript/hooks/useThemeColor.d.ts +11 -0
- package/lib/typescript/hooks/useThemeColor.d.ts.map +1 -0
- package/lib/typescript/index.d.ts +16 -0
- package/lib/typescript/index.d.ts.map +1 -1
- package/package.json +28 -4
- package/setup/MedwayUiProvider.tsx +64 -0
- package/setup/babel-brownfield.js +120 -0
- package/setup/createMedwayUiNavigator.tsx +94 -0
- package/setup/global.css +5 -0
- package/setup/index.ts +12 -0
- package/setup/index.tsx +42 -0
- package/setup/lazyScreen.tsx +14 -0
- package/setup/metro.js +266 -0
- package/setup/tailwind.js +84 -0
- package/setup/tokens.native.css +873 -0
- package/src/components/Alert.tsx +3 -1
- package/src/components/AlertDialog.tsx +63 -19
- package/src/components/Avatar.tsx +130 -0
- package/src/components/CardNews.tsx +412 -0
- package/src/components/Checkbox.tsx +51 -23
- package/src/components/Dialog.tsx +13 -7
- package/src/components/EmptyState.tsx +57 -0
- package/src/components/FallbackImage.tsx +58 -0
- package/src/components/Input.tsx +65 -19
- package/src/components/Label.tsx +49 -14
- package/src/components/Loading.tsx +13 -2
- package/src/components/PageHeader.tsx +50 -0
- package/src/components/Select.tsx +22 -10
- package/src/components/Sheet.tsx +30 -24
- package/src/components/Skeleton.tsx +45 -0
- package/src/components/Switch.tsx +64 -32
- package/src/components/ThemedIcon.tsx +46 -0
- package/src/components/Toast.tsx +26 -13
- package/src/components/Tooltip.tsx +1 -0
- package/src/hooks/useThemeColor.ts +79 -0
- package/src/index.ts +60 -0
|
@@ -9,9 +9,10 @@ import React, {
|
|
|
9
9
|
} from "react";
|
|
10
10
|
import { View, Text, type ViewProps, type TextProps } from "react-native";
|
|
11
11
|
import * as SelectPrimitive from "@rn-primitives/select";
|
|
12
|
-
import { Check, ChevronDown, ChevronUp } from "@medway-ui/icons/native";
|
|
13
12
|
import { cva } from "class-variance-authority";
|
|
14
13
|
import { cn } from "@/lib/utils";
|
|
14
|
+
import { Check, ChevronDown, ChevronUp } from "@medway-ui/icons/native";
|
|
15
|
+
import { useThemeColor } from "@/hooks/useThemeColor";
|
|
15
16
|
|
|
16
17
|
type SelectSize = "md" | "lg";
|
|
17
18
|
|
|
@@ -53,6 +54,11 @@ const selectVariants = cva(
|
|
|
53
54
|
}
|
|
54
55
|
);
|
|
55
56
|
|
|
57
|
+
const SELECT_HEIGHT: Record<SelectSize, number> = {
|
|
58
|
+
lg: 48,
|
|
59
|
+
md: 40,
|
|
60
|
+
};
|
|
61
|
+
|
|
56
62
|
const SelectContext = createContext<SelectContextValue>({
|
|
57
63
|
invalid: false,
|
|
58
64
|
size: "lg",
|
|
@@ -71,20 +77,21 @@ function SelectWrapper({ className, ...props }: ViewProps) {
|
|
|
71
77
|
return <View className={cn("relative flex-col gap-2", className)} {...props} />;
|
|
72
78
|
}
|
|
73
79
|
|
|
74
|
-
function SelectTrigger({ className, children, ...props }: SelectTriggerProps) {
|
|
80
|
+
function SelectTrigger({ className, children, style, ...props }: SelectTriggerProps & { style?: ViewProps['style'] }) {
|
|
75
81
|
const { invalid, size } = useContext(SelectContext);
|
|
82
|
+
const chevronSize = size === "lg" ? 24 : 20;
|
|
83
|
+
const chevronColor = useThemeColor("gray-foreground");
|
|
76
84
|
|
|
77
85
|
return (
|
|
78
86
|
<SelectPrimitive.Trigger
|
|
87
|
+
style={[{ height: SELECT_HEIGHT[size], minHeight: SELECT_HEIGHT[size] }, style]}
|
|
79
88
|
className={cn(selectVariants({ size, invalid }), className)}
|
|
80
89
|
{...props}
|
|
81
90
|
>
|
|
82
91
|
{children}
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
className="text-gray-foreground shrink-0"
|
|
87
|
-
/>
|
|
92
|
+
{chevronColor && (
|
|
93
|
+
<ChevronDown width={chevronSize} height={chevronSize} strokeWidth={1.6} color={chevronColor} />
|
|
94
|
+
)}
|
|
88
95
|
</SelectPrimitive.Trigger>
|
|
89
96
|
);
|
|
90
97
|
}
|
|
@@ -142,6 +149,7 @@ function SelectHeader({ className, ...props }: SelectPrimitive.LabelProps) {
|
|
|
142
149
|
function SelectItem({ className, children, icon, label, ...props }: SelectItemProps) {
|
|
143
150
|
const { size } = useContext(SelectContext);
|
|
144
151
|
const resolvedLabel = label ?? (typeof children === "string" ? children : "");
|
|
152
|
+
const checkColor = useThemeColor("secondary-foreground");
|
|
145
153
|
|
|
146
154
|
return (
|
|
147
155
|
<SelectPrimitive.Item
|
|
@@ -163,7 +171,7 @@ function SelectItem({ className, children, icon, label, ...props }: SelectItemPr
|
|
|
163
171
|
)}
|
|
164
172
|
<SelectPrimitive.ItemText className="flex-1 text-sm font-medium text-gray-foreground" />
|
|
165
173
|
<SelectPrimitive.ItemIndicator className="absolute right-2 h-3.5 w-3.5 items-center justify-center">
|
|
166
|
-
<Check
|
|
174
|
+
{checkColor && <Check width={14} height={14} strokeWidth={1.6} color={checkColor} />}
|
|
167
175
|
</SelectPrimitive.ItemIndicator>
|
|
168
176
|
</SelectPrimitive.Item>
|
|
169
177
|
);
|
|
@@ -179,23 +187,27 @@ function SelectSeparator({ className, ...props }: SelectPrimitive.SeparatorProps
|
|
|
179
187
|
}
|
|
180
188
|
|
|
181
189
|
function SelectScrollUpButton({ className, ...props }: SelectPrimitive.ScrollUpButtonProps) {
|
|
190
|
+
const chevronColor = useThemeColor("gray-foreground");
|
|
191
|
+
|
|
182
192
|
return (
|
|
183
193
|
<SelectPrimitive.ScrollUpButton
|
|
184
194
|
className={cn("items-center justify-center py-1", className)}
|
|
185
195
|
{...props}
|
|
186
196
|
>
|
|
187
|
-
<ChevronUp
|
|
197
|
+
{chevronColor && <ChevronUp width={16} height={16} strokeWidth={1.6} color={chevronColor} />}
|
|
188
198
|
</SelectPrimitive.ScrollUpButton>
|
|
189
199
|
);
|
|
190
200
|
}
|
|
191
201
|
|
|
192
202
|
function SelectScrollDownButton({ className, ...props }: SelectPrimitive.ScrollDownButtonProps) {
|
|
203
|
+
const chevronColor = useThemeColor("gray-foreground");
|
|
204
|
+
|
|
193
205
|
return (
|
|
194
206
|
<SelectPrimitive.ScrollDownButton
|
|
195
207
|
className={cn("items-center justify-center py-1", className)}
|
|
196
208
|
{...props}
|
|
197
209
|
>
|
|
198
|
-
<ChevronDown
|
|
210
|
+
{chevronColor && <ChevronDown width={16} height={16} strokeWidth={1.6} color={chevronColor} />}
|
|
199
211
|
</SelectPrimitive.ScrollDownButton>
|
|
200
212
|
);
|
|
201
213
|
}
|
package/src/components/Sheet.tsx
CHANGED
|
@@ -2,6 +2,7 @@ import { type ReactNode } from "react";
|
|
|
2
2
|
import { View, ScrollView, type ViewProps } from "react-native";
|
|
3
3
|
import * as DialogPrimitive from "@rn-primitives/dialog";
|
|
4
4
|
import { CloseMd } from "@medway-ui/icons/native";
|
|
5
|
+
import { useThemeColor } from "@/hooks/useThemeColor";
|
|
5
6
|
import { cn } from "@/lib/utils";
|
|
6
7
|
import { Separator } from "@/components/Separator";
|
|
7
8
|
|
|
@@ -62,33 +63,38 @@ function SheetContainer({
|
|
|
62
63
|
showCloseButton = true,
|
|
63
64
|
...props
|
|
64
65
|
}: SheetContainerProps) {
|
|
66
|
+
const closeIconColor = useThemeColor("gray-foreground");
|
|
67
|
+
|
|
65
68
|
return (
|
|
66
69
|
<DialogPrimitive.Portal>
|
|
67
|
-
|
|
68
|
-
|
|
70
|
+
<DialogPrimitive.Overlay
|
|
71
|
+
className={cn("absolute inset-0 bg-black/50", overlayClassName)}
|
|
72
|
+
/>
|
|
73
|
+
<DialogPrimitive.Content
|
|
74
|
+
className={cn(overlayPositionMap[side])}
|
|
75
|
+
{...props}
|
|
76
|
+
>
|
|
77
|
+
<View
|
|
78
|
+
className={cn(
|
|
79
|
+
"relative flex-col bg-background shadow-lg overflow-hidden",
|
|
80
|
+
contentSizeMap[side],
|
|
81
|
+
className
|
|
82
|
+
)}
|
|
69
83
|
>
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
)}
|
|
85
|
-
>
|
|
86
|
-
<CloseMd size={16} className="text-gray-foreground" />
|
|
87
|
-
</DialogPrimitive.Close>
|
|
88
|
-
)}
|
|
89
|
-
</DialogPrimitive.Content>
|
|
90
|
-
</DialogPrimitive.Overlay>
|
|
91
|
-
</DialogPrimitive.Portal>
|
|
84
|
+
{children}
|
|
85
|
+
{showCloseButton && (
|
|
86
|
+
<DialogPrimitive.Close
|
|
87
|
+
className={cn(
|
|
88
|
+
closeButtonPositionMap[side],
|
|
89
|
+
"rounded-pill p-1.5 active:bg-gray-background-soft"
|
|
90
|
+
)}
|
|
91
|
+
>
|
|
92
|
+
{closeIconColor && <CloseMd width={16} height={16} color={closeIconColor} />}
|
|
93
|
+
</DialogPrimitive.Close>
|
|
94
|
+
)}
|
|
95
|
+
</View>
|
|
96
|
+
</DialogPrimitive.Content>
|
|
97
|
+
</DialogPrimitive.Portal>
|
|
92
98
|
);
|
|
93
99
|
}
|
|
94
100
|
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { useEffect } from "react";
|
|
2
|
+
import { type ViewProps } from "react-native";
|
|
3
|
+
import Animated, {
|
|
4
|
+
cancelAnimation,
|
|
5
|
+
Easing,
|
|
6
|
+
interpolate,
|
|
7
|
+
useAnimatedStyle,
|
|
8
|
+
useSharedValue,
|
|
9
|
+
withRepeat,
|
|
10
|
+
withTiming,
|
|
11
|
+
} from "react-native-reanimated";
|
|
12
|
+
|
|
13
|
+
import { cn } from "@/lib/utils";
|
|
14
|
+
|
|
15
|
+
interface SkeletonProps extends ViewProps {
|
|
16
|
+
className?: string;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
function Skeleton({ className, style, ...props }: SkeletonProps) {
|
|
20
|
+
const shimmer = useSharedValue(0);
|
|
21
|
+
|
|
22
|
+
useEffect(() => {
|
|
23
|
+
shimmer.value = withRepeat(
|
|
24
|
+
withTiming(1, { duration: 1200, easing: Easing.inOut(Easing.ease) }),
|
|
25
|
+
-1,
|
|
26
|
+
true
|
|
27
|
+
);
|
|
28
|
+
return () => cancelAnimation(shimmer);
|
|
29
|
+
}, [shimmer]);
|
|
30
|
+
|
|
31
|
+
const animatedStyle = useAnimatedStyle(() => ({
|
|
32
|
+
opacity: interpolate(shimmer.value, [0, 1], [0.35, 0.75]),
|
|
33
|
+
}));
|
|
34
|
+
|
|
35
|
+
return (
|
|
36
|
+
<Animated.View
|
|
37
|
+
style={[animatedStyle, style]}
|
|
38
|
+
className={cn("rounded-md bg-gray-150", className)}
|
|
39
|
+
{...props}
|
|
40
|
+
/>
|
|
41
|
+
);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export { Skeleton };
|
|
45
|
+
export type { SkeletonProps };
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { useState, useEffect, type ReactNode } from "react";
|
|
2
|
-
import { View } from "react-native";
|
|
2
|
+
import { View, type ViewStyle } from "react-native";
|
|
3
3
|
import * as SwitchPrimitive from "@rn-primitives/switch";
|
|
4
4
|
import Animated, {
|
|
5
5
|
useSharedValue,
|
|
@@ -10,7 +10,12 @@ import Animated, {
|
|
|
10
10
|
import { cva, type VariantProps } from "class-variance-authority";
|
|
11
11
|
import { cn } from "@/lib/utils";
|
|
12
12
|
|
|
13
|
-
interface SwitchProps
|
|
13
|
+
interface SwitchProps
|
|
14
|
+
extends Omit<
|
|
15
|
+
SwitchPrimitive.RootProps,
|
|
16
|
+
"checked" | "onCheckedChange" | "children"
|
|
17
|
+
>,
|
|
18
|
+
VariantProps<typeof switchVariants> {
|
|
14
19
|
checked?: boolean;
|
|
15
20
|
defaultChecked?: boolean;
|
|
16
21
|
onCheckedChange?: (checked: boolean) => void;
|
|
@@ -30,6 +35,12 @@ const THUMB_TRANSLATE: Record<"sm" | "md" | "lg", number> = {
|
|
|
30
35
|
lg: 19,
|
|
31
36
|
};
|
|
32
37
|
|
|
38
|
+
const SWITCH_TRACK: Record<"sm" | "md" | "lg", { width: number; height: number }> = {
|
|
39
|
+
sm: { width: 24, height: 16 },
|
|
40
|
+
md: { width: 32, height: 20 },
|
|
41
|
+
lg: { width: 40, height: 24 },
|
|
42
|
+
};
|
|
43
|
+
|
|
33
44
|
const switchVariants = cva(
|
|
34
45
|
"rounded-full border-2 items-center shrink-0",
|
|
35
46
|
{
|
|
@@ -60,9 +71,11 @@ function Switch({
|
|
|
60
71
|
defaultChecked,
|
|
61
72
|
onCheckedChange,
|
|
62
73
|
disabled,
|
|
74
|
+
style,
|
|
63
75
|
...props
|
|
64
76
|
}: SwitchProps) {
|
|
65
77
|
const resolvedSize = size ?? "md";
|
|
78
|
+
const trackSize = SWITCH_TRACK[resolvedSize];
|
|
66
79
|
const [internalChecked, setInternalChecked] = useState(defaultChecked ?? false);
|
|
67
80
|
const isControlled = checked !== undefined;
|
|
68
81
|
const isChecked = isControlled ? (checked ?? false) : internalChecked;
|
|
@@ -83,9 +96,19 @@ function Switch({
|
|
|
83
96
|
const hasIcons = checkedIcon || uncheckedIcon;
|
|
84
97
|
const thumbSize = THUMB_SIZES[resolvedSize];
|
|
85
98
|
|
|
86
|
-
const handleCheckedChange = (
|
|
87
|
-
if (!isControlled) setInternalChecked(
|
|
88
|
-
onCheckedChange?.(
|
|
99
|
+
const handleCheckedChange = (nextChecked: boolean) => {
|
|
100
|
+
if (!isControlled) setInternalChecked(nextChecked);
|
|
101
|
+
onCheckedChange?.(nextChecked);
|
|
102
|
+
};
|
|
103
|
+
|
|
104
|
+
const trackStyle: ViewStyle = {
|
|
105
|
+
width: trackSize.width,
|
|
106
|
+
height: trackSize.height,
|
|
107
|
+
minWidth: trackSize.width,
|
|
108
|
+
minHeight: trackSize.height,
|
|
109
|
+
borderRadius: trackSize.height / 2,
|
|
110
|
+
borderWidth: 2,
|
|
111
|
+
justifyContent: "center",
|
|
89
112
|
};
|
|
90
113
|
|
|
91
114
|
return (
|
|
@@ -93,43 +116,52 @@ function Switch({
|
|
|
93
116
|
checked={isChecked}
|
|
94
117
|
onCheckedChange={handleCheckedChange}
|
|
95
118
|
disabled={disabled}
|
|
119
|
+
style={(state) => [
|
|
120
|
+
trackStyle,
|
|
121
|
+
typeof style === "function" ? style(state) : style,
|
|
122
|
+
]}
|
|
96
123
|
className={cn(
|
|
97
124
|
switchVariants({ size, variant }),
|
|
98
125
|
disabled
|
|
99
126
|
? "bg-gray-background-soft-muted border-gray-stroke-muted"
|
|
100
127
|
: isChecked
|
|
101
|
-
|
|
102
|
-
|
|
128
|
+
? "bg-primary-background-fill border-primary-background-fill"
|
|
129
|
+
: "bg-surface-card border-gray-stroke-muted",
|
|
103
130
|
className
|
|
104
131
|
)}
|
|
105
132
|
{...props}
|
|
106
133
|
>
|
|
107
|
-
<
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
{
|
|
134
|
+
<SwitchPrimitive.Thumb asChild>
|
|
135
|
+
<Animated.View
|
|
136
|
+
style={[
|
|
137
|
+
thumbStyle,
|
|
138
|
+
{
|
|
139
|
+
width: thumbSize,
|
|
140
|
+
height: thumbSize,
|
|
141
|
+
},
|
|
142
|
+
]}
|
|
143
|
+
>
|
|
144
|
+
<View
|
|
145
|
+
className={cn(
|
|
146
|
+
"flex-1 items-center justify-center rounded-full",
|
|
147
|
+
disabled
|
|
148
|
+
? "bg-gray-background-fill-muted"
|
|
149
|
+
: hasIcons
|
|
150
|
+
? "bg-transparent"
|
|
151
|
+
: isChecked
|
|
152
|
+
? "bg-primary-foreground-onfill"
|
|
153
|
+
: "bg-gray-foreground-muted"
|
|
154
|
+
)}
|
|
155
|
+
>
|
|
156
|
+
{hasIcons ? (
|
|
157
|
+
<>
|
|
158
|
+
{isChecked && checkedIcon}
|
|
159
|
+
{!isChecked && uncheckedIcon}
|
|
160
|
+
</>
|
|
161
|
+
) : null}
|
|
130
162
|
</View>
|
|
131
|
-
|
|
132
|
-
</
|
|
163
|
+
</Animated.View>
|
|
164
|
+
</SwitchPrimitive.Thumb>
|
|
133
165
|
</SwitchPrimitive.Root>
|
|
134
166
|
);
|
|
135
167
|
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import type { ComponentType } from "react";
|
|
2
|
+
|
|
3
|
+
import { useThemeColor, type ThemeColorToken } from "@/hooks/useThemeColor";
|
|
4
|
+
|
|
5
|
+
type NativeIconProps = {
|
|
6
|
+
width?: number;
|
|
7
|
+
height?: number;
|
|
8
|
+
color?: string;
|
|
9
|
+
strokeWidth?: number;
|
|
10
|
+
className?: string;
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
interface ThemedIconProps {
|
|
14
|
+
icon: ComponentType<NativeIconProps>;
|
|
15
|
+
size?: number;
|
|
16
|
+
colorToken: ThemeColorToken;
|
|
17
|
+
strokeWidth?: number;
|
|
18
|
+
className?: string;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Ícone @medway-ui/icons com cor vinda do theme (CSS variables / NativeWind).
|
|
23
|
+
* Substitui `size` + `className` nos SVGs, que não resolvem cor sozinhos.
|
|
24
|
+
*/
|
|
25
|
+
function ThemedIcon({
|
|
26
|
+
icon: Icon,
|
|
27
|
+
size = 24,
|
|
28
|
+
colorToken,
|
|
29
|
+
strokeWidth = 2,
|
|
30
|
+
className,
|
|
31
|
+
}: ThemedIconProps) {
|
|
32
|
+
const color = useThemeColor(colorToken);
|
|
33
|
+
|
|
34
|
+
return (
|
|
35
|
+
<Icon
|
|
36
|
+
width={size}
|
|
37
|
+
height={size}
|
|
38
|
+
color={color}
|
|
39
|
+
strokeWidth={strokeWidth}
|
|
40
|
+
className={className}
|
|
41
|
+
/>
|
|
42
|
+
);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export { ThemedIcon };
|
|
46
|
+
export type { ThemedIconProps, NativeIconProps };
|
package/src/components/Toast.tsx
CHANGED
|
@@ -1,12 +1,5 @@
|
|
|
1
1
|
import { useState, useEffect, type ReactElement, type ReactNode } from "react";
|
|
2
2
|
import { View, Text, Pressable, type ViewProps } from "react-native";
|
|
3
|
-
import {
|
|
4
|
-
Info,
|
|
5
|
-
CircleCheck,
|
|
6
|
-
TriangleWarning,
|
|
7
|
-
OctagonWarning,
|
|
8
|
-
CloseMd,
|
|
9
|
-
} from "@medway-ui/icons/native";
|
|
10
3
|
import { cva } from "class-variance-authority";
|
|
11
4
|
import Animated, {
|
|
12
5
|
useSharedValue,
|
|
@@ -16,8 +9,16 @@ import Animated, {
|
|
|
16
9
|
runOnJS,
|
|
17
10
|
} from "react-native-reanimated";
|
|
18
11
|
import { cn } from "@/lib/utils";
|
|
12
|
+
import {
|
|
13
|
+
CircleCheck,
|
|
14
|
+
CloseMd,
|
|
15
|
+
Info,
|
|
16
|
+
OctagonWarning,
|
|
17
|
+
TriangleWarning,
|
|
18
|
+
} from "@medway-ui/icons/native";
|
|
19
19
|
import { Button, type ButtonProps } from "@/components/Button";
|
|
20
20
|
import { useToast } from "@/hooks/use-toast";
|
|
21
|
+
import { useThemeColor } from "@/hooks/useThemeColor";
|
|
21
22
|
|
|
22
23
|
type ToastVariant = "primary" | "secondary" | "success" | "warning" | "error";
|
|
23
24
|
type ToastActionVariant = ToastVariant;
|
|
@@ -81,13 +82,21 @@ const toastActionButtonVariantMap: Record<ToastActionVariant, ButtonProps["varia
|
|
|
81
82
|
error: "error-soft",
|
|
82
83
|
};
|
|
83
84
|
|
|
84
|
-
const
|
|
85
|
+
const toastIconColorTokens: Record<ToastVariant, string> = {
|
|
86
|
+
primary: "primary-foreground",
|
|
87
|
+
secondary: "secondary-foreground",
|
|
88
|
+
success: "feedback-success-foreground",
|
|
89
|
+
warning: "feedback-warning-foreground",
|
|
90
|
+
error: "feedback-error-foreground",
|
|
91
|
+
};
|
|
92
|
+
|
|
93
|
+
const variantIcons = {
|
|
85
94
|
primary: Info,
|
|
86
95
|
secondary: Info,
|
|
87
96
|
success: CircleCheck,
|
|
88
97
|
warning: TriangleWarning,
|
|
89
98
|
error: OctagonWarning,
|
|
90
|
-
};
|
|
99
|
+
} as const;
|
|
91
100
|
|
|
92
101
|
function ToastItem({
|
|
93
102
|
className,
|
|
@@ -106,6 +115,8 @@ function ToastItem({
|
|
|
106
115
|
transform: [{ translateY: translateY.value }],
|
|
107
116
|
opacity: opacity.value,
|
|
108
117
|
}));
|
|
118
|
+
const iconColor = useThemeColor(toastIconColorTokens[variant]);
|
|
119
|
+
const closeIconColor = useThemeColor("gray-foreground");
|
|
109
120
|
|
|
110
121
|
useEffect(() => {
|
|
111
122
|
if (open) {
|
|
@@ -127,8 +138,8 @@ function ToastItem({
|
|
|
127
138
|
return (
|
|
128
139
|
<Animated.View style={animatedStyle}>
|
|
129
140
|
<View className={cn(toastVariants({ variant }), className)} {...props}>
|
|
130
|
-
{showIcon && (
|
|
131
|
-
<IconComponent
|
|
141
|
+
{showIcon && iconColor && (
|
|
142
|
+
<IconComponent width={20} height={20} color={iconColor} />
|
|
132
143
|
)}
|
|
133
144
|
<View className="flex-1 flex-row items-center justify-between gap-3">
|
|
134
145
|
{children}
|
|
@@ -137,7 +148,7 @@ function ToastItem({
|
|
|
137
148
|
onPress={() => onOpenChange?.(false)}
|
|
138
149
|
className="rounded-pill p-1 active:bg-gray-background-soft"
|
|
139
150
|
>
|
|
140
|
-
<CloseMd
|
|
151
|
+
{closeIconColor && <CloseMd width={16} height={16} color={closeIconColor} />}
|
|
141
152
|
</Pressable>
|
|
142
153
|
</View>
|
|
143
154
|
</Animated.View>
|
|
@@ -216,6 +227,8 @@ function ToastViewport({ className, children, ...props }: ViewProps & { children
|
|
|
216
227
|
}
|
|
217
228
|
|
|
218
229
|
function ToastClose({ className, onPress, label = "Close", ...props }: ToastCloseProps) {
|
|
230
|
+
const closeIconColor = useThemeColor("gray-foreground");
|
|
231
|
+
|
|
219
232
|
return (
|
|
220
233
|
<Pressable
|
|
221
234
|
onPress={onPress}
|
|
@@ -223,7 +236,7 @@ function ToastClose({ className, onPress, label = "Close", ...props }: ToastClos
|
|
|
223
236
|
className={cn("rounded-pill p-1 active:bg-gray-background-soft", className)}
|
|
224
237
|
{...props}
|
|
225
238
|
>
|
|
226
|
-
<CloseMd
|
|
239
|
+
{closeIconColor && <CloseMd width={16} height={16} color={closeIconColor} />}
|
|
227
240
|
</Pressable>
|
|
228
241
|
);
|
|
229
242
|
}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { useColorScheme, useUnstableNativeVariable } from "nativewind";
|
|
2
|
+
|
|
3
|
+
/** Token sem prefixo `--color-` (ex.: `gray-foreground`, `primary-background-fill`). */
|
|
4
|
+
type ThemeColorToken = string;
|
|
5
|
+
|
|
6
|
+
/** Fallback quando NativeWind não resolve cadeias `var()` — light mode. */
|
|
7
|
+
const LIGHT_COLOR_ALIAS_MAP: Record<string, string> = {
|
|
8
|
+
"content-title": "primary",
|
|
9
|
+
"content-paragraph": "gray-600",
|
|
10
|
+
"gray-foreground": "gray-600",
|
|
11
|
+
"primary-foreground": "primary",
|
|
12
|
+
"secondary-foreground": "secondary-darken-3",
|
|
13
|
+
"surface-card": "white",
|
|
14
|
+
"gray-foreground-muted": "gray-450",
|
|
15
|
+
"gray-stroke-muted": "gray-100",
|
|
16
|
+
"gray-background-fill-muted": "gray-400",
|
|
17
|
+
"gray-background-soft-muted": "gray-30",
|
|
18
|
+
"primary-foreground-onfill": "white",
|
|
19
|
+
"primary-background-fill": "primary",
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
/** Fallback — dark mode (espelha tokens.css `.dark`). */
|
|
23
|
+
const DARK_COLOR_ALIAS_MAP: Record<string, string> = {
|
|
24
|
+
"content-title": "white",
|
|
25
|
+
"content-paragraph": "gray-150",
|
|
26
|
+
"gray-foreground": "gray-100",
|
|
27
|
+
"primary-foreground": "gray-100",
|
|
28
|
+
"secondary-foreground": "secondary-lighten-1",
|
|
29
|
+
"surface-card": "gray-850",
|
|
30
|
+
"gray-foreground-muted": "gray-150",
|
|
31
|
+
"gray-stroke-muted": "gray-700",
|
|
32
|
+
"gray-background-fill-muted": "gray-300",
|
|
33
|
+
"gray-background-soft-muted": "gray-700",
|
|
34
|
+
"primary-foreground-onfill": "primary",
|
|
35
|
+
"primary-background-fill": "gray-70",
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
function toCssVariable(token: ThemeColorToken): string {
|
|
39
|
+
return token.startsWith("--") ? token : `--color-${token}`;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function toTokenName(token: ThemeColorToken): string {
|
|
43
|
+
return token.startsWith("--color-") ? token.slice("--color-".length) : token;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function toResolvedCssVariable(
|
|
47
|
+
token: ThemeColorToken,
|
|
48
|
+
aliasMap: Record<string, string>
|
|
49
|
+
): string {
|
|
50
|
+
const tokenName = toTokenName(token);
|
|
51
|
+
return toCssVariable(aliasMap[tokenName] ?? tokenName);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
function isResolvedColor(value: unknown): value is string {
|
|
55
|
+
return typeof value === "string" && !value.startsWith("var(");
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Resolve uma cor semântica do design system (tokens.native.css) em runtime.
|
|
60
|
+
* Use quando a prop `color` for obrigatória (SVG, stroke Reanimated, etc.).
|
|
61
|
+
*/
|
|
62
|
+
function useThemeColor(token: ThemeColorToken): string | undefined {
|
|
63
|
+
const { colorScheme } = useColorScheme();
|
|
64
|
+
const aliasMap =
|
|
65
|
+
colorScheme === "dark" ? DARK_COLOR_ALIAS_MAP : LIGHT_COLOR_ALIAS_MAP;
|
|
66
|
+
|
|
67
|
+
const value = useUnstableNativeVariable(toCssVariable(token));
|
|
68
|
+
const resolvedValue = useUnstableNativeVariable(
|
|
69
|
+
toResolvedCssVariable(token, aliasMap)
|
|
70
|
+
);
|
|
71
|
+
|
|
72
|
+
if (isResolvedColor(value)) return value;
|
|
73
|
+
if (isResolvedColor(resolvedValue)) return resolvedValue;
|
|
74
|
+
|
|
75
|
+
return undefined;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
export { useThemeColor, toCssVariable };
|
|
79
|
+
export type { ThemeColorToken };
|
package/src/index.ts
CHANGED
|
@@ -17,6 +17,56 @@ export type { AlertButtonProps, AlertProps } from "@/components/Alert";
|
|
|
17
17
|
export { Badge, badgeVariants } from "@/components/Badge";
|
|
18
18
|
export type { BadgeAnimation, BadgeProps } from "@/components/Badge";
|
|
19
19
|
|
|
20
|
+
// Avatar
|
|
21
|
+
export {
|
|
22
|
+
Avatar,
|
|
23
|
+
AvatarFallback,
|
|
24
|
+
AvatarImage,
|
|
25
|
+
avatarVariants,
|
|
26
|
+
} from "@/components/Avatar";
|
|
27
|
+
export type {
|
|
28
|
+
AvatarFallbackProps,
|
|
29
|
+
AvatarImageProps,
|
|
30
|
+
AvatarProps,
|
|
31
|
+
} from "@/components/Avatar";
|
|
32
|
+
|
|
33
|
+
// FallbackImage
|
|
34
|
+
export { FallbackImage } from "@/components/FallbackImage";
|
|
35
|
+
export type { FallbackImageProps } from "@/components/FallbackImage";
|
|
36
|
+
|
|
37
|
+
// CardNews
|
|
38
|
+
export {
|
|
39
|
+
CardNews,
|
|
40
|
+
CardNewsAuthor,
|
|
41
|
+
CardNewsBody,
|
|
42
|
+
CardNewsContent,
|
|
43
|
+
CardNewsDate,
|
|
44
|
+
CardNewsDescription,
|
|
45
|
+
CardNewsFooter,
|
|
46
|
+
CardNewsHeader,
|
|
47
|
+
CardNewsImage,
|
|
48
|
+
CardNewsResourceItem,
|
|
49
|
+
CardNewsResources,
|
|
50
|
+
CardNewsSkeleton,
|
|
51
|
+
CardNewsTags,
|
|
52
|
+
CardNewsTitle,
|
|
53
|
+
} from "@/components/CardNews";
|
|
54
|
+
export type {
|
|
55
|
+
CardNewsAuthorProps,
|
|
56
|
+
CardNewsDateProps,
|
|
57
|
+
CardNewsImageProps,
|
|
58
|
+
CardNewsProps,
|
|
59
|
+
CardNewsResourcesProps,
|
|
60
|
+
} from "@/components/CardNews";
|
|
61
|
+
|
|
62
|
+
// EmptyState
|
|
63
|
+
export { EmptyState } from "@/components/EmptyState";
|
|
64
|
+
export type { EmptyStateProps } from "@/components/EmptyState";
|
|
65
|
+
|
|
66
|
+
// PageHeader
|
|
67
|
+
export { PageHeader } from "@/components/PageHeader";
|
|
68
|
+
export type { PageHeaderProps } from "@/components/PageHeader";
|
|
69
|
+
|
|
20
70
|
// Button
|
|
21
71
|
export { Button, buttonVariants, buttonTextVariants } from "@/components/Button";
|
|
22
72
|
export type { ButtonProps } from "@/components/Button";
|
|
@@ -84,6 +134,10 @@ export type { SelectProps, SelectItemProps, SelectSize } from "@/components/Sele
|
|
|
84
134
|
export { Separator } from "@/components/Separator";
|
|
85
135
|
export type { SeparatorProps } from "@/components/Separator";
|
|
86
136
|
|
|
137
|
+
// Skeleton
|
|
138
|
+
export { Skeleton } from "@/components/Skeleton";
|
|
139
|
+
export type { SkeletonProps } from "@/components/Skeleton";
|
|
140
|
+
|
|
87
141
|
// Switch
|
|
88
142
|
export { Switch, switchVariants } from "@/components/Switch";
|
|
89
143
|
export type { SwitchProps } from "@/components/Switch";
|
|
@@ -191,3 +245,9 @@ export type { TooltipContentProps } from "@/components/Tooltip";
|
|
|
191
245
|
|
|
192
246
|
// Hooks
|
|
193
247
|
export { useToast, toast } from "@/hooks/use-toast";
|
|
248
|
+
export { useThemeColor } from "@/hooks/useThemeColor";
|
|
249
|
+
export type { ThemeColorToken } from "@/hooks/useThemeColor";
|
|
250
|
+
|
|
251
|
+
// Theme-aware icon helper
|
|
252
|
+
export { ThemedIcon } from "@/components/ThemedIcon";
|
|
253
|
+
export type { ThemedIconProps } from "@/components/ThemedIcon";
|