@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.
- package/dist/index.d.mts +568 -0
- package/dist/index.d.ts +568 -0
- package/dist/index.js +1 -0
- package/dist/index.mjs +1 -0
- package/global.css +53 -0
- package/nativewind-env.d.ts +2 -0
- package/package.json +88 -0
- package/src/MAlert.tsx +38 -0
- package/src/MAnimation.tsx +55 -0
- package/src/MAvatar.tsx +111 -0
- package/src/MBadge.tsx +72 -0
- package/src/MButton.tsx +90 -0
- package/src/MCard.tsx +15 -0
- package/src/MChevron.tsx +47 -0
- package/src/MConfirmation.tsx +68 -0
- package/src/MCountDown.tsx +120 -0
- package/src/MDateTimePicker.tsx +124 -0
- package/src/MDivider.tsx +69 -0
- package/src/MDrawerRightPanel.tsx +187 -0
- package/src/MDropdown.tsx +277 -0
- package/src/MInput.tsx +162 -0
- package/src/MLabel.tsx +3 -0
- package/src/MLucideIcon.tsx +21 -0
- package/src/MModal.tsx +287 -0
- package/src/MNativeAlert.tsx +33 -0
- package/src/MNumpad.tsx +520 -0
- package/src/MPicker.tsx +150 -0
- package/src/MPinPadKeys.tsx +104 -0
- package/src/MPortal.tsx +4 -0
- package/src/MProgressBar.tsx +74 -0
- package/src/MRadioGroup.tsx +4 -0
- package/src/MRequiredLabel.tsx +21 -0
- package/src/MResponsiveContainer.tsx +74 -0
- package/src/MSearch.tsx +138 -0
- package/src/MSelector.tsx +48 -0
- package/src/MSkeleton.tsx +3 -0
- package/src/MSwitch.tsx +13 -0
- package/src/MTable.tsx +17 -0
- package/src/MTabs.tsx +198 -0
- package/src/MText.tsx +51 -0
- package/src/MTimerUp.tsx +88 -0
- package/src/MToggle.tsx +51 -0
- package/src/constants.ts +19 -0
- package/src/hooks/useColorScheme.tsx +12 -0
- package/src/hooks/useIconColors.ts +19 -0
- package/src/index.ts +124 -0
- package/src/primitives/accordion.tsx +143 -0
- package/src/primitives/alert-dialog.tsx +181 -0
- package/src/primitives/alert.tsx +94 -0
- package/src/primitives/aspect-ratio.tsx +5 -0
- package/src/primitives/avatar.tsx +47 -0
- package/src/primitives/badge.tsx +57 -0
- package/src/primitives/button.tsx +92 -0
- package/src/primitives/card.tsx +86 -0
- package/src/primitives/checkbox.tsx +35 -0
- package/src/primitives/collapsible.tsx +9 -0
- package/src/primitives/context-menu.tsx +255 -0
- package/src/primitives/dialog.tsx +166 -0
- package/src/primitives/dropdown-menu.tsx +264 -0
- package/src/primitives/hover-card.tsx +45 -0
- package/src/primitives/input.tsx +25 -0
- package/src/primitives/label.tsx +33 -0
- package/src/primitives/menubar.tsx +266 -0
- package/src/primitives/navigation-menu.tsx +192 -0
- package/src/primitives/popover.tsx +46 -0
- package/src/primitives/progress.tsx +82 -0
- package/src/primitives/radio-group.tsx +42 -0
- package/src/primitives/select.tsx +192 -0
- package/src/primitives/separator.tsx +28 -0
- package/src/primitives/skeleton.tsx +39 -0
- package/src/primitives/switch.tsx +102 -0
- package/src/primitives/table.tsx +107 -0
- package/src/primitives/tabs.tsx +66 -0
- package/src/primitives/text.tsx +28 -0
- package/src/primitives/textarea.tsx +39 -0
- package/src/primitives/toggle-group.tsx +89 -0
- package/src/primitives/toggle.tsx +91 -0
- package/src/primitives/tooltip.tsx +40 -0
- package/src/primitives/typography.tsx +214 -0
- package/src/theme.ts +43 -0
- package/src/tokens.ts +7 -0
- package/src/utils.ts +14 -0
- 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";
|