@gv-tech/ui-native 2.24.0 → 2.25.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/calendar.d.ts +111 -1
- package/dist/calendar.d.ts.map +1 -1
- package/dist/combobox.d.ts +17 -10
- package/dist/combobox.d.ts.map +1 -1
- package/dist/dialog.d.ts.map +1 -1
- package/dist/hooks/use-theme.d.ts +1 -1
- package/dist/theme-toggle.d.ts.map +1 -1
- package/dist/ui-native.cjs +2 -2
- package/dist/ui-native.esm.js +1081 -944
- package/package.json +2 -1
- package/src/calendar.tsx +52 -3
- package/src/combobox.tsx +190 -27
- package/src/dialog.tsx +72 -25
- package/src/theme-toggle.tsx +16 -13
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gv-tech/ui-native",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.25.0",
|
|
4
4
|
"description": "React Native implementations of the GV Tech design system components",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -36,6 +36,7 @@
|
|
|
36
36
|
"dependencies": {
|
|
37
37
|
"@gv-tech/design-tokens": "^2.12.0",
|
|
38
38
|
"@gv-tech/ui-core": "^2.12.0",
|
|
39
|
+
"@react-native-community/datetimepicker": "^9.1.0",
|
|
39
40
|
"@rn-primitives/accordion": "^1.2.0",
|
|
40
41
|
"@rn-primitives/alert-dialog": "^1.2.0",
|
|
41
42
|
"@rn-primitives/aspect-ratio": "^1.2.0",
|
package/src/calendar.tsx
CHANGED
|
@@ -1,7 +1,56 @@
|
|
|
1
1
|
import type { CalendarBaseProps } from '@gv-tech/ui-core';
|
|
2
|
+
import DateTimePicker from '@react-native-community/datetimepicker';
|
|
2
3
|
import * as React from 'react';
|
|
3
4
|
import { View } from 'react-native';
|
|
5
|
+
import { cn } from './lib/utils';
|
|
4
6
|
|
|
5
|
-
export
|
|
6
|
-
|
|
7
|
-
|
|
7
|
+
export type CalendarProps = Omit<
|
|
8
|
+
React.ComponentProps<typeof DateTimePicker>,
|
|
9
|
+
'value' | 'className' | 'display' | 'minuteInterval'
|
|
10
|
+
> &
|
|
11
|
+
CalendarBaseProps & {
|
|
12
|
+
value?: Date;
|
|
13
|
+
onChange?: (event: unknown, date?: Date) => void;
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
export const Calendar = React.forwardRef<View, CalendarProps>(
|
|
17
|
+
({ className, value, onChange, showOutsideDays, ...props }, ref) => {
|
|
18
|
+
// If no value is provided, default to current date so the picker doesn't crash
|
|
19
|
+
const [date, setDate] = React.useState<Date>(value || new Date());
|
|
20
|
+
|
|
21
|
+
// Sync internal state if external value changes
|
|
22
|
+
React.useEffect(() => {
|
|
23
|
+
if (value) {
|
|
24
|
+
setDate(value);
|
|
25
|
+
}
|
|
26
|
+
}, [value]);
|
|
27
|
+
|
|
28
|
+
const handleValueChange = (event: unknown, selectedDate: Date) => {
|
|
29
|
+
setDate(selectedDate);
|
|
30
|
+
if (onChange) {
|
|
31
|
+
onChange(event, selectedDate);
|
|
32
|
+
}
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
const handleDismiss = () => {
|
|
36
|
+
if (onChange) {
|
|
37
|
+
onChange({ type: 'dismissed' }, date);
|
|
38
|
+
}
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
return (
|
|
42
|
+
<View ref={ref} className={cn('bg-background overflow-hidden rounded-md', className)}>
|
|
43
|
+
<DateTimePicker
|
|
44
|
+
value={date}
|
|
45
|
+
mode="date"
|
|
46
|
+
display="inline"
|
|
47
|
+
onValueChange={handleValueChange}
|
|
48
|
+
onDismiss={handleDismiss}
|
|
49
|
+
{...props}
|
|
50
|
+
/>
|
|
51
|
+
</View>
|
|
52
|
+
);
|
|
53
|
+
},
|
|
54
|
+
);
|
|
55
|
+
|
|
56
|
+
Calendar.displayName = 'Calendar';
|
package/src/combobox.tsx
CHANGED
|
@@ -15,37 +15,126 @@ import type {
|
|
|
15
15
|
ComboboxTriggerBaseProps,
|
|
16
16
|
ComboboxValueBaseProps,
|
|
17
17
|
} from '@gv-tech/ui-core';
|
|
18
|
+
import { Check, ChevronDown, X } from 'lucide-react-native';
|
|
18
19
|
import * as React from 'react';
|
|
19
|
-
import {
|
|
20
|
+
import { Pressable, TextInput, View } from 'react-native';
|
|
21
|
+
import { Dialog, DialogContent, DialogTrigger } from './dialog';
|
|
22
|
+
import { wrapTextChildren } from './lib/render-native';
|
|
20
23
|
import { cn } from './lib/utils';
|
|
24
|
+
import { Text } from './text';
|
|
25
|
+
|
|
26
|
+
// Context to share state across compound components
|
|
27
|
+
const ComboboxContext = React.createContext<{
|
|
28
|
+
open: boolean;
|
|
29
|
+
setOpen: (open: boolean) => void;
|
|
30
|
+
value: string;
|
|
31
|
+
setValue: (value: string) => void;
|
|
32
|
+
searchQuery: string;
|
|
33
|
+
setSearchQuery: (query: string) => void;
|
|
34
|
+
} | null>(null);
|
|
35
|
+
|
|
36
|
+
function useCombobox() {
|
|
37
|
+
const context = React.useContext(ComboboxContext);
|
|
38
|
+
if (!context) {
|
|
39
|
+
throw new Error('Combobox components must be rendered within a Combobox provider');
|
|
40
|
+
}
|
|
41
|
+
return context;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export interface ComboboxProps extends React.ComponentProps<typeof View> {
|
|
45
|
+
value?: string;
|
|
46
|
+
onValueChange?: (value: string) => void;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
function Combobox({ className, value: controlledValue, onValueChange, ...props }: ComboboxProps) {
|
|
50
|
+
const [open, setOpen] = React.useState(false);
|
|
51
|
+
const [internalValue, setInternalValue] = React.useState(controlledValue || '');
|
|
52
|
+
const [searchQuery, setSearchQuery] = React.useState('');
|
|
53
|
+
|
|
54
|
+
const value = controlledValue !== undefined ? controlledValue : internalValue;
|
|
55
|
+
const setValue = (newValue: string) => {
|
|
56
|
+
setInternalValue(newValue);
|
|
57
|
+
onValueChange?.(newValue);
|
|
58
|
+
setOpen(false);
|
|
59
|
+
};
|
|
21
60
|
|
|
22
|
-
function Combobox({ className, ...props }: React.ComponentProps<typeof View>) {
|
|
23
61
|
return (
|
|
24
|
-
<
|
|
25
|
-
<
|
|
26
|
-
|
|
62
|
+
<ComboboxContext.Provider value={{ open, setOpen, value, setValue, searchQuery, setSearchQuery }}>
|
|
63
|
+
<Dialog open={open} onOpenChange={setOpen}>
|
|
64
|
+
<View className={cn('relative', className)} {...props} />
|
|
65
|
+
</Dialog>
|
|
66
|
+
</ComboboxContext.Provider>
|
|
27
67
|
);
|
|
28
68
|
}
|
|
29
69
|
|
|
30
|
-
function ComboboxValue({ className, ...props }: React.ComponentProps<typeof View> & ComboboxValueBaseProps) {
|
|
31
|
-
|
|
70
|
+
function ComboboxValue({ className, children, ...props }: React.ComponentProps<typeof View> & ComboboxValueBaseProps) {
|
|
71
|
+
const { value } = useCombobox();
|
|
72
|
+
return (
|
|
73
|
+
<View className={className} {...props}>
|
|
74
|
+
<Text className="text-sm">{children || value || 'Select an item...'}</Text>
|
|
75
|
+
</View>
|
|
76
|
+
);
|
|
32
77
|
}
|
|
33
78
|
|
|
34
|
-
function ComboboxTrigger({
|
|
35
|
-
|
|
79
|
+
function ComboboxTrigger({
|
|
80
|
+
className,
|
|
81
|
+
children,
|
|
82
|
+
...props
|
|
83
|
+
}: React.ComponentProps<typeof Pressable> & ComboboxTriggerBaseProps) {
|
|
84
|
+
return (
|
|
85
|
+
<DialogTrigger asChild>
|
|
86
|
+
<Pressable
|
|
87
|
+
className={cn(
|
|
88
|
+
'border-input bg-background text-foreground flex h-10 w-full flex-row items-center justify-between rounded-md border px-3 py-2 text-sm',
|
|
89
|
+
className,
|
|
90
|
+
)}
|
|
91
|
+
{...props}
|
|
92
|
+
>
|
|
93
|
+
<View className="flex-1 flex-row items-center">{wrapTextChildren(children, Text)}</View>
|
|
94
|
+
<ChevronDown size={16} className="text-muted-foreground opacity-50" />
|
|
95
|
+
</Pressable>
|
|
96
|
+
</DialogTrigger>
|
|
97
|
+
);
|
|
36
98
|
}
|
|
37
99
|
|
|
38
|
-
function ComboboxClear({
|
|
39
|
-
|
|
100
|
+
function ComboboxClear({
|
|
101
|
+
className,
|
|
102
|
+
children,
|
|
103
|
+
...props
|
|
104
|
+
}: React.ComponentProps<typeof Pressable> & ComboboxClearBaseProps) {
|
|
105
|
+
const { setValue } = useCombobox();
|
|
106
|
+
return (
|
|
107
|
+
<Pressable
|
|
108
|
+
className={cn('flex items-center justify-center p-1', className)}
|
|
109
|
+
onPress={() => setValue('')}
|
|
110
|
+
{...props}
|
|
111
|
+
>
|
|
112
|
+
{children || <X size={14} className="text-muted-foreground" />}
|
|
113
|
+
</Pressable>
|
|
114
|
+
);
|
|
40
115
|
}
|
|
41
116
|
|
|
42
117
|
function ComboboxInput({
|
|
43
118
|
className,
|
|
44
119
|
showClear,
|
|
45
120
|
showTrigger,
|
|
121
|
+
placeholder = 'Search...',
|
|
46
122
|
...props
|
|
47
|
-
}: React.ComponentProps<typeof
|
|
48
|
-
|
|
123
|
+
}: React.ComponentProps<typeof TextInput> & ComboboxInputBaseProps) {
|
|
124
|
+
const { searchQuery, setSearchQuery } = useCombobox();
|
|
125
|
+
return (
|
|
126
|
+
<View className="border-border flex flex-row items-center border-b px-3">
|
|
127
|
+
<TextInput
|
|
128
|
+
className={cn('flex h-12 w-full rounded-md bg-transparent py-3 text-sm outline-none', className)}
|
|
129
|
+
placeholder={placeholder}
|
|
130
|
+
placeholderTextColor="#a1a1aa"
|
|
131
|
+
value={searchQuery}
|
|
132
|
+
onChangeText={setSearchQuery}
|
|
133
|
+
autoFocus
|
|
134
|
+
{...props}
|
|
135
|
+
/>
|
|
136
|
+
</View>
|
|
137
|
+
);
|
|
49
138
|
}
|
|
50
139
|
|
|
51
140
|
function ComboboxContent({
|
|
@@ -57,47 +146,121 @@ function ComboboxContent({
|
|
|
57
146
|
anchor,
|
|
58
147
|
...props
|
|
59
148
|
}: React.ComponentProps<typeof View> & ComboboxContentBaseProps) {
|
|
60
|
-
return
|
|
149
|
+
return (
|
|
150
|
+
<DialogContent className="p-0">
|
|
151
|
+
<View
|
|
152
|
+
className={cn('bg-popover flex max-h-96 w-full flex-col overflow-hidden rounded-md', className)}
|
|
153
|
+
{...props}
|
|
154
|
+
/>
|
|
155
|
+
</DialogContent>
|
|
156
|
+
);
|
|
61
157
|
}
|
|
62
158
|
|
|
63
159
|
function ComboboxList({ className, ...props }: React.ComponentProps<typeof View> & ComboboxListBaseProps) {
|
|
64
|
-
return <View className={className} {...props} />;
|
|
160
|
+
return <View className={cn('max-h-[300px] overflow-hidden', className)} {...props} />;
|
|
65
161
|
}
|
|
66
162
|
|
|
67
|
-
|
|
68
|
-
|
|
163
|
+
export type ComboboxItemProps = React.ComponentProps<typeof Pressable> &
|
|
164
|
+
ComboboxItemBaseProps & {
|
|
165
|
+
value: string;
|
|
166
|
+
};
|
|
167
|
+
|
|
168
|
+
function ComboboxItem({ className, children, value: itemValue, ...props }: ComboboxItemProps) {
|
|
169
|
+
const { value, setValue, searchQuery } = useCombobox();
|
|
170
|
+
|
|
171
|
+
// Basic filtering mechanism
|
|
172
|
+
const textContent = React.Children.toArray(children).join('').toLowerCase();
|
|
173
|
+
if (
|
|
174
|
+
searchQuery &&
|
|
175
|
+
!textContent.includes(searchQuery.toLowerCase()) &&
|
|
176
|
+
!itemValue.toLowerCase().includes(searchQuery.toLowerCase())
|
|
177
|
+
) {
|
|
178
|
+
return null;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
const isSelected = value === itemValue;
|
|
182
|
+
|
|
183
|
+
return (
|
|
184
|
+
<Pressable
|
|
185
|
+
className={cn(
|
|
186
|
+
'active:bg-accent relative flex w-full flex-row items-center rounded-sm py-2.5 pr-8 pl-2 text-sm outline-none',
|
|
187
|
+
isSelected && 'bg-accent',
|
|
188
|
+
className,
|
|
189
|
+
)}
|
|
190
|
+
onPress={() => setValue(itemValue)}
|
|
191
|
+
{...props}
|
|
192
|
+
>
|
|
193
|
+
<View className="flex-1">
|
|
194
|
+
{wrapTextChildren(children, Text, { className: isSelected ? 'font-semibold' : '' })}
|
|
195
|
+
</View>
|
|
196
|
+
{isSelected && (
|
|
197
|
+
<View className="absolute right-2 flex h-3.5 w-3.5 items-center justify-center">
|
|
198
|
+
<Check size={16} className="text-foreground" />
|
|
199
|
+
</View>
|
|
200
|
+
)}
|
|
201
|
+
</Pressable>
|
|
202
|
+
);
|
|
69
203
|
}
|
|
70
204
|
|
|
71
205
|
function ComboboxGroup({ className, ...props }: React.ComponentProps<typeof View> & ComboboxGroupBaseProps) {
|
|
72
|
-
return <View className={className} {...props} />;
|
|
206
|
+
return <View className={cn('text-foreground overflow-hidden p-1', className)} {...props} />;
|
|
73
207
|
}
|
|
74
208
|
|
|
75
209
|
function ComboboxLabel({ className, ...props }: React.ComponentProps<typeof View> & ComboboxLabelBaseProps) {
|
|
76
|
-
return <View className={className} {...props} />;
|
|
210
|
+
return <View className={cn('text-muted-foreground px-2 py-1.5 text-xs font-semibold', className)} {...props} />;
|
|
77
211
|
}
|
|
78
212
|
|
|
79
213
|
function ComboboxCollection({ className, ...props }: React.ComponentProps<typeof View> & ComboboxCollectionBaseProps) {
|
|
80
214
|
return <View className={className} {...props} />;
|
|
81
215
|
}
|
|
82
216
|
|
|
83
|
-
function ComboboxEmpty({ className, ...props }: React.ComponentProps<typeof View> & ComboboxEmptyBaseProps) {
|
|
84
|
-
|
|
217
|
+
function ComboboxEmpty({ className, children, ...props }: React.ComponentProps<typeof View> & ComboboxEmptyBaseProps) {
|
|
218
|
+
const { searchQuery } = useCombobox();
|
|
219
|
+
|
|
220
|
+
if (!searchQuery) {
|
|
221
|
+
return null;
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
return (
|
|
225
|
+
<View className={cn('py-6 text-center text-sm', className)} {...props}>
|
|
226
|
+
<Text className="text-muted-foreground text-center">{children || 'No results found.'}</Text>
|
|
227
|
+
</View>
|
|
228
|
+
);
|
|
85
229
|
}
|
|
86
230
|
|
|
87
231
|
function ComboboxSeparator({ className, ...props }: React.ComponentProps<typeof View> & ComboboxSeparatorBaseProps) {
|
|
88
|
-
return <View className={className} {...props} />;
|
|
232
|
+
return <View className={cn('bg-muted -mx-1 h-px', className)} {...props} />;
|
|
89
233
|
}
|
|
90
234
|
|
|
91
235
|
function ComboboxChips({ className, ...props }: React.ComponentProps<typeof View> & ComboboxChipsBaseProps) {
|
|
92
|
-
return <View className={className} {...props} />;
|
|
236
|
+
return <View className={cn('flex flex-row flex-wrap gap-1', className)} {...props} />;
|
|
93
237
|
}
|
|
94
238
|
|
|
95
|
-
function ComboboxChip({
|
|
96
|
-
|
|
239
|
+
function ComboboxChip({
|
|
240
|
+
className,
|
|
241
|
+
showRemove,
|
|
242
|
+
children,
|
|
243
|
+
...props
|
|
244
|
+
}: React.ComponentProps<typeof View> & ComboboxChipBaseProps) {
|
|
245
|
+
return (
|
|
246
|
+
<View
|
|
247
|
+
className={cn(
|
|
248
|
+
'bg-secondary text-secondary-foreground flex flex-row items-center rounded-md px-2 py-1',
|
|
249
|
+
className,
|
|
250
|
+
)}
|
|
251
|
+
{...props}
|
|
252
|
+
>
|
|
253
|
+
{wrapTextChildren(children, Text, { className: 'text-xs' })}
|
|
254
|
+
{showRemove && <X size={12} className="ml-1 opacity-50" />}
|
|
255
|
+
</View>
|
|
256
|
+
);
|
|
97
257
|
}
|
|
98
258
|
|
|
99
|
-
function ComboboxChipsInput({
|
|
100
|
-
|
|
259
|
+
function ComboboxChipsInput({
|
|
260
|
+
className,
|
|
261
|
+
...props
|
|
262
|
+
}: React.ComponentProps<typeof TextInput> & ComboboxChipsInputBaseProps) {
|
|
263
|
+
return <TextInput className={cn('flex-1 bg-transparent px-2 py-1 outline-none', className)} {...props} />;
|
|
101
264
|
}
|
|
102
265
|
|
|
103
266
|
function useComboboxAnchor() {
|
package/src/dialog.tsx
CHANGED
|
@@ -2,7 +2,7 @@ import { DialogBaseProps, DialogContentBaseProps } from '@gv-tech/ui-core';
|
|
|
2
2
|
import * as DialogPrimitive from '@rn-primitives/dialog';
|
|
3
3
|
import { X } from 'lucide-react-native';
|
|
4
4
|
import * as React from 'react';
|
|
5
|
-
import {
|
|
5
|
+
import { Platform, View, type StyleProp, type ViewStyle } from 'react-native';
|
|
6
6
|
import Animated, { FadeIn, FadeOut } from 'react-native-reanimated';
|
|
7
7
|
|
|
8
8
|
import { cn } from './lib/utils';
|
|
@@ -28,13 +28,28 @@ export type DialogOverlayProps = React.ComponentPropsWithoutRef<typeof DialogPri
|
|
|
28
28
|
export type DialogOverlayRef = React.ComponentRef<typeof DialogPrimitive.Overlay>;
|
|
29
29
|
|
|
30
30
|
const DialogOverlay: React.ForwardRefExoticComponent<DialogOverlayProps & React.RefAttributes<DialogOverlayRef>> =
|
|
31
|
-
React.forwardRef<DialogOverlayRef, DialogOverlayProps>(({ className, ...props }, ref) => {
|
|
31
|
+
React.forwardRef<DialogOverlayRef, DialogOverlayProps>(({ className, style, ...props }, ref) => {
|
|
32
32
|
return (
|
|
33
|
-
<DialogPrimitive.Overlay
|
|
33
|
+
<DialogPrimitive.Overlay
|
|
34
|
+
style={[
|
|
35
|
+
{
|
|
36
|
+
position: Platform.OS === 'web' ? 'fixed' : 'absolute',
|
|
37
|
+
top: 0,
|
|
38
|
+
right: 0,
|
|
39
|
+
bottom: 0,
|
|
40
|
+
left: 0,
|
|
41
|
+
zIndex: 50,
|
|
42
|
+
} as unknown as ViewStyle,
|
|
43
|
+
style as StyleProp<ViewStyle>,
|
|
44
|
+
]}
|
|
45
|
+
asChild
|
|
46
|
+
ref={ref}
|
|
47
|
+
{...props}
|
|
48
|
+
>
|
|
34
49
|
<Animated.View
|
|
35
50
|
entering={FadeIn.duration(150)}
|
|
36
51
|
exiting={FadeOut.duration(150)}
|
|
37
|
-
className={cn('
|
|
52
|
+
className={cn('flex items-center justify-center bg-black/80 p-2', className)}
|
|
38
53
|
/>
|
|
39
54
|
</DialogPrimitive.Overlay>
|
|
40
55
|
);
|
|
@@ -45,31 +60,63 @@ export type DialogContentRef = React.ComponentRef<typeof DialogPrimitive.Content
|
|
|
45
60
|
const DialogContent: React.ForwardRefExoticComponent<DialogContentProps & React.RefAttributes<DialogContentRef>> =
|
|
46
61
|
React.forwardRef<DialogContentRef, DialogContentProps>(
|
|
47
62
|
({ className, children, portalHost, overlayClassName, overlayStyle, ...props }, ref) => {
|
|
63
|
+
const PlatformWrapper = React.useCallback(({ children }: { children: React.ReactNode }) => {
|
|
64
|
+
if (Platform.OS === 'web') {
|
|
65
|
+
return <>{children}</>;
|
|
66
|
+
}
|
|
67
|
+
return (
|
|
68
|
+
<View
|
|
69
|
+
pointerEvents="box-none"
|
|
70
|
+
style={{
|
|
71
|
+
position: 'absolute',
|
|
72
|
+
top: 0,
|
|
73
|
+
right: 0,
|
|
74
|
+
bottom: 0,
|
|
75
|
+
left: 0,
|
|
76
|
+
zIndex: 50,
|
|
77
|
+
alignItems: 'center',
|
|
78
|
+
justifyContent: 'center',
|
|
79
|
+
padding: 16,
|
|
80
|
+
}}
|
|
81
|
+
>
|
|
82
|
+
{children}
|
|
83
|
+
</View>
|
|
84
|
+
);
|
|
85
|
+
}, []);
|
|
86
|
+
|
|
48
87
|
return (
|
|
49
88
|
<DialogPortal hostName={portalHost}>
|
|
50
89
|
<DialogOverlay className={overlayClassName} style={overlayStyle} />
|
|
51
|
-
<
|
|
52
|
-
<
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
'
|
|
57
|
-
className,
|
|
58
|
-
)}
|
|
59
|
-
>
|
|
60
|
-
{children}
|
|
61
|
-
<DialogPrimitive.Close
|
|
62
|
-
className={
|
|
63
|
-
'ring-offset-background focus:ring-ring data-[state=open]:bg-accent data-[state=open]:text-muted-foreground absolute top-4 right-4 rounded-sm opacity-70 transition-opacity hover:opacity-100 focus:ring-2 focus:ring-offset-2 focus:outline-none disabled:pointer-events-none'
|
|
64
|
-
}
|
|
90
|
+
<PlatformWrapper>
|
|
91
|
+
<DialogPrimitive.Content ref={ref} {...props}>
|
|
92
|
+
<View
|
|
93
|
+
pointerEvents="box-none"
|
|
94
|
+
className="absolute inset-0 z-50 flex items-center justify-center"
|
|
95
|
+
style={Platform.OS === 'web' ? ({ position: 'fixed' } as unknown as ViewStyle) : undefined}
|
|
65
96
|
>
|
|
66
|
-
<
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
97
|
+
<Animated.View
|
|
98
|
+
entering={FadeIn.duration(150)}
|
|
99
|
+
exiting={FadeOut.duration(150)}
|
|
100
|
+
className={cn(
|
|
101
|
+
'border-border bg-background w-full max-w-lg gap-4 rounded-xl border p-6 shadow-lg sm:rounded-lg',
|
|
102
|
+
className,
|
|
103
|
+
)}
|
|
104
|
+
>
|
|
105
|
+
{children}
|
|
106
|
+
<DialogPrimitive.Close
|
|
107
|
+
className={
|
|
108
|
+
'ring-offset-background focus:ring-ring data-[state=open]:bg-accent data-[state=open]:text-muted-foreground absolute top-4 right-4 rounded-sm opacity-70 transition-opacity hover:opacity-100 focus:ring-2 focus:ring-offset-2 focus:outline-none disabled:pointer-events-none'
|
|
109
|
+
}
|
|
110
|
+
>
|
|
111
|
+
<X size={18} className="text-muted-foreground" />
|
|
112
|
+
<View className="sr-only">
|
|
113
|
+
<DialogPrimitive.Title>Close</DialogPrimitive.Title>
|
|
114
|
+
</View>
|
|
115
|
+
</DialogPrimitive.Close>
|
|
116
|
+
</Animated.View>
|
|
117
|
+
</View>
|
|
118
|
+
</DialogPrimitive.Content>
|
|
119
|
+
</PlatformWrapper>
|
|
73
120
|
</DialogPortal>
|
|
74
121
|
);
|
|
75
122
|
},
|
package/src/theme-toggle.tsx
CHANGED
|
@@ -33,28 +33,31 @@ export function ThemeToggle({ variant = 'binary', onThemeChange, customTheme, cl
|
|
|
33
33
|
};
|
|
34
34
|
|
|
35
35
|
const IconToggle = () => (
|
|
36
|
-
<View className="flex items-center justify-center">
|
|
37
|
-
<
|
|
38
|
-
size={18}
|
|
36
|
+
<View className="flex h-6 w-6 items-center justify-center">
|
|
37
|
+
<View
|
|
39
38
|
className={cn(
|
|
40
|
-
'
|
|
39
|
+
'items-center justify-center transition-all',
|
|
41
40
|
!isSystem && !isDark ? 'scale-100 rotate-0 opacity-100' : 'absolute scale-0 -rotate-90 opacity-0',
|
|
42
41
|
)}
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
42
|
+
>
|
|
43
|
+
<Sun size={18} className="text-foreground" />
|
|
44
|
+
</View>
|
|
45
|
+
<View
|
|
46
46
|
className={cn(
|
|
47
|
-
'
|
|
47
|
+
'items-center justify-center transition-all',
|
|
48
48
|
!isSystem && isDark ? 'scale-100 rotate-0 opacity-100' : 'absolute scale-0 rotate-90 opacity-0',
|
|
49
49
|
)}
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
50
|
+
>
|
|
51
|
+
<Moon size={18} className="text-foreground" />
|
|
52
|
+
</View>
|
|
53
|
+
<View
|
|
53
54
|
className={cn(
|
|
54
|
-
'
|
|
55
|
+
'items-center justify-center transition-all',
|
|
55
56
|
isSystem ? 'scale-100 rotate-0 opacity-100' : 'absolute scale-0 rotate-90 opacity-0',
|
|
56
57
|
)}
|
|
57
|
-
|
|
58
|
+
>
|
|
59
|
+
<SunMoon size={18} className="text-foreground" />
|
|
60
|
+
</View>
|
|
58
61
|
</View>
|
|
59
62
|
);
|
|
60
63
|
|