linked-data-browser 0.0.6 → 0.0.8-alpha.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.
Files changed (103) hide show
  1. package/.env +2 -0
  2. package/.eslintrc.js +1 -0
  3. package/.ldo/profile.shapeTypes.ts +18 -18
  4. package/.ldo/profile.typings.ts +17 -17
  5. package/app/index.tsx +3 -0
  6. package/babel.config.js +9 -1
  7. package/components/DataBrowser.tsx +9 -19
  8. package/components/DataBrowserContext.ts +24 -0
  9. package/components/TargetResourceProvider.tsx +1 -1
  10. package/components/ThemeProvider.tsx +2 -4
  11. package/components/common/LoadingBar.tsx +11 -1
  12. package/components/common/ProfileAvatar.tsx +6 -9
  13. package/components/nav/Layout.tsx +20 -4
  14. package/components/nav/header/AddressBox.tsx +104 -48
  15. package/components/nav/header/AvatarMenu.tsx +44 -12
  16. package/components/nav/header/Header.tsx +26 -19
  17. package/components/nav/header/SignInMenu.tsx +63 -36
  18. package/components/nav/header/ThemeToggleMenu.tsx +21 -9
  19. package/components/nav/header/ViewMenu.tsx +79 -71
  20. package/components/sharing/AccessDropdown.tsx +18 -7
  21. package/components/sharing/CopyLink.tsx +15 -3
  22. package/components/sharing/PermissionRow.tsx +17 -2
  23. package/components/sharing/SharingModal.tsx +30 -3
  24. package/components/sharing/WacRuleForm.tsx +12 -3
  25. package/components/sharing/agentPermissions/AgentInformation.tsx +18 -6
  26. package/components/sharing/agentPermissions/AgentInput.tsx +21 -6
  27. package/components/sharing/agentPermissions/AgentPermissionRow.tsx +24 -6
  28. package/components/ui/accordion.tsx +1 -1
  29. package/components/ui/alert.tsx +62 -46
  30. package/components/ui/avatar.tsx +38 -13
  31. package/components/ui/badge.tsx +63 -48
  32. package/components/ui/button.tsx +226 -108
  33. package/components/ui/card.tsx +53 -38
  34. package/components/ui/checkbox.tsx +53 -16
  35. package/components/ui/context-menu.tsx +4 -4
  36. package/components/ui/dialog.tsx +116 -65
  37. package/components/ui/dropdown-menu.tsx +304 -105
  38. package/components/ui/icon.tsx +23 -0
  39. package/components/ui/input-dropdown.tsx +42 -5
  40. package/components/ui/input.tsx +85 -22
  41. package/components/ui/label.tsx +16 -7
  42. package/components/ui/menubar.tsx +4 -4
  43. package/components/ui/navigation-menu.tsx +157 -90
  44. package/components/ui/progress.tsx +38 -24
  45. package/components/ui/select.tsx +139 -67
  46. package/components/ui/separator.tsx +22 -7
  47. package/components/ui/skeleton.tsx +14 -11
  48. package/components/ui/switch.tsx +82 -37
  49. package/components/ui/table.tsx +57 -35
  50. package/components/ui/tabs.tsx +66 -35
  51. package/components/ui/text.tsx +221 -30
  52. package/components/ui/textarea.tsx +34 -10
  53. package/components/ui/typography.tsx +94 -65
  54. package/components/useViewContext.tsx +8 -8
  55. package/global.css +93 -3
  56. package/metro.config.js +21 -3
  57. package/package.json +6 -9
  58. package/resourceViews/Container/ContainerConfig.tsx +1 -1
  59. package/resourceViews/Container/ContainerView.tsx +63 -25
  60. package/resourceViews/Profile/ProfileConfig.tsx +3 -3
  61. package/resourceViews/Profile/ProfileKnows.tsx +20 -11
  62. package/resourceViews/Profile/ProfileView.tsx +23 -6
  63. package/resourceViews/RawCode/RawCodeConfig.tsx +1 -1
  64. package/resourceViews/RawCode/RawCodeView.tsx +20 -6
  65. package/components.json +0 -7
  66. package/lib/icons/ArrowRight.tsx +0 -4
  67. package/lib/icons/Check.tsx +0 -4
  68. package/lib/icons/ChevronDown.tsx +0 -4
  69. package/lib/icons/ChevronRight.tsx +0 -4
  70. package/lib/icons/ChevronUp.tsx +0 -4
  71. package/lib/icons/ChevronsRight.tsx +0 -4
  72. package/lib/icons/CircleSlash.tsx +0 -4
  73. package/lib/icons/CircleX.tsx +0 -4
  74. package/lib/icons/Code.tsx +0 -4
  75. package/lib/icons/EllipsisVertical.tsx +0 -4
  76. package/lib/icons/EyeOff.tsx +0 -4
  77. package/lib/icons/File.tsx +0 -4
  78. package/lib/icons/Fingerprint.tsx +0 -4
  79. package/lib/icons/Folder.tsx +0 -4
  80. package/lib/icons/Folders.tsx +0 -4
  81. package/lib/icons/Info.tsx +0 -4
  82. package/lib/icons/Link.tsx +0 -4
  83. package/lib/icons/Loader.tsx +0 -4
  84. package/lib/icons/LogOut.tsx +0 -4
  85. package/lib/icons/MonitorSmartphone.tsx +0 -4
  86. package/lib/icons/MoonStar.tsx +0 -4
  87. package/lib/icons/OctagonX.tsx +0 -4
  88. package/lib/icons/Plus.tsx +0 -4
  89. package/lib/icons/RefreshCw.tsx +0 -4
  90. package/lib/icons/Save.tsx +0 -4
  91. package/lib/icons/ShieldX.tsx +0 -4
  92. package/lib/icons/Sun.tsx +0 -4
  93. package/lib/icons/TextCursorInput.tsx +0 -4
  94. package/lib/icons/Trash.tsx +0 -4
  95. package/lib/icons/User.tsx +0 -4
  96. package/lib/icons/UserPlus.tsx +0 -4
  97. package/lib/icons/Users.tsx +0 -4
  98. package/lib/icons/ViewIcon.tsx +0 -4
  99. package/lib/icons/X.tsx +0 -4
  100. package/lib/icons/iconWithClassName.ts +0 -14
  101. package/lib/utils.ts +0 -6
  102. package/nativewind-env.d.ts +0 -1
  103. package/tailwind.config.js +0 -69
