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
@@ -2,19 +2,22 @@ import * as DropdownMenuPrimitive from '@rn-primitives/dropdown-menu';
2
2
  import * as React from 'react';
3
3
  import {
4
4
  Platform,
5
+ Pressable,
5
6
  type StyleProp,
6
7
  StyleSheet,
7
8
  Text,
8
9
  type TextProps,
10
+ TextStyle,
9
11
  View,
10
12
  type ViewStyle,
11
13
  } from 'react-native';
12
- import { Check } from '../../lib/icons/Check';
13
- import { ChevronDown } from '../../lib/icons/ChevronDown';
14
- import { ChevronRight } from '../../lib/icons/ChevronRight';
15
- import { ChevronUp } from '../../lib/icons/ChevronUp';
16
- import { cn } from '../../lib/utils';
17
- import { TextClassContext } from '../../components/ui/text';
14
+ import { Check } from 'lucide-react-native';
15
+ import { ChevronDown } from 'lucide-react-native';
16
+ import { ChevronRight } from 'lucide-react-native';
17
+ import { ChevronUp } from 'lucide-react-native';
18
+ import { useTheme } from '@react-navigation/native';
19
+ import { TextStyleProvider } from '../../components/ui/text';
20
+ import { Icon } from './icon';
18
21
 
19
22
  const DropdownMenu = DropdownMenuPrimitive.Root;
20
23
 
@@ -29,76 +32,82 @@ const DropdownMenuSub = DropdownMenuPrimitive.Sub;
29
32
  const DropdownMenuRadioGroup = DropdownMenuPrimitive.RadioGroup;
30
33
 
31
34
  function DropdownMenuSubTrigger({
32
- className,
35
+ style,
33
36
  inset,
34
37
  children,
35
38
  ...props
36
39
  }: DropdownMenuPrimitive.SubTriggerProps & {
37
40
  ref?: React.RefObject<DropdownMenuPrimitive.SubTriggerRef>;
38
- className?: string;
41
+ style?: StyleProp<ViewStyle>;
39
42
  inset?: boolean;
40
43
  children?: React.ReactNode;
41
44
  }) {
45
+ const theme = useTheme();
42
46
  const { open } = DropdownMenuPrimitive.useSubContext();
43
- const Icon =
47
+ const SubIcon =
44
48
  Platform.OS === 'web' ? ChevronRight : open ? ChevronUp : ChevronDown;
45
49
  return (
46
- <TextClassContext.Provider
47
- value={cn(
48
- 'select-none text-sm native:text-lg text-primary',
49
- open && 'native:text-accent-foreground',
50
- )}
50
+ <TextStyleProvider
51
+ style={StyleSheet.flatten([
52
+ styles.subTriggerText,
53
+ { color: theme.colors.text },
54
+ ])}
51
55
  >
52
- <DropdownMenuPrimitive.SubTrigger
53
- className={cn(
54
- 'flex flex-row web:cursor-default web:select-none gap-2 items-center web:focus:bg-accent web:hover:bg-accent active:bg-accent rounded-sm px-2 py-1.5 native:py-2 web:outline-none',
55
- open && 'bg-accent',
56
- inset && 'pl-8',
57
- className,
58
- )}
59
- {...props}
60
- >
61
- {children}
62
- <Icon size={18} className="ml-auto text-foreground" />
56
+ <DropdownMenuPrimitive.SubTrigger asChild {...props}>
57
+ <Pressable
58
+ style={({ pressed, hovered }) =>
59
+ StyleSheet.flatten([
60
+ styles.subTrigger,
61
+ open && { backgroundColor: theme.colors.border },
62
+ (pressed || hovered) && { backgroundColor: theme.colors.border },
63
+ inset && styles.subTriggerInset,
64
+ style,
65
+ ])
66
+ }
67
+ >
68
+ {children}
69
+ <Icon icon={SubIcon} style={styles.subTriggerIcon} />
70
+ </Pressable>
63
71
  </DropdownMenuPrimitive.SubTrigger>
64
- </TextClassContext.Provider>
72
+ </TextStyleProvider>
65
73
  );
66
74
  }
67
75
 
