@urbint/cl 1.0.1

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 (206) hide show
  1. package/.cursor/rules +313 -0
  2. package/.rnstorybook/index.ts +11 -0
  3. package/.rnstorybook/main.ts +8 -0
  4. package/.rnstorybook/preview.tsx +14 -0
  5. package/.rnstorybook/storybook.requires.ts +49 -0
  6. package/.storybook/main.ts +16 -0
  7. package/.storybook/preview.ts +32 -0
  8. package/.storybook/vitest.setup.ts +7 -0
  9. package/App.tsx +422 -0
  10. package/README.md +229 -0
  11. package/app.json +33 -0
  12. package/assets/adaptive-icon.png +0 -0
  13. package/assets/favicon.png +0 -0
  14. package/assets/icon.png +0 -0
  15. package/assets/splash-icon.png +0 -0
  16. package/babel.config.js +16 -0
  17. package/docs/components/CodeBlock.tsx +80 -0
  18. package/docs/components/PropTable.tsx +93 -0
  19. package/docs/components/Sidebar.tsx +199 -0
  20. package/docs/components/index.ts +8 -0
  21. package/docs/data/colorTokens.ts +70 -0
  22. package/docs/data/componentData.tsx +1685 -0
  23. package/docs/data/index.ts +7 -0
  24. package/docs/index.ts +19 -0
  25. package/docs/navigation.ts +94 -0
  26. package/docs/pages/ColorsPage.tsx +226 -0
  27. package/docs/pages/ComponentPage.tsx +235 -0
  28. package/docs/pages/InstallationPage.tsx +232 -0
  29. package/docs/pages/IntroductionPage.tsx +163 -0
  30. package/docs/pages/ThemingPage.tsx +251 -0
  31. package/docs/pages/index.ts +10 -0
  32. package/docs/theme.ts +64 -0
  33. package/docs/types.ts +54 -0
  34. package/index.ts +8 -0
  35. package/llms.txt +1893 -0
  36. package/mcp-config.example.json +10 -0
  37. package/mcp-server/README.md +192 -0
  38. package/mcp-server/package-lock.json +1707 -0
  39. package/mcp-server/package.json +38 -0
  40. package/mcp-server/src/index.ts +1136 -0
  41. package/mcp-server/src/registry/components.ts +1446 -0
  42. package/mcp-server/src/registry/index.ts +3 -0
  43. package/mcp-server/src/registry/tokens.ts +256 -0
  44. package/mcp-server/tsconfig.json +19 -0
  45. package/package.json +92 -0
  46. package/src/components/Accordion/Accordion.stories.tsx +226 -0
  47. package/src/components/Accordion/Accordion.tsx +255 -0
  48. package/src/components/Accordion/index.ts +12 -0
  49. package/src/components/ActionSheet/ActionSheet.stories.tsx +393 -0
  50. package/src/components/ActionSheet/ActionSheet.tsx +258 -0
  51. package/src/components/ActionSheet/index.ts +2 -0
  52. package/src/components/Alert/Alert.stories.tsx +165 -0
  53. package/src/components/Alert/Alert.tsx +164 -0
  54. package/src/components/Alert/index.ts +2 -0
  55. package/src/components/AlertDialog/AlertDialog.stories.tsx +330 -0
  56. package/src/components/AlertDialog/AlertDialog.tsx +234 -0
  57. package/src/components/AlertDialog/index.ts +2 -0
  58. package/src/components/Avatar/Avatar.stories.tsx +154 -0
  59. package/src/components/Avatar/Avatar.tsx +219 -0
  60. package/src/components/Avatar/index.ts +2 -0
  61. package/src/components/Badge/Badge.stories.tsx +146 -0
  62. package/src/components/Badge/Badge.tsx +125 -0
  63. package/src/components/Badge/index.ts +2 -0
  64. package/src/components/Box/Box.stories.tsx +192 -0
  65. package/src/components/Box/Box.tsx +184 -0
  66. package/src/components/Box/index.ts +2 -0
  67. package/src/components/Button/Button.stories.tsx +157 -0
  68. package/src/components/Button/Button.tsx +180 -0
  69. package/src/components/Button/index.ts +2 -0
  70. package/src/components/Card/Card.stories.tsx +145 -0
  71. package/src/components/Card/Card.tsx +169 -0
  72. package/src/components/Card/index.ts +11 -0
  73. package/src/components/Center/Center.stories.tsx +215 -0
  74. package/src/components/Center/Center.tsx +29 -0
  75. package/src/components/Center/index.ts +2 -0
  76. package/src/components/Checkbox/Checkbox.stories.tsx +94 -0
  77. package/src/components/Checkbox/Checkbox.tsx +242 -0
  78. package/src/components/Checkbox/index.ts +2 -0
  79. package/src/components/DatePicker/DatePicker.stories.tsx +623 -0
  80. package/src/components/DatePicker/DatePicker.tsx +1228 -0
  81. package/src/components/DatePicker/index.ts +8 -0
  82. package/src/components/Divider/Divider.stories.tsx +224 -0
  83. package/src/components/Divider/Divider.tsx +73 -0
  84. package/src/components/Divider/index.ts +2 -0
  85. package/src/components/Drawer/Drawer.stories.tsx +414 -0
  86. package/src/components/Drawer/Drawer.tsx +342 -0
  87. package/src/components/Drawer/index.ts +11 -0
  88. package/src/components/Fab/Fab.stories.tsx +360 -0
  89. package/src/components/Fab/Fab.tsx +185 -0
  90. package/src/components/Fab/index.ts +2 -0
  91. package/src/components/FormControl/FormControl.stories.tsx +276 -0
  92. package/src/components/FormControl/FormControl.tsx +185 -0
  93. package/src/components/FormControl/index.ts +12 -0
  94. package/src/components/Grid/Grid.stories.tsx +244 -0
  95. package/src/components/Grid/Grid.tsx +93 -0
  96. package/src/components/Grid/index.ts +2 -0
  97. package/src/components/HStack/HStack.stories.tsx +230 -0
  98. package/src/components/HStack/HStack.tsx +80 -0
  99. package/src/components/HStack/index.ts +2 -0
  100. package/src/components/Heading/Heading.stories.tsx +111 -0
  101. package/src/components/Heading/Heading.tsx +85 -0
  102. package/src/components/Heading/index.ts +2 -0
  103. package/src/components/Icon/Icon.stories.tsx +320 -0
  104. package/src/components/Icon/Icon.tsx +117 -0
  105. package/src/components/Icon/index.ts +2 -0
  106. package/src/components/Image/Image.stories.tsx +357 -0
  107. package/src/components/Image/Image.tsx +168 -0
  108. package/src/components/Image/index.ts +2 -0
  109. package/src/components/Input/Input.stories.tsx +164 -0
  110. package/src/components/Input/Input.tsx +274 -0
  111. package/src/components/Input/index.ts +2 -0
  112. package/src/components/Link/Link.stories.tsx +187 -0
  113. package/src/components/Link/Link.tsx +104 -0
  114. package/src/components/Link/index.ts +2 -0
  115. package/src/components/Menu/Menu.stories.tsx +363 -0
  116. package/src/components/Menu/Menu.tsx +238 -0
  117. package/src/components/Menu/index.ts +2 -0
  118. package/src/components/Modal/Modal.stories.tsx +156 -0
  119. package/src/components/Modal/Modal.tsx +280 -0
  120. package/src/components/Modal/index.ts +11 -0
  121. package/src/components/Popover/Popover.stories.tsx +330 -0
  122. package/src/components/Popover/Popover.tsx +315 -0
  123. package/src/components/Popover/index.ts +11 -0
  124. package/src/components/Portal/Portal.stories.tsx +376 -0
  125. package/src/components/Portal/Portal.tsx +100 -0
  126. package/src/components/Portal/index.ts +2 -0
  127. package/src/components/Pressable/Pressable.stories.tsx +338 -0
  128. package/src/components/Pressable/Pressable.tsx +71 -0
  129. package/src/components/Pressable/index.ts +2 -0
  130. package/src/components/Progress/Progress.stories.tsx +131 -0
  131. package/src/components/Progress/Progress.tsx +219 -0
  132. package/src/components/Progress/index.ts +2 -0
  133. package/src/components/Radio/Radio.stories.tsx +101 -0
  134. package/src/components/Radio/Radio.tsx +234 -0
  135. package/src/components/Radio/index.ts +2 -0
  136. package/src/components/Select/Select.stories.tsx +908 -0
  137. package/src/components/Select/Select.tsx +659 -0
  138. package/src/components/Select/index.ts +8 -0
  139. package/src/components/Skeleton/Skeleton.stories.tsx +154 -0
  140. package/src/components/Skeleton/Skeleton.tsx +192 -0
  141. package/src/components/Skeleton/index.ts +8 -0
  142. package/src/components/Slider/Slider.stories.tsx +363 -0
  143. package/src/components/Slider/Slider.tsx +209 -0
  144. package/src/components/Slider/index.ts +2 -0
  145. package/src/components/Spinner/Spinner.stories.tsx +108 -0
  146. package/src/components/Spinner/Spinner.tsx +121 -0
  147. package/src/components/Spinner/index.ts +2 -0
  148. package/src/components/Switch/Switch.stories.tsx +116 -0
  149. package/src/components/Switch/Switch.tsx +172 -0
  150. package/src/components/Switch/index.ts +2 -0
  151. package/src/components/Table/Table.stories.tsx +417 -0
  152. package/src/components/Table/Table.tsx +233 -0
  153. package/src/components/Table/index.ts +2 -0
  154. package/src/components/Text/Text.stories.tsx +93 -0
  155. package/src/components/Text/Text.tsx +119 -0
  156. package/src/components/Text/index.ts +2 -0
  157. package/src/components/Textarea/Textarea.stories.tsx +280 -0
  158. package/src/components/Textarea/Textarea.tsx +212 -0
  159. package/src/components/Textarea/index.ts +2 -0
  160. package/src/components/Toast/Toast.stories.tsx +446 -0
  161. package/src/components/Toast/Toast.tsx +221 -0
  162. package/src/components/Toast/index.ts +2 -0
  163. package/src/components/Tooltip/Tooltip.stories.tsx +354 -0
  164. package/src/components/Tooltip/Tooltip.tsx +261 -0
  165. package/src/components/Tooltip/index.ts +2 -0
  166. package/src/components/VStack/VStack.stories.tsx +183 -0
  167. package/src/components/VStack/VStack.tsx +76 -0
  168. package/src/components/VStack/index.ts +2 -0
  169. package/src/components/index.ts +62 -0
  170. package/src/hooks/index.ts +7 -0
  171. package/src/hooks/useControllableState.ts +41 -0
  172. package/src/hooks/useDisclosure.ts +51 -0
  173. package/src/index.ts +22 -0
  174. package/src/stories/Button.stories.tsx +53 -0
  175. package/src/stories/Button.tsx +101 -0
  176. package/src/stories/Configure.mdx +364 -0
  177. package/src/stories/Header.stories.tsx +33 -0
  178. package/src/stories/Header.tsx +75 -0
  179. package/src/stories/Page.stories.tsx +25 -0
  180. package/src/stories/Page.tsx +154 -0
  181. package/src/stories/assets/accessibility.png +0 -0
  182. package/src/stories/assets/accessibility.svg +1 -0
  183. package/src/stories/assets/addon-library.png +0 -0
  184. package/src/stories/assets/assets.png +0 -0
  185. package/src/stories/assets/avif-test-image.avif +0 -0
  186. package/src/stories/assets/context.png +0 -0
  187. package/src/stories/assets/discord.svg +1 -0
  188. package/src/stories/assets/docs.png +0 -0
  189. package/src/stories/assets/figma-plugin.png +0 -0
  190. package/src/stories/assets/github.svg +1 -0
  191. package/src/stories/assets/share.png +0 -0
  192. package/src/stories/assets/styling.png +0 -0
  193. package/src/stories/assets/testing.png +0 -0
  194. package/src/stories/assets/theming.png +0 -0
  195. package/src/stories/assets/tutorials.svg +1 -0
  196. package/src/stories/assets/youtube.svg +1 -0
  197. package/src/styles/index.ts +7 -0
  198. package/src/styles/tokens.ts +318 -0
  199. package/src/styles/unistyles.ts +254 -0
  200. package/src/utils/createContext.tsx +25 -0
  201. package/src/utils/index.ts +7 -0
  202. package/src/utils/mergeRefs.ts +21 -0
  203. package/tsconfig.json +26 -0
  204. package/urbint-cl-1.0.0.tgz +0 -0
  205. package/vitest.config.ts +37 -0
  206. package/vitest.shims.d.ts +1 -0