package/.env ADDED
@@ -0,0 +1,2 @@
1
+ EXPO_PUBLIC_IS_SERVER_HOSTED=false
2
+ EXPO_PUBLIC_DEFAULT_ISSUER=http://localhost:3000
package/.eslintrc.js CHANGED
@@ -8,6 +8,7 @@ module.exports = {
8
8
  rules: {
9
9
  'prettier/prettier': ['error'],
10
10
  'react/no-unstable-nested-components': 0,
11
+ 'react-native/no-inline-styles': 0,
11
12
  '@typescript-eslint/no-unused-vars': 1,
12
13
  'no-restricted-imports': [
13
14
  'error',
@@ -2,12 +2,12 @@ import { ShapeType } from "@ldo/ldo";
2
2
  import { profileSchema } from "./profile.schema";
3
3
  import { profileContext } from "./profile.context";
4
4
  import {
5
- SolidProfileShape,
6
- AddressShape,
7
- EmailShape,
8
- PhoneNumberShape,
9
- TrustedAppShape,
10
- RSAPublicKeyShape,
5
+ SolidProfile,
6
+ Address,
7
+ Email,
8
+ PhoneNumber,
9
+ TrustedApp,
10
+ RSAPublicKey,
11
11
  } from "./profile.typings";
12
12
 
13
13
  /**
@@ -17,54 +17,54 @@ import {
17
17
  */
18
18
 
19
19
  /**
20
- * SolidProfileShape ShapeType
20
+ * SolidProfile ShapeType
21
21
  */
22
- export const SolidProfileShapeShapeType: ShapeType<SolidProfileShape> = {
22
+ export const SolidProfileShapeType: ShapeType<SolidProfile> = {
23
23
  schema: profileSchema,
24
24
  shape: "https://shaperepo.com/schemas/solidProfile#SolidProfileShape",
25
25
  context: profileContext,
26
26
  };
27
27
 
28
28
  /**
29
- * AddressShape ShapeType
29
+ * Address ShapeType
30
30
  */
31
- export const AddressShapeShapeType: ShapeType<AddressShape> = {
31
+ export const AddressShapeType: ShapeType<Address> = {
32
32
  schema: profileSchema,
33
33
  shape: "https://shaperepo.com/schemas/solidProfile#AddressShape",
34
34
  context: profileContext,
35
35
  };
36
36
 
37
37
  /**
38
- * EmailShape ShapeType
38
+ * Email ShapeType
39
39
  */
40
- export const EmailShapeShapeType: ShapeType<EmailShape> = {
40
+ export const EmailShapeType: ShapeType<Email> = {
41
41
  schema: profileSchema,
42
42
  shape: "https://shaperepo.com/schemas/solidProfile#EmailShape",
43
43
  context: profileContext,
44
44
  };
45
45
 
46
46
  /**
47
- * PhoneNumberShape ShapeType
47
+ * PhoneNumber ShapeType
48
48
  */
49
- export const PhoneNumberShapeShapeType: ShapeType<PhoneNumberShape> = {
49
+ export const PhoneNumberShapeType: ShapeType<PhoneNumber> = {
50
50
  schema: profileSchema,
51
51
  shape: "https://shaperepo.com/schemas/solidProfile#PhoneNumberShape",
52
52
  context: profileContext,
53
53
  };
54
54
 
55
55
  /**
56
- * TrustedAppShape ShapeType
56
+ * TrustedApp ShapeType
57
57
  */
58
- export const TrustedAppShapeShapeType: ShapeType<TrustedAppShape> = {
58
+ export const TrustedAppShapeType: ShapeType<TrustedApp> = {
59
59
  schema: profileSchema,
60
60
  shape: "https://shaperepo.com/schemas/solidProfile#TrustedAppShape",
61
61
  context: profileContext,
62
62
  };
63
63
 
64
64
  /**
65
- * RSAPublicKeyShape ShapeType
65
+ * RSAPublicKey ShapeType
66
66
  */
67
- export const RSAPublicKeyShapeShapeType: ShapeType<RSAPublicKeyShape> = {
67
+ export const RSAPublicKeyShapeType: ShapeType<RSAPublicKey> = {
68
68
  schema: profileSchema,
69
69
  shape: "https://shaperepo.com/schemas/solidProfile#RSAPublicKeyShape",
70
70
  context: profileContext,
@@ -7,9 +7,9 @@ import { LdoJsonldContext, LdSet } from "@ldo/ldo";
7
7
  */
8
8
 
9
9
  /**
10
- * SolidProfileShape Type
10
+ * SolidProfile Type
11
11
  */
12
- export interface SolidProfileShape {
12
+ export interface SolidProfile {
13
13
  "@id"?: string;
14
14
  "@context"?: LdoJsonldContext;
15
15
  /**
@@ -34,11 +34,11 @@ export interface SolidProfileShape {
34
34
  /**
35
35
  * The person's street address.
36
36
  */
37
- hasAddress?: LdSet<AddressShape>;
37
+ hasAddress?: LdSet<Address>;
38
38
  /**
39
39
  * The person's email.
40
40
  */
41
- hasEmail?: LdSet<EmailShape>;
41
+ hasEmail?: LdSet<Email>;
42
42
  /**
43
43
  * A link to the person's photo
44
44
  */
@@ -52,7 +52,7 @@ export interface SolidProfileShape {
52
52
  /**
53
53
  * Person's telephone number
54
54
  */
55
- hasTelephone?: LdSet<PhoneNumberShape>;
55
+ hasTelephone?: LdSet<PhoneNumber>;
56
56
  /**
57
57
  * An alternative way to define a person's telephone number using a string
58
58
  */
@@ -68,11 +68,11 @@ export interface SolidProfileShape {
68
68
  /**
69
69
  * A list of app origins that are trusted by this user
70
70
  */
71
- trustedApp?: LdSet<TrustedAppShape>;
71
+ trustedApp?: LdSet<TrustedApp>;
72
72
  /**
73
73
  * A list of RSA public keys that are associated with private keys the user holds.
74
74
  */
75
- key?: LdSet<RSAPublicKeyShape>;
75
+ key?: LdSet<RSAPublicKey>;
76
76
  /**
77
77
  * The user's LDP inbox to which apps can post notifications
78
78
  */
@@ -118,9 +118,9 @@ export interface SolidProfileShape {
118
118
  }
119
119
 
120
120
  /**
121
- * AddressShape Type
121
+ * Address Type
122
122
  */
123
- export interface AddressShape {
123
+ export interface Address {
124
124
  "@id"?: string;
125
125
  "@context"?: LdoJsonldContext;
126
126
  /**
@@ -146,9 +146,9 @@ export interface AddressShape {
146
146
  }
147
147
 
148
148
  /**
149
- * EmailShape Type
149
+ * Email Type
150
150
  */
151
- export interface EmailShape {
151
+ export interface Email {
152
152
  "@id"?: string;
153
153
  "@context"?: LdoJsonldContext;
154
154
  /**
@@ -198,9 +198,9 @@ export interface EmailShape {
198
198
  }
199
199
 
200
200
  /**
201
- * PhoneNumberShape Type
201
+ * PhoneNumber Type
202
202
  */
203
- export interface PhoneNumberShape {
203
+ export interface PhoneNumber {
204
204
  "@id"?: string;
205
205
  "@context"?: LdoJsonldContext;
206
206
  /**
@@ -250,9 +250,9 @@ export interface PhoneNumberShape {
250
250
  }
251
251
 
252
252
  /**
253
- * TrustedAppShape Type
253
+ * TrustedApp Type
254
254
  */
255
- export interface TrustedAppShape {
255
+ export interface TrustedApp {
256
256
  "@id"?: string;
257
257
  "@context"?: LdoJsonldContext;
258
258
  /**
@@ -281,9 +281,9 @@ export interface TrustedAppShape {
281
281
  }
282
282
 
283
283
  /**
284
- * RSAPublicKeyShape Type
284
+ * RSAPublicKey Type
285
285
  */
286
- export interface RSAPublicKeyShape {
286
+ export interface RSAPublicKey {
287
287
  "@id"?: string;
288
288
  "@context"?: LdoJsonldContext;
289
289
  /**
package/app/index.tsx CHANGED
@@ -12,6 +12,8 @@ export function Screen() {
12
12
  ? 'server-ui'
13
13
  : 'standalone-app';
14
14
 
15
+ const defaultIssuer = process.env.EXPO_PUBLIC_DEFAULT_ISSUER;
16
+
15
17
  return (
16
18
  <SafeAreaProvider>
17
19
  <StatusBar />
@@ -20,6 +22,7 @@ export function Screen() {
20
22
  mode={mode}
21
23
  renderHomepage={() => <Text>Hopepage</Text>}
22
24
  renderLogo={() => <Text>Logo</Text>}
25
+ defaultIssuer={defaultIssuer}
23
26
  />
24
27
  </SafeAreaProvider>
25
28
  );
package/babel.config.js CHANGED
@@ -1,6 +1,14 @@
1
1
  module.exports = function (api) {
2
2
  api.cache(true);
3
3
  return {
4
- presets: [['babel-preset-expo', { jsxImportSource: 'nativewind' }], 'nativewind/babel'],
4
+ presets: [
5
+ [
6
+ 'babel-preset-expo',
7
+ {
8
+ unstable_transformProfile: 'hermes-canary',
9
+ },
10
+ ],
11
+ ],
12
+ plugins: ['@babel/plugin-syntax-import-meta'],
5
13
  };
6
14
  };
@@ -1,31 +1,21 @@
1
- import { createContext, ReactNode, useContext, useMemo } from 'react';
1
+ import { useMemo } from 'react';
2
2
  import { BrowserSolidLdoProvider } from '@ldo/solid-react';
3
3
  import React, { FunctionComponent } from 'react';
4
4
  import { Layout } from './nav/Layout';
5
5
  import { PortalHost } from '@rn-primitives/portal';
6
6
  import { TargetResourceProvider } from './TargetResourceProvider';
7
- import { ResourceViewConfig } from './ResourceView';
8
7
  import { NotifierWrapper } from 'react-native-notifier';
9
8
  import { Platform } from 'react-native';
10
9
  import { ThemeProvider } from './ThemeProvider';
10
+ import {
11
+ DataBrowserConfig,
12
+ DataBrowserConfigContext,
13
+ DataBrowserConfigProps,
14
+ } from './DataBrowserContext';
11
15
 
12
- export interface DataBrowserConfig {
13
- views: ResourceViewConfig[];
14
- mode: 'standalone-app' | 'server-ui';
15
- defaultIssuer?: string;
16
- origin?: string;
17
- renderHomepage?: () => ReactNode;
18
- renderLogo?: () => ReactNode;
19
- }
20
-
21
- // @ts-ignore This will be filled in once the component mounts
22
- export const DataBrowserConfigContext = createContext<DataBrowserConfig>({});
23
-
24
- export function useDataBrowserConfig() {
25
- return useContext(DataBrowserConfigContext);
26
- }
27
-
28
- export const DataBrowser: FunctionComponent<DataBrowserConfig> = (props) => {
16
+ export const DataBrowser: FunctionComponent<DataBrowserConfigProps> = (
17
+ props,
18
+ ) => {
29
19
  const providerProps = useMemo<DataBrowserConfig>(() => {
30
20
  return {
31
21
  origin:
@@ -0,0 +1,24 @@
1
+ import { createContext, ReactNode, useContext } from 'react';
2
+ import { ResourceViewConfig } from './ResourceView';
3
+
4
+ export interface DataBrowserConfigProps {
5
+ views: ResourceViewConfig[];
6
+ mode: 'standalone-app' | 'server-ui';
7
+ defaultIssuer?: string;
8
+ origin?: string;
9
+ renderHomepage?: () => ReactNode;
10
+ renderLogo?: () => ReactNode;
11
+ }
12
+
13
+ export interface DataBrowserConfig extends DataBrowserConfigProps {
14
+ defaultIssuer: string;
15
+ }
16
+
17
+ export const DataBrowserConfigContext = createContext<DataBrowserConfig>(
18
+ // @ts-ignore This will be filled in once the component mounts
19
+ {},
20
+ );
21
+
22
+ export function useDataBrowserConfig() {
23
+ return useContext(DataBrowserConfigContext);
24
+ }
@@ -7,7 +7,7 @@ import {
7
7
  } from 'react';
8
8
  import { SolidLeaf, SolidContainer } from '@ldo/connected-solid';
9
9
  import { InvalidIdentifierResource } from '@ldo/connected';
10
- import { useDataBrowserConfig } from './DataBrowser';
10
+ import { useDataBrowserConfig } from './DataBrowserContext';
11
11
  import { useResource } from '@ldo/solid-react';
12
12
  import { Platform } from 'react-native';
13
13
 
@@ -17,7 +17,6 @@ import {
17
17
  Theme,
18
18
  } from '@react-navigation/native';
19
19
  import { NAV_THEME } from '../lib/constants';
20
- import { useColorScheme } from 'nativewind';
21
20
  import { setAndroidNavigationBar } from '../lib/android-navigation-bar';
22
21
 
23
22
  const COLOR_SCHEME_KEY = 'colorScheme';
@@ -57,14 +56,14 @@ const usePlatformSpecificSetup = Platform.select({
57
56
  export const ThemeProvider: FunctionComponent<PropsWithChildren> = ({
58
57
  children,
59
58
  }) => {
60
- const { colorScheme, setColorScheme } = useColorScheme();
59
+ const [colorScheme, setColorScheme] = useState<ColorSchemeName>();
61
60
  const [loadingColorScheme, setLoadingColorScheme] = useState(true);
62
61
 
63
62
  usePlatformSpecificSetup();
64
63
 
65
64
  useEffect(() => {
66
65
  const lookupCurColorScheme = async () => {
67
- setColorScheme(Appearance.getColorScheme() ?? 'system');
66
+ setColorScheme(Appearance.getColorScheme() ?? 'light');
68
67
  const storedColorSchemeName: ColorSchemeName =
69
68
  ((await AsyncStorage.getItem(COLOR_SCHEME_KEY)) as ColorSchemeName) ||
70
69
  Appearance.getColorScheme();
@@ -74,7 +73,6 @@ export const ThemeProvider: FunctionComponent<PropsWithChildren> = ({
74
73
  setLoadingColorScheme(false);
75
74
  };
76
75
  lookupCurColorScheme();
77
- // eslint-disable-next-line react-hooks/exhaustive-deps
78
76
  }, []);
79
77
 
80
78
  const context = useMemo(
@@ -2,6 +2,7 @@ import React from 'react';
2
2
  import { useTheme } from '@react-navigation/native';
3
3
  import { FunctionComponent } from 'react';
4
4
  import { Bar } from 'react-native-progress';
5
+ import { StyleSheet } from 'react-native';
5
6
 
6
7
  interface LoadingBarProps {
7
8
  isLoading: boolean;
@@ -21,7 +22,16 @@ export const LoadingBar: FunctionComponent<LoadingBarProps> = ({
21
22
  borderWidth={0}
22
23
  borderRadius={0}
23
24
  width={null}
24
- className="absolute top-0 left-0 right-0"
25
+ style={styles.bar}
25
26
  />
26
27
  );
27
28
  };
29
+
30
+ const styles = StyleSheet.create({
31
+ bar: {
32
+ position: 'absolute',
33
+ top: 0,
34
+ left: 0,
35
+ right: 0,
36
+ },
37
+ });
@@ -1,23 +1,20 @@
1
1
  import React from 'react';
2
- import { SolidProfileShape } from '../../.ldo/profile.typings';
2
+ import { SolidProfile } from '../../.ldo/profile.typings';
3
3
  import { Avatar, AvatarFallback, AvatarImage } from '../ui/avatar';
4
4
  import { Text } from '../ui/text';
5
- import { User } from '../../lib/icons/User';
5
+ import { User } from 'lucide-react-native';
6
6
  import { FunctionComponent } from 'react';
7
7
 
8
8
  interface ProfileAvatarProps {
9
- profile?: SolidProfileShape;
10
- className?: string;
9
+ profile?: SolidProfile;
10
+ style?: any;
11
11
  }
12
12
 
13
13
  export const ProfileAvatar: FunctionComponent<ProfileAvatarProps> = ({
14
14
  profile,
15
- className,
15
+ style,
16
16
  }) => (
17
- <Avatar
18
- alt={profile?.fn ? `${profile.fn}'s Avatar` : ''}
19
- className={className}
20
- >
17
+ <Avatar alt={profile?.fn ? `${profile.fn}'s Avatar` : ''} style={style}>
21
18
  <AvatarImage source={{ uri: profile?.hasPhoto?.['@id'] }} />
22
19
  <AvatarFallback>
23
20
  <Text>
@@ -7,11 +7,12 @@ import React, {
7
7
  import { ResourceViewConfig } from '../ResourceView';
8
8
 
9
9
  import { Header } from './header/Header';
10
- import { View } from 'react-native';
10
+ import { View, StyleSheet } from 'react-native';
11
11
  import { useViewContext, ViewContextProvider } from '../useViewContext';
12
12
  import { DialogProvider } from './DialogProvider';
13
13
  import { useSolidAuth } from '@ldo/solid-react';
14
14
  import { SharingModalProvider } from '../sharing/SharingModal';
15
+ import { useTheme } from '@react-navigation/native';
15
16
 
16
17
  export const ValidViewContext = createContext<{
17
18
  validViews: ResourceViewConfig[];
@@ -22,6 +23,7 @@ export const ValidViewContext = createContext<{
22
23
 
23
24
  export const Layout: FunctionComponent = () => {
24
25
  const { ranInitialAuthCheck } = useSolidAuth();
26
+ const { colors } = useTheme();
25
27
 
26
28
  if (!ranInitialAuthCheck) {
27
29
  return <></>;
@@ -31,9 +33,13 @@ export const Layout: FunctionComponent = () => {
31
33
  <DialogProvider>
32
34
  <ViewContextProvider>
33
35
  <SharingModalProvider>
34
- <Header />
35
- <View className="flex-1 z-0">
36
- <RenderView />
36
+ <View
37
+ style={[styles.container, { backgroundColor: colors.background }]}
38
+ >
39
+ <Header />
40
+ <View style={styles.contentView}>
41
+ <RenderView />
42
+ </View>
37
43
  </View>
38
44
  </SharingModalProvider>
39
45
  </ViewContextProvider>
@@ -55,3 +61,13 @@ export const RenderView: FunctionComponent = () => {
55
61
  const CurView = curViewConfig.view;
56
62
  return <CurView />;
57
63
  };
64
+
65
+ const styles = StyleSheet.create({
66
+ container: {
67
+ flex: 1,
68
+ },
69
+ contentView: {
70
+ flex: 1,
71
+ zIndex: 0,
72
+ },
73
+ });
@@ -1,20 +1,23 @@
1
1
  import React, { useEffect, useMemo } from 'react';
2
2
  import { FunctionComponent, useState } from 'react';
3
- import { TouchableOpacity, View } from 'react-native';
3
+ import { TouchableOpacity, View, StyleSheet, ScrollView } from 'react-native';
4
4
  import { Input } from '../../ui/input';
5
- import { ChevronRight } from '../../../lib/icons/ChevronRight';
6
- import { ChevronsRight } from '../../../lib/icons/ChevronsRight';
7
- import { TextCursorInput } from '../../../lib/icons/TextCursorInput';
8
- import { RefreshCw } from '../../../lib/icons/RefreshCw';
9
- import { ArrowRight } from '../../../lib/icons/ArrowRight';
5
+ import { ChevronRight } from 'lucide-react-native';
6
+ import { ChevronsRight } from 'lucide-react-native';
7
+ import { TextCursorInput } from 'lucide-react-native';
8
+ import { RefreshCw } from 'lucide-react-native';
9
+ import { ArrowRight } from 'lucide-react-native';
10
10
  import { Button } from '../../../components/ui/button';
11
11
  import { Text } from '../../ui/text';
12
12
  import { useTargetResource } from '../../TargetResourceProvider';
13
+ import { useTheme } from '@react-navigation/native';
14
+ import { Icon } from '../../../components/ui/icon';
13
15
 
14
16
  export const AddressBox: FunctionComponent = () => {
15
17
  const [isTextMode, setIsTextMode] = useState(false);
16
18
  const { targetUri, refresh, navigateTo, targetResource } =
17
19
  useTargetResource();
20
+ const { colors } = useTheme();
18
21
 
19
22
  const [textBoxValue, setTextBoxValue] = useState(targetUri ?? '');
20
23
  useEffect(() => {
@@ -51,9 +54,9 @@ export const AddressBox: FunctionComponent = () => {
51
54
  }, [targetUri]);
52
55
 
53
56
  return (
54
- <View className="flex-1">
57
+ <View style={styles.container}>
55
58
  <Input
56
- className="flex-1 bg-secondary web:py-2.5 border-none pl-10 pr-10 h-[40px] text-sm web:focus-visible:ring-0 web:focus-visible:ring-transparent web:focus-visible:ring-offset-0 web:focus:outline-none web:outline-none"
59
+ style={[styles.input, { backgroundColor: colors.border }]}
57
60
  onFocus={() => setIsTextMode(true)}
58
61
  onBlur={() => setTimeout(() => setIsTextMode(false), 100)}
59
62
  onChangeText={setTextBoxValue}
@@ -66,22 +69,41 @@ export const AddressBox: FunctionComponent = () => {
66
69
  />
67
70
  <Button
68
71
  variant="secondary"
69
- className="absolute left-0 w-10 h-10"
72
+ style={styles.leftButton}
70
73
  onPress={() => setIsTextMode((val) => !val)}
71
- iconLeft={
72
- isTextMode ? (
73
- <ChevronsRight size={20} />
74
- ) : (
75
- <TextCursorInput size={20} />
76
- )
77
- }
74
+ iconLeft={isTextMode ? ChevronsRight : TextCursorInput}
75
+ textStyle={styles.buttonText}
78
76
  />
77
+ <ScrollView
78
+ style={styles.breadcrumbContainer}
79
+ contentContainerStyle={styles.breadcrumbContentContainer}
80
+ pointerEvents="none"
81
+ horizontal
82
+ >
83
+ {!isTextMode &&
84
+ breadcrumbInfo.map((item, index) => (
85
+ <View style={styles.breadcrumbItem} key={item.uri}>
86
+ <TouchableOpacity onPress={() => navigateTo(item.uri)}>
87
+ <View pointerEvents="auto">
88
+ <Text style={styles.breadcrumbText} size="sm">
89
+ {item.name}
90
+ </Text>
91
+ </View>
92
+ </TouchableOpacity>
93
+ {index !== breadcrumbInfo.length - 1 ? (
94
+ <Icon icon={ChevronRight} style={styles.chevron} />
95
+ ) : (
96
+ <View style={styles.spacer} />
97
+ )}
98
+ </View>
99
+ ))}
100
+ </ScrollView>
79
101
  {(() => {
80
102
  const shouldRefresh = targetUri === textBoxValue || !isTextMode;
81
103
  return (
82
104
  <Button
83
105
  variant="secondary"
84
- className="absolute right-0 w-10 h-10"
106
+ style={styles.rightButton}
85
107
  onPressIn={() => {
86
108
  if (shouldRefresh) {
87
109
  refresh();
@@ -89,39 +111,73 @@ export const AddressBox: FunctionComponent = () => {
89
111
  navigateTo(textBoxValue);
90
112
  }
91
113
  }}
92
- >
93
- <Text className={targetResource?.isLoading() ? 'animate-spin' : ''}>
94
- {shouldRefresh || targetResource?.isLoading() ? (
95
- <RefreshCw size={20} />
96
- ) : (
97
- <ArrowRight size={20} />
98
- )}
99
- </Text>
100
- </Button>
114
+ iconLeft={
115
+ shouldRefresh || targetResource?.isLoading()
116
+ ? RefreshCw
117
+ : ArrowRight
118
+ }
119
+ textStyle={styles.buttonText}
120
+ />
101
121
  );
102
122
  })()}
103
- <View
104
- className="absolute top-0 left-0 right-0 bottom-0 flex-row-reverse items-center ml-10 mr-10 overflow-x-auto scrollbar-hide [direction:rtl]"
105
- pointerEvents="none"
106
- >
107
- {!isTextMode &&
108
- breadcrumbInfo.map((item, index) => (
109
- <View className="flex-row" key={item.uri}>
110
- {index !== breadcrumbInfo.length - 1 ? (
111
- <ChevronRight className="w-4 h-4 mr-0.5 mt-0.5 text-gray-500" />
112
- ) : (
113
- <View className="w-2" />
114
- )}
115
- <TouchableOpacity onPress={() => navigateTo(item.uri)}>
116
- <View pointerEvents="auto">
117
- <Text className="mr-0.5 underline" size="sm">
118
- {item.name}
119
- </Text>
120
- </View>
121
- </TouchableOpacity>
122
- </View>
123
- ))}
124
- </View>
125
123
  </View>
126
124
  );
127
125
  };
126
+
127
+ const styles = StyleSheet.create({
128
+ container: {
129
+ flex: 1,
130
+ height: 40,
131
+ },
132
+ input: {
133
+ flex: 1,
134
+ borderWidth: 0,
135
+ paddingHorizontal: 40,
136
+ height: 40,
137
+ fontSize: 14,
138
+ },
139
+ leftButton: {
140
+ position: 'absolute',
141
+ left: 0,
142
+ width: 40,
143
+ height: 40,
144
+ },
145
+ rightButton: {
146
+ position: 'absolute',
147
+ right: 0,
148
+ width: 40,
149
+ height: 40,
150
+ },
151
+ breadcrumbContainer: {
152
+ position: 'absolute',
153
+ top: 0,
154
+ left: 0,
155
+ right: 0,
156
+ bottom: 0,
157
+ marginLeft: 40,
158
+ marginRight: 40,
159
+ },
160
+ breadcrumbContentContainer: {
161
+ flexDirection: 'row',
162
+ alignItems: 'center',
163
+ },
164
+ breadcrumbItem: {
165
+ flexDirection: 'row',
166
+ },
167
+ chevron: {
168
+ width: 16,
169
+ height: 16,
170
+ marginRight: 2,
171
+ color: 'hsl(var(--muted-foreground))',
172
+ },
173
+ spacer: {
174
+ width: 8,
175
+ },
176
+ breadcrumbText: {
177
+ marginRight: 2,
178
+ textDecorationLine: 'underline',
179
+ },
180
+ buttonText: {
181
+ fontSize: 20,
182
+ },
183
+ });