linked-data-browser 0.0.7 → 0.0.8-alpha.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 (111) hide show
  1. package/.env +2 -0
  2. package/.eslintrc.js +1 -0
  3. package/{index.js → App.js} +1 -4
  4. package/README.md +6 -0
  5. package/app/index.tsx +4 -2
  6. package/app.json +1 -0
  7. package/babel.config.js +7 -8
  8. package/components/DataBrowser.tsx +9 -19
  9. package/components/DataBrowserContext.ts +23 -0
  10. package/components/TargetResourceProvider.tsx +1 -1
  11. package/components/ThemeProvider.tsx +2 -4
  12. package/components/common/LoadingBar.tsx +11 -1
  13. package/components/common/ProfileAvatar.tsx +4 -7
  14. package/components/nav/Layout.tsx +20 -4
  15. package/components/nav/header/AddressBox.tsx +104 -48
  16. package/components/nav/header/AvatarMenu.tsx +42 -10
  17. package/components/nav/header/Header.tsx +26 -19
  18. package/components/nav/header/SignInMenu.tsx +63 -36
  19. package/components/nav/header/ThemeToggleMenu.tsx +21 -9
  20. package/components/nav/header/ViewMenu.tsx +79 -71
  21. package/components/sharing/AccessDropdown.tsx +18 -7
  22. package/components/sharing/CopyLink.tsx +15 -3
  23. package/components/sharing/PermissionRow.tsx +17 -2
  24. package/components/sharing/SharingModal.tsx +30 -3
  25. package/components/sharing/WacRuleForm.tsx +12 -3
  26. package/components/sharing/agentPermissions/AgentInformation.tsx +16 -3
  27. package/components/sharing/agentPermissions/AgentInput.tsx +19 -4
  28. package/components/sharing/agentPermissions/AgentPermissionRow.tsx +24 -6
  29. package/components/ui/accordion.tsx +77 -33
  30. package/components/ui/alert.tsx +75 -42
  31. package/components/ui/avatar.tsx +38 -13
  32. package/components/ui/badge.tsx +76 -48
  33. package/components/ui/button.tsx +226 -108
  34. package/components/ui/card.tsx +60 -30
  35. package/components/ui/checkbox.tsx +53 -16
  36. package/components/ui/context-menu.tsx +238 -117
  37. package/components/ui/dialog.tsx +116 -65
  38. package/components/ui/dropdown-menu.tsx +304 -105
  39. package/components/ui/hover-card.tsx +36 -13
  40. package/components/ui/icon.tsx +23 -0
  41. package/components/ui/input-dropdown.tsx +42 -5
  42. package/components/ui/input.tsx +85 -22
  43. package/components/ui/label.tsx +16 -7
  44. package/components/ui/menubar.tsx +284 -136
  45. package/components/ui/navigation-menu.tsx +157 -90
  46. package/components/ui/popover.tsx +36 -9
  47. package/components/ui/progress.tsx +53 -27
  48. package/components/ui/radio-group.tsx +61 -17
  49. package/components/ui/select.tsx +139 -67
  50. package/components/ui/separator.tsx +22 -7
  51. package/components/ui/skeleton.tsx +16 -11
  52. package/components/ui/switch.tsx +83 -51
  53. package/components/ui/table.tsx +57 -35
  54. package/components/ui/tabs.tsx +66 -35
  55. package/components/ui/text.tsx +221 -30
  56. package/components/ui/textarea.tsx +34 -10
  57. package/components/ui/toggle-group.tsx +103 -46
  58. package/components/ui/toggle.tsx +97 -74
  59. package/components/ui/tooltip.tsx +38 -9
  60. package/components/ui/typography.tsx +94 -65
  61. package/components/useViewContext.tsx +8 -8
  62. package/global.css +93 -3
  63. package/lib/index.js +88 -0
  64. package/metro.config.js +1 -3
  65. package/package.json +14 -10
  66. package/resourceViews/Container/ContainerConfig.tsx +1 -1
  67. package/resourceViews/Container/ContainerView.tsx +63 -25
  68. package/resourceViews/Profile/ProfileConfig.tsx +1 -1
  69. package/resourceViews/Profile/ProfileKnows.tsx +17 -9
  70. package/resourceViews/Profile/ProfileView.tsx +21 -4
  71. package/resourceViews/RawCode/RawCodeConfig.tsx +1 -1
  72. package/resourceViews/RawCode/RawCodeView.tsx +20 -6
  73. package/components.json +0 -7
  74. package/lib/icons/ArrowRight.tsx +0 -4
  75. package/lib/icons/Check.tsx +0 -4
  76. package/lib/icons/ChevronDown.tsx +0 -4
  77. package/lib/icons/ChevronRight.tsx +0 -4
  78. package/lib/icons/ChevronUp.tsx +0 -4
  79. package/lib/icons/ChevronsRight.tsx +0 -4
  80. package/lib/icons/CircleSlash.tsx +0 -4
  81. package/lib/icons/CircleX.tsx +0 -4
  82. package/lib/icons/Code.tsx +0 -4
  83. package/lib/icons/EllipsisVertical.tsx +0 -4
  84. package/lib/icons/EyeOff.tsx +0 -4
  85. package/lib/icons/File.tsx +0 -4
  86. package/lib/icons/Fingerprint.tsx +0 -4
  87. package/lib/icons/Folder.tsx +0 -4
  88. package/lib/icons/Folders.tsx +0 -4
  89. package/lib/icons/Info.tsx +0 -4
  90. package/lib/icons/Link.tsx +0 -4
  91. package/lib/icons/Loader.tsx +0 -4
  92. package/lib/icons/LogOut.tsx +0 -4
  93. package/lib/icons/MonitorSmartphone.tsx +0 -4
  94. package/lib/icons/MoonStar.tsx +0 -4
  95. package/lib/icons/OctagonX.tsx +0 -4
  96. package/lib/icons/Plus.tsx +0 -4
  97. package/lib/icons/RefreshCw.tsx +0 -4
  98. package/lib/icons/Save.tsx +0 -4
  99. package/lib/icons/ShieldX.tsx +0 -4
  100. package/lib/icons/Sun.tsx +0 -4
  101. package/lib/icons/TextCursorInput.tsx +0 -4
  102. package/lib/icons/Trash.tsx +0 -4
  103. package/lib/icons/User.tsx +0 -4
  104. package/lib/icons/UserPlus.tsx +0 -4
  105. package/lib/icons/Users.tsx +0 -4
  106. package/lib/icons/ViewIcon.tsx +0 -4
  107. package/lib/icons/X.tsx +0 -4
  108. package/lib/icons/iconWithClassName.ts +0 -14
  109. package/lib/utils.ts +0 -6
  110. package/nativewind-env.d.ts +0 -1
  111. package/tailwind.config.js +0 -69