@@ -0,0 +1,156 @@
1
+ import type { Meta, StoryObj } from '@storybook/react';
2
+ import React from 'react';
3
+ import { View, StyleSheet } from 'react-native';
4
+ import { Modal, ModalHeader, ModalBody, ModalFooter } from './Modal';
5
+ import { Button } from '../Button';
6
+ import { VStack } from '../VStack';
7
+ import { Text } from '../Text';
8
+ import { Input } from '../Input';
9
+ import { colors, spacing, borderRadius } from '../../styles/tokens';
10
+
11
+ /**
12
+ * Story container with design system tokens
13
+ */
14
+ const StoryContainer: React.FC<{ children: React.ReactNode }> = ({ children }) => (
15
+ <View style={styles.container}>{children}</View>
16
+ );
17
+
18
+ const meta: Meta<typeof Modal> = {
19
+ title: 'Components/Modal',
20
+ component: Modal,
21
+ decorators: [
22
+ (Story) => (
23
+ <StoryContainer>
24
+ <Story />
25
+ </StoryContainer>
26
+ ),
27
+ ],
28
+ };
29
+
30
+ export default meta;
31
+
32
+ type Story = StoryObj<typeof Modal>;
33
+
34
+ export const Default: Story = {
35
+ render: () => {
36
+ const [isOpen, setIsOpen] = React.useState(false);
37
+
38
+ return (
39
+ <VStack>
40
+ <Button onPress={() => setIsOpen(true)}>Open Modal</Button>
41
+ <Modal isOpen={isOpen} onClose={() => setIsOpen(false)}>
42
+ <ModalHeader>Modal Title</ModalHeader>
43
+ <ModalBody>
44
+ <Text>
45
+ This is the modal content. You can add any content here including
46
+ forms, images, or other components.
47
+ </Text>
48
+ </ModalBody>
49
+ <ModalFooter>
50
+ <Button variant="ghost" onPress={() => setIsOpen(false)}>Cancel</Button>
51
+ <Button onPress={() => setIsOpen(false)}>Confirm</Button>
52
+ </ModalFooter>
53
+ </Modal>
54
+ </VStack>
55
+ );
56
+ },
57
+ };
58
+
59
+ export const Sizes: Story = {
60
+ render: () => {
61
+ const [size, setSize] = React.useState<'sm' | 'md' | 'lg' | 'xl' | null>(null);
62
+
63
+ return (
64
+ <VStack space={spacing.sm}>
65
+ <Text weight="semiBold">Modal Sizes</Text>
66
+ <VStack space={spacing.sm}>
67
+ <Button size="sm" onPress={() => setSize('sm')}>Small</Button>
68
+ <Button size="sm" onPress={() => setSize('md')}>Medium</Button>
69
+ <Button size="sm" onPress={() => setSize('lg')}>Large</Button>
70
+ <Button size="sm" onPress={() => setSize('xl')}>Extra Large</Button>
71
+ </VStack>
72
+ <Modal isOpen={size !== null} onClose={() => setSize(null)} size={size || 'md'}>
73
+ <ModalHeader>{size?.toUpperCase()} Modal</ModalHeader>
74
+ <ModalBody>
75
+ <Text>This is a {size} sized modal.</Text>
76
+ </ModalBody>
77
+ <ModalFooter>
78
+ <Button onPress={() => setSize(null)}>Close</Button>
79
+ </ModalFooter>
80
+ </Modal>
81
+ </VStack>
82
+ );
83
+ },
84
+ };
85
+
86
+ export const FormModal: Story = {
87
+ render: () => {
88
+ const [isOpen, setIsOpen] = React.useState(false);
89
+
90
+ return (
91
+ <VStack>
92
+ <Button onPress={() => setIsOpen(true)}>Create Account</Button>
93
+ <Modal isOpen={isOpen} onClose={() => setIsOpen(false)} size="md">
94
+ <ModalHeader>Create New Account</ModalHeader>
95
+ <ModalBody>
96
+ <VStack space={spacing.lg}>
97
+ <Input label="Full Name" placeholder="Enter your name" />
98
+ <Input label="Email" placeholder="Enter your email" />
99
+ <Input label="Password" placeholder="Enter password" isPassword />
100
+ </VStack>
101
+ </ModalBody>
102
+ <ModalFooter>
103
+ <Button variant="ghost" onPress={() => setIsOpen(false)}>Cancel</Button>
104
+ <Button onPress={() => setIsOpen(false)}>Create Account</Button>
105
+ </ModalFooter>
106
+ </Modal>
107
+ </VStack>
108
+ );
109
+ },
110
+ };
111
+
112
+ export const ScrollableContent: Story = {
113
+ render: () => {
114
+ const [isOpen, setIsOpen] = React.useState(false);
115
+
116
+ return (
117
+ <VStack>
118
+ <Button onPress={() => setIsOpen(true)}>Terms & Conditions</Button>
119
+ <Modal
120
+ isOpen={isOpen}
121
+ onClose={() => setIsOpen(false)}
122
+ scrollBehavior="inside"
123
+ >
124
+ <ModalHeader>Terms and Conditions</ModalHeader>
125
+ <ModalBody>
126
+ <VStack space={spacing.md}>
127
+ {Array.from({ length: 10 }).map((_, i) => (
128
+ <Text key={i}>
129
+ Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do
130
+ eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut
131
+ enim ad minim veniam, quis nostrud exercitation ullamco laboris.
132
+ </Text>
133
+ ))}
134
+ </VStack>
135
+ </ModalBody>
136
+ <ModalFooter>
137
+ <Button variant="ghost" onPress={() => setIsOpen(false)}>Decline</Button>
138
+ <Button onPress={() => setIsOpen(false)}>Accept</Button>
139
+ </ModalFooter>
140
+ </Modal>
141
+ </VStack>
142
+ );
143
+ },
144
+ };
145
+
146
+ /**
147
+ * Styles using design system tokens
148
+ */
149
+ const styles = StyleSheet.create({
150
+ container: {
151
+ padding: spacing.lg,
152
+ backgroundColor: colors.background.default,
153
+ borderRadius: borderRadius.lg,
154
+ },
155
+ });
156
+
@@ -0,0 +1,280 @@
1
+ /**
2
+ * Modal Component
3
+ * Overlay dialog for content
4
+ */
5
+
6
+ import React, { forwardRef, useRef, useEffect } from 'react';
7
+ import {
8
+ View,
9
+ ViewProps,
10
+ Modal as RNModal,
11
+ Pressable,
12
+ Text,
13
+ Animated,
14
+ ScrollView,
15
+ KeyboardAvoidingView,
16
+ Platform,
17
+ StyleSheet,
18
+ } from 'react-native';
19
+ import Svg, { Path } from 'react-native-svg';
20
+ import { colors, spacing, borderRadius, typography, elevation } from '../../styles/tokens';
21
+
22
+ export interface ModalProps extends ViewProps {
23
+ /** Is open */
24
+ isOpen: boolean;
25
+ /** On close handler */
26
+ onClose: () => void;
27
+ /** Close on overlay click */
28
+ closeOnOverlayClick?: boolean;
29
+ /** Modal size */
30
+ size?: 'sm' | 'md' | 'lg' | 'xl' | 'full';
31
+ /** Show close button */
32
+ showCloseButton?: boolean;
33
+ /** Scroll behavior */
34
+ scrollBehavior?: 'inside' | 'outside';
35
+ /** Is centered */
36
+ isCentered?: boolean;
37
+ /** Motion preset */
38
+ motionPreset?: 'slideInBottom' | 'scale' | 'none';
39
+ }
40
+
41
+ export const Modal = forwardRef<View, ModalProps>(
42
+ (
43
+ {
44
+ style,
45
+ isOpen,
46
+ onClose,
47
+ closeOnOverlayClick = true,
48
+ size = 'md',
49
+ showCloseButton = true,
50
+ scrollBehavior = 'outside',
51
+ isCentered = true,
52
+ motionPreset = 'scale',
53
+ children,
54
+ ...props
55
+ },
56
+ ref
57
+ ) => {
58
+ const scaleAnim = useRef(new Animated.Value(motionPreset === 'scale' ? 0.9 : 1)).current;
59
+ const translateYAnim = useRef(new Animated.Value(motionPreset === 'slideInBottom' ? 100 : 0)).current;
60
+ const opacityAnim = useRef(new Animated.Value(0)).current;
61
+
62
+ useEffect(() => {
63
+ if (isOpen) {
64
+ Animated.parallel([
65
+ ...(motionPreset === 'scale'
66
+ ? [
67
+ Animated.spring(scaleAnim, {
68
+ toValue: 1,
69
+ useNativeDriver: true,
70
+ tension: 50,
71
+ friction: 7,
72
+ }),
73
+ ]
74
+ : []),
75
+ ...(motionPreset === 'slideInBottom'
76
+ ? [
77
+ Animated.spring(translateYAnim, {
78
+ toValue: 0,
79
+ useNativeDriver: true,
80
+ tension: 50,
81
+ friction: 7,
82
+ }),
83
+ ]
84
+ : []),
85
+ Animated.timing(opacityAnim, {
86
+ toValue: 1,
87
+ duration: 200,
88
+ useNativeDriver: true,
89
+ }),
90
+ ]).start();
91
+ } else {
92
+ scaleAnim.setValue(motionPreset === 'scale' ? 0.9 : 1);
93
+ translateYAnim.setValue(motionPreset === 'slideInBottom' ? 100 : 0);
94
+ opacityAnim.setValue(0);
95
+ }
96
+ }, [isOpen, motionPreset]);
97
+
98
+ const sizeStyles = {
99
+ sm: { maxWidth: 320 },
100
+ md: { maxWidth: 448 },
101
+ lg: { maxWidth: 512 },
102
+ xl: { maxWidth: 640 },
103
+ full: { maxWidth: '100%', margin: 0, borderRadius: 0, height: '100%' },
104
+ };
105
+
106
+ const ModalContent = (
107
+ <Animated.View
108
+ ref={ref}
109
+ style={[
110
+ styles.modal,
111
+ sizeStyles[size],
112
+ {
113
+ transform: [
114
+ { scale: scaleAnim },
115
+ { translateY: translateYAnim },
116
+ ],
117
+ opacity: opacityAnim,
118
+ },
119
+ style,
120
+ ]}
121
+ {...props}
122
+ >
123
+ {showCloseButton && (
124
+ <Pressable onPress={onClose} style={styles.closeButton}>
125
+ <Svg width={24} height={24} viewBox="0 0 24 24" fill="none">
126
+ <Path
127
+ d="M18 6L6 18M6 6l12 12"
128
+ stroke={colors.text.secondary}
129
+ strokeWidth={2}
130
+ strokeLinecap="round"
131
+ strokeLinejoin="round"
132
+ />
133
+ </Svg>
134
+ </Pressable>
135
+ )}
136
+ {scrollBehavior === 'inside' ? (
137
+ <ScrollView contentContainerStyle={styles.scrollContent}>
138
+ {children}
139
+ </ScrollView>
140
+ ) : (
141
+ children
142
+ )}
143
+ </Animated.View>
144
+ );
145
+
146
+ return (
147
+ <RNModal
148
+ visible={isOpen}
149
+ transparent
150
+ animationType="fade"
151
+ onRequestClose={onClose}
152
+ >
153
+ <KeyboardAvoidingView
154
+ behavior={Platform.OS === 'ios' ? 'padding' : 'height'}
155
+ style={styles.keyboardView}
156
+ >
157
+ {scrollBehavior === 'outside' ? (
158
+ <ScrollView
159
+ contentContainerStyle={[
160
+ styles.overlay,
161
+ isCentered && styles.centered,
162
+ ]}
163
+ >
164
+ <Pressable
165
+ style={StyleSheet.absoluteFillObject}
166
+ onPress={closeOnOverlayClick ? onClose : undefined}
167
+ />
168
+ {ModalContent}
169
+ </ScrollView>
170
+ ) : (
171
+ <Pressable
172
+ style={[styles.overlay, isCentered && styles.centered]}
173
+ onPress={closeOnOverlayClick ? onClose : undefined}
174
+ >
175
+ <Pressable>{ModalContent}</Pressable>
176
+ </Pressable>
177
+ )}
178
+ </KeyboardAvoidingView>
179
+ </RNModal>
180
+ );
181
+ }
182
+ );
183
+
184
+ Modal.displayName = 'Modal';
185
+
186
+ export interface ModalHeaderProps extends ViewProps {}
187
+ export interface ModalBodyProps extends ViewProps {}
188
+ export interface ModalFooterProps extends ViewProps {}
189
+
190
+ export const ModalHeader = forwardRef<View, ModalHeaderProps>(
191
+ ({ style, children, ...props }, ref) => {
192
+ return (
193
+ <View ref={ref} style={[styles.header, style]} {...props}>
194
+ {typeof children === 'string' ? (
195
+ <Text style={styles.headerText}>{children}</Text>
196
+ ) : (
197
+ children
198
+ )}
199
+ </View>
200
+ );
201
+ }
202
+ );
203
+
204
+ ModalHeader.displayName = 'ModalHeader';
205
+
206
+ export const ModalBody = forwardRef<View, ModalBodyProps>(
207
+ ({ style, children, ...props }, ref) => {
208
+ return (
209
+ <View ref={ref} style={[styles.body, style]} {...props}>
210
+ {children}
211
+ </View>
212
+ );
213
+ }
214
+ );
215
+
216
+ ModalBody.displayName = 'ModalBody';
217
+
218
+ export const ModalFooter = forwardRef<View, ModalFooterProps>(
219
+ ({ style, children, ...props }, ref) => {
220
+ return (
221
+ <View ref={ref} style={[styles.footer, style]} {...props}>
222
+ {children}
223
+ </View>
224
+ );
225
+ }
226
+ );
227
+
228
+ ModalFooter.displayName = 'ModalFooter';
229
+
230
+ const styles = StyleSheet.create({
231
+ keyboardView: {
232
+ flex: 1,
233
+ },
234
+ overlay: {
235
+ flexGrow: 1,
236
+ backgroundColor: 'rgba(0, 0, 0, 0.5)',
237
+ padding: spacing['4x'],
238
+ },
239
+ centered: {
240
+ justifyContent: 'center',
241
+ alignItems: 'center',
242
+ },
243
+ modal: {
244
+ backgroundColor: colors.background.default,
245
+ borderRadius: borderRadius.lg,
246
+ width: '100%',
247
+ ...elevation['40'],
248
+ },
249
+ closeButton: {
250
+ position: 'absolute',
251
+ top: spacing['3x'],
252
+ right: spacing['3x'],
253
+ zIndex: 1,
254
+ padding: spacing.base,
255
+ },
256
+ scrollContent: {
257
+ flexGrow: 1,
258
+ },
259
+ header: {
260
+ padding: spacing['4x'],
261
+ paddingBottom: spacing['2x'],
262
+ paddingRight: spacing['12x'],
263
+ },
264
+ headerText: {
265
+ fontSize: typography.fontSize.h3,
266
+ fontWeight: typography.fontWeight.semiBold,
267
+ color: colors.text.default,
268
+ },
269
+ body: {
270
+ padding: spacing['4x'],
271
+ paddingTop: spacing['2x'],
272
+ },
273
+ footer: {
274
+ flexDirection: 'row',
275
+ justifyContent: 'flex-end',
276
+ padding: spacing['4x'],
277
+ paddingTop: spacing['2x'],
278
+ gap: spacing['2x'],
279
+ },
280
+ });
@@ -0,0 +1,11 @@
1
+ export {
2
+ Modal,
3
+ ModalHeader,
4
+ ModalBody,
5
+ ModalFooter,
6
+ type ModalProps,
7
+ type ModalHeaderProps,
8
+ type ModalBodyProps,
9
+ type ModalFooterProps,
10
+ } from './Modal';
11
+