@munchi_oy/native-ui 0.1.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 (83) hide show
  1. package/dist/index.d.mts +568 -0
  2. package/dist/index.d.ts +568 -0
  3. package/dist/index.js +1 -0
  4. package/dist/index.mjs +1 -0
  5. package/global.css +53 -0
  6. package/nativewind-env.d.ts +2 -0
  7. package/package.json +88 -0
  8. package/src/MAlert.tsx +38 -0
  9. package/src/MAnimation.tsx +55 -0
  10. package/src/MAvatar.tsx +111 -0
  11. package/src/MBadge.tsx +72 -0
  12. package/src/MButton.tsx +90 -0
  13. package/src/MCard.tsx +15 -0
  14. package/src/MChevron.tsx +47 -0
  15. package/src/MConfirmation.tsx +68 -0
  16. package/src/MCountDown.tsx +120 -0
  17. package/src/MDateTimePicker.tsx +124 -0
  18. package/src/MDivider.tsx +69 -0
  19. package/src/MDrawerRightPanel.tsx +187 -0
  20. package/src/MDropdown.tsx +277 -0
  21. package/src/MInput.tsx +162 -0
  22. package/src/MLabel.tsx +3 -0
  23. package/src/MLucideIcon.tsx +21 -0
  24. package/src/MModal.tsx +287 -0
  25. package/src/MNativeAlert.tsx +33 -0
  26. package/src/MNumpad.tsx +520 -0
  27. package/src/MPicker.tsx +150 -0
  28. package/src/MPinPadKeys.tsx +104 -0
  29. package/src/MPortal.tsx +4 -0
  30. package/src/MProgressBar.tsx +74 -0
  31. package/src/MRadioGroup.tsx +4 -0
  32. package/src/MRequiredLabel.tsx +21 -0
  33. package/src/MResponsiveContainer.tsx +74 -0
  34. package/src/MSearch.tsx +138 -0
  35. package/src/MSelector.tsx +48 -0
  36. package/src/MSkeleton.tsx +3 -0
  37. package/src/MSwitch.tsx +13 -0
  38. package/src/MTable.tsx +17 -0
  39. package/src/MTabs.tsx +198 -0
  40. package/src/MText.tsx +51 -0
  41. package/src/MTimerUp.tsx +88 -0
  42. package/src/MToggle.tsx +51 -0
  43. package/src/constants.ts +19 -0
  44. package/src/hooks/useColorScheme.tsx +12 -0
  45. package/src/hooks/useIconColors.ts +19 -0
  46. package/src/index.ts +124 -0
  47. package/src/primitives/accordion.tsx +143 -0
  48. package/src/primitives/alert-dialog.tsx +181 -0
  49. package/src/primitives/alert.tsx +94 -0
  50. package/src/primitives/aspect-ratio.tsx +5 -0
  51. package/src/primitives/avatar.tsx +47 -0
  52. package/src/primitives/badge.tsx +57 -0
  53. package/src/primitives/button.tsx +92 -0
  54. package/src/primitives/card.tsx +86 -0
  55. package/src/primitives/checkbox.tsx +35 -0
  56. package/src/primitives/collapsible.tsx +9 -0
  57. package/src/primitives/context-menu.tsx +255 -0
  58. package/src/primitives/dialog.tsx +166 -0
  59. package/src/primitives/dropdown-menu.tsx +264 -0
  60. package/src/primitives/hover-card.tsx +45 -0
  61. package/src/primitives/input.tsx +25 -0
  62. package/src/primitives/label.tsx +33 -0
  63. package/src/primitives/menubar.tsx +266 -0
  64. package/src/primitives/navigation-menu.tsx +192 -0
  65. package/src/primitives/popover.tsx +46 -0
  66. package/src/primitives/progress.tsx +82 -0
  67. package/src/primitives/radio-group.tsx +42 -0
  68. package/src/primitives/select.tsx +192 -0
  69. package/src/primitives/separator.tsx +28 -0
  70. package/src/primitives/skeleton.tsx +39 -0
  71. package/src/primitives/switch.tsx +102 -0
  72. package/src/primitives/table.tsx +107 -0
  73. package/src/primitives/tabs.tsx +66 -0
  74. package/src/primitives/text.tsx +28 -0
  75. package/src/primitives/textarea.tsx +39 -0
  76. package/src/primitives/toggle-group.tsx +89 -0
  77. package/src/primitives/toggle.tsx +91 -0
  78. package/src/primitives/tooltip.tsx +40 -0
  79. package/src/primitives/typography.tsx +214 -0
  80. package/src/theme.ts +43 -0
  81. package/src/tokens.ts +7 -0
  82. package/src/utils.ts +14 -0
  83. package/tailwind.config.ts +112 -0
