@medway-ui/native 1.0.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.
Files changed (155) hide show
  1. package/README.md +153 -0
  2. package/lib/commonjs/components/Alert.js +206 -0
  3. package/lib/commonjs/components/Alert.js.map +1 -0
  4. package/lib/commonjs/components/AlertDialog.js +273 -0
  5. package/lib/commonjs/components/AlertDialog.js.map +1 -0
  6. package/lib/commonjs/components/Badge.js +94 -0
  7. package/lib/commonjs/components/Badge.js.map +1 -0
  8. package/lib/commonjs/components/Button.js +181 -0
  9. package/lib/commonjs/components/Button.js.map +1 -0
  10. package/lib/commonjs/components/Checkbox.js +91 -0
  11. package/lib/commonjs/components/Checkbox.js.map +1 -0
  12. package/lib/commonjs/components/Dialog.js +164 -0
  13. package/lib/commonjs/components/Dialog.js.map +1 -0
  14. package/lib/commonjs/components/Input.js +364 -0
  15. package/lib/commonjs/components/Input.js.map +1 -0
  16. package/lib/commonjs/components/Label.js +90 -0
  17. package/lib/commonjs/components/Label.js.map +1 -0
  18. package/lib/commonjs/components/Loading.js +49 -0
  19. package/lib/commonjs/components/Loading.js.map +1 -0
  20. package/lib/commonjs/components/Popover.js +54 -0
  21. package/lib/commonjs/components/Popover.js.map +1 -0
  22. package/lib/commonjs/components/RadioGroup.js +72 -0
  23. package/lib/commonjs/components/RadioGroup.js.map +1 -0
  24. package/lib/commonjs/components/Select.js +234 -0
  25. package/lib/commonjs/components/Select.js.map +1 -0
  26. package/lib/commonjs/components/Separator.js +22 -0
  27. package/lib/commonjs/components/Separator.js.map +1 -0
  28. package/lib/commonjs/components/Sheet.js +148 -0
  29. package/lib/commonjs/components/Sheet.js.map +1 -0
  30. package/lib/commonjs/components/Switch.js +99 -0
  31. package/lib/commonjs/components/Switch.js.map +1 -0
  32. package/lib/commonjs/components/Tag.js +132 -0
  33. package/lib/commonjs/components/Tag.js.map +1 -0
  34. package/lib/commonjs/components/Toast.js +244 -0
  35. package/lib/commonjs/components/Toast.js.map +1 -0
  36. package/lib/commonjs/components/Tooltip.js +54 -0
  37. package/lib/commonjs/components/Tooltip.js.map +1 -0
  38. package/lib/commonjs/hooks/use-toast.js +136 -0
  39. package/lib/commonjs/hooks/use-toast.js.map +1 -0
  40. package/lib/commonjs/index.js +667 -0
  41. package/lib/commonjs/index.js.map +1 -0
  42. package/lib/commonjs/lib/utils.js +22 -0
  43. package/lib/commonjs/lib/utils.js.map +1 -0
  44. package/lib/commonjs/nativewind-env.d.js +3 -0
  45. package/lib/commonjs/nativewind-env.d.js.map +1 -0
  46. package/lib/module/components/Alert.js +195 -0
  47. package/lib/module/components/Alert.js.map +1 -0
  48. package/lib/module/components/AlertDialog.js +257 -0
  49. package/lib/module/components/AlertDialog.js.map +1 -0
  50. package/lib/module/components/Badge.js +90 -0
  51. package/lib/module/components/Badge.js.map +1 -0
  52. package/lib/module/components/Button.js +177 -0
  53. package/lib/module/components/Button.js.map +1 -0
  54. package/lib/module/components/Checkbox.js +86 -0
  55. package/lib/module/components/Checkbox.js.map +1 -0
  56. package/lib/module/components/Dialog.js +150 -0
  57. package/lib/module/components/Dialog.js.map +1 -0
  58. package/lib/module/components/Input.js +349 -0
  59. package/lib/module/components/Input.js.map +1 -0
  60. package/lib/module/components/Label.js +86 -0
  61. package/lib/module/components/Label.js.map +1 -0
  62. package/lib/module/components/Loading.js +45 -0
  63. package/lib/module/components/Loading.js.map +1 -0
  64. package/lib/module/components/Popover.js +47 -0
  65. package/lib/module/components/Popover.js.map +1 -0
  66. package/lib/module/components/RadioGroup.js +66 -0
  67. package/lib/module/components/RadioGroup.js.map +1 -0
  68. package/lib/module/components/Select.js +217 -0
  69. package/lib/module/components/Select.js.map +1 -0
  70. package/lib/module/components/Separator.js +19 -0
  71. package/lib/module/components/Separator.js.map +1 -0
  72. package/lib/module/components/Sheet.js +136 -0
  73. package/lib/module/components/Sheet.js.map +1 -0
  74. package/lib/module/components/Switch.js +94 -0
  75. package/lib/module/components/Switch.js.map +1 -0
  76. package/lib/module/components/Tag.js +128 -0
  77. package/lib/module/components/Tag.js.map +1 -0
  78. package/lib/module/components/Toast.js +233 -0
  79. package/lib/module/components/Toast.js.map +1 -0
  80. package/lib/module/components/Tooltip.js +47 -0
  81. package/lib/module/components/Tooltip.js.map +1 -0
  82. package/lib/module/hooks/use-toast.js +130 -0
  83. package/lib/module/hooks/use-toast.js.map +1 -0
  84. package/lib/module/index.js +41 -0
  85. package/lib/module/index.js.map +1 -0
  86. package/lib/module/lib/utils.js +18 -0
  87. package/lib/module/lib/utils.js.map +1 -0
  88. package/lib/module/nativewind-env.d.js +3 -0
  89. package/lib/module/nativewind-env.d.js.map +1 -0
  90. package/lib/module/package.json +1 -0
  91. package/lib/typescript/components/Alert.d.ts +36 -0
  92. package/lib/typescript/components/Alert.d.ts.map +1 -0
  93. package/lib/typescript/components/AlertDialog.d.ts +44 -0
  94. package/lib/typescript/components/AlertDialog.d.ts.map +1 -0
  95. package/lib/typescript/components/Badge.d.ts +17 -0
  96. package/lib/typescript/components/Badge.d.ts.map +1 -0
  97. package/lib/typescript/components/Button.d.ts +24 -0
  98. package/lib/typescript/components/Button.d.ts.map +1 -0
  99. package/lib/typescript/components/Checkbox.d.ts +20 -0
  100. package/lib/typescript/components/Checkbox.d.ts.map +1 -0
  101. package/lib/typescript/components/Dialog.d.ts +35 -0
  102. package/lib/typescript/components/Dialog.d.ts.map +1 -0
  103. package/lib/typescript/components/Input.d.ts +57 -0
  104. package/lib/typescript/components/Input.d.ts.map +1 -0
  105. package/lib/typescript/components/Label.d.ts +21 -0
  106. package/lib/typescript/components/Label.d.ts.map +1 -0
  107. package/lib/typescript/components/Loading.d.ts +9 -0
  108. package/lib/typescript/components/Loading.d.ts.map +1 -0
  109. package/lib/typescript/components/Popover.d.ts +11 -0
  110. package/lib/typescript/components/Popover.d.ts.map +1 -0
  111. package/lib/typescript/components/RadioGroup.d.ts +13 -0
  112. package/lib/typescript/components/RadioGroup.d.ts.map +1 -0
  113. package/lib/typescript/components/Select.d.ts +37 -0
  114. package/lib/typescript/components/Select.d.ts.map +1 -0
  115. package/lib/typescript/components/Separator.d.ts +9 -0
  116. package/lib/typescript/components/Separator.d.ts.map +1 -0
  117. package/lib/typescript/components/Sheet.d.ts +31 -0
  118. package/lib/typescript/components/Sheet.d.ts.map +1 -0
  119. package/lib/typescript/components/Switch.d.ts +18 -0
  120. package/lib/typescript/components/Switch.d.ts.map +1 -0
  121. package/lib/typescript/components/Tag.d.ts +17 -0
  122. package/lib/typescript/components/Tag.d.ts.map +1 -0
  123. package/lib/typescript/components/Toast.d.ts +42 -0
  124. package/lib/typescript/components/Toast.d.ts.map +1 -0
  125. package/lib/typescript/components/Tooltip.d.ts +14 -0
  126. package/lib/typescript/components/Tooltip.d.ts.map +1 -0
  127. package/lib/typescript/hooks/use-toast.d.ts +46 -0
  128. package/lib/typescript/hooks/use-toast.d.ts.map +1 -0
  129. package/lib/typescript/index.d.ts +38 -0
  130. package/lib/typescript/index.d.ts.map +1 -0
  131. package/lib/typescript/lib/utils.d.ts +3 -0
  132. package/lib/typescript/lib/utils.d.ts.map +1 -0
  133. package/package.json +111 -0
  134. package/src/components/Alert.tsx +185 -0
  135. package/src/components/AlertDialog.tsx +277 -0
  136. package/src/components/Badge.tsx +113 -0
  137. package/src/components/Button.tsx +224 -0
  138. package/src/components/Checkbox.tsx +106 -0
  139. package/src/components/Dialog.tsx +175 -0
  140. package/src/components/Input.tsx +439 -0
  141. package/src/components/Label.tsx +95 -0
  142. package/src/components/Loading.tsx +54 -0
  143. package/src/components/Popover.tsx +46 -0
  144. package/src/components/RadioGroup.tsx +62 -0
  145. package/src/components/Select.tsx +246 -0
  146. package/src/components/Separator.tsx +24 -0
  147. package/src/components/Sheet.tsx +165 -0
  148. package/src/components/Switch.tsx +138 -0
  149. package/src/components/Tag.tsx +116 -0
  150. package/src/components/Toast.tsx +265 -0
  151. package/src/components/Tooltip.tsx +49 -0
  152. package/src/hooks/use-toast.ts +144 -0
  153. package/src/index.ts +193 -0
  154. package/src/lib/utils.ts +63 -0
  155. package/src/nativewind-env.d.ts +1 -0
