@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
@@ -0,0 +1,246 @@
1
+ import React, {
2
+ createContext,
3
+ useContext,
4
+ useMemo,
5
+ isValidElement,
6
+ cloneElement,
7
+ type ReactNode,
8
+ type ReactElement,
9
+ } from "react";
10
+ import { View, Text, type ViewProps, type TextProps } from "react-native";
11
+ import * as SelectPrimitive from "@rn-primitives/select";
12
+ import { Check, ChevronDown, ChevronUp } from "@medway-ui/icons/native";
13
+ import { cva } from "class-variance-authority";
14
+ import { cn } from "@/lib/utils";
15
+
16
+ type SelectSize = "md" | "lg";
17
+
18
+ interface SelectContextValue {
19
+ invalid: boolean;
20
+ size: SelectSize;
21
+ }
22
+
23
+ interface SelectProps extends SelectPrimitive.RootProps {
24
+ invalid?: boolean;
25
+ size?: SelectSize;
26
+ }
27
+
28
+ interface SelectTriggerProps extends Omit<SelectPrimitive.TriggerProps, "children"> {
29
+ children?: React.ReactNode;
30
+ }
31
+
32
+ interface SelectItemProps extends SelectPrimitive.ItemProps {
33
+ icon?: ReactNode;
34
+ }
35
+
36
+ const selectVariants = cva(
37
+ "flex-row w-full items-center justify-between gap-2 rounded-md border-2 border-gray-stroke-muted bg-surface-card px-4",
38
+ {
39
+ variants: {
40
+ size: {
41
+ lg: "h-12 max-h-12",
42
+ md: "h-10 max-h-10",
43
+ },
44
+ invalid: {
45
+ true: "border-feedback-error-stroke",
46
+ false: "",
47
+ },
48
+ },
49
+ defaultVariants: {
50
+ size: "lg",
51
+ invalid: false,
52
+ },
53
+ }
54
+ );
55
+
56
+ const SelectContext = createContext<SelectContextValue>({
57
+ invalid: false,
58
+ size: "lg",
59
+ });
60
+
61
+ function Select({ invalid = false, size = "lg", ...props }: SelectProps) {
62
+ const ctx = useMemo(() => ({ invalid, size }), [invalid, size]);
63
+ return (
64
+ <SelectContext.Provider value={ctx}>
65
+ <SelectPrimitive.Root {...props} />
66
+ </SelectContext.Provider>
67
+ );
68
+ }
69
+
70
+ function SelectWrapper({ className, ...props }: ViewProps) {
71
+ return <View className={cn("relative flex-col gap-2", className)} {...props} />;
72
+ }
73
+
74
+ function SelectTrigger({ className, children, ...props }: SelectTriggerProps) {
75
+ const { invalid, size } = useContext(SelectContext);
76
+
77
+ return (
78
+ <SelectPrimitive.Trigger
79
+ className={cn(selectVariants({ size, invalid }), className)}
80
+ {...props}
81
+ >
82
+ {children}
83
+ <ChevronDown
84
+ size={size === "lg" ? 24 : 20}
85
+ strokeWidth={1.6}
86
+ className="text-gray-foreground shrink-0"
87
+ />
88
+ </SelectPrimitive.Trigger>
89
+ );
90
+ }
91
+
92
+ function SelectValue({ className, placeholder, ...props }: SelectPrimitive.ValueProps) {
93
+ const { size } = useContext(SelectContext);
94
+ return (
95
+ <SelectPrimitive.Value
96
+ className={cn(
97
+ "text-gray-foreground flex-1",
98
+ size === "lg" ? "text-md" : "text-sm",
99
+ className
100
+ )}
101
+ placeholder={placeholder}
102
+ {...props}
103
+ />
104
+ );
105
+ }
106
+
107
+ function SelectContent({ className, children, ...props }: SelectPrimitive.ContentProps) {
108
+ return (
109
+ <SelectPrimitive.Portal>
110
+ <SelectPrimitive.Overlay className="absolute inset-0 bg-black/20">
111
+ <SelectPrimitive.Content
112
+ className={cn(
113
+ "z-50 min-w-48 overflow-hidden rounded-md border border-gray-stroke-muted bg-surface-elevated shadow-lg",
114
+ className
115
+ )}
116
+ {...props}
117
+ >
118
+ <SelectScrollUpButton />
119
+ <SelectPrimitive.Viewport className="p-1">
120
+ {children}
121
+ </SelectPrimitive.Viewport>
122
+ <SelectScrollDownButton />
123
+ </SelectPrimitive.Content>
124
+ </SelectPrimitive.Overlay>
125
+ </SelectPrimitive.Portal>
126
+ );
127
+ }
128
+
129
+ function SelectGroup({ ...props }: SelectPrimitive.GroupProps) {
130
+ return <SelectPrimitive.Group {...props} />;
131
+ }
132
+
133
+ function SelectHeader({ className, ...props }: SelectPrimitive.LabelProps) {
134
+ return (
135
+ <SelectPrimitive.Label
136
+ className={cn("px-2 py-2 text-xs font-medium text-gray-foreground-muted", className)}
137
+ {...props}
138
+ />
139
+ );
140
+ }
141
+
142
+ function SelectItem({ className, children, icon, label, ...props }: SelectItemProps) {
143
+ const { size } = useContext(SelectContext);
144
+ const resolvedLabel = label ?? (typeof children === "string" ? children : "");
145
+
146
+ return (
147
+ <SelectPrimitive.Item
148
+ label={resolvedLabel}
149
+ className={cn(
150
+ "relative flex-row w-full items-center rounded px-2 gap-3",
151
+ size === "lg" ? "py-2" : "py-1.5",
152
+ "active:bg-secondary-background-soft-emphasis",
153
+ className
154
+ )}
155
+ {...props}
156
+ >
157
+ {icon && (
158
+ <View className="shrink-0 items-center justify-center text-gray-foreground">
159
+ {isValidElement(icon)
160
+ ? cloneElement(icon as ReactElement<{ strokeWidth?: number }>, { strokeWidth: 1.6 })
161
+ : icon}
162
+ </View>
163
+ )}
164
+ <SelectPrimitive.ItemText className="flex-1 text-sm font-medium text-gray-foreground" />
165
+ <SelectPrimitive.ItemIndicator className="absolute right-2 h-3.5 w-3.5 items-center justify-center">
166
+ <Check size={14} strokeWidth={1.6} className="text-secondary-foreground" />
167
+ </SelectPrimitive.ItemIndicator>
168
+ </SelectPrimitive.Item>
169
+ );
170
+ }
171
+
172
+ function SelectSeparator({ className, ...props }: SelectPrimitive.SeparatorProps) {
173
+ return (
174
+ <SelectPrimitive.Separator
175
+ className={cn("-mx-1 my-1 h-px bg-gray-stroke-muted", className)}
176
+ {...props}
177
+ />
178
+ );
179
+ }
180
+
181
+ function SelectScrollUpButton({ className, ...props }: SelectPrimitive.ScrollUpButtonProps) {
182
+ return (
183
+ <SelectPrimitive.ScrollUpButton
184
+ className={cn("items-center justify-center py-1", className)}
185
+ {...props}
186
+ >
187
+ <ChevronUp size={16} strokeWidth={1.6} className="text-gray-foreground" />
188
+ </SelectPrimitive.ScrollUpButton>
189
+ );
190
+ }
191
+
192
+ function SelectScrollDownButton({ className, ...props }: SelectPrimitive.ScrollDownButtonProps) {
193
+ return (
194
+ <SelectPrimitive.ScrollDownButton
195
+ className={cn("items-center justify-center py-1", className)}
196
+ {...props}
197
+ >
198
+ <ChevronDown size={16} strokeWidth={1.6} className="text-gray-foreground" />
199
+ </SelectPrimitive.ScrollDownButton>
200
+ );
201
+ }
202
+
203
+ function SelectText({ className, ...props }: TextProps) {
204
+ const { invalid } = useContext(SelectContext);
205
+ return (
206
+ <Text
207
+ className={cn(
208
+ "-mt-1 text-xs",
209
+ invalid ? "text-feedback-error-foreground" : "text-gray-foreground",
210
+ className
211
+ )}
212
+ {...props}
213
+ />
214
+ );
215
+ }
216
+
217
+ function SelectLabel({ children, disabled = false }: { children?: ReactNode; disabled?: boolean }) {
218
+ return (
219
+ <Text
220
+ className={cn(
221
+ "text-xs font-medium text-gray-foreground",
222
+ disabled ? "text-gray-foreground-muted" : ""
223
+ )}
224
+ >
225
+ {children}
226
+ </Text>
227
+ );
228
+ }
229
+
230
+ export {
231
+ Select,
232
+ SelectContent,
233
+ SelectGroup,
234
+ SelectHeader,
235
+ SelectItem,
236
+ SelectLabel,
237
+ SelectScrollDownButton,
238
+ SelectScrollUpButton,
239
+ SelectSeparator,
240
+ SelectText,
241
+ SelectTrigger,
242
+ SelectValue,
243
+ SelectWrapper,
244
+ selectVariants,
245
+ };
246
+ export type { SelectProps, SelectItemProps, SelectSize };
@@ -0,0 +1,24 @@
1
+ import { View, type ViewProps, type AccessibilityRole } from "react-native";
2
+ import { cn } from "@/lib/utils";
3
+
4
+ interface SeparatorProps extends ViewProps {
5
+ orientation?: "horizontal" | "vertical";
6
+ decorative?: boolean;
7
+ }
8
+
9
+ function Separator({ className, orientation = "horizontal", decorative = true, ...props }: SeparatorProps) {
10
+ return (
11
+ <View
12
+ accessibilityRole={decorative ? undefined : ("separator" as AccessibilityRole)}
13
+ className={cn(
14
+ "shrink-0 bg-gray-stroke-muted",
15
+ orientation === "horizontal" ? "h-px w-full" : "w-px h-full",
16
+ className
17
+ )}
18
+ {...props}
19
+ />
20
+ );
21
+ }
22
+
23
+ export { Separator };
24
+ export type { SeparatorProps };
@@ -0,0 +1,165 @@
1
+ import { type ReactNode } from "react";
2
+ import { View, ScrollView, type ViewProps } from "react-native";
3
+ import * as DialogPrimitive from "@rn-primitives/dialog";
4
+ import { CloseMd } from "@medway-ui/icons/native";
5
+ import { cn } from "@/lib/utils";
6
+ import { Separator } from "@/components/Separator";
7
+
8
+ type SheetSide = "top" | "right" | "bottom" | "left";
9
+
10
+ interface SheetContainerProps extends DialogPrimitive.ContentProps {
11
+ side?: SheetSide;
12
+ showCloseButton?: boolean;
13
+ overlayClassName?: string;
14
+ }
15
+
16
+ interface SheetHeaderProps extends ViewProps {
17
+ separator?: boolean;
18
+ }
19
+
20
+ interface SheetFooterProps extends ViewProps {
21
+ separator?: boolean;
22
+ }
23
+
24
+ const overlayPositionMap: Record<SheetSide, string> = {
25
+ bottom: "absolute inset-0 justify-end",
26
+ top: "absolute inset-0 justify-start",
27
+ left: "absolute inset-0 items-start",
28
+ right: "absolute inset-0 items-end",
29
+ };
30
+
31
+ const contentSizeMap: Record<SheetSide, string> = {
32
+ bottom: "w-full max-h-[90%] rounded-t-xl",
33
+ top: "w-full max-h-[90%] rounded-b-xl",
34
+ left: "h-full max-w-[80%] rounded-r-xl",
35
+ right: "h-full max-w-[80%] rounded-l-xl",
36
+ };
37
+
38
+ const closeButtonPositionMap: Record<SheetSide, string> = {
39
+ bottom: "absolute right-3 top-3",
40
+ top: "absolute right-3 bottom-3",
41
+ left: "absolute right-3 top-3",
42
+ right: "absolute left-3 top-3",
43
+ };
44
+
45
+ function Sheet({ ...props }: DialogPrimitive.RootProps) {
46
+ return <DialogPrimitive.Root {...props} />;
47
+ }
48
+
49
+ function SheetTrigger({ ...props }: DialogPrimitive.TriggerProps) {
50
+ return <DialogPrimitive.Trigger {...props} />;
51
+ }
52
+
53
+ function SheetClose({ ...props }: DialogPrimitive.CloseProps) {
54
+ return <DialogPrimitive.Close {...props} />;
55
+ }
56
+
57
+ function SheetContainer({
58
+ className,
59
+ overlayClassName,
60
+ children,
61
+ side = "bottom",
62
+ showCloseButton = true,
63
+ ...props
64
+ }: SheetContainerProps) {
65
+ return (
66
+ <DialogPrimitive.Portal>
67
+ <DialogPrimitive.Overlay
68
+ className={cn("bg-black/50", overlayPositionMap[side], overlayClassName)}
69
+ >
70
+ <DialogPrimitive.Content
71
+ className={cn(
72
+ "relative flex-col bg-background shadow-lg overflow-hidden",
73
+ contentSizeMap[side],
74
+ className
75
+ )}
76
+ {...props}
77
+ >
78
+ {children}
79
+ {showCloseButton && (
80
+ <DialogPrimitive.Close
81
+ className={cn(
82
+ closeButtonPositionMap[side],
83
+ "rounded-pill p-1.5 active:bg-gray-background-soft"
84
+ )}
85
+ >
86
+ <CloseMd size={16} className="text-gray-foreground" />
87
+ </DialogPrimitive.Close>
88
+ )}
89
+ </DialogPrimitive.Content>
90
+ </DialogPrimitive.Overlay>
91
+ </DialogPrimitive.Portal>
92
+ );
93
+ }
94
+
95
+ function SheetContent({
96
+ containerClassName,
97
+ className,
98
+ children,
99
+ }: {
100
+ containerClassName?: string;
101
+ className?: string;
102
+ children: ReactNode;
103
+ }) {
104
+ return (
105
+ <ScrollView
106
+ className={cn("flex-1", containerClassName)}
107
+ contentContainerStyle={{ flexGrow: 1 }}
108
+ >
109
+ <View className={cn("px-6 py-4", className)}>{children}</View>
110
+ </ScrollView>
111
+ );
112
+ }
113
+
114
+ function SheetHeader({ className, separator = false, children, ...props }: SheetHeaderProps) {
115
+ return (
116
+ <>
117
+ <View className={cn("flex-col gap-2 px-6 pt-6 pb-4", className)} {...props}>
118
+ {children}
119
+ </View>
120
+ {separator && <Separator />}
121
+ </>
122
+ );
123
+ }
124
+
125
+ function SheetFooter({ className, separator = false, children, ...props }: SheetFooterProps) {
126
+ return (
127
+ <>
128
+ {separator && <Separator />}
129
+ <View className={cn("flex-col gap-2 px-6 py-5", className)} {...props}>
130
+ {children}
131
+ </View>
132
+ </>
133
+ );
134
+ }
135
+
136
+ function SheetTitle({ className, ...props }: DialogPrimitive.TitleProps) {
137
+ return (
138
+ <DialogPrimitive.Title
139
+ className={cn("text-title-md font-semibold leading-title-md text-content-title", className)}
140
+ {...props}
141
+ />
142
+ );
143
+ }
144
+
145
+ function SheetDescription({ className, ...props }: DialogPrimitive.DescriptionProps) {
146
+ return (
147
+ <DialogPrimitive.Description
148
+ className={cn("text-md leading-md text-content-paragraph", className)}
149
+ {...props}
150
+ />
151
+ );
152
+ }
153
+
154
+ export {
155
+ Sheet,
156
+ SheetClose,
157
+ SheetContainer,
158
+ SheetContent,
159
+ SheetDescription,
160
+ SheetFooter,
161
+ SheetHeader,
162
+ SheetTitle,
163
+ SheetTrigger,
164
+ };
165
+ export type { SheetContainerProps, SheetHeaderProps, SheetFooterProps, SheetSide };
@@ -0,0 +1,138 @@
1
+ import { useState, useEffect, type ReactNode } from "react";
2
+ import { View } from "react-native";
3
+ import * as SwitchPrimitive from "@rn-primitives/switch";
4
+ import Animated, {
5
+ useSharedValue,
6
+ useAnimatedStyle,
7
+ withTiming,
8
+ Easing,
9
+ } from "react-native-reanimated";
10
+ import { cva, type VariantProps } from "class-variance-authority";
11
+ import { cn } from "@/lib/utils";
12
+
13
+ interface SwitchProps extends Omit<SwitchPrimitive.RootProps, "checked" | "onCheckedChange">, VariantProps<typeof switchVariants> {
14
+ checked?: boolean;
15
+ defaultChecked?: boolean;
16
+ onCheckedChange?: (checked: boolean) => void;
17
+ checkedIcon?: ReactNode;
18
+ uncheckedIcon?: ReactNode;
19
+ }
20
+
21
+ const THUMB_SIZES: Record<"sm" | "md" | "lg", number> = {
22
+ sm: 8,
23
+ md: 12,
24
+ lg: 16,
25
+ };
26
+
27
+ const THUMB_TRANSLATE: Record<"sm" | "md" | "lg", number> = {
28
+ sm: 11,
29
+ md: 15,
30
+ lg: 19,
31
+ };
32
+
33
+ const switchVariants = cva(
34
+ "rounded-full border-2 items-center shrink-0",
35
+ {
36
+ variants: {
37
+ variant: {
38
+ regular: "",
39
+ },
40
+ size: {
41
+ sm: "h-4 w-6",
42
+ md: "h-5 w-8",
43
+ lg: "h-6 w-10",
44
+ },
45
+ },
46
+ defaultVariants: {
47
+ variant: "regular",
48
+ size: "md",
49
+ },
50
+ }
51
+ );
52
+
53
+ function Switch({
54
+ className,
55
+ size = "md",
56
+ variant,
57
+ checkedIcon,
58
+ uncheckedIcon,
59
+ checked,
60
+ defaultChecked,
61
+ onCheckedChange,
62
+ disabled,
63
+ ...props
64
+ }: SwitchProps) {
65
+ const resolvedSize = size ?? "md";
66
+ const [internalChecked, setInternalChecked] = useState(defaultChecked ?? false);
67
+ const isControlled = checked !== undefined;
68
+ const isChecked = isControlled ? (checked ?? false) : internalChecked;
69
+
70
+ const translateX = useSharedValue(isChecked ? THUMB_TRANSLATE[resolvedSize] : 2);
71
+
72
+ useEffect(() => {
73
+ translateX.value = withTiming(
74
+ isChecked ? THUMB_TRANSLATE[resolvedSize] : 2,
75
+ { duration: 180, easing: Easing.out(Easing.ease) }
76
+ );
77
+ }, [isChecked, resolvedSize, translateX]);
78
+
79
+ const thumbStyle = useAnimatedStyle(() => ({
80
+ transform: [{ translateX: translateX.value }],
81
+ }));
82
+
83
+ const hasIcons = checkedIcon || uncheckedIcon;
84
+ const thumbSize = THUMB_SIZES[resolvedSize];
85
+
86
+ const handleCheckedChange = (val: boolean) => {
87
+ if (!isControlled) setInternalChecked(val);
88
+ onCheckedChange?.(val);
89
+ };
90
+
91
+ return (
92
+ <SwitchPrimitive.Root
93
+ checked={isChecked}
94
+ onCheckedChange={handleCheckedChange}
95
+ disabled={disabled}
96
+ className={cn(
97
+ switchVariants({ size, variant }),
98
+ disabled
99
+ ? "bg-gray-background-soft-muted border-gray-stroke-muted"
100
+ : isChecked
101
+ ? "bg-primary-background-fill border-transparent"
102
+ : "bg-surface-card border-gray-stroke-muted",
103
+ className
104
+ )}
105
+ {...props}
106
+ >
107
+ <Animated.View
108
+ style={[
109
+ thumbStyle,
110
+ {
111
+ width: thumbSize,
112
+ height: thumbSize,
113
+ borderRadius: thumbSize / 2,
114
+ },
115
+ ]}
116
+ className={cn(
117
+ disabled
118
+ ? "bg-gray-background-fill-muted"
119
+ : hasIcons
120
+ ? "bg-transparent"
121
+ : isChecked
122
+ ? "bg-primary-foreground-onfill"
123
+ : "bg-gray-foreground-muted"
124
+ )}
125
+ >
126
+ {hasIcons && (
127
+ <View className="flex-1 items-center justify-center">
128
+ {isChecked && checkedIcon}
129
+ {!isChecked && uncheckedIcon}
130
+ </View>
131
+ )}
132
+ </Animated.View>
133
+ </SwitchPrimitive.Root>
134
+ );
135
+ }
136
+
137
+ export { Switch, switchVariants };
138
+ export type { SwitchProps };
@@ -0,0 +1,116 @@
1
+ import { type ReactNode, type ReactElement } 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
+ interface TagProps extends ViewProps, VariantProps<typeof tagVariants> {
7
+ icon?: ReactElement;
8
+ children?: ReactNode;
9
+ }
10
+
11
+ const tagVariants = cva(
12
+ "flex-row items-center justify-center rounded-md px-2 py-1 gap-1.5 max-h-6 overflow-hidden shrink-0",
13
+ {
14
+ variants: {
15
+ variant: {
16
+ regular: "bg-primary-background-fill",
17
+ "regular-soft": "bg-primary-background-soft",
18
+ "regular-basic": "bg-transparent",
19
+ emphasis: "bg-secondary-background-fill",
20
+ "emphasis-soft": "bg-secondary-background-soft",
21
+ "emphasis-basic": "bg-transparent",
22
+ gray: "bg-gray-background-fill",
23
+ "gray-soft": "bg-gray-background-soft",
24
+ "gray-basic": "bg-transparent",
25
+ success: "bg-green-background-fill",
26
+ "success-soft": "bg-green-background-soft",
27
+ "success-basic": "bg-transparent",
28
+ error: "bg-red-background-fill",
29
+ "error-soft": "bg-red-background-soft",
30
+ "error-basic": "bg-transparent",
31
+ warning: "bg-yellow-background-fill",
32
+ "warning-soft": "bg-yellow-background-soft",
33
+ "warning-basic": "bg-transparent",
34
+ cm: "bg-cm-background-fill",
35
+ "cm-soft": "bg-cm-background-soft",
36
+ "cm-basic": "bg-transparent",
37
+ go: "bg-go-background-fill",
38
+ "go-soft": "bg-go-background-soft",
39
+ "go-basic": "bg-transparent",
40
+ cir: "bg-cir-background-fill",
41
+ "cir-soft": "bg-cir-background-soft",
42
+ "cir-basic": "bg-transparent",
43
+ ped: "bg-ped-background-fill",
44
+ "ped-soft": "bg-ped-background-soft",
45
+ "ped-basic": "bg-transparent",
46
+ prev: "bg-prev-background-fill",
47
+ "prev-soft": "bg-prev-background-soft",
48
+ "prev-basic": "bg-transparent",
49
+ ia: "bg-secondary-background-fill",
50
+ "ia-soft": "bg-secondary-background-soft",
51
+ "ia-basic": "bg-transparent",
52
+ },
53
+ },
54
+ defaultVariants: { variant: "regular" },
55
+ }
56
+ );
57
+
58
+ const tagTextVariants = cva("text-xs font-semibold", {
59
+ variants: {
60
+ variant: {
61
+ regular: "text-primary-foreground-onfill",
62
+ "regular-soft": "text-primary-foreground",
63
+ "regular-basic": "text-primary-foreground",
64
+ emphasis: "text-secondary-foreground-onfill",
65
+ "emphasis-soft": "text-secondary-foreground",
66
+ "emphasis-basic": "text-secondary-foreground",
67
+ gray: "text-gray-foreground-onfill",
68
+ "gray-soft": "text-gray-foreground",
69
+ "gray-basic": "text-gray-foreground",
70
+ success: "text-green-foreground-onfill",
71
+ "success-soft": "text-green-foreground",
72
+ "success-basic": "text-green-foreground",
73
+ error: "text-red-foreground-onfill",
74
+ "error-soft": "text-red-foreground",
75
+ "error-basic": "text-red-foreground",
76
+ warning: "text-yellow-foreground-onfill",
77
+ "warning-soft": "text-yellow-foreground",
78
+ "warning-basic": "text-yellow-foreground",
79
+ cm: "text-cm-foreground-onfill",
80
+ "cm-soft": "text-cm-foreground",
81
+ "cm-basic": "text-cm-foreground",
82
+ go: "text-go-foreground-onfill",
83
+ "go-soft": "text-go-foreground",
84
+ "go-basic": "text-go-foreground",
85
+ cir: "text-cir-foreground-onfill",
86
+ "cir-soft": "text-cir-foreground",
87
+ "cir-basic": "text-cir-foreground",
88
+ ped: "text-ped-foreground-onfill",
89
+ "ped-soft": "text-ped-foreground",
90
+ "ped-basic": "text-ped-foreground",
91
+ prev: "text-prev-foreground-onfill",
92
+ "prev-soft": "text-prev-foreground",
93
+ "prev-basic": "text-prev-foreground",
94
+ ia: "text-primary-foreground-onfill",
95
+ "ia-soft": "text-secondary-foreground",
96
+ "ia-basic": "text-secondary-foreground",
97
+ },
98
+ },
99
+ defaultVariants: { variant: "regular" },
100
+ });
101
+
102
+ function TagIcon({ icon }: { icon?: ReactNode }) {
103
+ return <View className="w-3.5 h-3.5 items-center justify-center">{icon}</View>;
104
+ }
105
+
106
+ function Tag({ className, variant, icon, children, ...props }: TagProps) {
107
+ return (
108
+ <View className={cn(tagVariants({ variant }), className)} {...props}>
109
+ {icon && <TagIcon icon={icon} />}
110
+ <Text className={cn(tagTextVariants({ variant }))}>{children}</Text>
111
+ </View>
112
+ );
113
+ }
114
+
115
+ export { Tag, tagVariants, tagTextVariants };
116
+ export type { TagProps };