@campxdev/react-native-blueprint 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/LICENSE +20 -0
- package/README.md +358 -0
- package/lib/module/app/_layout.js +23 -0
- package/lib/module/app/_layout.js.map +1 -0
- package/lib/module/assets/icons/weather_icons/drizzle.png +0 -0
- package/lib/module/assets/icons/weather_icons/foggy.png +0 -0
- package/lib/module/assets/icons/weather_icons/freezing_rain.png +0 -0
- package/lib/module/assets/icons/weather_icons/partly_cloudy.png +0 -0
- package/lib/module/assets/icons/weather_icons/rainy.png +0 -0
- package/lib/module/assets/icons/weather_icons/showers.png +0 -0
- package/lib/module/assets/icons/weather_icons/sunny_weather.png +0 -0
- package/lib/module/assets/icons/weather_icons/thunderstorm.png +0 -0
- package/lib/module/assets/icons/weather_icons/thunderstorm_hail.png +0 -0
- package/lib/module/components/theme-config.js +265 -0
- package/lib/module/components/theme-config.js.map +1 -0
- package/lib/module/components/ui/Accordion.js +228 -0
- package/lib/module/components/ui/Accordion.js.map +1 -0
- package/lib/module/components/ui/Alert-Dialog.js +266 -0
- package/lib/module/components/ui/Alert-Dialog.js.map +1 -0
- package/lib/module/components/ui/Alert.js +107 -0
- package/lib/module/components/ui/Alert.js.map +1 -0
- package/lib/module/components/ui/AppBar.js +403 -0
- package/lib/module/components/ui/AppBar.js.map +1 -0
- package/lib/module/components/ui/Aspect-Ratio.js +27 -0
- package/lib/module/components/ui/Aspect-Ratio.js.map +1 -0
- package/lib/module/components/ui/Avatar.js +97 -0
- package/lib/module/components/ui/Avatar.js.map +1 -0
- package/lib/module/components/ui/Badge.js +127 -0
- package/lib/module/components/ui/Badge.js.map +1 -0
- package/lib/module/components/ui/Bottom-Sheet.js +144 -0
- package/lib/module/components/ui/Bottom-Sheet.js.map +1 -0
- package/lib/module/components/ui/Button.js +88 -0
- package/lib/module/components/ui/Button.js.map +1 -0
- package/lib/module/components/ui/Card.js +176 -0
- package/lib/module/components/ui/Card.js.map +1 -0
- package/lib/module/components/ui/Checkbox.js +65 -0
- package/lib/module/components/ui/Checkbox.js.map +1 -0
- package/lib/module/components/ui/Collapsible.js +42 -0
- package/lib/module/components/ui/Collapsible.js.map +1 -0
- package/lib/module/components/ui/Context-Menu.js +287 -0
- package/lib/module/components/ui/Context-Menu.js.map +1 -0
- package/lib/module/components/ui/Custom-Card.js +202 -0
- package/lib/module/components/ui/Custom-Card.js.map +1 -0
- package/lib/module/components/ui/Dialog.js +202 -0
- package/lib/module/components/ui/Dialog.js.map +1 -0
- package/lib/module/components/ui/Dropdown-Menu.js +421 -0
- package/lib/module/components/ui/Dropdown-Menu.js.map +1 -0
- package/lib/module/components/ui/Floating-Action.js +50 -0
- package/lib/module/components/ui/Floating-Action.js.map +1 -0
- package/lib/module/components/ui/Greeting-Card.js +392 -0
- package/lib/module/components/ui/Greeting-Card.js.map +1 -0
- package/lib/module/components/ui/Hover-Card.js +96 -0
- package/lib/module/components/ui/Hover-Card.js.map +1 -0
- package/lib/module/components/ui/Icon.js +73 -0
- package/lib/module/components/ui/Icon.js.map +1 -0
- package/lib/module/components/ui/Input.js +74 -0
- package/lib/module/components/ui/Input.js.map +1 -0
- package/lib/module/components/ui/Label.js +44 -0
- package/lib/module/components/ui/Label.js.map +1 -0
- package/lib/module/components/ui/Menubar.js +375 -0
- package/lib/module/components/ui/Menubar.js.map +1 -0
- package/lib/module/components/ui/Native-Only-Animated-View.js +41 -0
- package/lib/module/components/ui/Native-Only-Animated-View.js.map +1 -0
- package/lib/module/components/ui/NavBar.js +352 -0
- package/lib/module/components/ui/NavBar.js.map +1 -0
- package/lib/module/components/ui/Popover.js +101 -0
- package/lib/module/components/ui/Popover.js.map +1 -0
- package/lib/module/components/ui/Progress.js +124 -0
- package/lib/module/components/ui/Progress.js.map +1 -0
- package/lib/module/components/ui/Radio-Group.js +75 -0
- package/lib/module/components/ui/Radio-Group.js.map +1 -0
- package/lib/module/components/ui/Select.js +269 -0
- package/lib/module/components/ui/Select.js.map +1 -0
- package/lib/module/components/ui/Separator.js +58 -0
- package/lib/module/components/ui/Separator.js.map +1 -0
- package/lib/module/components/ui/SizedBox.js +101 -0
- package/lib/module/components/ui/SizedBox.js.map +1 -0
- package/lib/module/components/ui/Skeleton.js +57 -0
- package/lib/module/components/ui/Skeleton.js.map +1 -0
- package/lib/module/components/ui/Slider.js +169 -0
- package/lib/module/components/ui/Slider.js.map +1 -0
- package/lib/module/components/ui/Switch.js +55 -0
- package/lib/module/components/ui/Switch.js.map +1 -0
- package/lib/module/components/ui/Table.js +150 -0
- package/lib/module/components/ui/Table.js.map +1 -0
- package/lib/module/components/ui/Tabs.js +106 -0
- package/lib/module/components/ui/Tabs.js.map +1 -0
- package/lib/module/components/ui/Text.js +69 -0
- package/lib/module/components/ui/Text.js.map +1 -0
- package/lib/module/components/ui/Textarea.js +88 -0
- package/lib/module/components/ui/Textarea.js.map +1 -0
- package/lib/module/components/ui/Theme-Toggle.js +156 -0
- package/lib/module/components/ui/Theme-Toggle.js.map +1 -0
- package/lib/module/components/ui/Toast.js +101 -0
- package/lib/module/components/ui/Toast.js.map +1 -0
- package/lib/module/components/ui/Toggle-Group.js +129 -0
- package/lib/module/components/ui/Toggle-Group.js.map +1 -0
- package/lib/module/components/ui/Toggle.js +106 -0
- package/lib/module/components/ui/Toggle.js.map +1 -0
- package/lib/module/components/ui/Tooltip.js +106 -0
- package/lib/module/components/ui/Tooltip.js.map +1 -0
- package/lib/module/components/ui/index.js +45 -0
- package/lib/module/components/ui/index.js.map +1 -0
- package/lib/module/index.js +19 -0
- package/lib/module/index.js.map +1 -0
- package/lib/module/lib/ThemeProvider.js +173 -0
- package/lib/module/lib/ThemeProvider.js.map +1 -0
- package/lib/module/lib/cornerRadius.js +164 -0
- package/lib/module/lib/cornerRadius.js.map +1 -0
- package/lib/module/lib/fonts.js +25 -0
- package/lib/module/lib/fonts.js.map +1 -0
- package/lib/module/lib/theme.js +212 -0
- package/lib/module/lib/theme.js.map +1 -0
- package/lib/module/lib/utils.js +137 -0
- package/lib/module/lib/utils.js.map +1 -0
- package/lib/module/package.json +1 -0
- package/package.json +208 -0
- package/src/app/_layout.tsx +25 -0
- package/src/assets/icons/weather_icons/drizzle.png +0 -0
- package/src/assets/icons/weather_icons/foggy.png +0 -0
- package/src/assets/icons/weather_icons/freezing_rain.png +0 -0
- package/src/assets/icons/weather_icons/partly_cloudy.png +0 -0
- package/src/assets/icons/weather_icons/rainy.png +0 -0
- package/src/assets/icons/weather_icons/showers.png +0 -0
- package/src/assets/icons/weather_icons/sunny_weather.png +0 -0
- package/src/assets/icons/weather_icons/thunderstorm.png +0 -0
- package/src/assets/icons/weather_icons/thunderstorm_hail.png +0 -0
- package/src/components/theme-config.ts +331 -0
- package/src/components/ui/Accordion.tsx +253 -0
- package/src/components/ui/Alert-Dialog.tsx +295 -0
- package/src/components/ui/Alert.tsx +137 -0
- package/src/components/ui/AppBar.tsx +551 -0
- package/src/components/ui/Aspect-Ratio.tsx +25 -0
- package/src/components/ui/Avatar.tsx +103 -0
- package/src/components/ui/Badge.tsx +121 -0
- package/src/components/ui/Bottom-Sheet.tsx +224 -0
- package/src/components/ui/Button.tsx +100 -0
- package/src/components/ui/Card.tsx +185 -0
- package/src/components/ui/Checkbox.tsx +81 -0
- package/src/components/ui/Collapsible.tsx +40 -0
- package/src/components/ui/Context-Menu.tsx +407 -0
- package/src/components/ui/Custom-Card.tsx +226 -0
- package/src/components/ui/Dialog.tsx +240 -0
- package/src/components/ui/Dropdown-Menu.tsx +544 -0
- package/src/components/ui/Floating-Action.tsx +54 -0
- package/src/components/ui/Greeting-Card.tsx +471 -0
- package/src/components/ui/Hover-Card.tsx +101 -0
- package/src/components/ui/Icon.tsx +75 -0
- package/src/components/ui/Input.tsx +90 -0
- package/src/components/ui/Label.tsx +48 -0
- package/src/components/ui/Menubar.tsx +509 -0
- package/src/components/ui/Native-Only-Animated-View.tsx +37 -0
- package/src/components/ui/NavBar.tsx +397 -0
- package/src/components/ui/Popover.tsx +110 -0
- package/src/components/ui/Progress.tsx +138 -0
- package/src/components/ui/Radio-Group.tsx +79 -0
- package/src/components/ui/Select.tsx +344 -0
- package/src/components/ui/Separator.tsx +68 -0
- package/src/components/ui/SizedBox.tsx +116 -0
- package/src/components/ui/Skeleton.tsx +55 -0
- package/src/components/ui/Slider.tsx +222 -0
- package/src/components/ui/Switch.tsx +67 -0
- package/src/components/ui/Table.tsx +170 -0
- package/src/components/ui/Tabs.tsx +119 -0
- package/src/components/ui/Text.tsx +73 -0
- package/src/components/ui/Textarea.tsx +93 -0
- package/src/components/ui/Theme-Toggle.tsx +204 -0
- package/src/components/ui/Toast.tsx +127 -0
- package/src/components/ui/Toggle-Group.tsx +160 -0
- package/src/components/ui/Toggle.tsx +122 -0
- package/src/components/ui/Tooltip.tsx +117 -0
- package/src/components/ui/index.ts +42 -0
- package/src/index.tsx +24 -0
- package/src/lib/ThemeProvider.tsx +204 -0
- package/src/lib/cornerRadius.ts +160 -0
- package/src/lib/fonts.ts +28 -0
- package/src/lib/theme.ts +151 -0
- package/src/lib/utils.ts +146 -0
|
@@ -0,0 +1,544 @@
|
|
|
1
|
+
import { Icon } from './Icon';
|
|
2
|
+
import { NativeOnlyAnimatedView } from './Native-Only-Animated-View';
|
|
3
|
+
import { TextClassContext } from './Text';
|
|
4
|
+
import { cn } from '../../lib/utils';
|
|
5
|
+
import * as DropdownMenuPrimitive from '@rn-primitives/dropdown-menu';
|
|
6
|
+
import {
|
|
7
|
+
Check,
|
|
8
|
+
ChevronDown,
|
|
9
|
+
ChevronRight,
|
|
10
|
+
ChevronUp,
|
|
11
|
+
} from 'lucide-react-native';
|
|
12
|
+
import * as React from 'react';
|
|
13
|
+
import {
|
|
14
|
+
Platform,
|
|
15
|
+
type StyleProp,
|
|
16
|
+
StyleSheet,
|
|
17
|
+
Text,
|
|
18
|
+
type TextProps,
|
|
19
|
+
View,
|
|
20
|
+
type ViewStyle,
|
|
21
|
+
} from 'react-native';
|
|
22
|
+
import { cssInterop } from 'nativewind';
|
|
23
|
+
import { FadeIn } from 'react-native-reanimated';
|
|
24
|
+
import { FullWindowOverlay as RNFullWindowOverlay } from 'react-native-screens';
|
|
25
|
+
|
|
26
|
+
cssInterop(View, { className: 'style' });
|
|
27
|
+
cssInterop(Text, { className: 'style' });
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Root component for dropdown menu - provides context for all dropdown menu children
|
|
31
|
+
*
|
|
32
|
+
* @component
|
|
33
|
+
* @example
|
|
34
|
+
* ```tsx
|
|
35
|
+
* <DropdownMenu>
|
|
36
|
+
* <DropdownMenuTrigger>
|
|
37
|
+
* <Button variant="outline">
|
|
38
|
+
* <Text>Open Menu</Text>
|
|
39
|
+
* </Button>
|
|
40
|
+
* </DropdownMenuTrigger>
|
|
41
|
+
* <DropdownMenuContent>
|
|
42
|
+
* <DropdownMenuItem>
|
|
43
|
+
* <Text>Profile</Text>
|
|
44
|
+
* </DropdownMenuItem>
|
|
45
|
+
* </DropdownMenuContent>
|
|
46
|
+
* </DropdownMenu>
|
|
47
|
+
* ```
|
|
48
|
+
*/
|
|
49
|
+
const DropdownMenu = DropdownMenuPrimitive.Root;
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Trigger component that opens the dropdown menu when pressed
|
|
53
|
+
*
|
|
54
|
+
* @component
|
|
55
|
+
*/
|
|
56
|
+
const DropdownMenuTrigger = DropdownMenuPrimitive.Trigger;
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Groups related menu items together
|
|
60
|
+
*
|
|
61
|
+
* @component
|
|
62
|
+
*/
|
|
63
|
+
const DropdownMenuGroup = DropdownMenuPrimitive.Group;
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Portal component to render menu content outside the DOM hierarchy
|
|
67
|
+
*
|
|
68
|
+
* @component
|
|
69
|
+
*/
|
|
70
|
+
const DropdownMenuPortal = DropdownMenuPrimitive.Portal;
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Root component for nested submenu
|
|
74
|
+
*
|
|
75
|
+
* @component
|
|
76
|
+
*/
|
|
77
|
+
const DropdownMenuSub = DropdownMenuPrimitive.Sub;
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Groups radio items together with single selection
|
|
81
|
+
*
|
|
82
|
+
* @component
|
|
83
|
+
*/
|
|
84
|
+
const DropdownMenuRadioGroup = DropdownMenuPrimitive.RadioGroup;
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Trigger for opening a nested submenu
|
|
88
|
+
*
|
|
89
|
+
* Displays a chevron icon that indicates expandable content. The icon direction
|
|
90
|
+
* changes based on platform and submenu state.
|
|
91
|
+
*
|
|
92
|
+
* @component
|
|
93
|
+
* @example
|
|
94
|
+
* ```tsx
|
|
95
|
+
* <DropdownMenuSub>
|
|
96
|
+
* <DropdownMenuSubTrigger>
|
|
97
|
+
* <Text>More Options</Text>
|
|
98
|
+
* </DropdownMenuSubTrigger>
|
|
99
|
+
* <DropdownMenuSubContent>
|
|
100
|
+
* <DropdownMenuItem>
|
|
101
|
+
* <Text>Nested Item</Text>
|
|
102
|
+
* </DropdownMenuItem>
|
|
103
|
+
* </DropdownMenuSubContent>
|
|
104
|
+
* </DropdownMenuSub>
|
|
105
|
+
* ```
|
|
106
|
+
*/
|
|
107
|
+
function DropdownMenuSubTrigger({
|
|
108
|
+
className: _className,
|
|
109
|
+
inset,
|
|
110
|
+
children,
|
|
111
|
+
iconClassName,
|
|
112
|
+
...props
|
|
113
|
+
}: DropdownMenuPrimitive.SubTriggerProps &
|
|
114
|
+
React.RefAttributes<DropdownMenuPrimitive.SubTriggerRef> & {
|
|
115
|
+
children?: React.ReactNode;
|
|
116
|
+
iconClassName?: string;
|
|
117
|
+
inset?: boolean;
|
|
118
|
+
}) {
|
|
119
|
+
const { open } = DropdownMenuPrimitive.useSubContext();
|
|
120
|
+
const icon =
|
|
121
|
+
Platform.OS === 'web' ? ChevronRight : open ? ChevronUp : ChevronDown;
|
|
122
|
+
return (
|
|
123
|
+
<TextClassContext.Provider
|
|
124
|
+
value={cn(
|
|
125
|
+
'text-sm select-none group-active:text-accent-foreground',
|
|
126
|
+
open && 'text-accent-foreground'
|
|
127
|
+
)}
|
|
128
|
+
>
|
|
129
|
+
<DropdownMenuPrimitive.SubTrigger
|
|
130
|
+
className={cn(
|
|
131
|
+
'active:bg-accent group flex flex-row items-center rounded-sm px-2 py-2 sm:py-1.5',
|
|
132
|
+
Platform.select({
|
|
133
|
+
web: 'focus:bg-accent focus:text-accent-foreground cursor-default outline-none [&_svg]:pointer-events-none',
|
|
134
|
+
}),
|
|
135
|
+
open && 'bg-accent',
|
|
136
|
+
inset && 'pl-8'
|
|
137
|
+
)}
|
|
138
|
+
{...props}
|
|
139
|
+
>
|
|
140
|
+
<>{children}</>
|
|
141
|
+
<Icon
|
|
142
|
+
as={icon}
|
|
143
|
+
className={cn(
|
|
144
|
+
'text-foreground ml-auto size-4 shrink-0',
|
|
145
|
+
iconClassName
|
|
146
|
+
)}
|
|
147
|
+
/>
|
|
148
|
+
</DropdownMenuPrimitive.SubTrigger>
|
|
149
|
+
</TextClassContext.Provider>
|
|
150
|
+
);
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
/**
|
|
154
|
+
* Content container for nested submenu items
|
|
155
|
+
*
|
|
156
|
+
* @component
|
|
157
|
+
* @example
|
|
158
|
+
* ```tsx
|
|
159
|
+
* <DropdownMenuSubContent>
|
|
160
|
+
* <DropdownMenuItem>
|
|
161
|
+
* <Text>Submenu Item</Text>
|
|
162
|
+
* </DropdownMenuItem>
|
|
163
|
+
* </DropdownMenuSubContent>
|
|
164
|
+
* ```
|
|
165
|
+
*/
|
|
166
|
+
function DropdownMenuSubContent({
|
|
167
|
+
className,
|
|
168
|
+
...props
|
|
169
|
+
}: DropdownMenuPrimitive.SubContentProps &
|
|
170
|
+
React.RefAttributes<DropdownMenuPrimitive.SubContentRef>) {
|
|
171
|
+
return (
|
|
172
|
+
<NativeOnlyAnimatedView entering={FadeIn}>
|
|
173
|
+
<DropdownMenuPrimitive.SubContent
|
|
174
|
+
className={cn(
|
|
175
|
+
'bg-popover border-border overflow-hidden rounded-md border p-1 shadow-lg shadow-black/5',
|
|
176
|
+
Platform.select({
|
|
177
|
+
web: 'animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 fade-in-0 data-[state=closed]:zoom-out-95 zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 origin-(--radix-context-menu-content-transform-origin) z-50 min-w-[8rem]',
|
|
178
|
+
}),
|
|
179
|
+
className
|
|
180
|
+
)}
|
|
181
|
+
{...props}
|
|
182
|
+
/>
|
|
183
|
+
</NativeOnlyAnimatedView>
|
|
184
|
+
);
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
/**
|
|
188
|
+
* Full window overlay wrapper for iOS, Fragment for other platforms
|
|
189
|
+
*/
|
|
190
|
+
const FullWindowOverlay =
|
|
191
|
+
Platform.OS === 'ios' ? RNFullWindowOverlay : React.Fragment;
|
|
192
|
+
|
|
193
|
+
/**
|
|
194
|
+
* Main content container for dropdown menu items
|
|
195
|
+
*
|
|
196
|
+
* Renders menu items in a popover with proper positioning, animations,
|
|
197
|
+
* and overlay handling. Uses a portal to render outside the parent hierarchy.
|
|
198
|
+
*
|
|
199
|
+
* @component
|
|
200
|
+
* @example
|
|
201
|
+
* ```tsx
|
|
202
|
+
* <DropdownMenuContent>
|
|
203
|
+
* <DropdownMenuItem>
|
|
204
|
+
* <Text>Profile</Text>
|
|
205
|
+
* </DropdownMenuItem>
|
|
206
|
+
* <DropdownMenuSeparator />
|
|
207
|
+
* <DropdownMenuItem>
|
|
208
|
+
* <Text>Settings</Text>
|
|
209
|
+
* </DropdownMenuItem>
|
|
210
|
+
* </DropdownMenuContent>
|
|
211
|
+
* ```
|
|
212
|
+
*
|
|
213
|
+
* @accessibility
|
|
214
|
+
* - Properly handles focus management
|
|
215
|
+
* - Supports keyboard navigation
|
|
216
|
+
* - Screen reader friendly menu structure
|
|
217
|
+
*/
|
|
218
|
+
function DropdownMenuContent({
|
|
219
|
+
className,
|
|
220
|
+
overlayClassName,
|
|
221
|
+
overlayStyle,
|
|
222
|
+
portalHost,
|
|
223
|
+
...props
|
|
224
|
+
}: DropdownMenuPrimitive.ContentProps &
|
|
225
|
+
React.RefAttributes<DropdownMenuPrimitive.ContentRef> & {
|
|
226
|
+
overlayStyle?: StyleProp<ViewStyle>;
|
|
227
|
+
overlayClassName?: string;
|
|
228
|
+
portalHost?: string;
|
|
229
|
+
}) {
|
|
230
|
+
return (
|
|
231
|
+
<DropdownMenuPrimitive.Portal hostName={portalHost}>
|
|
232
|
+
<FullWindowOverlay>
|
|
233
|
+
<DropdownMenuPrimitive.Overlay
|
|
234
|
+
style={Platform.select({
|
|
235
|
+
web: overlayStyle ?? undefined,
|
|
236
|
+
native: overlayStyle
|
|
237
|
+
? StyleSheet.flatten([
|
|
238
|
+
StyleSheet.absoluteFill,
|
|
239
|
+
overlayStyle as typeof StyleSheet.absoluteFill,
|
|
240
|
+
])
|
|
241
|
+
: StyleSheet.absoluteFill,
|
|
242
|
+
})}
|
|
243
|
+
className={overlayClassName}
|
|
244
|
+
>
|
|
245
|
+
<NativeOnlyAnimatedView entering={FadeIn}>
|
|
246
|
+
<TextClassContext.Provider value="text-popover-foreground">
|
|
247
|
+
<DropdownMenuPrimitive.Content
|
|
248
|
+
className={cn(
|
|
249
|
+
'bg-popover border-border min-w-[8rem] overflow-hidden rounded-md border p-1 shadow-lg shadow-black/5',
|
|
250
|
+
Platform.select({
|
|
251
|
+
web: cn(
|
|
252
|
+
'animate-in fade-in-0 zoom-in-95 max-h-(--radix-context-menu-content-available-height) origin-(--radix-context-menu-content-transform-origin) z-50 cursor-default',
|
|
253
|
+
props.side === 'bottom' && 'slide-in-from-top-2',
|
|
254
|
+
props.side === 'top' && 'slide-in-from-bottom-2'
|
|
255
|
+
),
|
|
256
|
+
}),
|
|
257
|
+
className
|
|
258
|
+
)}
|
|
259
|
+
{...props}
|
|
260
|
+
/>
|
|
261
|
+
</TextClassContext.Provider>
|
|
262
|
+
</NativeOnlyAnimatedView>
|
|
263
|
+
</DropdownMenuPrimitive.Overlay>
|
|
264
|
+
</FullWindowOverlay>
|
|
265
|
+
</DropdownMenuPrimitive.Portal>
|
|
266
|
+
);
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
/**
|
|
270
|
+
* Individual menu item component
|
|
271
|
+
*
|
|
272
|
+
* Supports both default and destructive variants for different actions.
|
|
273
|
+
* Includes proper hover, active, and focus states.
|
|
274
|
+
*
|
|
275
|
+
* @component
|
|
276
|
+
* @example
|
|
277
|
+
* ```tsx
|
|
278
|
+
* <DropdownMenuItem onSelect={() => console.log('Selected')}>
|
|
279
|
+
* <Text>Edit Profile</Text>
|
|
280
|
+
* </DropdownMenuItem>
|
|
281
|
+
*
|
|
282
|
+
* <DropdownMenuItem variant="destructive">
|
|
283
|
+
* <Text>Delete Account</Text>
|
|
284
|
+
* </DropdownMenuItem>
|
|
285
|
+
* ```
|
|
286
|
+
*
|
|
287
|
+
* @accessibility
|
|
288
|
+
* - Disabled items cannot be interacted with
|
|
289
|
+
* - Proper focus indicators on web
|
|
290
|
+
*/
|
|
291
|
+
function DropdownMenuItem({
|
|
292
|
+
className,
|
|
293
|
+
inset,
|
|
294
|
+
variant,
|
|
295
|
+
...props
|
|
296
|
+
}: DropdownMenuPrimitive.ItemProps &
|
|
297
|
+
React.RefAttributes<DropdownMenuPrimitive.ItemRef> & {
|
|
298
|
+
className?: string;
|
|
299
|
+
inset?: boolean;
|
|
300
|
+
variant?: 'default' | 'destructive';
|
|
301
|
+
}) {
|
|
302
|
+
return (
|
|
303
|
+
<TextClassContext.Provider
|
|
304
|
+
value={cn(
|
|
305
|
+
'select-none text-sm text-popover-foreground group-active:text-popover-foreground',
|
|
306
|
+
variant === 'destructive' &&
|
|
307
|
+
'text-destructive group-active:text-destructive'
|
|
308
|
+
)}
|
|
309
|
+
>
|
|
310
|
+
<DropdownMenuPrimitive.Item
|
|
311
|
+
className={cn(
|
|
312
|
+
'active:bg-accent group relative flex flex-row items-center gap-2 rounded-sm px-2 py-2 sm:py-1.5',
|
|
313
|
+
Platform.select({
|
|
314
|
+
web: cn(
|
|
315
|
+
'focus:bg-accent focus:text-accent-foreground cursor-default outline-none data-[disabled]:pointer-events-none',
|
|
316
|
+
variant === 'destructive' &&
|
|
317
|
+
'focus:bg-destructive/10 dark:focus:bg-destructive/20'
|
|
318
|
+
),
|
|
319
|
+
}),
|
|
320
|
+
variant === 'destructive' &&
|
|
321
|
+
'active:bg-destructive/10 dark:active:bg-destructive/20',
|
|
322
|
+
props.disabled && 'opacity-50',
|
|
323
|
+
inset && 'pl-8',
|
|
324
|
+
className
|
|
325
|
+
)}
|
|
326
|
+
{...props}
|
|
327
|
+
/>
|
|
328
|
+
</TextClassContext.Provider>
|
|
329
|
+
);
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
/**
|
|
333
|
+
* Menu item with checkbox for multi-selection
|
|
334
|
+
*
|
|
335
|
+
* Shows a checkmark when selected. Useful for toggling multiple options.
|
|
336
|
+
*
|
|
337
|
+
* @component
|
|
338
|
+
* @example
|
|
339
|
+
* ```tsx
|
|
340
|
+
* <DropdownMenuCheckboxItem
|
|
341
|
+
* checked={showPanel}
|
|
342
|
+
* onCheckedChange={setShowPanel}
|
|
343
|
+
* >
|
|
344
|
+
* <Text>Show Side Panel</Text>
|
|
345
|
+
* </DropdownMenuCheckboxItem>
|
|
346
|
+
* ```
|
|
347
|
+
*/
|
|
348
|
+
function DropdownMenuCheckboxItem({
|
|
349
|
+
className,
|
|
350
|
+
children,
|
|
351
|
+
...props
|
|
352
|
+
}: DropdownMenuPrimitive.CheckboxItemProps &
|
|
353
|
+
React.RefAttributes<DropdownMenuPrimitive.CheckboxItemRef> & {
|
|
354
|
+
children?: React.ReactNode;
|
|
355
|
+
}) {
|
|
356
|
+
return (
|
|
357
|
+
<TextClassContext.Provider value="text-sm text-popover-foreground select-none group-active:text-accent-foreground">
|
|
358
|
+
<DropdownMenuPrimitive.CheckboxItem
|
|
359
|
+
className={cn(
|
|
360
|
+
'active:bg-accent group relative flex flex-row items-center gap-2 rounded-sm py-2 pl-8 pr-2 sm:py-1.5',
|
|
361
|
+
Platform.select({
|
|
362
|
+
web: 'focus:bg-accent focus:text-accent-foreground cursor-default outline-none data-[disabled]:pointer-events-none',
|
|
363
|
+
}),
|
|
364
|
+
props.disabled && 'opacity-50',
|
|
365
|
+
className
|
|
366
|
+
)}
|
|
367
|
+
{...props}
|
|
368
|
+
>
|
|
369
|
+
<View className="absolute left-2 flex h-3.5 w-3.5 items-center justify-center">
|
|
370
|
+
<DropdownMenuPrimitive.ItemIndicator>
|
|
371
|
+
<Icon
|
|
372
|
+
as={Check}
|
|
373
|
+
className={cn(
|
|
374
|
+
'text-foreground size-4',
|
|
375
|
+
Platform.select({ web: 'pointer-events-none' })
|
|
376
|
+
)}
|
|
377
|
+
/>
|
|
378
|
+
</DropdownMenuPrimitive.ItemIndicator>
|
|
379
|
+
</View>
|
|
380
|
+
<>{children}</>
|
|
381
|
+
</DropdownMenuPrimitive.CheckboxItem>
|
|
382
|
+
</TextClassContext.Provider>
|
|
383
|
+
);
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
/**
|
|
387
|
+
* Menu item with radio button for single selection within a group
|
|
388
|
+
*
|
|
389
|
+
* Shows a filled circle when selected. Use within DropdownMenuRadioGroup.
|
|
390
|
+
*
|
|
391
|
+
* @component
|
|
392
|
+
* @example
|
|
393
|
+
* ```tsx
|
|
394
|
+
* <DropdownMenuRadioGroup value={sortBy} onValueChange={setSortBy}>
|
|
395
|
+
* <DropdownMenuRadioItem value="name">
|
|
396
|
+
* <Text>Sort by Name</Text>
|
|
397
|
+
* </DropdownMenuRadioItem>
|
|
398
|
+
* <DropdownMenuRadioItem value="date">
|
|
399
|
+
* <Text>Sort by Date</Text>
|
|
400
|
+
* </DropdownMenuRadioItem>
|
|
401
|
+
* </DropdownMenuRadioGroup>
|
|
402
|
+
* ```
|
|
403
|
+
*/
|
|
404
|
+
function DropdownMenuRadioItem({
|
|
405
|
+
className,
|
|
406
|
+
children,
|
|
407
|
+
...props
|
|
408
|
+
}: DropdownMenuPrimitive.RadioItemProps &
|
|
409
|
+
React.RefAttributes<DropdownMenuPrimitive.RadioItemRef> & {
|
|
410
|
+
children?: React.ReactNode;
|
|
411
|
+
}) {
|
|
412
|
+
return (
|
|
413
|
+
<TextClassContext.Provider value="text-sm text-popover-foreground select-none group-active:text-accent-foreground">
|
|
414
|
+
<DropdownMenuPrimitive.RadioItem
|
|
415
|
+
className={cn(
|
|
416
|
+
'active:bg-accent group relative flex flex-row items-center gap-2 rounded-sm py-2 pl-8 pr-2 sm:py-1.5',
|
|
417
|
+
Platform.select({
|
|
418
|
+
web: 'focus:bg-accent focus:text-accent-foreground cursor-default outline-none data-[disabled]:pointer-events-none',
|
|
419
|
+
}),
|
|
420
|
+
props.disabled && 'opacity-50',
|
|
421
|
+
className
|
|
422
|
+
)}
|
|
423
|
+
{...props}
|
|
424
|
+
>
|
|
425
|
+
<View className="absolute left-2 flex h-3.5 w-3.5 items-center justify-center">
|
|
426
|
+
<DropdownMenuPrimitive.ItemIndicator>
|
|
427
|
+
<View className="bg-foreground h-2 w-2 rounded-full" />
|
|
428
|
+
</DropdownMenuPrimitive.ItemIndicator>
|
|
429
|
+
</View>
|
|
430
|
+
<>{children}</>
|
|
431
|
+
</DropdownMenuPrimitive.RadioItem>
|
|
432
|
+
</TextClassContext.Provider>
|
|
433
|
+
);
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
/**
|
|
437
|
+
* Label component for grouping and describing menu sections
|
|
438
|
+
*
|
|
439
|
+
* @component
|
|
440
|
+
* @example
|
|
441
|
+
* ```tsx
|
|
442
|
+
* <DropdownMenuLabel>
|
|
443
|
+
* <Text>Account</Text>
|
|
444
|
+
* </DropdownMenuLabel>
|
|
445
|
+
* <DropdownMenuItem>
|
|
446
|
+
* <Text>Profile</Text>
|
|
447
|
+
* </DropdownMenuItem>
|
|
448
|
+
* ```
|
|
449
|
+
*/
|
|
450
|
+
function DropdownMenuLabel({
|
|
451
|
+
className,
|
|
452
|
+
inset,
|
|
453
|
+
...props
|
|
454
|
+
}: DropdownMenuPrimitive.LabelProps &
|
|
455
|
+
React.RefAttributes<DropdownMenuPrimitive.LabelRef> & {
|
|
456
|
+
className?: string;
|
|
457
|
+
inset?: boolean;
|
|
458
|
+
}) {
|
|
459
|
+
return (
|
|
460
|
+
<DropdownMenuPrimitive.Label
|
|
461
|
+
className={cn(
|
|
462
|
+
'text-foreground px-2 py-2 text-sm font-medium sm:py-1.5',
|
|
463
|
+
inset && 'pl-8',
|
|
464
|
+
className
|
|
465
|
+
)}
|
|
466
|
+
{...props}
|
|
467
|
+
/>
|
|
468
|
+
);
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
/**
|
|
472
|
+
* Visual separator between menu items or sections
|
|
473
|
+
*
|
|
474
|
+
* @component
|
|
475
|
+
* @example
|
|
476
|
+
* ```tsx
|
|
477
|
+
* <DropdownMenuItem>
|
|
478
|
+
* <Text>Edit</Text>
|
|
479
|
+
* </DropdownMenuItem>
|
|
480
|
+
* <DropdownMenuSeparator />
|
|
481
|
+
* <DropdownMenuItem variant="destructive">
|
|
482
|
+
* <Text>Delete</Text>
|
|
483
|
+
* </DropdownMenuItem>
|
|
484
|
+
* ```
|
|
485
|
+
*/
|
|
486
|
+
function DropdownMenuSeparator({
|
|
487
|
+
className,
|
|
488
|
+
...props
|
|
489
|
+
}: DropdownMenuPrimitive.SeparatorProps &
|
|
490
|
+
React.RefAttributes<DropdownMenuPrimitive.SeparatorRef>) {
|
|
491
|
+
return (
|
|
492
|
+
<DropdownMenuPrimitive.Separator
|
|
493
|
+
className={cn('bg-border -mx-1 my-1 h-px', className)}
|
|
494
|
+
{...props}
|
|
495
|
+
/>
|
|
496
|
+
);
|
|
497
|
+
}
|
|
498
|
+
|
|
499
|
+
/**
|
|
500
|
+
* Displays keyboard shortcut hint for menu items
|
|
501
|
+
*
|
|
502
|
+
* @component
|
|
503
|
+
* @example
|
|
504
|
+
* ```tsx
|
|
505
|
+
* <DropdownMenuItem>
|
|
506
|
+
* <Text>Save</Text>
|
|
507
|
+
* <DropdownMenuShortcut>
|
|
508
|
+
* <Text>⌘S</Text>
|
|
509
|
+
* </DropdownMenuShortcut>
|
|
510
|
+
* </DropdownMenuItem>
|
|
511
|
+
* ```
|
|
512
|
+
*/
|
|
513
|
+
function DropdownMenuShortcut({
|
|
514
|
+
className,
|
|
515
|
+
...props
|
|
516
|
+
}: TextProps & React.RefAttributes<Text>) {
|
|
517
|
+
return (
|
|
518
|
+
<Text
|
|
519
|
+
className={cn(
|
|
520
|
+
'text-muted-foreground ml-auto text-xs tracking-widest',
|
|
521
|
+
className
|
|
522
|
+
)}
|
|
523
|
+
{...props}
|
|
524
|
+
/>
|
|
525
|
+
);
|
|
526
|
+
}
|
|
527
|
+
|
|
528
|
+
export {
|
|
529
|
+
DropdownMenu,
|
|
530
|
+
DropdownMenuCheckboxItem,
|
|
531
|
+
DropdownMenuContent,
|
|
532
|
+
DropdownMenuGroup,
|
|
533
|
+
DropdownMenuItem,
|
|
534
|
+
DropdownMenuLabel,
|
|
535
|
+
DropdownMenuPortal,
|
|
536
|
+
DropdownMenuRadioGroup,
|
|
537
|
+
DropdownMenuRadioItem,
|
|
538
|
+
DropdownMenuSeparator,
|
|
539
|
+
DropdownMenuShortcut,
|
|
540
|
+
DropdownMenuSub,
|
|
541
|
+
DropdownMenuSubContent,
|
|
542
|
+
DropdownMenuSubTrigger,
|
|
543
|
+
DropdownMenuTrigger,
|
|
544
|
+
};
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import type { IFloatingActionProps as RNFloatingActionProps } from 'react-native-floating-action';
|
|
3
|
+
import { FloatingAction as RNFloatingAction } from 'react-native-floating-action';
|
|
4
|
+
|
|
5
|
+
export interface FloatingActionProps extends RNFloatingActionProps {
|
|
6
|
+
/**
|
|
7
|
+
* Custom className for styling (if using NativeWind)
|
|
8
|
+
*/
|
|
9
|
+
className?: string;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* FloatingAction Component
|
|
14
|
+
*
|
|
15
|
+
* A customizable floating action button (FAB) component with support for multiple actions.
|
|
16
|
+
* Based on react-native-floating-action with additional styling capabilities.
|
|
17
|
+
*
|
|
18
|
+
* @example
|
|
19
|
+
* ```tsx
|
|
20
|
+
* import { FloatingAction } from 'react-native-blueprint';
|
|
21
|
+
*
|
|
22
|
+
* const actions = [
|
|
23
|
+
* {
|
|
24
|
+
* text: 'Add',
|
|
25
|
+
* icon: require('./add-icon.png'),
|
|
26
|
+
* name: 'bt_add',
|
|
27
|
+
* position: 1
|
|
28
|
+
* },
|
|
29
|
+
* {
|
|
30
|
+
* text: 'Delete',
|
|
31
|
+
* icon: require('./delete-icon.png'),
|
|
32
|
+
* name: 'bt_delete',
|
|
33
|
+
* position: 2
|
|
34
|
+
* }
|
|
35
|
+
* ];
|
|
36
|
+
*
|
|
37
|
+
* <FloatingAction
|
|
38
|
+
* actions={actions}
|
|
39
|
+
* onPressItem={(name) => {
|
|
40
|
+
* console.log(`Selected button: ${name}`);
|
|
41
|
+
* }}
|
|
42
|
+
* />
|
|
43
|
+
* ```
|
|
44
|
+
*/
|
|
45
|
+
export const FloatingAction: React.FC<FloatingActionProps> = React.forwardRef<
|
|
46
|
+
RNFloatingAction,
|
|
47
|
+
FloatingActionProps
|
|
48
|
+
>(({ className: _className, ...props }, ref) => {
|
|
49
|
+
return <RNFloatingAction ref={ref} {...props} />;
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
FloatingAction.displayName = 'FloatingAction';
|
|
53
|
+
|
|
54
|
+
export default FloatingAction;
|