package/package.json ADDED
@@ -0,0 +1,111 @@
1
+ {
2
+ "name": "@medway-ui/native",
3
+ "version": "1.0.2",
4
+ "description": "Medway UI components for React Native (iOS/Android via Expo)",
5
+ "author": "Alekcarvalho",
6
+ "license": "MIT",
7
+ "main": "lib/commonjs/index.js",
8
+ "module": "lib/module/index.js",
9
+ "types": "lib/typescript/index.d.ts",
10
+ "react-native": "lib/module/index.js",
11
+ "source": "src/index.ts",
12
+ "exports": {
13
+ ".": {
14
+ "types": "./lib/typescript/index.d.ts",
15
+ "react-native": "./lib/module/index.js",
16
+ "require": "./lib/commonjs/index.js",
17
+ "default": "./lib/module/index.js"
18
+ }
19
+ },
20
+ "files": [
21
+ "lib",
22
+ "src",
23
+ "README.md"
24
+ ],
25
+ "sideEffects": false,
26
+ "scripts": {
27
+ "build:lib": "bob build",
28
+ "typecheck": "tsc --noEmit",
29
+ "release": "npm publish --access public",
30
+ "publish": "yarn build:lib && npm publish --access public"
31
+ },
32
+ "dependencies": {
33
+ "@rn-primitives/alert-dialog": "^1.0.0",
34
+ "@rn-primitives/checkbox": "^1.0.0",
35
+ "@rn-primitives/dialog": "^1.0.0",
36
+ "@rn-primitives/popover": "^1.0.0",
37
+ "@rn-primitives/portal": "^1.4.0",
38
+ "@rn-primitives/radio-group": "^1.0.0",
39
+ "@rn-primitives/select": "^1.0.0",
40
+ "@rn-primitives/slot": "^1.0.0",
41
+ "@rn-primitives/switch": "^1.0.0",
42
+ "@rn-primitives/tooltip": "^1.0.0"
43
+ },
44
+ "peerDependencies": {
45
+ "@medway-ui/icons": "^1.0.2",
46
+ "class-variance-authority": "^0.7.1",
47
+ "clsx": "^2.1.1",
48
+ "nativewind": "^4.0.0",
49
+ "react": ">=18.0.0",
50
+ "react-native": ">=0.73.0",
51
+ "react-native-reanimated": ">=3.0.0",
52
+ "react-native-svg": ">=15.0.0",
53
+ "tailwind-merge": "^3.2.0"
54
+ },
55
+ "peerDependenciesMeta": {
56
+ "class-variance-authority": {
57
+ "optional": false
58
+ },
59
+ "clsx": {
60
+ "optional": false
61
+ },
62
+ "tailwind-merge": {
63
+ "optional": false
64
+ }
65
+ },
66
+ "devDependencies": {
67
+ "@types/react": "^19",
68
+ "class-variance-authority": "^0.7.1",
69
+ "clsx": "^2.1.1",
70
+ "nativewind": "^4.2.4",
71
+ "react": "^19.2.6",
72
+ "react-native": "^0.85.3",
73
+ "react-native-builder-bob": "^0.30.0",
74
+ "react-native-reanimated": "^4.4.0",
75
+ "react-native-svg": "^15.15.5",
76
+ "tailwind-merge": "^3.2.0",
77
+ "typescript": "^5"
78
+ },
79
+ "react-native-builder-bob": {
80
+ "source": "src",
81
+ "output": "lib",
82
+ "targets": [
83
+ [
84
+ "commonjs",
85
+ {
86
+ "esm": true
87
+ }
88
+ ],
89
+ "module",
90
+ "typescript"
91
+ ]
92
+ },
93
+ "publishConfig": {
94
+ "access": "public"
95
+ },
96
+ "repository": {
97
+ "type": "git",
98
+ "url": "https://github.com/medway-dev/medway-ui.git",
99
+ "directory": "native"
100
+ },
101
+ "keywords": [
102
+ "react-native",
103
+ "expo",
104
+ "components",
105
+ "ui",
106
+ "design-system",
107
+ "medway",
108
+ "ios",
109
+ "android"
110
+ ]
111
+ }
@@ -0,0 +1,185 @@
1
+ import {
2
+ createContext,
3
+ useContext,
4
+ useMemo,
5
+ type ReactNode,
6
+ } from "react";
7
+ import { View, Text, Pressable, type ViewProps, type PressableProps } from "react-native";
8
+ import { cva, type VariantProps } from "class-variance-authority";
9
+ import { CloseMd } from "@medway-ui/icons/native";
10
+ import { cn } from "@/lib/utils";
11
+
12
+ type AlertVariant = "regular" | "emphasis" | "success" | "warning" | "error";
13
+
14
+ interface AlertProps extends ViewProps {
15
+ variant?: AlertVariant;
16
+ onClose?: () => void;
17
+ children?: ReactNode;
18
+ }
19
+
20
+ interface AlertButtonProps extends PressableProps, VariantProps<typeof alertButtonVariants> {
21
+ children?: ReactNode;
22
+ }
23
+
24
+ const AlertContext = createContext<{
25
+ variant: AlertVariant;
26
+ onClose?: () => void;
27
+ } | null>(null);
28
+
29
+ const alertVariants = cva("relative w-full rounded-md px-4 py-3 flex-col gap-1", {
30
+ variants: {
31
+ variant: {
32
+ regular: "bg-primary-background-soft",
33
+ emphasis: "bg-secondary-background-soft",
34
+ success: "bg-green-background-soft",
35
+ warning: "bg-yellow-background-soft",
36
+ error: "bg-red-background-soft",
37
+ },
38
+ },
39
+ defaultVariants: { variant: "regular" },
40
+ });
41
+
42
+ const alertTextColorVariants = cva("", {
43
+ variants: {
44
+ variant: {
45
+ regular: "text-primary-foreground",
46
+ emphasis: "text-secondary-foreground",
47
+ success: "text-green-foreground",
48
+ warning: "text-yellow-foreground",
49
+ error: "text-red-foreground",
50
+ },
51
+ },
52
+ defaultVariants: { variant: "regular" },
53
+ });
54
+
55
+ const alertButtonVariants = cva(
56
+ "flex-row items-center justify-center rounded-pill px-3 min-h-10",
57
+ {
58
+ variants: {
59
+ variant: {
60
+ regular: "",
61
+ basic: "bg-transparent",
62
+ },
63
+ alertVariant: {
64
+ regular: "bg-primary-background-soft",
65
+ emphasis: "bg-secondary-background-soft",
66
+ success: "bg-green-background-soft",
67
+ warning: "bg-yellow-background-soft",
68
+ error: "bg-red-background-soft",
69
+ },
70
+ },
71
+ defaultVariants: { variant: "regular", alertVariant: "regular" },
72
+ }
73
+ );
74
+
75
+ function useAlertContext() {
76
+ const context = useContext(AlertContext);
77
+ if (!context) throw new Error("Alert sub-components must be used inside <Alert>");
78
+ return context;
79
+ }
80
+
81
+ function Alert({ className, variant = "regular", onClose, children, ...props }: AlertProps) {
82
+ const ctx = useMemo(() => ({ variant, onClose }), [variant, onClose]);
83
+
84
+ return (
85
+ <AlertContext.Provider value={ctx}>
86
+ <View
87
+ accessibilityRole="alert"
88
+ className={cn(alertVariants({ variant }), className)}
89
+ {...props}
90
+ >
91
+ {children}
92
+ {onClose && (
93
+ <Pressable
94
+ onPress={onClose}
95
+ accessibilityLabel="Close alert"
96
+ className="absolute right-4 top-2"
97
+ >
98
+ <CloseMd size={16} className="text-gray-foreground" />
99
+ </Pressable>
100
+ )}
101
+ </View>
102
+ </AlertContext.Provider>
103
+ );
104
+ }
105
+
106
+ function AlertContainer({ className, ...props }: ViewProps) {
107
+ return <View className={cn("flex-row gap-3", className)} {...props} />;
108
+ }
109
+
110
+ function AlertContent({ className, ...props }: ViewProps) {
111
+ return <View className={cn("flex-col gap-1 flex-1", className)} {...props} />;
112
+ }
113
+
114
+ function AlertIcon({ className, icon, ...props }: ViewProps & { icon?: ReactNode }) {
115
+ return (
116
+ <View className={cn("w-6 h-6", className)} {...props}>
117
+ {icon}
118
+ </View>
119
+ );
120
+ }
121
+
122
+ function AlertTitle({ className, children, ...props }: ViewProps & { children?: ReactNode }) {
123
+ const { variant } = useAlertContext();
124
+ return (
125
+ <View className={cn("", className)} {...props}>
126
+ <Text
127
+ numberOfLines={1}
128
+ className={cn("text-md font-medium", alertTextColorVariants({ variant }))}
129
+ >
130
+ {children}
131
+ </Text>
132
+ </View>
133
+ );
134
+ }
135
+
136
+ function AlertDescription({ className, children, ...props }: ViewProps & { children?: ReactNode }) {
137
+ const { variant } = useAlertContext();
138
+ return (
139
+ <View className={cn("", className)} {...props}>
140
+ <Text
141
+ numberOfLines={3}
142
+ className={cn("text-sm leading-5", alertTextColorVariants({ variant }))}
143
+ >
144
+ {children}
145
+ </Text>
146
+ </View>
147
+ );
148
+ }
149
+
150
+ function AlertActions({ className, ...props }: ViewProps) {
151
+ return (
152
+ <View className={cn("flex-row flex-wrap items-center gap-2 mt-2", className)} {...props} />
153
+ );
154
+ }
155
+
156
+ function AlertButton({ className, variant, children, ...props }: AlertButtonProps) {
157
+ const context = useContext(AlertContext);
158
+ const alertVariant = context?.variant ?? "regular";
159
+
160
+ return (
161
+ <Pressable
162
+ className={cn(alertButtonVariants({ variant, alertVariant }), className)}
163
+ accessibilityRole="button"
164
+ {...props}
165
+ >
166
+ <Text className={cn("text-sm font-semibold", alertTextColorVariants({ variant: alertVariant }))}>
167
+ {children}
168
+ </Text>
169
+ </Pressable>
170
+ );
171
+ }
172
+
173
+ export {
174
+ Alert,
175
+ AlertContainer,
176
+ AlertContent,
177
+ AlertIcon,
178
+ AlertTitle,
179
+ AlertDescription,
180
+ AlertActions,
181
+ AlertButton,
182
+ alertVariants,
183
+ alertButtonVariants,
184
+ };
185
+ export type { AlertProps, AlertButtonProps };
@@ -0,0 +1,277 @@
1
+ import { createContext, useContext, useMemo, type ReactNode } from "react";
2
+ import { View, Text, type ViewProps } from "react-native";
3
+ import * as AlertDialogPrimitive from "@rn-primitives/alert-dialog";
4
+ import { CloseMd } from "@medway-ui/icons/native";
5
+ import { cva } from "class-variance-authority";
6
+ import { cn } from "@/lib/utils";
7
+ import { Button, type ButtonProps } from "@/components/Button";
8
+ import { Tag, type TagProps } from "@/components/Tag";
9
+
10
+ type AlertDialogVariant = "regular" | "emphasis" | "warning" | "error" | "success";
11
+
12
+ interface AlertDialogProps extends AlertDialogPrimitive.RootProps {
13
+ variant?: AlertDialogVariant;
14
+ }
15
+
16
+ interface AlertDialogContentProps extends AlertDialogPrimitive.ContentProps {
17
+ overlayClassName?: string;
18
+ showCloseButton?: boolean;
19
+ }
20
+
21
+ interface AlertDialogIconProps extends ViewProps {
22
+ icon: ReactNode;
23
+ }
24
+
25
+ interface AlertDialogTagProps {
26
+ variant?: AlertDialogVariant;
27
+ className?: string;
28
+ children?: ReactNode;
29
+ }
30
+
31
+ interface AlertDialogActionProps extends AlertDialogPrimitive.ActionProps {
32
+ variant?: ButtonProps["variant"];
33
+ size?: ButtonProps["size"];
34
+ }
35
+
36
+ interface AlertDialogCancelProps extends AlertDialogPrimitive.CancelProps {
37
+ variant?: ButtonProps["variant"];
38
+ size?: ButtonProps["size"];
39
+ }
40
+
41
+ const DEFAULT_VARIANT: AlertDialogVariant = "regular";
42
+
43
+ const AlertDialogContext = createContext<{ variant: AlertDialogVariant } | null>(null);
44
+
45
+ const alertDialogIconSectionVariants = cva(
46
+ "w-full items-center justify-center px-8 py-8",
47
+ {
48
+ variants: {
49
+ variant: {
50
+ regular: "bg-primary-background-soft",
51
+ emphasis: "bg-secondary-background-soft",
52
+ warning: "bg-feedback-warning-background-soft",
53
+ error: "bg-feedback-error-background-soft",
54
+ success: "bg-feedback-success-background-soft",
55
+ },
56
+ },
57
+ defaultVariants: { variant: DEFAULT_VARIANT },
58
+ }
59
+ );
60
+
61
+ const alertDialogIconContainerVariants = cva(
62
+ "items-center justify-center rounded-full p-4",
63
+ {
64
+ variants: {
65
+ variant: {
66
+ regular: "bg-primary-background-fill",
67
+ emphasis: "bg-secondary-background-fill",
68
+ warning: "bg-yellow-background-fill",
69
+ error: "bg-red-background-fill",
70
+ success: "bg-green-background-fill",
71
+ },
72
+ },
73
+ defaultVariants: { variant: DEFAULT_VARIANT },
74
+ }
75
+ );
76
+
77
+ const alertDialogIconTextVariants = cva("", {
78
+ variants: {
79
+ variant: {
80
+ regular: "text-primary-foreground-onfill",
81
+ emphasis: "text-secondary-foreground-onfill",
82
+ warning: "text-yellow-foreground-onfill",
83
+ error: "text-red-foreground-onfill",
84
+ success: "text-green-foreground-onfill",
85
+ },
86
+ },
87
+ defaultVariants: { variant: DEFAULT_VARIANT },
88
+ });
89
+
90
+ const alertDialogTagVariantMap: Record<AlertDialogVariant, TagProps["variant"]> = {
91
+ regular: "regular-soft",
92
+ emphasis: "emphasis-soft",
93
+ warning: "warning-soft",
94
+ error: "error-soft",
95
+ success: "success-soft",
96
+ };
97
+
98
+ const actionVariantMap: Record<AlertDialogVariant, NonNullable<ButtonProps["variant"]>> = {
99
+ regular: "regular",
100
+ emphasis: "emphasis",
101
+ warning: "warning",
102
+ error: "error",
103
+ success: "success",
104
+ };
105
+
106
+ function AlertDialog({ variant = DEFAULT_VARIANT, ...props }: AlertDialogProps) {
107
+ const ctx = useMemo(() => ({ variant }), [variant]);
108
+ return (
109
+ <AlertDialogContext.Provider value={ctx}>
110
+ <AlertDialogPrimitive.Root {...props} />
111
+ </AlertDialogContext.Provider>
112
+ );
113
+ }
114
+
115
+ function AlertDialogTrigger({ ...props }: AlertDialogPrimitive.TriggerProps) {
116
+ return <AlertDialogPrimitive.Trigger {...props} />;
117
+ }
118
+
119
+ function AlertDialogPortal({ ...props }: AlertDialogPrimitive.PortalProps) {
120
+ return <AlertDialogPrimitive.Portal {...props} />;
121
+ }
122
+
123
+ function AlertDialogOverlay({ className, ...props }: AlertDialogPrimitive.OverlayProps) {
124
+ return (
125
+ <AlertDialogPrimitive.Overlay
126
+ className={cn("absolute inset-0 bg-black/50", className)}
127
+ {...props}
128
+ />
129
+ );
130
+ }
131
+
132
+ function AlertDialogContent({
133
+ className,
134
+ overlayClassName,
135
+ children,
136
+ showCloseButton = false,
137
+ ...props
138
+ }: AlertDialogContentProps) {
139
+ return (
140
+ <AlertDialogPrimitive.Portal>
141
+ <AlertDialogPrimitive.Overlay
142
+ className={cn("absolute inset-0 items-center justify-center bg-black/50", overlayClassName)}
143
+ >
144
+ <AlertDialogPrimitive.Content
145
+ className={cn(
146
+ "relative flex-col w-full max-w-[calc(100%-2rem)] rounded-xl bg-background shadow-lg overflow-hidden",
147
+ className
148
+ )}
149
+ {...props}
150
+ >
151
+ {children}
152
+ {showCloseButton && (
153
+ <AlertDialogPrimitive.Cancel className="absolute right-3 top-3 rounded-pill p-1.5 active:bg-gray-background-soft">
154
+ <CloseMd size={16} className="text-gray-foreground" />
155
+ </AlertDialogPrimitive.Cancel>
156
+ )}
157
+ </AlertDialogPrimitive.Content>
158
+ </AlertDialogPrimitive.Overlay>
159
+ </AlertDialogPrimitive.Portal>
160
+ );
161
+ }
162
+
163
+ function AlertDialogHeader({ className, ...props }: ViewProps) {
164
+ return (
165
+ <View
166
+ className={cn("flex-col items-center gap-3 px-8 pt-8 text-center", className)}
167
+ {...props}
168
+ />
169
+ );
170
+ }
171
+
172
+ function AlertDialogIcon({ className, icon, ...props }: AlertDialogIconProps) {
173
+ const ctx = useContext(AlertDialogContext);
174
+ const variant = ctx?.variant ?? DEFAULT_VARIANT;
175
+
176
+ return (
177
+ <View className={cn(alertDialogIconSectionVariants({ variant }), className)} {...props}>
178
+ <View className={cn(alertDialogIconContainerVariants({ variant }))}>
179
+ <View className={cn("w-8 h-8 items-center justify-center", alertDialogIconTextVariants({ variant }))}>
180
+ {icon}
181
+ </View>
182
+ </View>
183
+ </View>
184
+ );
185
+ }
186
+
187
+ function AlertDialogTag({ className, variant, children }: AlertDialogTagProps) {
188
+ const ctx = useContext(AlertDialogContext);
189
+ const resolvedVariant = variant ?? ctx?.variant ?? DEFAULT_VARIANT;
190
+ return (
191
+ <View className="items-center">
192
+ <Tag variant={alertDialogTagVariantMap[resolvedVariant]} className={className}>
193
+ {children}
194
+ </Tag>
195
+ </View>
196
+ );
197
+ }
198
+
199
+ function AlertDialogTitle({ className, children, ...props }: AlertDialogPrimitive.TitleProps) {
200
+ return (
201
+ <AlertDialogPrimitive.Title className={cn("", className)} {...props}>
202
+ <Text className="text-title-sm font-semibold leading-title-sm text-content-title text-center">
203
+ {children}
204
+ </Text>
205
+ </AlertDialogPrimitive.Title>
206
+ );
207
+ }
208
+
209
+ function AlertDialogDescription({ className, children, ...props }: AlertDialogPrimitive.DescriptionProps) {
210
+ return (
211
+ <AlertDialogPrimitive.Description className={cn("", className)} {...props}>
212
+ <Text className="text-md leading-md text-content-paragraph text-center">
213
+ {children}
214
+ </Text>
215
+ </AlertDialogPrimitive.Description>
216
+ );
217
+ }
218
+
219
+ function AlertDialogFooter({ className, ...props }: ViewProps) {
220
+ return (
221
+ <View
222
+ className={cn("flex-row items-center justify-center gap-4 px-8 pb-8 pt-6", className)}
223
+ {...props}
224
+ />
225
+ );
226
+ }
227
+
228
+ function AlertDialogAction({ className, variant, size = "lg", children, ...props }: AlertDialogActionProps) {
229
+ const ctx = useContext(AlertDialogContext);
230
+ const resolvedVariant = variant ?? actionVariantMap[ctx?.variant ?? DEFAULT_VARIANT];
231
+
232
+ return (
233
+ <AlertDialogPrimitive.Action
234
+ className={cn("flex-1", className)}
235
+ {...props}
236
+ >
237
+ <Button variant={resolvedVariant} size={size} className="w-full">
238
+ {children as ReactNode}
239
+ </Button>
240
+ </AlertDialogPrimitive.Action>
241
+ );
242
+ }
243
+
244
+ function AlertDialogCancel({ className, variant = "regular-soft", size = "lg", children, ...props }: AlertDialogCancelProps) {
245
+ return (
246
+ <AlertDialogPrimitive.Cancel className={cn("flex-1", className)} {...props}>
247
+ <Button variant={variant} size={size} className="w-full">
248
+ {children as ReactNode}
249
+ </Button>
250
+ </AlertDialogPrimitive.Cancel>
251
+ );
252
+ }
253
+
254
+ export {
255
+ AlertDialog,
256
+ AlertDialogAction,
257
+ AlertDialogCancel,
258
+ AlertDialogContent,
259
+ AlertDialogDescription,
260
+ AlertDialogFooter,
261
+ AlertDialogHeader,
262
+ AlertDialogIcon,
263
+ AlertDialogOverlay,
264
+ AlertDialogPortal,
265
+ AlertDialogTag,
266
+ AlertDialogTitle,
267
+ AlertDialogTrigger,
268
+ };
269
+ export type {
270
+ AlertDialogVariant,
271
+ AlertDialogProps,
272
+ AlertDialogContentProps,
273
+ AlertDialogActionProps,
274
+ AlertDialogCancelProps,
275
+ AlertDialogTagProps,
276
+ AlertDialogIconProps,
277
+ };
@@ -0,0 +1,113 @@
1
+ import { type ReactNode } from "react";
2
+ import { View, Text, type ViewProps } from "react-native";
3
+ import { cva, type VariantProps } from "class-variance-authority";
4
+ import { cn } from "@/lib/utils";
5
+
6
+ type BadgeAnimation = "shine";
7
+
8
+ interface BadgeProps extends ViewProps, VariantProps<typeof badgeVariants> {
9
+ icon?: ReactNode;
10
+ animation?: BadgeAnimation;
11
+ children?: ReactNode;
12
+ }
13
+
14
+ const ICON_ONLY_SIZES: Record<"sm" | "md" | "lg" | "xl", string> = {
15
+ sm: "h-4 w-4 p-0",
16
+ md: "h-5 w-5 p-0",
17
+ lg: "h-6 w-6 p-0",
18
+ xl: "h-7 w-7 p-0",
19
+ };
20
+
21
+ const CHAR_PADDING: Record<"sm" | "md" | "lg" | "xl", string> = {
22
+ sm: "px-1",
23
+ md: "px-1",
24
+ lg: "px-1",
25
+ xl: "px-1.5",
26
+ };
27
+
28
+ const badgeVariants = cva(
29
+ "flex-row items-center justify-center rounded-full px-2",
30
+ {
31
+ variants: {
32
+ variant: {
33
+ regular: "bg-secondary-background-fill",
34
+ error: "bg-red-background-soft",
35
+ warning: "bg-yellow-background-soft",
36
+ freemium: "bg-primary-background-fill",
37
+ },
38
+ size: {
39
+ sm: "min-h-4 min-w-4",
40
+ md: "min-h-5 min-w-5",
41
+ lg: "min-h-6 min-w-6",
42
+ xl: "min-h-7 min-w-7",
43
+ },
44
+ },
45
+ defaultVariants: {
46
+ variant: "regular",
47
+ size: "md",
48
+ },
49
+ }
50
+ );
51
+
52
+ const badgeTextVariants = cva("font-semibold", {
53
+ variants: {
54
+ variant: {
55
+ regular: "text-secondary-foreground-onfill",
56
+ error: "text-red-stroke-emphasis",
57
+ warning: "text-yellow-foreground",
58
+ freemium: "text-white",
59
+ },
60
+ size: {
61
+ sm: "text-xs",
62
+ md: "text-xs",
63
+ lg: "text-xs",
64
+ xl: "text-sm",
65
+ },
66
+ },
67
+ defaultVariants: {
68
+ variant: "regular",
69
+ size: "md",
70
+ },
71
+ });
72
+
73
+ function Badge({
74
+ className,
75
+ variant,
76
+ size,
77
+ icon,
78
+ animation: _animation,
79
+ children,
80
+ ...props
81
+ }: BadgeProps) {
82
+ const childText =
83
+ typeof children === "string" || typeof children === "number"
84
+ ? String(children).trim()
85
+ : "";
86
+ const isSingleAlphaNum = /^[A-Za-z0-9]$/.test(childText);
87
+ const isShortAlnumUpTo3 = /^[A-Za-z0-9]{2,3}$/.test(childText);
88
+ const isDigitsWithSuffix = /^\d{1,2}\S$/.test(childText);
89
+ const isIconOnly = !!icon && !children;
90
+ const isShortUpTo3 = isShortAlnumUpTo3 || isDigitsWithSuffix;
91
+
92
+ return (
93
+ <View
94
+ className={cn(
95
+ badgeVariants({ variant, size }),
96
+ (isIconOnly || isSingleAlphaNum) && ICON_ONLY_SIZES[size ?? "md"],
97
+ !isIconOnly && isShortUpTo3 && CHAR_PADDING[size ?? "md"],
98
+ className
99
+ )}
100
+ {...props}
101
+ >
102
+ {icon}
103
+ {children != null && (
104
+ <Text className={cn(badgeTextVariants({ variant, size }))}>
105
+ {children}
106
+ </Text>
107
+ )}
108
+ </View>
109
+ );
110
+ }
111
+
112
+ export { Badge, badgeVariants };
113
+ export type { BadgeAnimation, BadgeProps };