@ramses-superapp/ramses-ui
Version:
Skinless UI primitives for Ramses Built Apps
344 lines (256 loc) • 8.46 kB
Markdown
# Ramses UI
A modern, theme-aware UI kit for React Native, designed for Ramses-built apps. Includes customizable components, seamless light/dark theming, and built-in Cairo font support.
## Features
- Light & dark mode with auto device detection
- Cairo font family integration (Android/iOS)
- Ready-to-use components: Button, Text, TextInput
- Simple, powerful theming via `ThemeProvider`
- Ergonomic, theme-aware styling utilities
## Installation
```sh
npm install @ramses-superapp/ramses-ui
# or
yarn add @ramses-superapp/ramses-ui
```
## Quick Start
Wrap your app with the `ThemeProvider` for automatic theming:
```tsx
import { ThemeProvider } from '@ramses-superapp/ramses-ui';
export default function App() {
return <ThemeProvider>{/* your app code */}</ThemeProvider>;
}
```
## What ThemeProvider Does
When you wrap your app with `ThemeProvider`, it does more than just provide theming:
- **Safe Area Handling:** Your app is automatically wrapped in a `SafeAreaView` for proper layout on all devices.
- **Keyboard Avoidance:** A `KeyboardAvoidingView` is included, so your UI adjusts automatically when the keyboard appears (on both iOS and Android).
- **Keyboard Dismissal:** The entire app is wrapped in a touchable area, so tapping outside of inputs will dismiss the keyboard by default.
- **Status Bar Styling:** The status bar style and color are set based on the current theme.
This means you get best-practice layout and keyboard handling out of the box—no need to add these wrappers yourself!
## Components
### RsButton
- `title` (string/number): Button label
- `primary` (bool): Primary style (default: true)
- `isLoading` (bool): Show spinner
- `disabled` (bool): Disable button
- `onPress` (fn): Press handler
- `fontSize`, `fontWeight`, `textStyle`, `style`, `width`
### RsText
- `text` (string/number): Content
- `fontSize`, `fontWeight`, `textAlign`, `textTransform`, `color`
- `pressable` (bool), `onPress` (fn)
- `style`, `containerStyle`
### RsTextInput
- All standard `TextInput` props
- All `RsText` style props
- `containerStyle`
- Floating label with Cairo font
#### FontWeight
All components support:
`'ExtraLight' | 'Light' | 'Regular' | 'Medium' | 'SemiBold' | 'Bold' | 'ExtraBold' | 'Black'`
### RsDivider
A flexible, theme-aware divider for separating content, supporting horizontal/vertical orientation, custom thickness, color, margin, and center content (text or custom node).
**Props:**
- `direction` (`'row' | 'column'`): Divider orientation. `'column'` (default) is horizontal, `'row'` is vertical.
- `thickness` (number): Line thickness. Default: `1`.
- `color` (string): Line color. Default: theme border color.
- `margin` (number): Margin in the _opposite_ direction. Default: `8`.
- `content` (string | ReactNode): Center content (e.g., "or", icon, etc.). Optional.
- `textProps` (`RsTextStyle`): Props for customizing `RsText` if `content` is a string.
- `style` (ViewStyle): Style for the outer container.
- `lineStyle` (ViewStyle): Style for the line(s).
**Usage:**
```tsx
import { RsDivider } from '@ramses-superapp/ramses-ui';
// Horizontal divider with text
<RsDivider content="or" />
// Vertical divider (for row layouts)
<RsDivider direction="row" thickness={2} margin={16} />
// Divider with custom node in the center
<RsDivider content={<MyIcon />} color="#A549E5" />
// Simple horizontal line
<RsDivider />
```
### RsToggleButton
A two-option, animated toggle switch for binary choices (e.g., Yes/No, On/Off). Theme-aware, fully animated, and adapts to parent width.
**Props:**
- `choices` (`[{ label: string, value: T }, { label: string, value: T }]`): Array of two options to display. Each option has a `label` and a `value`.
- `value` (`T`): The currently selected value.
- `onChange` (`(value: T) => void`): Callback when the selection changes.
- `style` (`ViewStyle`, optional): Style for the outer container.
**Usage:**
```tsx
import { RsToggleButton } from '@ramses-superapp/ramses-ui';
const [value, setValue] = useState<'yes' | 'no'>('yes');
<RsToggleButton
choices={[
{ label: 'Yes', value: 'yes' },
{ label: 'No', value: 'no' },
]}
value={value}
onChange={setValue}
/>;
```
## Theming & Customization
### ThemeProvider Props
- `mode`: `'light' | 'dark' | 'auto'` (default: `'auto'`)
- `'auto'`: Follows device color scheme
- `'light'`: Forces light mode
- `'dark'`: Forces dark mode
- `customLightTheme`: (optional) Custom theme object for light mode
- `customDarkTheme`: (optional) Custom theme object for dark mode
**Force Light or Dark Mode:**
```tsx
<ThemeProvider mode="light">{/* ... */}</ThemeProvider>
<ThemeProvider mode="dark">{/* ... */}</ThemeProvider>
```
**Provide Custom Themes:**
```tsx
import { ThemeProvider, colors } from '@ramses-superapp/ramses-ui';
const MyLightTheme = {
/* ...see below... */
};
const MyDarkTheme = {
/* ...see below... */
};
<ThemeProvider
mode="auto"
customLightTheme={MyLightTheme}
customDarkTheme={MyDarkTheme}
>
{/* ... */}
</ThemeProvider>;
```
#### Theme Object Structure
```ts
type Theme = {
Background: {
screen: string;
input: string;
primaryButton: string;
secondaryButton: string;
};
Text: {
primaryTitle: string;
text: string;
highlightText: string;
inputText: string;
inputPlaceholder: string;
primaryButtonText: string;
secondaryButtonText: string;
};
Borders: {
primaryButton: string;
secondaryButton: string;
input: string;
inputActive: string;
};
StatusBar: {
barStyle: 'light-content' | 'dark-content';
};
};
```
#### Accessing the Theme
Use the `useTheme()` hook in your components:
```tsx
import { useTheme } from '@ramses-superapp/ramses-ui';
const theme = useTheme();
```
## Cairo Font Integration
- Fonts are auto-linked for Android/iOS.
- **iOS only:** Add to your `Info.plist`:
```xml
<key>UIAppFonts</key>
<array>
<string>Cairo-Regular-Tight.ttf</string>
<string>Cairo-Bold-Tight.ttf</string>
<string>Cairo-ExtraBold-Tight.ttf</string>
<string>Cairo-Black-Tight.ttf</string>
<string>Cairo-ExtraLight-Tight.ttf</string>
<string>Cairo-Light-Tight.ttf</string>
<string>Cairo-Medium-Tight.ttf</string>
<string>Cairo-SemiBold-Tight.ttf</string>
</array>
```
- Clean & rebuild your app after linking fonts.
## Theme-Aware Styling
### User-Friendly: `useStyles`
The easiest way to create theme-aware and dynamic styles.
Just provide a style object factory that receives the current theme and any state/props you want.
```tsx
import { useStyles } from '@ramses-superapp/ramses-ui';
function MyComponent({ isActive }) {
const styles = useStyles(
(theme, { isActive }) => ({
container: {
backgroundColor: isActive
? theme.Background.primaryButton
: theme.Background.screen,
padding: 16,
borderRadius: 8,
},
text: {
color: theme.Text.text,
fontSize: 18,
},
}),
{ isActive }
);
return (
<View style={styles.container}>
<Text style={styles.text}>Hello Themed World</Text>
</View>
);
}
```
- No need to call `StyleSheet.create` or `useMemo` yourself.
- Styles update automatically when the theme or any prop/state changes.
### Advanced: `useThemedStyles`
If you need more control over memoization or want to pass multiple arguments, use the lower-level `useThemedStyles` hook.
```tsx
import { useThemedStyles, type Theme } from '@ramses-superapp/ramses-ui';
import { StyleSheet } from 'react-native';
const generateStyles = (theme: Theme, isActive: boolean) =>
StyleSheet.create({
container: {
backgroundColor: isActive
? theme.Background.primaryButton
: theme.Background.screen,
padding: 16,
borderRadius: 8,
},
text: {
color: theme.Text.text,
fontSize: 18,
},
});
function MyComponent({ isActive }) {
const styles = useThemedStyles(generateStyles, isActive);
return (
<View style={styles.container}>
<Text style={styles.text}>Hello Themed World</Text>
</View>
);
}
```
## Scripts
- `yarn test` – Run tests
- `yarn lint` – Lint code
- `yarn typecheck` – TypeScript check
- `yarn clean` – Clean build artifacts
- `yarn example` – Run example app
## License
MIT
Made with [create-react-native-library](https://github.com/callstack/react-native-builder-bob)