package/src/MModal.tsx ADDED
@@ -0,0 +1,287 @@
1
+ import { type VariantProps, cva } from "class-variance-authority";
2
+ import { ArrowLeft, X } from "lucide-react-native";
3
+ import {
4
+ Fragment,
5
+ type ReactNode,
6
+ createContext,
7
+ useContext,
8
+ useRef
9
+ } from "react";
10
+ import {
11
+ type GestureResponderEvent,
12
+ KeyboardAvoidingView,
13
+ Modal,
14
+ Platform,
15
+ Pressable,
16
+ ScrollView,
17
+ View,
18
+ type ViewProps
19
+ } from "react-native";
20
+ import { MText } from "./MText";
21
+ import { useIconColors } from "./hooks/useIconColors";
22
+ import { cn } from "./utils";
23
+
24
+ export enum ModalHeight {
25
+ ExtraSmall = "xs",
26
+ Small = "sm",
27
+ Medium = "md",
28
+ Large = "lg",
29
+ ExtraLarge = "xl",
30
+ ExtraExtraLarge = "xxl",
31
+ Auto = "auto"
32
+ }
33
+
34
+ type ModalContextValue = {
35
+ isFixed: boolean;
36
+ };
37
+
38
+ const ModalContext = createContext<ModalContextValue>({ isFixed: false });
39
+ export const ModalScrollContext =
40
+ createContext<React.RefObject<ScrollView | null> | null>(null);
41
+
42
+ const modalVariants = cva("rounded-2xl p-6 shadow-lg flex flex-col", {
43
+ variants: {
44
+ variant: {
45
+ xs: "w-[40%]",
46
+ sm: "w-[60%]",
47
+ md: "w-[80%]",
48
+ lg: "w-[95%]",
49
+ auto: "w-auto self-center",
50
+ fullscreen: "w-full h-full rounded-none"
51
+ },
52
+ height: {
53
+ [ModalHeight.ExtraSmall]: "h-[30%]",
54
+ [ModalHeight.Small]: "h-[40%]",
55
+ [ModalHeight.Medium]: "h-[60%]",
56
+ [ModalHeight.Large]: "h-[80%]",
57
+ [ModalHeight.ExtraLarge]: "h-[90%]",
58
+ [ModalHeight.ExtraExtraLarge]: "h-[96%]",
59
+ [ModalHeight.Auto]: "h-auto"
60
+ },
61
+ background: {
62
+ white: "bg-card",
63
+ dark: "bg-secondary",
64
+ primary: "bg-muted",
65
+ transparent: "bg-transparent"
66
+ }
67
+ },
68
+ defaultVariants: {
69
+ variant: "md",
70
+ height: ModalHeight.Auto,
71
+ background: "white"
72
+ }
73
+ });
74
+
75
+ export interface MModalProps extends VariantProps<typeof modalVariants> {
76
+ isVisible: boolean;
77
+ onClose: () => void;
78
+ onButtonClose?: () => void;
79
+ onBack?: () => void;
80
+ onDismiss?: () => void;
81
+ children: React.ReactNode;
82
+ header?: React.ReactNode;
83
+ headingText?: string;
84
+ containerClassName?: ViewProps["className"];
85
+ closable?: boolean;
86
+ footer?: React.ReactNode;
87
+ showCloseButton?: boolean;
88
+ showBackButton?: boolean;
89
+ keyboardAvoidingEnabled?: boolean;
90
+ }
91
+
92
+ interface ModalBodyProps {
93
+ children: React.ReactNode;
94
+ scrollable?: boolean;
95
+ }
96
+
97
+ const ModalBody = ({ children, scrollable = true }: ModalBodyProps) => {
98
+ const { isFixed } = useContext(ModalContext);
99
+ const scrollViewRef = useContext(ModalScrollContext);
100
+ if (!scrollable) {
101
+ return (
102
+ <View
103
+ className={cn(isFixed && "flex-1")}
104
+ style={isFixed ? { flex: 1 } : undefined}
105
+ >
106
+ <Pressable style={{ flex: 1 }}>{children}</Pressable>
107
+ </View>
108
+ );
109
+ }
110
+ return (
111
+ <View className={cn(isFixed && "flex-1")}>
112
+ <ScrollView
113
+ ref={scrollViewRef}
114
+ showsVerticalScrollIndicator={false}
115
+ contentContainerStyle={{ flexGrow: 1 }}
116
+ keyboardShouldPersistTaps="handled"
117
+ style={isFixed ? { flex: 1 } : undefined}
118
+ >
119
+ <Pressable style={{ flex: 1 }}>{children}</Pressable>
120
+ </ScrollView>
121
+ </View>
122
+ );
123
+ };
124
+
125
+ ModalBody.displayName = "ModalBody";
126
+
127
+ const ModalFooter: React.FC<{ children: React.ReactNode }> = ({ children }) => {
128
+ return <View className="mt-auto flex-shrink-0">{children}</View>;
129
+ };
130
+
131
+ export const ModalContent: React.FC<{
132
+ body: ReactNode;
133
+ footer?: ReactNode;
134
+ }> = ({ body, footer }) => (
135
+ <Fragment>
136
+ <MModal.Body>{body}</MModal.Body>
137
+ {footer && <MModal.Footer>{footer}</MModal.Footer>}
138
+ </Fragment>
139
+ );
140
+
141
+ const MModalComponent: React.FC<MModalProps> = (props) => {
142
+ const {
143
+ isVisible,
144
+ onClose,
145
+ children,
146
+ onBack,
147
+ onDismiss,
148
+ header,
149
+ headingText,
150
+ closable = true,
151
+ variant = "sm",
152
+ containerClassName,
153
+ height,
154
+ background = "white",
155
+ footer,
156
+ onButtonClose,
157
+ showCloseButton = true,
158
+ showBackButton = true,
159
+ keyboardAvoidingEnabled = true
160
+ } = props;
161
+ const isFixed = height && height !== ModalHeight.Auto;
162
+ const contextValue: ModalContextValue = { isFixed: isFixed ?? false };
163
+ const scrollViewRef = useRef<ScrollView>(null);
164
+ const { foreground } = useIconColors();
165
+
166
+ const renderHeader = () => {
167
+ if (onBack && showBackButton) {
168
+ return (
169
+ <View className="flex-row items-center justify-between">
170
+ <Pressable onPress={onBack} className="bg-muted rounded-full p-2">
171
+ <ArrowLeft color={foreground} size={24} />
172
+ </Pressable>
173
+ {headingText && (
174
+ <MText
175
+ className="font-munchi-bold text-foreground flex-1 text-left mx-3"
176
+ size="2xl"
177
+ numberOfLines={1}
178
+ >
179
+ {headingText}
180
+ </MText>
181
+ )}
182
+
183
+ {showCloseButton && (
184
+ <Pressable onPress={onClose} className="bg-muted rounded-full p-3">
185
+ <X color={foreground} size={24} />
186
+ </Pressable>
187
+ )}
188
+ </View>
189
+ );
190
+ }
191
+
192
+ if (header) {
193
+ return header;
194
+ }
195
+
196
+ if (headingText) {
197
+ return (
198
+ <View className="flex-row items-center justify-between">
199
+ <MText
200
+ className="font-munchi-bold text-foreground w-11/12"
201
+ size="2xl"
202
+ numberOfLines={1}
203
+ >
204
+ {headingText}
205
+ </MText>
206
+ {showCloseButton && (
207
+ <Pressable
208
+ onPress={onButtonClose ?? onClose}
209
+ className="bg-muted rounded-full p-3"
210
+ >
211
+ <X color={foreground} size={24} />
212
+ </Pressable>
213
+ )}
214
+ </View>
215
+ );
216
+ }
217
+
218
+ if (showCloseButton) {
219
+ return (
220
+ <View className="flex-row items-center justify-between">
221
+ <View className="flex-1" />
222
+ <Pressable onPress={onClose} className="bg-muted rounded-full p-3">
223
+ <X color={foreground} size={24} />
224
+ </Pressable>
225
+ </View>
226
+ );
227
+ }
228
+
229
+ return null;
230
+ };
231
+ const handleBackdropPress = (event: GestureResponderEvent) => {
232
+ if (event.target === event.currentTarget && closable) {
233
+ onClose();
234
+ }
235
+ };
236
+
237
+ return (
238
+ <Modal
239
+ transparent
240
+ visible={isVisible}
241
+ onRequestClose={closable ? onClose : undefined}
242
+ animationType="fade"
243
+ onDismiss={onDismiss}
244
+ >
245
+ <KeyboardAvoidingView
246
+ className="flex-1"
247
+ enabled={keyboardAvoidingEnabled}
248
+ behavior={Platform.select({
249
+ ios: "padding",
250
+ default: "height"
251
+ })}
252
+ >
253
+ <Pressable
254
+ className="flex-1 items-center justify-center bg-black/50 p-4"
255
+ onPress={handleBackdropPress}
256
+ >
257
+ <View
258
+ className={cn(
259
+ "max-h-[95%]",
260
+ modalVariants({ variant, height, background }),
261
+ containerClassName
262
+ )}
263
+ >
264
+ <ModalContext.Provider value={contextValue}>
265
+ <ModalScrollContext.Provider value={scrollViewRef}>
266
+ {renderHeader() !== null && (
267
+ <View className="pb-4 flex-shrink-0">{renderHeader()}</View>
268
+ )}
269
+ {children}
270
+ {footer && <ModalFooter>{footer}</ModalFooter>}
271
+ </ModalScrollContext.Provider>
272
+ </ModalContext.Provider>
273
+ </View>
274
+ </Pressable>
275
+ </KeyboardAvoidingView>
276
+ </Modal>
277
+ );
278
+ };
279
+
280
+ export const MModal = Object.assign(MModalComponent, {
281
+ Body: ModalBody,
282
+ Footer: ModalFooter
283
+ });
284
+
285
+ MModal.displayName = "MModal";
286
+
287
+ export default MModal;
@@ -0,0 +1,33 @@
1
+ import { Alert } from "react-native";
2
+
3
+ export interface MNativeAlertProps {
4
+ title: string;
5
+ description: string;
6
+ onPress: () => void;
7
+ onPressText: string;
8
+ onCancel: () => void;
9
+ onCancelText: string;
10
+ }
11
+
12
+ export const MNativeAlert = ({
13
+ title,
14
+ description,
15
+ onPress,
16
+ onPressText,
17
+ onCancel,
18
+ onCancelText
19
+ }: MNativeAlertProps) => {
20
+ Alert.alert(title, description, [
21
+ {
22
+ text: onPressText,
23
+ onPress
24
+ },
25
+ {
26
+ text: onCancelText,
27
+ style: "cancel",
28
+ onPress: onCancel
29
+ }
30
+ ]);
31
+ };
32
+
33
+ MNativeAlert.displayName = "MNativeAlert";