68
76
  function DropdownMenuSubContent({
69
- className,
77
+ style,
70
78
  ...props
71
79
  }: DropdownMenuPrimitive.SubContentProps & {
72
80
  ref?: React.RefObject<DropdownMenuPrimitive.SubContentRef>;
81
+ style?: StyleProp<ViewStyle>;
73
82
  }) {
74
- const { open } = DropdownMenuPrimitive.useSubContext();
83
+ const theme = useTheme();
75
84
  return (
76
85
  <DropdownMenuPrimitive.SubContent
77
- className={cn(
78
- 'z-50 min-w-[8rem] overflow-hidden rounded-md border border-border mt-1 bg-popover p-1 shadow-md shadow-foreground/5 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',
79
- open
80
- ? 'web:animate-in web:fade-in-0 web:zoom-in-95'
81
- : 'web:animate-out web:fade-out-0 web:zoom-out',
82
- className,
83
- )}
86
+ style={[
87
+ styles.subContent,
88
+ {
89
+ borderColor: theme.colors.border,
90
+ backgroundColor: theme.colors.background,
91
+ shadowColor: theme.colors.text,
92
+ },
93
+ style,
94
+ ]}
84
95
  {...props}
85
96
  />
86
97
  );
87
98
  }
88
99
 
89
100
  function DropdownMenuContent({
90
- className,
91
- overlayClassName,
101
+ style,
92
102
  overlayStyle,
93
103
  portalHost,
94
104
  ...props
95
105
  }: DropdownMenuPrimitive.ContentProps & {
96
106
  ref?: React.RefObject<DropdownMenuPrimitive.ContentRef>;
97
107
  overlayStyle?: StyleProp<ViewStyle>;
98
- overlayClassName?: string;
99
108
  portalHost?: string;
100
109
  }) {
101
- const { open } = DropdownMenuPrimitive.useRootContext();
110
+ const theme = useTheme();
102
111
  return (
103
112
  <DropdownMenuPrimitive.Portal hostName={portalHost}>
104
113
  <DropdownMenuPrimitive.Overlay
@@ -112,16 +121,17 @@ function DropdownMenuContent({
112
121
  ? StyleSheet.absoluteFill
113
122
  : undefined
114
123
  }
115
- className={overlayClassName}
116
124
  >
117
125
  <DropdownMenuPrimitive.Content
118
- className={cn(
119
- 'z-50 min-w-[8rem] overflow-hidden rounded-md border border-border bg-popover p-1 shadow-md shadow-foreground/5 web:data-[side=bottom]:slide-in-from-top-2 web:data-[side=left]:slide-in-from-right-2 web:data-[side=right]:slide-in-from-left-2 web:data-[side=top]:slide-in-from-bottom-2',
120
- open
121
- ? 'web:animate-in web:fade-in-0 web:zoom-in-95'
122
- : 'web:animate-out web:fade-out-0 web:zoom-out-95',
123
- className,
124
- )}
126
+ style={StyleSheet.flatten([
127
+ styles.content,
128
+ {
129
+ borderColor: theme.colors.border,
130
+ backgroundColor: theme.colors.background,
131
+ shadowColor: theme.colors.text,
132
+ },
133
+ style,
134
+ ])}
125
135
  {...props}
126
136
  />
127
137
  </DropdownMenuPrimitive.Overlay>
@@ -130,127 +140,158 @@ function DropdownMenuContent({
130
140
  }
131
141
 
132
142
  function DropdownMenuItem({
133
- className,
143
+ style,
134
144
  inset,
145
+ children,
135
146
  ...props
136
147
  }: DropdownMenuPrimitive.ItemProps & {
137
148
  ref?: React.RefObject<DropdownMenuPrimitive.ItemRef>;
138
- className?: string;
149
+ style?: StyleProp<ViewStyle>;
139
150
  inset?: boolean;
140
151
  }) {
152
+ const theme = useTheme();
141
153
  return (
142
- <TextClassContext.Provider value="select-none text-sm native:text-lg text-popover-foreground web:group-focus:text-accent-foreground">
143
- <DropdownMenuPrimitive.Item
144
- className={cn(
145
- 'relative flex flex-row web:cursor-default gap-2 items-center rounded-sm px-2 py-1.5 native:py-2 web:outline-none web:focus:bg-accent active:bg-accent web:hover:bg-accent group',
146
- inset && 'pl-8',
147
- props.disabled && 'opacity-50 web:pointer-events-none',
148
- className,
149
- )}
150
- {...props}
151
- />
152
- </TextClassContext.Provider>
154
+ <TextStyleProvider style={{ color: theme.colors.text }}>
155
+ <DropdownMenuPrimitive.Item asChild {...props}>
156
+ <Pressable
157
+ style={({ pressed, hovered }) =>
158
+ StyleSheet.flatten([
159
+ styles.item,
160
+ inset && styles.itemInset,
161
+ props.disabled && styles.itemDisabled,
162
+ (pressed || hovered) && { backgroundColor: theme.colors.border },
163
+ style,
164
+ ])
165
+ }
166
+ >
167
+ {children}
168
+ </Pressable>
169
+ </DropdownMenuPrimitive.Item>
170
+ </TextStyleProvider>
153
171
  );
154
172
  }
155
173
 
156
174
  function DropdownMenuCheckboxItem({
157
- className,
175
+ style,
158
176
  children,
159
177
  checked,
160
178
  ...props
161
179
  }: DropdownMenuPrimitive.CheckboxItemProps & {
162
180
  ref?: React.RefObject<DropdownMenuPrimitive.CheckboxItemRef>;
181
+ style?: StyleProp<ViewStyle>;
163
182
  children?: React.ReactNode;
164
183
  }) {
184
+ const theme = useTheme();
165
185
  return (
166
- <DropdownMenuPrimitive.CheckboxItem
167
- className={cn(
168
- 'relative flex flex-row web:cursor-default items-center web:group rounded-sm py-1.5 native:py-2 pl-8 pr-2 web:outline-none web:focus:bg-accent active:bg-accent',
169
- props.disabled && 'web:pointer-events-none opacity-50',
170
- className,
171
- )}
172
- checked={checked}
173
- {...props}
174
- >
175
- <View className="absolute left-2 flex h-3.5 w-3.5 items-center justify-center">
176
- <DropdownMenuPrimitive.ItemIndicator>
177
- <Check size={14} strokeWidth={3} className="text-foreground" />
178
- </DropdownMenuPrimitive.ItemIndicator>
179
- </View>
180
- {children}
186
+ <DropdownMenuPrimitive.CheckboxItem asChild checked={checked} {...props}>
187
+ <Pressable
188
+ style={({ pressed, hovered }) =>
189
+ StyleSheet.flatten([
190
+ styles.checkboxItem,
191
+ props.disabled && styles.checkboxItemDisabled,
192
+ (pressed || hovered) && { backgroundColor: theme.colors.border },
193
+ style,
194
+ ])
195
+ }
196
+ >
197
+ <View style={styles.checkboxIndicator}>
198
+ <DropdownMenuPrimitive.ItemIndicator>
199
+ <Check size={14} strokeWidth={3} color={theme.colors.text} />
200
+ </DropdownMenuPrimitive.ItemIndicator>
201
+ </View>
202
+ {children}
203
+ </Pressable>
181
204
  </DropdownMenuPrimitive.CheckboxItem>
182
205
  );
183
206
  }
184
207
 
185
208
  function DropdownMenuRadioItem({
186
- className,
209
+ style,
187
210
  children,
188
211
  ...props
189
212
  }: DropdownMenuPrimitive.RadioItemProps & {
190
213
  ref?: React.RefObject<DropdownMenuPrimitive.RadioItemRef>;
214
+ style?: StyleProp<ViewStyle>;
191
215
  children?: React.ReactNode;
192
216
  }) {
217
+ const theme = useTheme();
193
218
  return (
194
- <DropdownMenuPrimitive.RadioItem
195
- className={cn(
196
- 'relative flex flex-row web:cursor-default web:group items-center rounded-sm py-1.5 native:py-2 pl-8 pr-2 web:outline-none web:focus:bg-accent active:bg-accent',
197
- props.disabled && 'web:pointer-events-none opacity-50',
198
- className,
199
- )}
200
- {...props}
201
- >
202
- <View className="absolute left-2 flex h-3.5 w-3.5 items-center justify-center">
203
- <DropdownMenuPrimitive.ItemIndicator>
204
- <View className="bg-foreground h-2 w-2 rounded-full" />
205
- </DropdownMenuPrimitive.ItemIndicator>
206
- </View>
207
- {children}
219
+ <DropdownMenuPrimitive.RadioItem asChild {...props}>
220
+ <Pressable
221
+ style={({ pressed, hovered }) =>
222
+ StyleSheet.flatten([
223
+ styles.radioItem,
224
+ props.disabled && styles.radioItemDisabled,
225
+ (pressed || hovered) && { backgroundColor: theme.colors.border },
226
+ style,
227
+ ])
228
+ }
229
+ >
230
+ <View style={styles.radioIndicator}>
231
+ <DropdownMenuPrimitive.ItemIndicator>
232
+ <View
233
+ style={[styles.radioDot, { backgroundColor: theme.colors.text }]}
234
+ />
235
+ </DropdownMenuPrimitive.ItemIndicator>
236
+ </View>
237
+ {children}
238
+ </Pressable>
208
239
  </DropdownMenuPrimitive.RadioItem>
209
240
  );
210
241
  }
211
242
 
212
243
  function DropdownMenuLabel({
213
- className,
244
+ style,
214
245
  inset,
215
246
  ...props
216
247
  }: DropdownMenuPrimitive.LabelProps & {
217
248
  ref?: React.RefObject<DropdownMenuPrimitive.LabelRef>;
218
- className?: string;
249
+ style?: StyleProp<ViewStyle>;
219
250
  inset?: boolean;
220
251
  }) {
252
+ const theme = useTheme();
221
253
  return (
222
254
  <DropdownMenuPrimitive.Label
223
- className={cn(
224
- 'px-2 py-1.5 text-sm native:text-base font-semibold text-foreground web:cursor-default',
225
- inset && 'pl-8',
226
- className,
227
- )}
255
+ style={StyleSheet.flatten<TextStyle>([
256
+ styles.label,
257
+ { color: theme.colors.text },
258
+ inset && styles.labelInset,
259
+ style,
260
+ ])}
228
261
  {...props}
229
262
  />
230
263
  );
231
264
  }
232
265
 
233
266
  function DropdownMenuSeparator({
234
- className,
267
+ style,
235
268
  ...props
236
269
  }: DropdownMenuPrimitive.SeparatorProps & {
237
270
  ref?: React.RefObject<DropdownMenuPrimitive.SeparatorRef>;
271
+ style?: StyleProp<ViewStyle>;
238
272
  }) {
273
+ const theme = useTheme();
239
274
  return (
240
275
  <DropdownMenuPrimitive.Separator
241
- className={cn('-mx-1 my-1 h-px bg-border', className)}
276
+ style={StyleSheet.flatten([
277
+ styles.separator,
278
+ { backgroundColor: theme.colors.border },
279
+ style,
280
+ ])}
242
281
  {...props}
243
282
  />
244
283
  );
245
284
  }
246
285
 
247
- function DropdownMenuShortcut({ className, ...props }: TextProps) {
286
+ function DropdownMenuShortcut({ style, ...props }: TextProps) {
287
+ const theme = useTheme();
248
288
  return (
249
289
  <Text
250
- className={cn(
251
- 'ml-auto text-xs native:text-sm tracking-widest text-muted-foreground',
252
- className,
253
- )}
290
+ style={[
291
+ styles.shortcut,
292
+ { color: theme.colors.text + '80' }, // muted text with opacity
293
+ style,
294
+ ]}
254
295
  {...props}
255
296
  />
256
297
  );
@@ -273,3 +314,161 @@ export {
273
314
  DropdownMenuSubTrigger,
274
315
  DropdownMenuTrigger,
275
316
  };
317
+
318
+ // Base styles that don't require theme
319
+ const styles = StyleSheet.create({
320
+ // SubTrigger styles
321
+ subTriggerText: {
322
+ fontSize: Platform.OS === 'web' ? 14 : 18, // text-sm native:text-lg
323
+ },
324
+ subTriggerTextOpen: {
325
+ // Color applied at render time
326
+ },
327
+ subTrigger: {
328
+ flexDirection: 'row',
329
+ alignItems: 'center',
330
+ gap: 8, // gap-2
331
+ paddingHorizontal: 8, // px-2
332
+ paddingVertical: Platform.OS === 'web' ? 6 : 8, // py-1.5 native:py-2
333
+ borderRadius: 2, // rounded-sm
334
+ },
335
+ subTriggerInset: {
336
+ paddingLeft: 32, // pl-8
337
+ },
338
+ subTriggerOpen: {
339
+ // Background color applied at render time
340
+ },
341
+ subTriggerIcon: {
342
+ marginLeft: 'auto',
343
+ fontSize: 18,
344
+ // Color applied at render time
345
+ },
346
+
347
+ // SubContent styles
348
+ subContent: {
349
+ zIndex: 50, // z-50
350
+ minWidth: 128, // min-w-[8rem]
351
+ overflow: 'hidden',
352
+ borderRadius: 6, // rounded-md
353
+ borderWidth: 1,
354
+ marginTop: 4, // mt-1
355
+ padding: 4, // p-1
356
+ shadowOffset: { width: 0, height: 1 },
357
+ shadowOpacity: 0.05, // shadow-foreground/5
358
+ shadowRadius: 2,
359
+ elevation: 2, // Android shadow
360
+ // Border color, background color, and shadow color applied at render time
361
+ },
362
+
363
+ // Content styles
364
+ content: {
365
+ zIndex: 50, // z-50
366
+ minWidth: 128, // min-w-[8rem]
367
+ overflow: 'hidden',
368
+ borderRadius: 6, // rounded-md
369
+ borderWidth: 1,
370
+ padding: 4, // p-1
371
+ shadowOffset: { width: 0, height: 1 },
372
+ shadowOpacity: 0.05, // shadow-foreground/5
373
+ shadowRadius: 2,
374
+ elevation: 2, // Android shadow
375
+ // Border color, background color, and shadow color applied at render time
376
+ },
377
+
378
+ item: {
379
+ position: 'relative',
380
+ flexDirection: 'row',
381
+ alignItems: 'center',
382
+ gap: 8, // gap-2
383
+ borderRadius: 2, // rounded-sm
384
+ paddingHorizontal: 8, // px-2
385
+ paddingVertical: Platform.OS === 'web' ? 6 : 8, // py-1.5 native:py-2
386
+ },
387
+ itemInset: {
388
+ paddingLeft: 32, // pl-8
389
+ },
390
+ itemDisabled: {
391
+ opacity: 0.5, // opacity-50
392
+ },
393
+
394
+ // CheckboxItem styles
395
+ checkboxItem: {
396
+ position: 'relative',
397
+ flexDirection: 'row',
398
+ alignItems: 'center',
399
+ borderRadius: 2, // rounded-sm
400
+ paddingVertical: Platform.OS === 'web' ? 6 : 8, // py-1.5 native:py-2
401
+ paddingLeft: 32, // pl-8
402
+ paddingRight: 8, // pr-2
403
+ },
404
+ checkboxItemDisabled: {
405
+ opacity: 0.5, // opacity-50
406
+ },
407
+ checkboxIndicator: {
408
+ position: 'absolute',
409
+ left: 8, // left-2
410
+ width: 14, // w-3.5
411
+ height: 14, // h-3.5
412
+ alignItems: 'center',
413
+ justifyContent: 'center',
414
+ },
415
+ checkboxIcon: {
416
+ // Color applied at render time
417
+ },
418
+
419
+ // RadioItem styles
420
+ radioItem: {
421
+ position: 'relative',
422
+ flexDirection: 'row',
423
+ alignItems: 'center',
424
+ borderRadius: 2, // rounded-sm
425
+ paddingVertical: Platform.OS === 'web' ? 6 : 8, // py-1.5 native:py-2
426
+ paddingLeft: 32, // pl-8
427
+ paddingRight: 8, // pr-2
428
+ },
429
+ radioItemDisabled: {
430
+ opacity: 0.5, // opacity-50
431
+ },
432
+ radioIndicator: {
433
+ position: 'absolute',
434
+ left: 8, // left-2
435
+ width: 14, // w-3.5
436
+ height: 14, // h-3.5
437
+ alignItems: 'center',
438
+ justifyContent: 'center',
439
+ },
440
+ radioDot: {
441
+ width: 8, // w-2
442
+ height: 8, // h-2
443
+ borderRadius: 4, // rounded-full
444
+ // Background color applied at render time
445
+ },
446
+
447
+ // Label styles
448
+ label: {
449
+ paddingHorizontal: 8, // px-2
450
+ paddingVertical: 6, // py-1.5
451
+ fontSize: Platform.OS === 'web' ? 14 : 16, // text-sm native:text-base
452
+ fontWeight: '600', // font-semibold
453
+ // Color applied at render time
454
+ },
455
+ labelInset: {
456
+ paddingLeft: 32, // pl-8
457
+ },
458
+
459
+ // Separator styles
460
+ separator: {
461
+ marginHorizontal: -4, // -mx-1
462
+ marginVertical: 4, // my-1
463
+ height: 1, // h-px
464
+ // Background color applied at render time
465
+ },
466
+
467
+ // Shortcut styles
468
+ shortcut: {
469
+ marginLeft: 'auto',
470
+ fontSize: Platform.OS === 'web' ? 12 : 14, // text-xs native:text-sm
471
+ letterSpacing: 0.1, // tracking-widest
472
+ // Color applied at render time
473
+ },
474
+ });
@@ -2,46 +2,69 @@ import * as HoverCardPrimitive from '@rn-primitives/hover-card';
2
2
  import * as React from 'react';
3
3
  import { Platform, StyleSheet } from 'react-native';
4
4
  import Animated, { FadeIn } from 'react-native-reanimated';
5
- import { cn } from '../../lib/utils';
6
- import { TextClassContext } from '../../components/ui/text';
5
+ import { useTheme } from '@react-navigation/native';
6
+ import { TextStyleProvider } from '../../components/ui/text';
7
7
 
8
8
  const HoverCard = HoverCardPrimitive.Root;
9
9
 
10
10
  const HoverCardTrigger = HoverCardPrimitive.Trigger;
11
11
 
12
12
  function HoverCardContent({
13
- className,
13
+ style,
14
14
  align = 'center',
15
15
  sideOffset = 4,
16
16
  ...props
17
17
  }: HoverCardPrimitive.ContentProps & {
18
18
  ref?: React.RefObject<HoverCardPrimitive.ContentRef>;
19
19
  }) {
20
- const { open } = HoverCardPrimitive.useRootContext();
20
+ const { colors } = useTheme();
21
+
22
+ const contentStyles = StyleSheet.flatten([
23
+ styles.content,
24
+ {
25
+ backgroundColor: colors.background,
26
+ borderColor: colors.border,
27
+ shadowColor: colors.text,
28
+ },
29
+ style,
30
+ ]);
31
+
32
+ const textStyles = {
33
+ color: colors.text,
34
+ };
35
+
21
36
  return (
22
37
  <HoverCardPrimitive.Portal>
23
38
  <HoverCardPrimitive.Overlay
24
39
  style={Platform.OS !== 'web' ? StyleSheet.absoluteFill : undefined}
25
40
  >
26
41
  <Animated.View entering={FadeIn}>
27
- <TextClassContext.Provider value="text-popover-foreground">
42
+ <TextStyleProvider style={textStyles}>
28
43
  <HoverCardPrimitive.Content
29
44
  align={align}
30
45
  sideOffset={sideOffset}
31
- className={cn(
32
- 'z-50 w-64 rounded-md border border-border bg-popover p-4 shadow-md shadow-foreground/5 web:outline-none web:cursor-auto 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',
33
- open
34
- ? 'web:animate-in web:fade-in-0 web:zoom-in-95'
35
- : 'web:animate-out web:fade-out-0 web:zoom-out-95',
36
- className,
37
- )}
46
+ style={contentStyles}
38
47
  {...props}
39
48
  />
40
- </TextClassContext.Provider>
49
+ </TextStyleProvider>
41
50
  </Animated.View>
42
51
  </HoverCardPrimitive.Overlay>
43
52
  </HoverCardPrimitive.Portal>
44
53
  );
45
54
  }
46
55
 
56
+ const styles = StyleSheet.create({
57
+ content: {
58
+ zIndex: 50,
59
+ width: 256,
60
+ borderRadius: 6,
61
+ borderWidth: 1,
62
+ padding: 16,
63
+ shadowOffset: { width: 0, height: 2 },
64
+ shadowOpacity: 0.05,
65
+ shadowRadius: 4,
66
+ elevation: 2,
67
+ },
68
+ });
69
+
47
70
  export { HoverCard, HoverCardContent, HoverCardTrigger };
@@ -0,0 +1,23 @@
1
+ import React, { FunctionComponent } from 'react';
2
+ import { TextStyleProps, useTextStyles } from './text';
3
+ import { LucideIcon } from 'lucide-react-native';
4
+ import { StyleSheet, View, ViewStyle } from 'react-native';
5
+
6
+ interface IconProps extends TextStyleProps {
7
+ icon: LucideIcon;
8
+ }
9
+
10
+ export const Icon: FunctionComponent<IconProps> = ({
11
+ icon,
12
+ ...textStyleProps
13
+ }) => {
14
+ const textStyles = useTextStyles(textStyleProps);
15
+ const IconComponent = icon;
16
+ const iconStyle = StyleSheet.flatten(textStyles);
17
+ const { fontSize, color, ...restStyles } = iconStyle;
18
+ return (
19
+ <View style={restStyles as ViewStyle}>
20
+ <IconComponent size={fontSize} color={color} />
21
+ </View>
22
+ );
23
+ };