@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.
Files changed (215) hide show
  1. package/lib/commonjs/components/Alert.js +5 -4
  2. package/lib/commonjs/components/Alert.js.map +1 -1
  3. package/lib/commonjs/components/Avatar.js +2 -1
  4. package/lib/commonjs/components/Avatar.js.map +1 -1
  5. package/lib/commonjs/components/Badge.js +2 -1
  6. package/lib/commonjs/components/Badge.js.map +1 -1
  7. package/lib/commonjs/components/Button.js +3 -2
  8. package/lib/commonjs/components/Button.js.map +1 -1
  9. package/lib/commonjs/components/CardNews.js +7 -6
  10. package/lib/commonjs/components/CardNews.js.map +1 -1
  11. package/lib/commonjs/components/Carousel.js +122 -0
  12. package/lib/commonjs/components/Carousel.js.map +1 -0
  13. package/lib/commonjs/components/Checkbox.js +11 -2
  14. package/lib/commonjs/components/Checkbox.js.map +1 -1
  15. package/lib/commonjs/components/DropdownMenu.js +225 -0
  16. package/lib/commonjs/components/DropdownMenu.js.map +1 -0
  17. package/lib/commonjs/components/EmptyState.js +19 -20
  18. package/lib/commonjs/components/EmptyState.js.map +1 -1
  19. package/lib/commonjs/components/Feed.js +82 -0
  20. package/lib/commonjs/components/Feed.js.map +1 -0
  21. package/lib/commonjs/components/FeedNotice.js +76 -0
  22. package/lib/commonjs/components/FeedNotice.js.map +1 -0
  23. package/lib/commonjs/components/Input.js +21 -9
  24. package/lib/commonjs/components/Input.js.map +1 -1
  25. package/lib/commonjs/components/InvitePopover.js +196 -0
  26. package/lib/commonjs/components/InvitePopover.js.map +1 -0
  27. package/lib/commonjs/components/Label.js +2 -1
  28. package/lib/commonjs/components/Label.js.map +1 -1
  29. package/lib/commonjs/components/LeaderboardCard.js +58 -0
  30. package/lib/commonjs/components/LeaderboardCard.js.map +1 -0
  31. package/lib/commonjs/components/MemberRow.js +131 -0
  32. package/lib/commonjs/components/MemberRow.js.map +1 -0
  33. package/lib/commonjs/components/PageHeader.js +3 -2
  34. package/lib/commonjs/components/PageHeader.js.map +1 -1
  35. package/lib/commonjs/components/PostForm.js +182 -0
  36. package/lib/commonjs/components/PostForm.js.map +1 -0
  37. package/lib/commonjs/components/PrizeCollection.js +135 -0
  38. package/lib/commonjs/components/PrizeCollection.js.map +1 -0
  39. package/lib/commonjs/components/RadioGroup.js +22 -0
  40. package/lib/commonjs/components/RadioGroup.js.map +1 -1
  41. package/lib/commonjs/components/SectionHeader.js +36 -0
  42. package/lib/commonjs/components/SectionHeader.js.map +1 -0
  43. package/lib/commonjs/components/Switch.js +33 -19
  44. package/lib/commonjs/components/Switch.js.map +1 -1
  45. package/lib/commonjs/components/Tabs.js +156 -0
  46. package/lib/commonjs/components/Tabs.js.map +1 -0
  47. package/lib/commonjs/components/Tag.js +2 -1
  48. package/lib/commonjs/components/Tag.js.map +1 -1
  49. package/lib/commonjs/components/Text.js +60 -0
  50. package/lib/commonjs/components/Text.js.map +1 -0
  51. package/lib/commonjs/components/Toast.js +3 -2
  52. package/lib/commonjs/components/Toast.js.map +1 -1
  53. package/lib/commonjs/components/Tooltip.js +2 -2
  54. package/lib/commonjs/components/Tooltip.js.map +1 -1
  55. package/lib/commonjs/hooks/useThemeColor.js +66 -29
  56. package/lib/commonjs/hooks/useThemeColor.js.map +1 -1
  57. package/lib/commonjs/index.js +319 -1
  58. package/lib/commonjs/index.js.map +1 -1
  59. package/lib/commonjs/lib/overlay-host.js +101 -0
  60. package/lib/commonjs/lib/overlay-host.js.map +1 -0
  61. package/lib/commonjs/lib/typography.js +26 -0
  62. package/lib/commonjs/lib/typography.js.map +1 -0
  63. package/lib/commonjs/nativewind-env.d.js +0 -1
  64. package/lib/commonjs/nativewind-env.d.js.map +1 -1
  65. package/lib/module/components/Alert.js +3 -2
  66. package/lib/module/components/Alert.js.map +1 -1
  67. package/lib/module/components/Avatar.js +2 -1
  68. package/lib/module/components/Avatar.js.map +1 -1
  69. package/lib/module/components/Badge.js +2 -1
  70. package/lib/module/components/Badge.js.map +1 -1
  71. package/lib/module/components/Button.js +2 -1
  72. package/lib/module/components/Button.js.map +1 -1
  73. package/lib/module/components/CardNews.js +2 -1
  74. package/lib/module/components/CardNews.js.map +1 -1
  75. package/lib/module/components/Carousel.js +117 -0
  76. package/lib/module/components/Carousel.js.map +1 -0
  77. package/lib/module/components/Checkbox.js +12 -2
  78. package/lib/module/components/Checkbox.js.map +1 -1
  79. package/lib/module/components/DropdownMenu.js +216 -0
  80. package/lib/module/components/DropdownMenu.js.map +1 -0
  81. package/lib/module/components/EmptyState.js +19 -20
  82. package/lib/module/components/EmptyState.js.map +1 -1
  83. package/lib/module/components/Feed.js +77 -0
  84. package/lib/module/components/Feed.js.map +1 -0
  85. package/lib/module/components/FeedNotice.js +73 -0
  86. package/lib/module/components/FeedNotice.js.map +1 -0
  87. package/lib/module/components/Input.js +21 -9
  88. package/lib/module/components/Input.js.map +1 -1
  89. package/lib/module/components/InvitePopover.js +183 -0
  90. package/lib/module/components/InvitePopover.js.map +1 -0
  91. package/lib/module/components/Label.js +2 -1
  92. package/lib/module/components/Label.js.map +1 -1
  93. package/lib/module/components/LeaderboardCard.js +53 -0
  94. package/lib/module/components/LeaderboardCard.js.map +1 -0
  95. package/lib/module/components/MemberRow.js +127 -0
  96. package/lib/module/components/MemberRow.js.map +1 -0
  97. package/lib/module/components/PageHeader.js +2 -1
  98. package/lib/module/components/PageHeader.js.map +1 -1
  99. package/lib/module/components/PostForm.js +174 -0
  100. package/lib/module/components/PostForm.js.map +1 -0
  101. package/lib/module/components/PrizeCollection.js +127 -0
  102. package/lib/module/components/PrizeCollection.js.map +1 -0
  103. package/lib/module/components/RadioGroup.js +21 -1
  104. package/lib/module/components/RadioGroup.js.map +1 -1
  105. package/lib/module/components/SectionHeader.js +33 -0
  106. package/lib/module/components/SectionHeader.js.map +1 -0
  107. package/lib/module/components/Switch.js +34 -20
  108. package/lib/module/components/Switch.js.map +1 -1
  109. package/lib/module/components/Tabs.js +148 -0
  110. package/lib/module/components/Tabs.js.map +1 -0
  111. package/lib/module/components/Tag.js +2 -1
  112. package/lib/module/components/Tag.js.map +1 -1
  113. package/lib/module/components/Text.js +58 -0
  114. package/lib/module/components/Text.js.map +1 -0
  115. package/lib/module/components/Toast.js +2 -1
  116. package/lib/module/components/Toast.js.map +1 -1
  117. package/lib/module/components/Tooltip.js +1 -1
  118. package/lib/module/components/Tooltip.js.map +1 -1
  119. package/lib/module/hooks/useThemeColor.js +66 -31
  120. package/lib/module/hooks/useThemeColor.js.map +1 -1
  121. package/lib/module/index.js +27 -3
  122. package/lib/module/index.js.map +1 -1
  123. package/lib/module/lib/overlay-host.js +96 -0
  124. package/lib/module/lib/overlay-host.js.map +1 -0
  125. package/lib/module/lib/typography.js +22 -0
  126. package/lib/module/lib/typography.js.map +1 -0
  127. package/lib/module/nativewind-env.d.js +0 -1
  128. package/lib/module/nativewind-env.d.js.map +1 -1
  129. package/lib/typescript/components/Alert.d.ts.map +1 -1
  130. package/lib/typescript/components/Avatar.d.ts.map +1 -1
  131. package/lib/typescript/components/Badge.d.ts.map +1 -1
  132. package/lib/typescript/components/Button.d.ts.map +1 -1
  133. package/lib/typescript/components/CardNews.d.ts.map +1 -1
  134. package/lib/typescript/components/Carousel.d.ts +29 -0
  135. package/lib/typescript/components/Carousel.d.ts.map +1 -0
  136. package/lib/typescript/components/Checkbox.d.ts.map +1 -1
  137. package/lib/typescript/components/DropdownMenu.d.ts +39 -0
  138. package/lib/typescript/components/DropdownMenu.d.ts.map +1 -0
  139. package/lib/typescript/components/EmptyState.d.ts +1 -1
  140. package/lib/typescript/components/EmptyState.d.ts.map +1 -1
  141. package/lib/typescript/components/Feed.d.ts +22 -0
  142. package/lib/typescript/components/Feed.d.ts.map +1 -0
  143. package/lib/typescript/components/FeedNotice.d.ts +17 -0
  144. package/lib/typescript/components/FeedNotice.d.ts.map +1 -0
  145. package/lib/typescript/components/Input.d.ts +3 -2
  146. package/lib/typescript/components/Input.d.ts.map +1 -1
  147. package/lib/typescript/components/InvitePopover.d.ts +46 -0
  148. package/lib/typescript/components/InvitePopover.d.ts.map +1 -0
  149. package/lib/typescript/components/Label.d.ts.map +1 -1
  150. package/lib/typescript/components/LeaderboardCard.d.ts +16 -0
  151. package/lib/typescript/components/LeaderboardCard.d.ts.map +1 -0
  152. package/lib/typescript/components/MemberRow.d.ts +40 -0
  153. package/lib/typescript/components/MemberRow.d.ts.map +1 -0
  154. package/lib/typescript/components/PageHeader.d.ts.map +1 -1
  155. package/lib/typescript/components/PostForm.d.ts +50 -0
  156. package/lib/typescript/components/PostForm.d.ts.map +1 -0
  157. package/lib/typescript/components/PrizeCollection.d.ts +35 -0
  158. package/lib/typescript/components/PrizeCollection.d.ts.map +1 -0
  159. package/lib/typescript/components/RadioGroup.d.ts +10 -2
  160. package/lib/typescript/components/RadioGroup.d.ts.map +1 -1
  161. package/lib/typescript/components/SectionHeader.d.ts +12 -0
  162. package/lib/typescript/components/SectionHeader.d.ts.map +1 -0
  163. package/lib/typescript/components/Switch.d.ts.map +1 -1
  164. package/lib/typescript/components/Tabs.d.ts +32 -0
  165. package/lib/typescript/components/Tabs.d.ts.map +1 -0
  166. package/lib/typescript/components/Tag.d.ts.map +1 -1
  167. package/lib/typescript/components/Text.d.ts +23 -0
  168. package/lib/typescript/components/Text.d.ts.map +1 -0
  169. package/lib/typescript/components/Toast.d.ts +1 -1
  170. package/lib/typescript/components/Toast.d.ts.map +1 -1
  171. package/lib/typescript/components/Tooltip.d.ts.map +1 -1
  172. package/lib/typescript/hooks/useThemeColor.d.ts +4 -2
  173. package/lib/typescript/hooks/useThemeColor.d.ts.map +1 -1
  174. package/lib/typescript/index.d.ts +28 -4
  175. package/lib/typescript/index.d.ts.map +1 -1
  176. package/lib/typescript/lib/overlay-host.d.ts +23 -0
  177. package/lib/typescript/lib/overlay-host.d.ts.map +1 -0
  178. package/lib/typescript/lib/typography.d.ts +12 -0
  179. package/lib/typescript/lib/typography.d.ts.map +1 -0
  180. package/package.json +13 -3
  181. package/setup/MedwayUiProvider.tsx +15 -3
  182. package/setup/tailwind.js +52 -4
  183. package/setup/tokens.native.css +8 -3
  184. package/src/components/Alert.tsx +4 -2
  185. package/src/components/Avatar.tsx +3 -1
  186. package/src/components/Badge.tsx +3 -1
  187. package/src/components/Button.tsx +3 -7
  188. package/src/components/CardNews.tsx +2 -1
  189. package/src/components/Carousel.tsx +152 -0
  190. package/src/components/Checkbox.tsx +14 -4
  191. package/src/components/DropdownMenu.tsx +312 -0
  192. package/src/components/EmptyState.tsx +21 -23
  193. package/src/components/Feed.tsx +96 -0
  194. package/src/components/FeedNotice.tsx +112 -0
  195. package/src/components/Input.tsx +11 -6
  196. package/src/components/InvitePopover.tsx +240 -0
  197. package/src/components/Label.tsx +3 -1
  198. package/src/components/LeaderboardCard.tsx +70 -0
  199. package/src/components/MemberRow.tsx +157 -0
  200. package/src/components/PageHeader.tsx +3 -1
  201. package/src/components/PostForm.tsx +250 -0
  202. package/src/components/PrizeCollection.tsx +190 -0
  203. package/src/components/RadioGroup.tsx +32 -3
  204. package/src/components/SectionHeader.tsx +45 -0
  205. package/src/components/Switch.tsx +65 -59
  206. package/src/components/Tabs.tsx +182 -0
  207. package/src/components/Tag.tsx +3 -1
  208. package/src/components/Text.tsx +66 -0
  209. package/src/components/Toast.tsx +3 -1
  210. package/src/components/Tooltip.tsx +2 -1
  211. package/src/hooks/useThemeColor.ts +77 -32
  212. package/src/index.ts +147 -6
  213. package/src/lib/overlay-host.tsx +102 -0
  214. package/src/lib/typography.ts +21 -0
  215. 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
- <CheckboxPrimitive.Root
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
- <CheckboxPrimitive.Indicator className="items-center justify-center">
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
- </CheckboxPrimitive.Indicator>
137
+ </StyledCheckboxIndicator>
128
138
  {children}
129
- </CheckboxPrimitive.Root>
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-lg border border-gray-stroke-muted bg-surface-card p-8",
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
- <Alert variant={variant} className="border-0 bg-transparent p-0">
41
- <AlertContainer>
42
- {icon ? <AlertIcon icon={icon} /> : null}
43
- <AlertContent>
44
- <AlertTitle>{title}</AlertTitle>
45
- {description ? (
46
- <AlertDescription>{description}</AlertDescription>
47
- ) : null}
48
- </AlertContent>
49
- </AlertContainer>
50
- {action ? <AlertActions>{action}</AlertActions> : null}
51
- </Alert>
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 };