@@ -1,4 +1,6 @@
1
1
  import React, { useCallback, useMemo, useState } from 'react';
2
+ import { StyleSheet } from 'react-native';
3
+ import { useTheme } from '@react-navigation/native';
2
4
  import { FunctionComponent } from 'react';
3
5
  import { Pressable } from 'react-native';
4
6
  import { useLinkQuery, useSolidAuth } from '@ldo/solid-react';
@@ -6,7 +8,7 @@ import { SolidProfileShapeType } from '../../../.ldo/profile.shapeTypes';
6
8
  import { AgentInformation } from './AgentInformation';
7
9
  import { InputDropdown } from '../../ui/input-dropdown';
8
10
  import { useContactFilter } from './useContactFilter';
9
- import { Plus } from '../../../lib/icons/Plus';
11
+ import { Plus } from 'lucide-react-native';
10
12
 
11
13
  interface AgentInputProps {
12
14
  onAddAgent: (webId: string) => void;
@@ -19,9 +21,14 @@ const ContactDropdownItem: FunctionComponent<{
19
21
  webId: string;
20
22
  onSelect: (webId: string) => void;
21
23
  }> = ({ webId, onSelect }) => {
24
+ const { colors } = useTheme();
22
25
  return (
23
26
  <Pressable
24
- className="p-2 border-b border-border last:border-b-0 hover:bg-accent active:bg-accent cursor-pointer"
27
+ style={({ hovered }) => [
28
+ styles.dropdownItem,
29
+ { borderBottomColor: colors.border },
30
+ hovered && { backgroundColor: colors.border },
31
+ ]}
25
32
  onPress={() => onSelect(webId)}
26
33
  >
27
34
  <AgentInformation webId={webId} />
@@ -115,12 +122,20 @@ export const AgentInput: FunctionComponent<AgentInputProps> = ({
115
122
  renderItem={renderContactItem}
116
123
  filterItems={filterContacts}
117
124
  buttonRight={{
118
- iconRight: <Plus />,
125
+ iconRight: Plus,
119
126
  onPress: handleInputSubmit,
120
127
  variant: 'secondary',
121
128
  }}
122
129
  onItemSelect={handleContactSelect}
123
- className={className}
130
+ style={className ? { zIndex: 999 } : undefined}
124
131
  />
125
132
  );
126
133
  };
134
+
135
+ const styles = StyleSheet.create({
136
+ dropdownItem: {
137
+ padding: 8,
138
+ borderBottomWidth: 1,
139
+ // hover and active states handled by Pressable
140
+ },
141
+ });
@@ -1,12 +1,12 @@
1
1
  import React from 'react';
2
+ import { StyleSheet } from 'react-native';
2
3
  import { AccessModeList } from '@ldo/connected-solid';
3
- import { Text } from '../../ui/text';
4
4
  import { FunctionComponent } from 'react';
5
5
  import { AgentInformation } from './AgentInformation';
6
6
  import { AccessDropdown } from '../AccessDropdown';
7
7
  import { View } from 'react-native';
8
8
  import { Button } from '../../ui/button';
9
- import { Trash } from '../../../lib/icons/Trash';
9
+ import { Trash } from 'lucide-react-native';
10
10
 
11
11
  interface AgentPermissionRowProps {
12
12
  webId: string;
@@ -20,17 +20,35 @@ export const AgentPermissionRow: FunctionComponent<AgentPermissionRowProps> = ({
20
20
  onChange,
21
21
  }) => {
22
22
  return (
23
- <View className="flex-row justify-between align-center">
23
+ <View style={styles.container}>
24
24
  <AgentInformation webId={webId} />
25
- <View className="flex-row">
25
+ <View style={styles.rightSection}>
26
26
  <Button
27
27
  variant="ghost"
28
28
  onPress={() => onChange(undefined)}
29
- className="w-10"
30
- iconLeft={<Trash size={14} />}
29
+ style={styles.deleteButton}
30
+ iconLeft={Trash}
31
+ textStyle={styles.deleteButtonText}
31
32
  />
32
33
  <AccessDropdown value={value} onChange={onChange} />
33
34
  </View>
34
35
  </View>
35
36
  );
36
37
  };
38
+
39
+ const styles = StyleSheet.create({
40
+ container: {
41
+ flexDirection: 'row',
42
+ justifyContent: 'space-between',
43
+ alignItems: 'center',
44
+ },
45
+ rightSection: {
46
+ flexDirection: 'row',
47
+ },
48
+ deleteButton: {
49
+ width: 40,
50
+ },
51
+ deleteButtonText: {
52
+ fontSize: 14,
53
+ },
54
+ });
@@ -1,6 +1,6 @@
1
1
  import * as AccordionPrimitive from '@rn-primitives/accordion';
2
2
  import * as React from 'react';
3
- import { Platform, Pressable, View } from 'react-native';
3
+ import { Platform, Pressable, View, StyleSheet } from 'react-native';
4
4
  import Animated, {
5
5
  Extrapolation,
6
6
  FadeIn,
@@ -12,9 +12,9 @@ import Animated, {
12
12
  useDerivedValue,
13
13
  withTiming,
14
14
  } from 'react-native-reanimated';
15
- import { ChevronDown } from '../../lib/icons/ChevronDown';
16
- import { cn } from '../../lib/utils';
17
- import { TextClassContext } from '../../components/ui/text';
15
+ import { ChevronDown } from 'lucide-react-native';
16
+ import { useTheme } from '@react-navigation/native';
17
+ import { TextStyleProvider } from '../../components/ui/text';
18
18
 
19
19
  function Accordion({
20
20
  children,
@@ -37,19 +37,24 @@ function Accordion({
37
37
  }
38
38
 
39
39
  function AccordionItem({
40
- className,
40
+ style,
41
41
  value,
42
42
  ...props
43
43
  }: AccordionPrimitive.ItemProps & {
44
44
  ref?: React.RefObject<AccordionPrimitive.ItemRef>;
45
45
  }) {
46
+ const { colors } = useTheme();
46
47
  return (
47
48
  <Animated.View
48
- className={'overflow-hidden'}
49
+ style={[styles.itemContainer, { overflow: 'hidden' }]}
49
50
  layout={LinearTransition.duration(200)}
50
51
  >
51
52
  <AccordionPrimitive.Item
52
- className={cn('border-b border-border', className)}
53
+ style={StyleSheet.flatten([
54
+ styles.item,
55
+ { borderBottomColor: colors.border },
56
+ style,
57
+ ])}
53
58
  value={value}
54
59
  {...props}
55
60
  />
@@ -60,13 +65,14 @@ function AccordionItem({
60
65
  const Trigger = Platform.OS === 'web' ? View : Pressable;
61
66
 
62
67
  function AccordionTrigger({
63
- className,
68
+ style,
64
69
  children,
65
70
  ...props
66
71
  }: AccordionPrimitive.TriggerProps & {
67
72
  children?: React.ReactNode;
68
73
  ref?: React.RefObject<AccordionPrimitive.TriggerRef>;
69
74
  }) {
75
+ const { colors } = useTheme();
70
76
  const { isExpanded } = AccordionPrimitive.useItemContext();
71
77
 
72
78
  const progress = useDerivedValue(() =>
@@ -79,73 +85,111 @@ function AccordionTrigger({
79
85
  opacity: interpolate(progress.value, [0, 1], [1, 0.8], Extrapolation.CLAMP),
80
86
  }));
81
87
 
88
+ const textStyles = {
89
+ fontSize: Platform.OS === 'web' ? 16 : 18,
90
+ fontWeight: '500' as const,
91
+ color: colors.text,
92
+ };
93
+
82
94
  return (
83
- <TextClassContext.Provider value="native:text-lg font-medium web:group-hover:underline">
84
- <AccordionPrimitive.Header className="flex">
95
+ <TextStyleProvider style={textStyles}>
96
+ <AccordionPrimitive.Header style={styles.header}>
85
97
  <AccordionPrimitive.Trigger {...props} asChild>
86
98
  <Trigger
87
- className={cn(
88
- 'flex flex-row web:flex-1 items-center justify-between py-4 web:transition-all group web:focus-visible:outline-none web:focus-visible:ring-1 web:focus-visible:ring-muted-foreground',
89
- className,
90
- )}
99
+ style={StyleSheet.flatten([
100
+ styles.trigger,
101
+ { flex: Platform.OS === 'web' ? 1 : undefined },
102
+ style,
103
+ ])}
91
104
  >
92
105
  {children}
93
106
  <Animated.View style={chevronStyle}>
94
- <ChevronDown size={18} className={'text-foreground shrink-0'} />
107
+ <ChevronDown size={18} color={colors.text} />
95
108
  </Animated.View>
96
109
  </Trigger>
97
110
  </AccordionPrimitive.Trigger>
98
111
  </AccordionPrimitive.Header>
99
- </TextClassContext.Provider>
112
+ </TextStyleProvider>
100
113
  );
101
114
  }
102
115
 
103
116
  function AccordionContent({
104
- className,
117
+ style,
105
118
  children,
106
119
  ...props
107
120
  }: AccordionPrimitive.ContentProps & {
108
121
  ref?: React.RefObject<AccordionPrimitive.ContentRef>;
109
122
  }) {
110
- const { isExpanded } = AccordionPrimitive.useItemContext();
123
+ const { colors } = useTheme();
124
+
125
+ const textStyles = {
126
+ fontSize: Platform.OS === 'web' ? 14 : 18,
127
+ color: colors.text,
128
+ };
129
+
111
130
  return (
112
- <TextClassContext.Provider value="native:text-lg">
131
+ <TextStyleProvider style={textStyles}>
113
132
  <AccordionPrimitive.Content
114
- className={cn(
115
- 'overflow-hidden text-sm web:transition-all',
116
- isExpanded
117
- ? 'web:animate-accordion-down'
118
- : 'web:animate-accordion-up',
119
- )}
133
+ style={StyleSheet.flatten([
134
+ styles.content,
135
+ { overflow: 'hidden' },
136
+ style,
137
+ ])}
120
138
  {...props}
121
139
  >
122
- <InnerContent className={cn('pb-4', className)}>
123
- {children}
124
- </InnerContent>
140
+ <InnerContent style={styles.innerContent}>{children}</InnerContent>
125
141
  </AccordionPrimitive.Content>
126
- </TextClassContext.Provider>
142
+ </TextStyleProvider>
127
143
  );
128
144
  }
129
145
 
130
146
  function InnerContent({
131
147
  children,
132
- className,
148
+ style,
133
149
  }: {
134
150
  children: React.ReactNode;
135
- className?: string;
151
+ style?: any;
136
152
  }) {
137
153
  if (Platform.OS === 'web') {
138
- return <View className={cn('pb-4', className)}>{children}</View>;
154
+ return (
155
+ <View style={StyleSheet.flatten([styles.innerContent, style])}>
156
+ {children}
157
+ </View>
158
+ );
139
159
  }
140
160
  return (
141
161
  <Animated.View
142
162
  entering={FadeIn}
143
163
  exiting={FadeOutUp.duration(200)}
144
- className={cn('pb-4', className)}
164
+ style={StyleSheet.flatten([styles.innerContent, style])}
145
165
  >
146
166
  {children}
147
167
  </Animated.View>
148
168
  );
149
169
  }
150
170
 
171
+ const styles = StyleSheet.create({
172
+ itemContainer: {
173
+ overflow: 'hidden',
174
+ },
175
+ item: {
176
+ borderBottomWidth: 1,
177
+ },
178
+ header: {
179
+ flexDirection: 'row',
180
+ },
181
+ trigger: {
182
+ flexDirection: 'row',
183
+ alignItems: 'center',
184
+ justifyContent: 'space-between',
185
+ paddingVertical: 16,
186
+ },
187
+ content: {
188
+ overflow: 'hidden',
189
+ },
190
+ innerContent: {
191
+ paddingBottom: 16,
192
+ },
193
+ });
194
+
151
195
  export { Accordion, AccordionContent, AccordionItem, AccordionTrigger };
@@ -1,48 +1,42 @@
1
1
  import { useTheme } from '@react-navigation/native';
2
- import { cva, type VariantProps } from 'class-variance-authority';
3
2
  import type { LucideIcon } from 'lucide-react-native';
4
3
  import * as React from 'react';
5
- import { View, type ViewProps } from 'react-native';
6
- import { cn } from '../../lib/utils';
4
+ import { View, type ViewProps, StyleSheet } from 'react-native';
7
5
  import { Text } from '../../components/ui/text';
8
6
 
9
- const alertVariants = cva(
10
- 'relative bg-background w-full rounded-lg border border-border p-4 shadow shadow-foreground/10',
11
- {
12
- variants: {
13
- variant: {
14
- default: '',
15
- destructive: 'border-destructive',
16
- },
17
- },
18
- defaultVariants: {
19
- variant: 'default',
20
- },
21
- },
22
- );
7
+ type AlertVariant = 'default' | 'destructive';
8
+
9
+ interface AlertProps extends ViewProps {
10
+ ref?: React.RefObject<View>;
11
+ icon: LucideIcon;
12
+ iconSize?: number;
13
+ variant?: AlertVariant;
14
+ }
23
15
 
24
16
  function Alert({
25
- className,
26
- variant,
17
+ style,
18
+ variant = 'default',
27
19
  children,
28
20
  icon: Icon,
29
21
  iconSize = 16,
30
22
  ...props
31
- }: ViewProps &
32
- VariantProps<typeof alertVariants> & {
33
- ref?: React.RefObject<View>;
34
- icon: LucideIcon;
35
- iconSize?: number;
36
- iconClassName?: string;
37
- }) {
23
+ }: AlertProps) {
38
24
  const { colors } = useTheme();
25
+
26
+ const getAlertStyles = () => {
27
+ const baseAlertStyles = {
28
+ backgroundColor: colors.background,
29
+ borderColor:
30
+ variant === 'destructive' ? colors.notification : colors.border,
31
+ shadowColor: colors.text,
32
+ };
33
+
34
+ return StyleSheet.flatten([styles.base, baseAlertStyles, style]);
35
+ };
36
+
39
37
  return (
40
- <View
41
- role="alert"
42
- className={alertVariants({ variant, className })}
43
- {...props}
44
- >
45
- <View className="absolute left-3.5 top-4 -translate-y-0.5">
38
+ <View role="alert" style={getAlertStyles()} {...props}>
39
+ <View style={styles.icon}>
46
40
  <Icon
47
41
  size={iconSize}
48
42
  color={variant === 'destructive' ? colors.notification : colors.text}
@@ -53,31 +47,70 @@ function Alert({
53
47
  );
54
48
  }
55
49
 
56
- function AlertTitle({
57
- className,
58
- ...props
59
- }: React.ComponentProps<typeof Text>) {
50
+ function AlertTitle({ style, ...props }: React.ComponentProps<typeof Text>) {
51
+ const { colors } = useTheme();
60
52
  return (
61
53
  <Text
62
- className={cn(
63
- 'pl-7 mb-1 font-medium text-base leading-none tracking-tight text-foreground',
64
- className,
65
- )}
54
+ style={StyleSheet.flatten([styles.title, { color: colors.text }, style])}
66
55
  {...props}
67
56
  />
68
57
  );
69
58
  }
70
59
 
71
60
  function AlertDescription({
72
- className,
61
+ style,
73
62
  ...props
74
63
  }: React.ComponentProps<typeof Text>) {
64
+ const { colors } = useTheme();
75
65
  return (
76
66
  <Text
77
- className={cn('pl-7 text-sm leading-relaxed text-foreground', className)}
67
+ style={StyleSheet.flatten([
68
+ styles.description,
69
+ { color: colors.text },
70
+ style,
71
+ ])}
78
72
  {...props}
79
73
  />
80
74
  );
81
75
  }
82
76
 
77
+ const styles = StyleSheet.create({
78
+ base: {
79
+ position: 'relative',
80
+ width: '100%',
81
+ borderRadius: 8,
82
+ borderWidth: 1,
83
+ padding: 16,
84
+ shadowOffset: { width: 0, height: 0 },
85
+ shadowOpacity: 0.1,
86
+ shadowRadius: 4,
87
+ elevation: 2,
88
+ },
89
+ default: {
90
+ // no additional styles
91
+ },
92
+ destructive: {
93
+ // border color will be applied dynamically
94
+ },
95
+ icon: {
96
+ position: 'absolute',
97
+ left: 14,
98
+ top: 16,
99
+ transform: [{ translateY: -2 }],
100
+ },
101
+ title: {
102
+ paddingLeft: 28,
103
+ marginBottom: 4,
104
+ fontWeight: '500',
105
+ fontSize: 16,
106
+ lineHeight: 16,
107
+ letterSpacing: -0.025,
108
+ },
109
+ description: {
110
+ paddingLeft: 28,
111
+ fontSize: 14,
112
+ lineHeight: 20,
113
+ },
114
+ });
115
+
83
116
  export { Alert, AlertDescription, AlertTitle };
@@ -1,53 +1,78 @@
1
+ import { useTheme } from '@react-navigation/native';
1
2
  import * as AvatarPrimitive from '@rn-primitives/avatar';
2
3
  import * as React from 'react';
3
- import { cn } from '../../lib/utils';
4
+ import { StyleSheet } from 'react-native';
4
5
 
5
6
  function Avatar({
6
- className,
7
+ style,
7
8
  ...props
8
9
  }: AvatarPrimitive.RootProps & {
9
10
  ref?: React.RefObject<AvatarPrimitive.RootRef>;
10
11
  }) {
11
12
  return (
12
13
  <AvatarPrimitive.Root
13
- className={cn(
14
- 'relative flex h-10 w-10 shrink-0 overflow-hidden rounded-full',
15
- className,
16
- )}
14
+ style={StyleSheet.flatten([styles.avatar, style])}
17
15
  {...props}
18
16
  />
19
17
  );
20
18
  }
21
19
 
22
20
  function AvatarImage({
23
- className,
21
+ style,
24
22
  ...props
25
23
  }: AvatarPrimitive.ImageProps & {
26
24
  ref?: React.RefObject<AvatarPrimitive.ImageRef>;
27
25
  }) {
28
26
  return (
29
27
  <AvatarPrimitive.Image
30
- className={cn('aspect-square h-full w-full', className)}
28
+ style={StyleSheet.flatten([styles.image, style])}
31
29
  {...props}
32
30
  />
33
31
  );
34
32
  }
35
33
 
36
34
  function AvatarFallback({
37
- className,
35
+ style,
38
36
  ...props
39
37
  }: AvatarPrimitive.FallbackProps & {
40
38
  ref?: React.RefObject<AvatarPrimitive.FallbackRef>;
41
39
  }) {
40
+ const { colors } = useTheme();
42
41
  return (
43
42
  <AvatarPrimitive.Fallback
44
- className={cn(
45
- 'flex h-full w-full items-center justify-center rounded-full bg-muted',
46
- className,
47
- )}
43
+ style={StyleSheet.flatten([
44
+ styles.fallback,
45
+ { backgroundColor: colors.border },
46
+ style,
47
+ ])}
48
48
  {...props}
49
49
  />
50
50
  );
51
51
  }
52
52
 
53
+ const styles = StyleSheet.create({
54
+ avatar: {
55
+ position: 'relative',
56
+ flexDirection: 'row',
57
+ height: 40,
58
+ width: 40,
59
+ flexShrink: 0,
60
+ overflow: 'hidden',
61
+ borderRadius: 20,
62
+ },
63
+ image: {
64
+ aspectRatio: 1,
65
+ height: '100%',
66
+ width: '100%',
67
+ },
68
+ fallback: {
69
+ flexDirection: 'row',
70
+ height: '100%',
71
+ width: '100%',
72
+ alignItems: 'center',
73
+ justifyContent: 'center',
74
+ borderRadius: 20,
75
+ },
76
+ });
77
+
53
78
  export { Avatar, AvatarFallback, AvatarImage };
@@ -1,59 +1,87 @@
1
1
  import React from 'react';
2
2
  import * as Slot from '@rn-primitives/slot';
3
- import { cva, type VariantProps } from 'class-variance-authority';
4
- import { View, ViewProps } from 'react-native';
5
- import { cn } from '../../lib/utils';
6
- import { TextClassContext } from '../ui/text';
7
-
8
- const badgeVariants = cva(
9
- 'web:inline-flex items-center rounded-full border border-border px-2.5 py-0.5 web:transition-colors web:focus:outline-none web:focus:ring-2 web:focus:ring-ring web:focus:ring-offset-2',
10
- {
11
- variants: {
12
- variant: {
13
- default:
14
- 'border-transparent bg-primary web:hover:opacity-80 active:opacity-80',
15
- secondary:
16
- 'border-transparent bg-secondary web:hover:opacity-80 active:opacity-80',
17
- destructive:
18
- 'border-transparent bg-destructive web:hover:opacity-80 active:opacity-80',
19
- outline: 'text-foreground',
20
- },
21
- },
22
- defaultVariants: {
23
- variant: 'default',
24
- },
25
- },
26
- );
27
-
28
- const badgeTextVariants = cva('text-xs font-semibold ', {
29
- variants: {
30
- variant: {
31
- default: 'text-primary-foreground',
32
- secondary: 'text-secondary-foreground',
33
- destructive: 'text-destructive-foreground',
34
- outline: 'text-foreground',
35
- },
36
- },
37
- defaultVariants: {
38
- variant: 'default',
39
- },
40
- });
3
+ import { View, ViewProps, StyleSheet } from 'react-native';
4
+ import { useTheme } from '@react-navigation/native';
5
+ import { TextStyleProvider } from '../ui/text';
6
+
7
+ type BadgeVariant = 'default' | 'secondary' | 'destructive' | 'outline';
41
8
 
42
9
  type BadgeProps = ViewProps & {
43
10
  asChild?: boolean;
44
- } & VariantProps<typeof badgeVariants>;
11
+ variant?: BadgeVariant;
12
+ };
45
13
 
46
- function Badge({ className, variant, asChild, ...props }: BadgeProps) {
14
+ function Badge({ style, variant = 'default', asChild, ...props }: BadgeProps) {
15
+ const { colors } = useTheme();
47
16
  const Component = asChild ? Slot.View : View;
17
+
18
+ const getVariantStyles = () => {
19
+ switch (variant) {
20
+ case 'default':
21
+ return { backgroundColor: colors.primary, borderColor: 'transparent' };
22
+ case 'secondary':
23
+ return { backgroundColor: colors.border, borderColor: 'transparent' };
24
+ case 'destructive':
25
+ return {
26
+ backgroundColor: colors.notification,
27
+ borderColor: 'transparent',
28
+ };
29
+ case 'outline':
30
+ return { backgroundColor: 'transparent', borderColor: colors.border };
31
+ default:
32
+ return { backgroundColor: colors.primary, borderColor: 'transparent' };
33
+ }
34
+ };
35
+
36
+ const getTextColor = () => {
37
+ switch (variant) {
38
+ case 'default':
39
+ return colors.background;
40
+ case 'secondary':
41
+ return colors.text;
42
+ case 'destructive':
43
+ return colors.background;
44
+ case 'outline':
45
+ return colors.text;
46
+ default:
47
+ return colors.background;
48
+ }
49
+ };
50
+
51
+ const badgeStyle = StyleSheet.flatten([
52
+ styles.base,
53
+ getVariantStyles(),
54
+ style,
55
+ ]);
56
+ const textStyle = StyleSheet.flatten([
57
+ textStyles.base,
58
+ { color: getTextColor() },
59
+ ]);
60
+
48
61
  return (
49
- <TextClassContext.Provider value={badgeTextVariants({ variant })}>
50
- <Component
51
- className={cn(badgeVariants({ variant }), className)}
52
- {...props}
53
- />
54
- </TextClassContext.Provider>
62
+ <TextStyleProvider style={textStyle}>
63
+ <Component style={badgeStyle} {...props} />
64
+ </TextStyleProvider>
55
65
  );
56
66
  }
57
67
 
58
- export { Badge, badgeTextVariants, badgeVariants };
59
- export type { BadgeProps };
68
+ const styles = StyleSheet.create({
69
+ base: {
70
+ flexDirection: 'row',
71
+ alignItems: 'center',
72
+ borderRadius: 20,
73
+ borderWidth: 1,
74
+ paddingHorizontal: 10,
75
+ paddingVertical: 2,
76
+ },
77
+ });
78
+
79
+ const textStyles = StyleSheet.create({
80
+ base: {
81
+ fontSize: 12,
82
+ fontWeight: '600',
83
+ },
84
+ });
85
+
86
+ export { Badge };
87
+ export type { BadgeProps, BadgeVariant };