@social.dev/rn-sdk
v0.0.1-alpha.66
Published
React Native SDK for Social.dev with reusable UI components
Maintainers
Readme
@social.dev/rn-sdk
React Native SDK and UI Kit for Social.dev - A comprehensive toolkit for building social media applications with React Native and Expo.
Overview
The @social.dev/rn-sdk package provides:
- 🎨 Pre-built UI Components - Complete set of customizable social media components
- 🔄 Component Override System - Replace any component with your own implementation
- 🎯 Navigation Setup - Pre-configured navigation with React Navigation
- 🔐 Authentication - Built-in auth flows with OIDC support
- 💬 Chat System - Real-time messaging components
- 📱 Mobile-First - Optimized for React Native with Expo support
- 🎭 Theming - Comprehensive theming system with dark mode support
Installation
# Using pnpm (recommended)
pnpm add @social.dev/rn-sdk @social.dev/js-sdk
# Using npm
npm install @social.dev/rn-sdk @social.dev/js-sdk
# Using yarn
yarn add @social.dev/rn-sdk @social.dev/js-sdkPeer Dependencies
Make sure you have the following peer dependencies installed:
# Required Expo modules
npx expo install expo-audio expo-auth-session expo-crypto expo-linking expo-secure-store expo-web-browser
# Required React Navigation
pnpm add @react-navigation/native @react-navigation/native-stack @react-navigation/bottom-tabs @react-navigation/drawer
# Required for React Navigation
npx expo install react-native-screens react-native-safe-area-context
# Required for gestures and animations
npx expo install react-native-gesture-handler react-native-reanimated
# Required for bottom sheets
pnpm add @gorhom/bottom-sheetQuick Start
Basic Setup
import React from 'react';
import { SocialDevProvider, SocialDevApp } from '@social.dev/rn-sdk';
import { Platform } from 'react-native';
export default function App() {
return (
<SocialDevProvider
apiBaseUrl={
Platform.OS === 'web' ? '/api' : 'https://your-server.social.dev/api/'
}
>
<SocialDevApp />
</SocialDevProvider>
);
}Advanced Setup with Component Overrides
import React from 'react';
import {
SocialDevProvider,
SocialDevApp,
ComponentLibrary,
DefaultComponents,
} from '@social.dev/rn-sdk';
import { defaultRouterConfig } from '@social.dev/rn-sdk/navigation/AppNavigator';
import { Platform, Text, View } from 'react-native';
// Custom components
import CustomAvatar from './components/CustomAvatar';
import CustomHomeScreen from './screens/CustomHomeScreen';
export default function App() {
// Custom navigation configuration
const navConfig = {
screens: {
...defaultRouterConfig?.screens,
Home: { path: 'home', alias: ['homepage'] },
Profile: { path: 'profile/:id' },
},
};
// Override specific components
const components: Partial<ComponentLibrary> = {
// Override a single component
Avatar: CustomAvatar,
// Override nested components
Post: {
Post: CustomPost,
PostToolbar: CustomPostToolbar,
},
// Override screens
Screens: {
...DefaultComponents.Screens,
HomeScreen: CustomHomeScreen,
NotificationScreen: () => (
<View>
<Text>Custom Notification Screen</Text>
</View>
),
},
};
return (
<SocialDevProvider
apiBaseUrl={
Platform.OS === 'web' ? '/api' : 'https://demo.social.dev/api/'
}
components={components}
sdkConfig={{
feed: {
chatMode: true, // Enable chat mode for feeds
},
}}
>
<SocialDevApp navigationConfig={navConfig} />
</SocialDevProvider>
);
}Component Override System
The SDK uses a powerful component override system that allows you to replace any component with your own implementation while maintaining the rest of the SDK functionality.
Available Component Categories
interface ComponentLibrary {
// Core UI Components
Avatar: React.ComponentType;
Button: React.ComponentType;
Core: {
Button: React.ComponentType;
Icon: React.ComponentType;
Pressable: React.ComponentType;
TextInput: React.ComponentType;
};
// Authentication Components
Auth: {
AuthForm: React.ComponentType;
OidcProvidersList: React.ComponentType;
};
// Chat Components
Chat: {
ChatConversationList: React.ComponentType;
ChatConversationPanel: React.ComponentType;
ChatCreate: React.ComponentType;
ChatMessage: React.ComponentType;
};
// Community Components
Community: {
CommunityFeed: React.ComponentType;
CommunityJoinButton: React.ComponentType;
CommunityMembersList: React.ComponentType;
};
// Post Creation Components
CreatePost: {
CreatePost: React.ComponentType;
CreatePostInline: React.ComponentType;
CreatePostButton: React.ComponentType;
ReplyToPostButton: React.ComponentType;
CreatePostFab: React.ComponentType;
};
// Feed Components
Feed: {
Feed: React.ComponentType;
};
// Post Components
Post: {
Post: React.ComponentType;
PostToolbar: React.ComponentType;
};
// User Components
User: {
UserListItem: React.ComponentType;
};
// Screen Components
Screens: {
AuthScreen: React.ComponentType;
ChatScreen: React.ComponentType;
ChatCreateScreen: React.ComponentType;
CommunityCreateScreen: React.ComponentType;
CommunityListScreen: React.ComponentType;
CommunityProfileScreen: React.ComponentType;
HomeScreen: React.ComponentType;
NotificationScreen: React.ComponentType;
PostViewScreen: React.ComponentType;
ProfileScreen: React.ComponentType;
};
// Audio Components
AudioPlayer: {
AudioPlayer: React.ComponentType;
};
AudioVisualizer: {
AudioVisualizer: React.ComponentType;
};
// Voice Recording
VoiceRecorder: {
VoiceRecorder: React.ComponentType;
VoiceRecorderModal: React.ComponentType;
};
// Layout
Layout: React.ComponentType;
}Override Examples
Example 1: Custom Avatar Component
// components/CustomAvatar.tsx
import React from 'react';
import { View, Image, Text, StyleSheet } from 'react-native';
export default function CustomAvatar({ user, size = 40, onPress }) {
return (
<View style={[styles.container, { width: size, height: size }]}>
{user?.avatar ? (
<Image source={{ uri: user.avatar }} style={styles.image} />
) : (
<Text style={styles.initial}>
{user?.name?.[0]?.toUpperCase() || '?'}
</Text>
)}
</View>
);
}
const styles = StyleSheet.create({
container: {
borderRadius: 999,
backgroundColor: '#007AFF',
alignItems: 'center',
justifyContent: 'center',
},
image: {
width: '100%',
height: '100%',
borderRadius: 999,
},
initial: {
color: 'white',
fontWeight: 'bold',
},
});Example 2: Custom Post Component
// components/CustomPost.tsx
import React from 'react';
import { View, Text, StyleSheet } from 'react-native';
import { useComponentLibrary } from '@social.dev/rn-sdk';
export default function CustomPost({ post }) {
const components = useComponentLibrary();
const Avatar = components.Avatar;
const PostToolbar = components.Post.PostToolbar;
return (
<View style={styles.container}>
<View style={styles.header}>
<Avatar user={post.author} size={32} />
<Text style={styles.authorName}>{post.author.name}</Text>
</View>
<Text style={styles.content}>{post.content}</Text>
<PostToolbar post={post} />
</View>
);
}
const styles = StyleSheet.create({
container: {
padding: 16,
backgroundColor: 'white',
marginBottom: 8,
},
header: {
flexDirection: 'row',
alignItems: 'center',
marginBottom: 12,
},
authorName: {
marginLeft: 8,
fontWeight: '600',
},
content: {
fontSize: 14,
marginBottom: 12,
},
});Example 3: Partial Screen Override
// App.tsx
const components: Partial<ComponentLibrary> = {
Screens: {
// Keep all default screens
...DefaultComponents.Screens,
// Override only the HomeScreen
HomeScreen: () => {
const { user } = useConfig();
return (
<View style={{ flex: 1, padding: 20 }}>
<Text>Welcome {user?.name || 'Guest'}!</Text>
<Feed />
</View>
);
},
},
};Hooks
useApi
Access the API client for making authenticated requests:
import { useApi } from '@social.dev/rn-sdk';
function MyComponent() {
const api = useApi();
const { data, error, isLoading } = api.useQuery(
'get',
'/posts',
{ params: { limit: 10 } }
);
const createPost = api.useMutation('post', '/posts');
const handleSubmit = async (content: string) => {
await createPost.mutateAsync({
body: { content }
});
};
return (
// Your component JSX
);
}useConfig
Access server configuration and user authentication state:
import { useConfig } from '@social.dev/rn-sdk';
function MyComponent() {
const { server, user, isLoggedIn, sdk, refetch } = useConfig();
if (!isLoggedIn) {
return <LoginPrompt />;
}
return (
<View>
<Text>Welcome {user.name}!</Text>
<Text>Server: {server.title}</Text>
<Button onPress={refetch} title="Refresh Config" />
</View>
);
}useComponentLibrary
Access the component library to use SDK components in your custom components:
import { useComponentLibrary } from '@social.dev/rn-sdk';
function CustomFeed() {
const components = useComponentLibrary();
const { Feed, Post, Avatar } = components;
return (
<View>
<Feed
renderItem={({ item }) => (
<View>
<Avatar user={item.author} />
<Post post={item} />
</View>
)}
/>
</View>
);
}useOpenChat
Navigate to or create a chat conversation:
import { useOpenChat } from '@social.dev/rn-sdk';
function UserProfile({ userId }) {
const { openChat, mutation } = useOpenChat({ userId });
return (
<Button onPress={openChat} title="Message" loading={mutation.isLoading} />
);
}useTheme
Access the theme system:
import { useTheme } from '@social.dev/rn-sdk';
function ThemedComponent() {
const { colors, fonts, spacing } = useTheme();
return (
<View
style={{
backgroundColor: colors.background,
padding: spacing.md,
}}
>
<Text
style={{
color: colors.text,
fontSize: fonts.sizes.body,
}}
>
Themed content
</Text>
</View>
);
}SDK Configuration
Configure the SDK behavior through the sdkConfig prop:
<SocialDevProvider
sdkConfig={{
feed: {
chatMode: true, // Reverse feed direction for chat-like experience
},
}}
>
{/* Your app */}
</SocialDevProvider>Push Notifications
Setup push notifications with Expo:
import * as Notifications from 'expo-notifications';
import * as Device from 'expo-device';
async function registerForPushNotificationsAsync() {
if (!Device.isDevice) return;
const { status } = await Notifications.requestPermissionsAsync();
if (status !== 'granted') return;
const token = await Notifications.getExpoPushTokenAsync();
return token.data;
}
export default function App() {
const [pushToken, setPushToken] = useState<string>();
useEffect(() => {
registerForPushNotificationsAsync().then((token) => setPushToken(token));
}, []);
return (
<SocialDevProvider
pushNotificationToken={pushToken}
// ... other props
>
<SocialDevApp />
</SocialDevProvider>
);
}Navigation Configuration
Customize the navigation structure:
import { defaultRouterConfig } from '@social.dev/rn-sdk/navigation/AppNavigator';
const navConfig = {
screens: {
...defaultRouterConfig?.screens,
// Custom routes
Home: { path: 'home', alias: ['homepage'] },
Profile: { path: 'profile/:id' },
Settings: { path: 'settings' },
},
// Deep linking configuration
config: {
initialRouteName: 'Home',
},
};
<SocialDevApp navigationConfig={navConfig} />;Testing
The SDK includes comprehensive test utilities and mocks:
# Run tests
pnpm test
# Run tests in watch mode
pnpm test:watch
# Generate coverage report
pnpm test --coverageWriting Tests for Components Using the SDK
import { render } from '@testing-library/react-native';
import { SocialDevProvider } from '@social.dev/rn-sdk';
function renderWithProviders(component, options = {}) {
return render(
<SocialDevProvider apiBaseUrl="/api" {...options}>
{component}
</SocialDevProvider>
);
}
test('my component renders', () => {
const { getByText } = renderWithProviders(<MyComponent />);
expect(getByText('Hello')).toBeTruthy();
});Development
# Install dependencies
pnpm install
# Build the package
pnpm build
# Watch for changes during development
pnpm dev
# Run tests
pnpm test
# Type checking
pnpm typecheck
# Linting
pnpm lintTypeScript Support
The SDK is written in TypeScript and provides full type definitions. Import types as needed:
import type {
ComponentLibrary,
SdkConfig,
User,
Post,
ApiComponents,
ApiPaths,
} from '@social.dev/rn-sdk';Examples
Check out the apps/mobile directory for a complete implementation example using the SDK.
Contributing
Contributions are welcome! Please read our contributing guidelines before submitting PRs.
License
MIT
