@medway-ui/native 1.1.2 → 1.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/lib/commonjs/components/Alert.js +5 -4
- package/lib/commonjs/components/Alert.js.map +1 -1
- package/lib/commonjs/components/Avatar.js +2 -1
- package/lib/commonjs/components/Avatar.js.map +1 -1
- package/lib/commonjs/components/Badge.js +2 -1
- package/lib/commonjs/components/Badge.js.map +1 -1
- package/lib/commonjs/components/Button.js +3 -2
- package/lib/commonjs/components/Button.js.map +1 -1
- package/lib/commonjs/components/CardNews.js +7 -6
- package/lib/commonjs/components/CardNews.js.map +1 -1
- package/lib/commonjs/components/Carousel.js +122 -0
- package/lib/commonjs/components/Carousel.js.map +1 -0
- package/lib/commonjs/components/Checkbox.js +11 -2
- package/lib/commonjs/components/Checkbox.js.map +1 -1
- package/lib/commonjs/components/DropdownMenu.js +225 -0
- package/lib/commonjs/components/DropdownMenu.js.map +1 -0
- package/lib/commonjs/components/EmptyState.js +19 -20
- package/lib/commonjs/components/EmptyState.js.map +1 -1
- package/lib/commonjs/components/Feed.js +82 -0
- package/lib/commonjs/components/Feed.js.map +1 -0
- package/lib/commonjs/components/FeedNotice.js +76 -0
- package/lib/commonjs/components/FeedNotice.js.map +1 -0
- package/lib/commonjs/components/Input.js +21 -9
- package/lib/commonjs/components/Input.js.map +1 -1
- package/lib/commonjs/components/InvitePopover.js +196 -0
- package/lib/commonjs/components/InvitePopover.js.map +1 -0
- package/lib/commonjs/components/Label.js +2 -1
- package/lib/commonjs/components/Label.js.map +1 -1
- package/lib/commonjs/components/LeaderboardCard.js +58 -0
- package/lib/commonjs/components/LeaderboardCard.js.map +1 -0
- package/lib/commonjs/components/MemberRow.js +131 -0
- package/lib/commonjs/components/MemberRow.js.map +1 -0
- package/lib/commonjs/components/PageHeader.js +3 -2
- package/lib/commonjs/components/PageHeader.js.map +1 -1
- package/lib/commonjs/components/PostForm.js +182 -0
- package/lib/commonjs/components/PostForm.js.map +1 -0
- package/lib/commonjs/components/PrizeCollection.js +135 -0
- package/lib/commonjs/components/PrizeCollection.js.map +1 -0
- package/lib/commonjs/components/RadioGroup.js +22 -0
- package/lib/commonjs/components/RadioGroup.js.map +1 -1
- package/lib/commonjs/components/SectionHeader.js +36 -0
- package/lib/commonjs/components/SectionHeader.js.map +1 -0
- package/lib/commonjs/components/Switch.js +33 -19
- package/lib/commonjs/components/Switch.js.map +1 -1
- package/lib/commonjs/components/Tabs.js +156 -0
- package/lib/commonjs/components/Tabs.js.map +1 -0
- package/lib/commonjs/components/Tag.js +2 -1
- package/lib/commonjs/components/Tag.js.map +1 -1
- package/lib/commonjs/components/Text.js +60 -0
- package/lib/commonjs/components/Text.js.map +1 -0
- package/lib/commonjs/components/Toast.js +3 -2
- package/lib/commonjs/components/Toast.js.map +1 -1
- package/lib/commonjs/components/Tooltip.js +2 -2
- package/lib/commonjs/components/Tooltip.js.map +1 -1
- package/lib/commonjs/hooks/useThemeColor.js +66 -29
- package/lib/commonjs/hooks/useThemeColor.js.map +1 -1
- package/lib/commonjs/index.js +319 -1
- package/lib/commonjs/index.js.map +1 -1
- package/lib/commonjs/lib/overlay-host.js +101 -0
- package/lib/commonjs/lib/overlay-host.js.map +1 -0
- package/lib/commonjs/lib/typography.js +26 -0
- package/lib/commonjs/lib/typography.js.map +1 -0
- package/lib/commonjs/nativewind-env.d.js +0 -1
- package/lib/commonjs/nativewind-env.d.js.map +1 -1
- package/lib/module/components/Alert.js +3 -2
- package/lib/module/components/Alert.js.map +1 -1
- package/lib/module/components/Avatar.js +2 -1
- package/lib/module/components/Avatar.js.map +1 -1
- package/lib/module/components/Badge.js +2 -1
- package/lib/module/components/Badge.js.map +1 -1
- package/lib/module/components/Button.js +2 -1
- package/lib/module/components/Button.js.map +1 -1
- package/lib/module/components/CardNews.js +2 -1
- package/lib/module/components/CardNews.js.map +1 -1
- package/lib/module/components/Carousel.js +117 -0
- package/lib/module/components/Carousel.js.map +1 -0
- package/lib/module/components/Checkbox.js +12 -2
- package/lib/module/components/Checkbox.js.map +1 -1
- package/lib/module/components/DropdownMenu.js +216 -0
- package/lib/module/components/DropdownMenu.js.map +1 -0
- package/lib/module/components/EmptyState.js +19 -20
- package/lib/module/components/EmptyState.js.map +1 -1
- package/lib/module/components/Feed.js +77 -0
- package/lib/module/components/Feed.js.map +1 -0
- package/lib/module/components/FeedNotice.js +73 -0
- package/lib/module/components/FeedNotice.js.map +1 -0
- package/lib/module/components/Input.js +21 -9
- package/lib/module/components/Input.js.map +1 -1
- package/lib/module/components/InvitePopover.js +183 -0
- package/lib/module/components/InvitePopover.js.map +1 -0
- package/lib/module/components/Label.js +2 -1
- package/lib/module/components/Label.js.map +1 -1
- package/lib/module/components/LeaderboardCard.js +53 -0
- package/lib/module/components/LeaderboardCard.js.map +1 -0
- package/lib/module/components/MemberRow.js +127 -0
- package/lib/module/components/MemberRow.js.map +1 -0
- package/lib/module/components/PageHeader.js +2 -1
- package/lib/module/components/PageHeader.js.map +1 -1
- package/lib/module/components/PostForm.js +174 -0
- package/lib/module/components/PostForm.js.map +1 -0
- package/lib/module/components/PrizeCollection.js +127 -0
- package/lib/module/components/PrizeCollection.js.map +1 -0
- package/lib/module/components/RadioGroup.js +21 -1
- package/lib/module/components/RadioGroup.js.map +1 -1
- package/lib/module/components/SectionHeader.js +33 -0
- package/lib/module/components/SectionHeader.js.map +1 -0
- package/lib/module/components/Switch.js +34 -20
- package/lib/module/components/Switch.js.map +1 -1
- package/lib/module/components/Tabs.js +148 -0
- package/lib/module/components/Tabs.js.map +1 -0
- package/lib/module/components/Tag.js +2 -1
- package/lib/module/components/Tag.js.map +1 -1
- package/lib/module/components/Text.js +58 -0
- package/lib/module/components/Text.js.map +1 -0
- package/lib/module/components/Toast.js +2 -1
- package/lib/module/components/Toast.js.map +1 -1
- package/lib/module/components/Tooltip.js +1 -1
- package/lib/module/components/Tooltip.js.map +1 -1
- package/lib/module/hooks/useThemeColor.js +66 -31
- package/lib/module/hooks/useThemeColor.js.map +1 -1
- package/lib/module/index.js +27 -3
- package/lib/module/index.js.map +1 -1
- package/lib/module/lib/overlay-host.js +96 -0
- package/lib/module/lib/overlay-host.js.map +1 -0
- package/lib/module/lib/typography.js +22 -0
- package/lib/module/lib/typography.js.map +1 -0
- package/lib/module/nativewind-env.d.js +0 -1
- package/lib/module/nativewind-env.d.js.map +1 -1
- package/lib/typescript/components/Alert.d.ts.map +1 -1
- package/lib/typescript/components/Avatar.d.ts.map +1 -1
- package/lib/typescript/components/Badge.d.ts.map +1 -1
- package/lib/typescript/components/Button.d.ts.map +1 -1
- package/lib/typescript/components/CardNews.d.ts.map +1 -1
- package/lib/typescript/components/Carousel.d.ts +29 -0
- package/lib/typescript/components/Carousel.d.ts.map +1 -0
- package/lib/typescript/components/Checkbox.d.ts.map +1 -1
- package/lib/typescript/components/DropdownMenu.d.ts +39 -0
- package/lib/typescript/components/DropdownMenu.d.ts.map +1 -0
- package/lib/typescript/components/EmptyState.d.ts +1 -1
- package/lib/typescript/components/EmptyState.d.ts.map +1 -1
- package/lib/typescript/components/Feed.d.ts +22 -0
- package/lib/typescript/components/Feed.d.ts.map +1 -0
- package/lib/typescript/components/FeedNotice.d.ts +17 -0
- package/lib/typescript/components/FeedNotice.d.ts.map +1 -0
- package/lib/typescript/components/Input.d.ts +3 -2
- package/lib/typescript/components/Input.d.ts.map +1 -1
- package/lib/typescript/components/InvitePopover.d.ts +46 -0
- package/lib/typescript/components/InvitePopover.d.ts.map +1 -0
- package/lib/typescript/components/Label.d.ts.map +1 -1
- package/lib/typescript/components/LeaderboardCard.d.ts +16 -0
- package/lib/typescript/components/LeaderboardCard.d.ts.map +1 -0
- package/lib/typescript/components/MemberRow.d.ts +40 -0
- package/lib/typescript/components/MemberRow.d.ts.map +1 -0
- package/lib/typescript/components/PageHeader.d.ts.map +1 -1
- package/lib/typescript/components/PostForm.d.ts +50 -0
- package/lib/typescript/components/PostForm.d.ts.map +1 -0
- package/lib/typescript/components/PrizeCollection.d.ts +35 -0
- package/lib/typescript/components/PrizeCollection.d.ts.map +1 -0
- package/lib/typescript/components/RadioGroup.d.ts +10 -2
- package/lib/typescript/components/RadioGroup.d.ts.map +1 -1
- package/lib/typescript/components/SectionHeader.d.ts +12 -0
- package/lib/typescript/components/SectionHeader.d.ts.map +1 -0
- package/lib/typescript/components/Switch.d.ts.map +1 -1
- package/lib/typescript/components/Tabs.d.ts +32 -0
- package/lib/typescript/components/Tabs.d.ts.map +1 -0
- package/lib/typescript/components/Tag.d.ts.map +1 -1
- package/lib/typescript/components/Text.d.ts +23 -0
- package/lib/typescript/components/Text.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 +4 -2
- package/lib/typescript/hooks/useThemeColor.d.ts.map +1 -1
- package/lib/typescript/index.d.ts +28 -4
- package/lib/typescript/index.d.ts.map +1 -1
- package/lib/typescript/lib/overlay-host.d.ts +23 -0
- package/lib/typescript/lib/overlay-host.d.ts.map +1 -0
- package/lib/typescript/lib/typography.d.ts +12 -0
- package/lib/typescript/lib/typography.d.ts.map +1 -0
- package/package.json +13 -3
- package/setup/MedwayUiProvider.tsx +15 -3
- package/setup/tailwind.js +52 -4
- package/setup/tokens.native.css +8 -3
- package/src/components/Alert.tsx +4 -2
- package/src/components/Avatar.tsx +3 -1
- package/src/components/Badge.tsx +3 -1
- package/src/components/Button.tsx +3 -7
- package/src/components/CardNews.tsx +2 -1
- package/src/components/Carousel.tsx +152 -0
- package/src/components/Checkbox.tsx +14 -4
- package/src/components/DropdownMenu.tsx +312 -0
- package/src/components/EmptyState.tsx +21 -23
- package/src/components/Feed.tsx +96 -0
- package/src/components/FeedNotice.tsx +112 -0
- package/src/components/Input.tsx +11 -6
- package/src/components/InvitePopover.tsx +240 -0
- package/src/components/Label.tsx +3 -1
- package/src/components/LeaderboardCard.tsx +70 -0
- package/src/components/MemberRow.tsx +157 -0
- package/src/components/PageHeader.tsx +3 -1
- package/src/components/PostForm.tsx +250 -0
- package/src/components/PrizeCollection.tsx +190 -0
- package/src/components/RadioGroup.tsx +32 -3
- package/src/components/SectionHeader.tsx +45 -0
- package/src/components/Switch.tsx +65 -59
- package/src/components/Tabs.tsx +182 -0
- package/src/components/Tag.tsx +3 -1
- package/src/components/Text.tsx +66 -0
- package/src/components/Toast.tsx +3 -1
- package/src/components/Tooltip.tsx +2 -1
- package/src/hooks/useThemeColor.ts +77 -32
- package/src/index.ts +147 -6
- package/src/lib/overlay-host.tsx +102 -0
- package/src/lib/typography.ts +21 -0
- package/src/nativewind-env.d.ts +2 -0
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
import { type ReactNode } from "react";
|
|
2
|
+
import { Image, Pressable, View, type ViewProps } from "react-native";
|
|
3
|
+
|
|
4
|
+
import { Text } from "@/components/Text";
|
|
5
|
+
import { ChevronLeftMd, ChevronRightMd } from "@medway-ui/icons/native";
|
|
6
|
+
|
|
7
|
+
import { Button } from "@/components/Button";
|
|
8
|
+
import { cn } from "@/lib/utils";
|
|
9
|
+
|
|
10
|
+
interface CarouselProps extends ViewProps {
|
|
11
|
+
slideIndex?: number;
|
|
12
|
+
slideCount?: number;
|
|
13
|
+
onPrevious?: () => void;
|
|
14
|
+
onNext?: () => void;
|
|
15
|
+
children?: ReactNode;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
interface CarouselMediaSlideProps extends ViewProps {
|
|
19
|
+
imageSrc?: string;
|
|
20
|
+
image?: ReactNode;
|
|
21
|
+
label: string;
|
|
22
|
+
title: string;
|
|
23
|
+
linkLabel?: string;
|
|
24
|
+
onLinkPress?: () => void;
|
|
25
|
+
linkIcon?: ReactNode;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
interface CarouselMetricSlideProps extends ViewProps {
|
|
29
|
+
icon?: ReactNode;
|
|
30
|
+
value: string;
|
|
31
|
+
description: string;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function Carousel({
|
|
35
|
+
className,
|
|
36
|
+
children,
|
|
37
|
+
onPrevious,
|
|
38
|
+
onNext,
|
|
39
|
+
...props
|
|
40
|
+
}: CarouselProps) {
|
|
41
|
+
return (
|
|
42
|
+
<View
|
|
43
|
+
className={cn(
|
|
44
|
+
"h-[284px] flex-row items-center justify-between px-6",
|
|
45
|
+
className
|
|
46
|
+
)}
|
|
47
|
+
{...props}
|
|
48
|
+
>
|
|
49
|
+
<Button
|
|
50
|
+
variant="regular-soft"
|
|
51
|
+
size="md"
|
|
52
|
+
className="size-10 min-h-10 min-w-10 max-w-10 p-0"
|
|
53
|
+
iconLeft={<ChevronLeftMd width={20} height={20} color="#00205B" />}
|
|
54
|
+
onPress={onPrevious}
|
|
55
|
+
accessibilityLabel="Slide anterior"
|
|
56
|
+
/>
|
|
57
|
+
<View className="h-full min-w-0 flex-1 items-center justify-center px-4">
|
|
58
|
+
{children}
|
|
59
|
+
</View>
|
|
60
|
+
<Button
|
|
61
|
+
variant="regular-soft"
|
|
62
|
+
size="md"
|
|
63
|
+
className="size-10 min-h-10 min-w-10 max-w-10 p-0"
|
|
64
|
+
iconLeft={<ChevronRightMd width={20} height={20} color="#00205B" />}
|
|
65
|
+
onPress={onNext}
|
|
66
|
+
accessibilityLabel="Próximo slide"
|
|
67
|
+
/>
|
|
68
|
+
</View>
|
|
69
|
+
);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
function CarouselMediaSlide({
|
|
73
|
+
className,
|
|
74
|
+
imageSrc,
|
|
75
|
+
image,
|
|
76
|
+
label,
|
|
77
|
+
title,
|
|
78
|
+
linkLabel = "Ver coleção",
|
|
79
|
+
onLinkPress,
|
|
80
|
+
linkIcon,
|
|
81
|
+
...props
|
|
82
|
+
}: CarouselMediaSlideProps) {
|
|
83
|
+
return (
|
|
84
|
+
<View className={cn("items-center gap-2", className)} {...props}>
|
|
85
|
+
{image ??
|
|
86
|
+
(imageSrc ? (
|
|
87
|
+
<Image
|
|
88
|
+
source={{ uri: imageSrc }}
|
|
89
|
+
accessibilityLabel={title}
|
|
90
|
+
className="h-[188px] w-[161px]"
|
|
91
|
+
resizeMode="contain"
|
|
92
|
+
/>
|
|
93
|
+
) : null)}
|
|
94
|
+
<View className="items-center gap-2">
|
|
95
|
+
<View className="items-center">
|
|
96
|
+
<Text className="text-sm font-medium text-primary-foreground">
|
|
97
|
+
{label}
|
|
98
|
+
</Text>
|
|
99
|
+
<Text className="text-center text-title-xs font-semibold text-primary-foreground">
|
|
100
|
+
{title}
|
|
101
|
+
</Text>
|
|
102
|
+
</View>
|
|
103
|
+
{linkLabel ? (
|
|
104
|
+
<Pressable
|
|
105
|
+
accessibilityRole="link"
|
|
106
|
+
className="flex-row items-center gap-1"
|
|
107
|
+
onPress={onLinkPress}
|
|
108
|
+
>
|
|
109
|
+
<Text className="text-xs font-semibold text-secondary-stroke-emphasis">
|
|
110
|
+
{linkLabel}
|
|
111
|
+
</Text>
|
|
112
|
+
{linkIcon}
|
|
113
|
+
</Pressable>
|
|
114
|
+
) : null}
|
|
115
|
+
</View>
|
|
116
|
+
</View>
|
|
117
|
+
);
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
function CarouselMetricSlide({
|
|
121
|
+
className,
|
|
122
|
+
icon,
|
|
123
|
+
value,
|
|
124
|
+
description,
|
|
125
|
+
...props
|
|
126
|
+
}: CarouselMetricSlideProps) {
|
|
127
|
+
return (
|
|
128
|
+
<View
|
|
129
|
+
className={cn("max-w-[242px] items-center gap-3", className)}
|
|
130
|
+
{...props}
|
|
131
|
+
>
|
|
132
|
+
{icon ? (
|
|
133
|
+
<View className="items-center justify-center">{icon}</View>
|
|
134
|
+
) : null}
|
|
135
|
+
<View className="w-full items-center gap-3">
|
|
136
|
+
<Text className="text-center text-[32px] font-bold leading-10 text-primary-foreground">
|
|
137
|
+
{value}
|
|
138
|
+
</Text>
|
|
139
|
+
<Text className="text-center text-sm font-semibold leading-sm text-primary-foreground">
|
|
140
|
+
{description}
|
|
141
|
+
</Text>
|
|
142
|
+
</View>
|
|
143
|
+
</View>
|
|
144
|
+
);
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
export { Carousel, CarouselMediaSlide, CarouselMetricSlide };
|
|
148
|
+
export type {
|
|
149
|
+
CarouselMediaSlideProps,
|
|
150
|
+
CarouselMetricSlideProps,
|
|
151
|
+
CarouselProps,
|
|
152
|
+
};
|
|
@@ -1,11 +1,21 @@
|
|
|
1
1
|
import { useState, type ReactNode } from "react";
|
|
2
2
|
import { type ViewStyle } from "react-native";
|
|
3
|
+
import { cssInterop } from "nativewind";
|
|
3
4
|
import * as CheckboxPrimitive from "@rn-primitives/checkbox";
|
|
4
5
|
import { cva, type VariantProps } from "class-variance-authority";
|
|
5
6
|
import { cn } from "@/lib/utils";
|
|
6
7
|
import { Check, RemoveMinus } from "@medway-ui/icons/native";
|
|
7
8
|
import { useThemeColor } from "@/hooks/useThemeColor";
|
|
8
9
|
|
|
10
|
+
// `@rn-primitives/checkbox` renders plain React Native primitives with no
|
|
11
|
+
// NativeWind support, so `className` is otherwise silently ignored.
|
|
12
|
+
const StyledCheckboxRoot = cssInterop(CheckboxPrimitive.Root, {
|
|
13
|
+
className: "style",
|
|
14
|
+
});
|
|
15
|
+
const StyledCheckboxIndicator = cssInterop(CheckboxPrimitive.Indicator, {
|
|
16
|
+
className: "style",
|
|
17
|
+
});
|
|
18
|
+
|
|
9
19
|
interface CheckboxProps
|
|
10
20
|
extends Omit<
|
|
11
21
|
CheckboxPrimitive.RootProps,
|
|
@@ -99,7 +109,7 @@ function Checkbox({
|
|
|
99
109
|
};
|
|
100
110
|
|
|
101
111
|
return (
|
|
102
|
-
<
|
|
112
|
+
<StyledCheckboxRoot
|
|
103
113
|
checked={isChecked}
|
|
104
114
|
onCheckedChange={handleCheckedChange}
|
|
105
115
|
disabled={disabled}
|
|
@@ -118,15 +128,15 @@ function Checkbox({
|
|
|
118
128
|
)}
|
|
119
129
|
{...props}
|
|
120
130
|
>
|
|
121
|
-
<
|
|
131
|
+
<StyledCheckboxIndicator className="items-center justify-center">
|
|
122
132
|
{iconColor && (uncheckIcon ? (
|
|
123
133
|
<RemoveMinus width={iconSize} height={iconSize} strokeWidth={2.6} color={iconColor} />
|
|
124
134
|
) : (
|
|
125
135
|
<Check width={iconSize} height={iconSize} strokeWidth={2.6} color={iconColor} />
|
|
126
136
|
))}
|
|
127
|
-
</
|
|
137
|
+
</StyledCheckboxIndicator>
|
|
128
138
|
{children}
|
|
129
|
-
</
|
|
139
|
+
</StyledCheckboxRoot>
|
|
130
140
|
);
|
|
131
141
|
}
|
|
132
142
|
|
|
@@ -0,0 +1,312 @@
|
|
|
1
|
+
import {
|
|
2
|
+
createContext,
|
|
3
|
+
forwardRef,
|
|
4
|
+
useContext,
|
|
5
|
+
useEffect,
|
|
6
|
+
useId,
|
|
7
|
+
useMemo,
|
|
8
|
+
type ReactNode,
|
|
9
|
+
} from "react";
|
|
10
|
+
import { Dimensions, Pressable, StyleSheet, View, type PressableProps, type ViewProps } from "react-native";
|
|
11
|
+
|
|
12
|
+
import { Text } from "@/components/Text";
|
|
13
|
+
import * as DropdownMenuPrimitive from "@rn-primitives/dropdown-menu";
|
|
14
|
+
|
|
15
|
+
import { useOverlayHost } from "@/lib/overlay-host";
|
|
16
|
+
import { cn } from "@/lib/utils";
|
|
17
|
+
|
|
18
|
+
interface DropdownMenuProps extends DropdownMenuPrimitive.RootProps {
|
|
19
|
+
children?: ReactNode;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
interface DropdownMenuTriggerProps extends DropdownMenuPrimitive.TriggerProps {
|
|
23
|
+
children?: ReactNode;
|
|
24
|
+
className?: string;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
interface DropdownMenuContentProps {
|
|
28
|
+
className?: string;
|
|
29
|
+
children?: ReactNode;
|
|
30
|
+
align?: "start" | "center" | "end";
|
|
31
|
+
sideOffset?: number;
|
|
32
|
+
/** Backdrop dim behind the menu. Defaults to true. */
|
|
33
|
+
overlay?: boolean;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
interface DropdownMenuItemProps extends Omit<PressableProps, "children"> {
|
|
37
|
+
icon?: ReactNode;
|
|
38
|
+
children?: ReactNode;
|
|
39
|
+
className?: string;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
type MenuActionsContextValue = {
|
|
43
|
+
close: () => void;
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
const MenuActionsContext = createContext<MenuActionsContextValue | null>(null);
|
|
47
|
+
|
|
48
|
+
function useMenuActions() {
|
|
49
|
+
const ctx = useContext(MenuActionsContext);
|
|
50
|
+
if (!ctx) {
|
|
51
|
+
throw new Error("DropdownMenuItem must be used within DropdownMenu");
|
|
52
|
+
}
|
|
53
|
+
return ctx;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
function MenuActionsBridge({ children }: { children: ReactNode }) {
|
|
57
|
+
const { onOpenChange, setTriggerPosition, setContentLayout } =
|
|
58
|
+
DropdownMenuPrimitive.useRootContext();
|
|
59
|
+
|
|
60
|
+
const value = useMemo<MenuActionsContextValue>(
|
|
61
|
+
() => ({
|
|
62
|
+
close: () => {
|
|
63
|
+
setTriggerPosition(null);
|
|
64
|
+
setContentLayout(null);
|
|
65
|
+
onOpenChange(false);
|
|
66
|
+
},
|
|
67
|
+
}),
|
|
68
|
+
[onOpenChange, setContentLayout, setTriggerPosition]
|
|
69
|
+
);
|
|
70
|
+
|
|
71
|
+
return (
|
|
72
|
+
<MenuActionsContext.Provider value={value}>{children}</MenuActionsContext.Provider>
|
|
73
|
+
);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
function DropdownMenu({ children, ...props }: DropdownMenuProps) {
|
|
77
|
+
return (
|
|
78
|
+
<DropdownMenuPrimitive.Root {...props}>
|
|
79
|
+
<MenuActionsBridge>{children}</MenuActionsBridge>
|
|
80
|
+
</DropdownMenuPrimitive.Root>
|
|
81
|
+
);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
const DropdownMenuTrigger = forwardRef<
|
|
85
|
+
DropdownMenuPrimitive.TriggerRef,
|
|
86
|
+
DropdownMenuTriggerProps
|
|
87
|
+
>(function DropdownMenuTrigger({ className, children, style, ...props }, ref) {
|
|
88
|
+
return (
|
|
89
|
+
<DropdownMenuPrimitive.Trigger
|
|
90
|
+
ref={ref}
|
|
91
|
+
collapsable={false}
|
|
92
|
+
accessibilityRole="button"
|
|
93
|
+
className={cn("items-center justify-center", className)}
|
|
94
|
+
style={(state) => [
|
|
95
|
+
{
|
|
96
|
+
minWidth: 32,
|
|
97
|
+
minHeight: 32,
|
|
98
|
+
alignItems: "center",
|
|
99
|
+
justifyContent: "center",
|
|
100
|
+
},
|
|
101
|
+
typeof style === "function" ? style(state) : style,
|
|
102
|
+
]}
|
|
103
|
+
{...props}
|
|
104
|
+
>
|
|
105
|
+
{children}
|
|
106
|
+
</DropdownMenuPrimitive.Trigger>
|
|
107
|
+
);
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* Content renderizado no OverlayHost do MedwayUiProvider (acima da stack).
|
|
112
|
+
* Mantém Root/Trigger do @rn-primitives/dropdown-menu para open + measure.
|
|
113
|
+
*
|
|
114
|
+
* `triggerPosition` vem em coordenadas de janela (pageX/pageY). O OverlayHost
|
|
115
|
+
* fica abaixo do header da navegação, então subtraímos a origem do host.
|
|
116
|
+
*/
|
|
117
|
+
function DropdownMenuContent({
|
|
118
|
+
className,
|
|
119
|
+
align = "end",
|
|
120
|
+
sideOffset = 8,
|
|
121
|
+
overlay: showOverlay = true,
|
|
122
|
+
children,
|
|
123
|
+
}: DropdownMenuContentProps) {
|
|
124
|
+
const id = useId();
|
|
125
|
+
const overlay = useOverlayHost();
|
|
126
|
+
const { close } = useMenuActions();
|
|
127
|
+
const { open, triggerPosition } = DropdownMenuPrimitive.useRootContext();
|
|
128
|
+
|
|
129
|
+
useEffect(() => {
|
|
130
|
+
if (!open || !triggerPosition) {
|
|
131
|
+
overlay.unmount(id);
|
|
132
|
+
return;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
let cancelled = false;
|
|
136
|
+
const menuWidth = 200;
|
|
137
|
+
const windowWidth = Dimensions.get("window").width;
|
|
138
|
+
|
|
139
|
+
overlay.measureHostOrigin((hostOrigin) => {
|
|
140
|
+
if (cancelled) {
|
|
141
|
+
return;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
let left =
|
|
145
|
+
triggerPosition.pageX - hostOrigin.x;
|
|
146
|
+
|
|
147
|
+
if (align === "end") {
|
|
148
|
+
left =
|
|
149
|
+
triggerPosition.pageX +
|
|
150
|
+
triggerPosition.width -
|
|
151
|
+
menuWidth -
|
|
152
|
+
hostOrigin.x;
|
|
153
|
+
} else if (align === "center") {
|
|
154
|
+
left =
|
|
155
|
+
triggerPosition.pageX +
|
|
156
|
+
triggerPosition.width / 2 -
|
|
157
|
+
menuWidth / 2 -
|
|
158
|
+
hostOrigin.x;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
left = Math.max(8, Math.min(left, windowWidth - hostOrigin.x - menuWidth - 8));
|
|
162
|
+
|
|
163
|
+
const top =
|
|
164
|
+
triggerPosition.pageY +
|
|
165
|
+
triggerPosition.height +
|
|
166
|
+
sideOffset -
|
|
167
|
+
hostOrigin.y;
|
|
168
|
+
|
|
169
|
+
overlay.mount(
|
|
170
|
+
id,
|
|
171
|
+
<MenuActionsContext.Provider value={{ close }}>
|
|
172
|
+
<View style={styles.layer} pointerEvents="box-none">
|
|
173
|
+
<Pressable
|
|
174
|
+
accessibilityLabel="Fechar menu"
|
|
175
|
+
style={[
|
|
176
|
+
StyleSheet.absoluteFill,
|
|
177
|
+
showOverlay ? styles.backdrop : null,
|
|
178
|
+
]}
|
|
179
|
+
onPress={close}
|
|
180
|
+
/>
|
|
181
|
+
<View
|
|
182
|
+
className={cn(
|
|
183
|
+
"overflow-hidden rounded-md border border-gray-stroke-muted bg-surface-elevated p-1 shadow-md",
|
|
184
|
+
className
|
|
185
|
+
)}
|
|
186
|
+
// Fallback visual caso NativeWind não aplique no host de overlay
|
|
187
|
+
style={[
|
|
188
|
+
styles.menu,
|
|
189
|
+
{
|
|
190
|
+
top,
|
|
191
|
+
left,
|
|
192
|
+
width: menuWidth,
|
|
193
|
+
backgroundColor: "white",
|
|
194
|
+
borderRadius: 8,
|
|
195
|
+
borderWidth: 1,
|
|
196
|
+
borderColor: "#E7E9EF",
|
|
197
|
+
padding: 4,
|
|
198
|
+
},
|
|
199
|
+
]}
|
|
200
|
+
>
|
|
201
|
+
{children}
|
|
202
|
+
</View>
|
|
203
|
+
</View>
|
|
204
|
+
</MenuActionsContext.Provider>
|
|
205
|
+
);
|
|
206
|
+
});
|
|
207
|
+
|
|
208
|
+
return () => {
|
|
209
|
+
cancelled = true;
|
|
210
|
+
overlay.unmount(id);
|
|
211
|
+
};
|
|
212
|
+
}, [
|
|
213
|
+
align,
|
|
214
|
+
children,
|
|
215
|
+
className,
|
|
216
|
+
close,
|
|
217
|
+
id,
|
|
218
|
+
open,
|
|
219
|
+
overlay,
|
|
220
|
+
showOverlay,
|
|
221
|
+
sideOffset,
|
|
222
|
+
triggerPosition,
|
|
223
|
+
]);
|
|
224
|
+
|
|
225
|
+
return null;
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
function DropdownMenuGroup({ className, children, ...props }: ViewProps) {
|
|
229
|
+
return (
|
|
230
|
+
<View className={cn("gap-0", className)} {...props}>
|
|
231
|
+
{children}
|
|
232
|
+
</View>
|
|
233
|
+
);
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
function DropdownMenuSeparator({ className, ...props }: ViewProps) {
|
|
237
|
+
return (
|
|
238
|
+
<View className={cn("my-1 h-px bg-gray-stroke-muted", className)} {...props} />
|
|
239
|
+
);
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
function DropdownMenuItem({
|
|
243
|
+
className,
|
|
244
|
+
icon,
|
|
245
|
+
children,
|
|
246
|
+
onPress,
|
|
247
|
+
...props
|
|
248
|
+
}: DropdownMenuItemProps) {
|
|
249
|
+
const { close } = useMenuActions();
|
|
250
|
+
|
|
251
|
+
return (
|
|
252
|
+
<Pressable
|
|
253
|
+
accessibilityRole="button"
|
|
254
|
+
className={cn(
|
|
255
|
+
"flex-row items-center gap-2 rounded-md px-3 py-2 active:bg-gray-background-soft",
|
|
256
|
+
className
|
|
257
|
+
)}
|
|
258
|
+
onPress={(event) => {
|
|
259
|
+
onPress?.(event);
|
|
260
|
+
close();
|
|
261
|
+
}}
|
|
262
|
+
{...props}
|
|
263
|
+
>
|
|
264
|
+
{icon ? (
|
|
265
|
+
<View className="size-4 shrink-0" pointerEvents="none">
|
|
266
|
+
{icon}
|
|
267
|
+
</View>
|
|
268
|
+
) : null}
|
|
269
|
+
{typeof children === "string" ? (
|
|
270
|
+
<Text
|
|
271
|
+
numberOfLines={1}
|
|
272
|
+
className="flex-1 text-xs font-medium text-gray-foreground"
|
|
273
|
+
>
|
|
274
|
+
{children}
|
|
275
|
+
</Text>
|
|
276
|
+
) : (
|
|
277
|
+
children
|
|
278
|
+
)}
|
|
279
|
+
</Pressable>
|
|
280
|
+
);
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
const styles = StyleSheet.create({
|
|
284
|
+
layer: {
|
|
285
|
+
...StyleSheet.absoluteFill,
|
|
286
|
+
},
|
|
287
|
+
backdrop: {
|
|
288
|
+
// Alinhado ao Dialog/Sheet (`bg-black/50`); style explícito porque
|
|
289
|
+
// NativeWind pode não aplicar classes montadas no OverlayHost.
|
|
290
|
+
backgroundColor: "rgba(0, 0, 0, 0.5)",
|
|
291
|
+
},
|
|
292
|
+
menu: {
|
|
293
|
+
position: "absolute",
|
|
294
|
+
zIndex: 2,
|
|
295
|
+
elevation: 8,
|
|
296
|
+
},
|
|
297
|
+
});
|
|
298
|
+
|
|
299
|
+
export {
|
|
300
|
+
DropdownMenu,
|
|
301
|
+
DropdownMenuContent,
|
|
302
|
+
DropdownMenuGroup,
|
|
303
|
+
DropdownMenuItem,
|
|
304
|
+
DropdownMenuSeparator,
|
|
305
|
+
DropdownMenuTrigger,
|
|
306
|
+
};
|
|
307
|
+
export type {
|
|
308
|
+
DropdownMenuContentProps,
|
|
309
|
+
DropdownMenuItemProps,
|
|
310
|
+
DropdownMenuProps,
|
|
311
|
+
DropdownMenuTriggerProps,
|
|
312
|
+
};
|
|
@@ -1,15 +1,7 @@
|
|
|
1
1
|
import { type ReactNode } from "react";
|
|
2
2
|
import { View, type ViewProps } from "react-native";
|
|
3
3
|
|
|
4
|
-
import {
|
|
5
|
-
Alert,
|
|
6
|
-
AlertActions,
|
|
7
|
-
AlertContainer,
|
|
8
|
-
AlertContent,
|
|
9
|
-
AlertDescription,
|
|
10
|
-
AlertIcon,
|
|
11
|
-
AlertTitle,
|
|
12
|
-
} from "@/components/Alert";
|
|
4
|
+
import { Text } from "@/components/Text";
|
|
13
5
|
import { cn } from "@/lib/utils";
|
|
14
6
|
|
|
15
7
|
interface EmptyStateProps extends ViewProps {
|
|
@@ -26,29 +18,35 @@ function EmptyState({
|
|
|
26
18
|
title,
|
|
27
19
|
description,
|
|
28
20
|
action,
|
|
29
|
-
variant = "regular",
|
|
21
|
+
variant: _variant = "regular",
|
|
30
22
|
...props
|
|
31
23
|
}: EmptyStateProps) {
|
|
32
24
|
return (
|
|
33
25
|
<View
|
|
34
26
|
className={cn(
|
|
35
|
-
"items-center gap-6 rounded-
|
|
27
|
+
"w-full items-center gap-6 rounded-xl border border-gray-stroke-muted bg-surface-card p-8 shadow-sm",
|
|
36
28
|
className
|
|
37
29
|
)}
|
|
38
30
|
{...props}
|
|
39
31
|
>
|
|
40
|
-
|
|
41
|
-
<
|
|
42
|
-
{icon
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
</
|
|
50
|
-
{
|
|
51
|
-
|
|
32
|
+
{icon ? (
|
|
33
|
+
<View className="size-16 items-center justify-center rounded-full bg-gray-background-soft">
|
|
34
|
+
{icon}
|
|
35
|
+
</View>
|
|
36
|
+
) : null}
|
|
37
|
+
|
|
38
|
+
<View className="w-full items-center gap-4">
|
|
39
|
+
<Text className="text-center text-lg font-semibold text-primary-foreground">
|
|
40
|
+
{title}
|
|
41
|
+
</Text>
|
|
42
|
+
{description ? (
|
|
43
|
+
<Text className="text-center text-sm font-medium text-primary-foreground-muted">
|
|
44
|
+
{description}
|
|
45
|
+
</Text>
|
|
46
|
+
) : null}
|
|
47
|
+
</View>
|
|
48
|
+
|
|
49
|
+
{action ? <View className="w-full">{action}</View> : null}
|
|
52
50
|
</View>
|
|
53
51
|
);
|
|
54
52
|
}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import { type ReactNode } from "react";
|
|
2
|
+
import { TextInput, View, type TextInputProps, type ViewProps } from "react-native";
|
|
3
|
+
|
|
4
|
+
import { Text } from "@/components/Text";
|
|
5
|
+
|
|
6
|
+
import { InputText, inputVariants } from "@/components/Input";
|
|
7
|
+
import { cn } from "@/lib/utils";
|
|
8
|
+
|
|
9
|
+
interface FeedProps extends ViewProps {
|
|
10
|
+
children?: ReactNode;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
interface FeedTitleProps extends ViewProps {
|
|
14
|
+
children?: ReactNode;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
interface FeedComposerProps extends Omit<TextInputProps, "value" | "defaultValue"> {
|
|
18
|
+
value?: string;
|
|
19
|
+
defaultValue?: string;
|
|
20
|
+
onChangeText?: (value: string) => void;
|
|
21
|
+
maxLength?: number;
|
|
22
|
+
placeholder?: string;
|
|
23
|
+
iconLeft?: ReactNode;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function Feed({ className, children, ...props }: FeedProps) {
|
|
27
|
+
return (
|
|
28
|
+
<View className={cn("gap-3", className)} {...props}>
|
|
29
|
+
{children}
|
|
30
|
+
</View>
|
|
31
|
+
);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function FeedTitle({ className, children, ...props }: FeedTitleProps) {
|
|
35
|
+
return (
|
|
36
|
+
<Text
|
|
37
|
+
className={cn("text-lg font-medium text-primary-foreground", className)}
|
|
38
|
+
{...props}
|
|
39
|
+
>
|
|
40
|
+
{children}
|
|
41
|
+
</Text>
|
|
42
|
+
);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
function FeedComposer({
|
|
46
|
+
className,
|
|
47
|
+
value,
|
|
48
|
+
defaultValue,
|
|
49
|
+
onChangeText,
|
|
50
|
+
maxLength = 120,
|
|
51
|
+
placeholder = "Diga alguma coisa",
|
|
52
|
+
iconLeft,
|
|
53
|
+
editable = true,
|
|
54
|
+
...props
|
|
55
|
+
}: FeedComposerProps) {
|
|
56
|
+
const currentLength = (value ?? defaultValue ?? "").length;
|
|
57
|
+
|
|
58
|
+
return (
|
|
59
|
+
<View className={cn("gap-1", className)}>
|
|
60
|
+
<View className="relative flex-row items-center">
|
|
61
|
+
{iconLeft ? (
|
|
62
|
+
<View className="absolute left-4 z-10 size-6">{iconLeft}</View>
|
|
63
|
+
) : null}
|
|
64
|
+
<TextInput
|
|
65
|
+
multiline
|
|
66
|
+
textAlignVertical="top"
|
|
67
|
+
maxLength={maxLength}
|
|
68
|
+
value={value}
|
|
69
|
+
defaultValue={defaultValue}
|
|
70
|
+
onChangeText={onChangeText}
|
|
71
|
+
placeholder={placeholder}
|
|
72
|
+
editable={editable}
|
|
73
|
+
className={cn(
|
|
74
|
+
inputVariants({
|
|
75
|
+
size: "lg",
|
|
76
|
+
invalid: false,
|
|
77
|
+
focused: false,
|
|
78
|
+
disabled: !editable,
|
|
79
|
+
}),
|
|
80
|
+
"min-h-12 py-3 font-medium",
|
|
81
|
+
iconLeft ? "pl-12" : ""
|
|
82
|
+
)}
|
|
83
|
+
accessibilityLabel={placeholder}
|
|
84
|
+
{...props}
|
|
85
|
+
style={[{ fontFamily: "MontserratMedium" }, props.style]}
|
|
86
|
+
/>
|
|
87
|
+
</View>
|
|
88
|
+
<InputText className="text-right text-xs font-medium text-gray-foreground">
|
|
89
|
+
{currentLength} / {maxLength}
|
|
90
|
+
</InputText>
|
|
91
|
+
</View>
|
|
92
|
+
);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
export { Feed, FeedComposer, FeedTitle };
|
|
96
|
+
export type { FeedComposerProps, FeedProps, FeedTitleProps };
|