rn-dynamic-ui-render
Version:
A dynamic UI rendering engine for React Native
383 lines (323 loc) β’ 12.5 kB
Markdown
# π¦ rn-dynamic-ui-render
A powerful **JSON-driven dynamic UI renderer for React Native**.
Define your UI using JSON schemas and let the renderer handle **component rendering, theming, dynamic data binding, conditionals, formatting, and event handling**.
---
## β¨ Features
- π **Schema-driven rendering** β Build UIs from JSON instead of hardcoding.
- π¨ **Theme integration** β Use centralized design tokens (colors, fonts, weights).
- β‘ **Dynamic props & expressions** β Bind values from data or handlers.
- πΌ **Conditional logic** β Show/hide or style components dynamically.
- π
**Date & number formatting** β Format inline with props.
- π **Translation-ready** β Works with `react-i18next`.
- π **List rendering** β FlatList support with `item` and `index`.
- π‘ **Error boundaries** β Prevent schema issues from crashing your app.
---
## π¦ Installation
```bash
npm install rn-dynamic-ui-render
# or
yarn add rn-dynamic-ui-render
```
---
## π Usage
### 1. Register Components & Theme
```tsx
import RNDynamicUIRender from "rn-dynamic-ui-render";
import { Text, View, Button, Image } from "react-native";
const components = {
View,
Text,
Button,
Image,
};
const theme = {
colors: {
primary: "#007bff",
secondary: "#6c757d",
white: "#ffffff",
},
font: {
h1: 32,
h2: 24,
h3: 18,
},
fontWeight: {
normal: "400",
bold: "700",
},
};
```
### 2. Define JSON Schema
```json
[
{
"name": "View",
"props": { "style": { "padding": 16 } },
"content": [
{
"name": "Text",
"props": {
"textContent": "Hello Dynamic UI",
"style": { "fontSize": "h2", "color": "primary" }
}
},
{
"name": "Button",
"props": {
"title": "Click Me",
"onPress": "handlePress"
}
}
]
}
]
```
### 3. Render
```tsx
const handlers = {
handlePress: () => alert("Button Pressed!"),
};
<RNDynamicUIRender
data={schema}
handlers={handlers}
theme={theme}
components={components}
/>;
```
---
## π Core Component
### `RNDynamicUIRender`
| **Prop** | **Type** | **Description** |
| ------------ | --------- | ----------------------------------------------------------------- |
| `data` | `array` | JSON schema for rendering UI. |
| `handlers` | `object` | Functions + data context used for expressions and event handlers. |
| `theme` | `object` | Theme object with colors, font sizes, font weights. |
| `components` | `object` | Registry of component names β actual React components. |
| `translate` | `boolean` | If true, integrates with `react-i18next`. |
---
## π Props Reference
| **Prop** | **Type** | **Description** | **Supports Expressions** | **Example** |
| --------------------- | -------------------- | ------------------------------------------------------------------------------- | ------------------------ | ------------------------------------------------ |
| `expression` | `boolean` | Marks that this propβs value should be resolved dynamically. | β
Yes (`true`) | `"textContent": "item.text", "expression": true` |
| `textContent` | `string` / `object` | Sets the text of a `Text` component. Can bind dynamic values. | β
Yes | `"textContent": "item.text"` |
| `source.uri` | `string` / `object` | Image URI. Supports ternary expression. | β
Yes | `"uri": { "expression": "ternary", ... }` |
| `style` | `object` | Style object. Keys can be static or ternary expressions. Resolves theme values. | β
Yes | `"color": "primary"` |
| `color` props | `string` | Props ending with `color` resolve from `theme.colors`. | β
Yes | `"backgroundColor": "primary"` |
| `fontSize` | `string` (theme key) | Maps to `theme.font`. | β
Yes | `"fontSize": "h3"` |
| `fontWeight` | `string` (theme key) | Maps to `theme.fontWeight`. | β
Yes | `"fontWeight": "bold"` |
| `visible` | `boolean` / `object` | Controls visibility without removing from render tree. Supports ternary. | β
Yes | `"visible": { "expression": "ternary", ... }` |
| `visibleExpression` | `boolean` | If true, `visible` is evaluated as a path/expression. | β
Yes | `"visibleExpression": true` |
| `type` | `string` | Special types: `"dateTime"`. | β
Yes | `"type": "dateTime", "format": "DD-MM-YYYY"` |
| `format` | `string` | Format string for `dateTime` type (uses `moment`). | β No | `"format": "DD-MM-YYYY hh:mm a"` |
| `fixedLength` | `number` | Converts numeric/string values to fixed decimal places. | β No | `"fixedLength": 2` |
| `onPress` (etc.) | `string` | Event handler name resolved from `handlers`. | β No | `"onPress": "handleSubmit"` |
| `passData` | `boolean` | If `true`, passes `(item, index)` into event handler. | β No | `"passData": true` |
| `passName` | `boolean` | If `true`, passes the prop name as an extra argument to handler. | β No | `"passName": true` |
| `data` (lists) | `array` / `string` | Used in `FlatList`. Can be bound via `expression: true`. | β
Yes | `"data": "messages"` |
| `listHeaderComponent` | `array` | Schema for `FlatList` header. | β No | JSON schema array |
| `listFooterComponent` | `array` | Schema for `FlatList` footer. | β No | JSON schema array |
| `listEmptyComponent` | `array` | Schema for empty state in `FlatList`. | β No | JSON schema array |
---
## β‘ Expressions & Conditionals
### 1. Expression Mode
```json
{
"name": "Text",
"props": { "textContent": "item.text", "expression": true }
}
```
### 2. Ternary Expressions
```json
{
"name": "Image",
"props": {
"expression": true,
"source": {
"uri": {
"expression": "ternary",
"condition": "{{item.type === 'CUSTOMER'}}",
"trueValue": "item.customerImage",
"falseValue": "https://cdn-icons-png.flaticon.com/128/3135/3135715.png"
}
}
}
}
```
### 3. Conditional Styles
```json
{
"name": "Text",
"props": {
"style": {
"backgroundColor": {
"expression": "ternary",
"condition": "{{item.type === 'CUSTOMER'}}",
"trueValue": "primary",
"falseValue": "secondary"
}
},
"textContent": "item.text",
"expression": true
}
}
```
### 4. Date Formatting
```json
{
"name": "Text",
"props": {
"textContent": "item.timestamp",
"expression": true,
"type": "dateTime",
"format": "DD-MM-YYYY hh:mm a"
}
}
```
### 5. Fixed Length
```json
{
"name": "Text",
"props": { "textContent": "item.price", "expression": true, "fixedLength": 2 }
}
```
---
## π Event Handling
Attach event handlers by string key:
```json
{
"name": "Button",
"props": { "title": "Submit", "onPress": "submitForm" }
}
```
```tsx
const handlers = {
submitForm: () => console.log("Form submitted"),
};
```
Options:
- `passData: true` β Pass `(item, index)` automatically.
- `passName: true` β Pass prop name to the handler.
---
## π¨ Styling & Theme
- Props ending in `style` resolve as style objects.
- Theme tokens supported:
- `"color": "primary"` β `theme.colors.primary`
- `"fontSize": "h3"` β `theme.font.h3`
- `"fontWeight": "bold"` β `theme.fontWeight.bold`
---
## π FlatList Support
```json
{
"name": "FlatList",
"props": { "data": "messages" },
"content": [
{
"name": "Text",
"props": {
"textContent": "item.text",
"expression": true,
"style": { "backgroundColor": "primary", "color": "white" }
}
}
]
}
```
π `item` and `index` are auto-injected.
π Supports `listHeaderComponent`, `listFooterComponent`, `listEmptyComponent`.
---
## β οΈ Best Practices
- Always pass `theme` + `components`.
- Use `expression: true` for data binding.
- Use ternary expressions for conditional logic.
- Prefer theme tokens over hardcoded colors/fonts.
- Wrap logic inside `{{ ... }}` for expressions.
---
## π Example: Chat UI
```json
{
"content": [
{
"name": "FlatList",
"props": {
"data": "messages",
"style": { "padding": 16, "marginTop": 40 }
},
"content": [
{
"name": "Image",
"props": {
"expression": true,
"source": {
"uri": {
"expression": "ternary",
"condition": "{{item.type === 'CUSTOMER'}}",
"trueValue": "item.customerImage",
"falseValue": "https://cdn-icons-png.flaticon.com/128/3135/3135715.png"
}
},
"style": {
"height": 40,
"width": 40,
"alignSelf": {
"expression": "ternary",
"condition": "{{item.type === 'CUSTOMER'}}",
"trueValue": "flex-start",
"falseValue": "flex-end"
}
}
}
},
{
"name": "Text",
"props": {
"expression": true,
"textContent": "item.text",
"style": {
"alignSelf": {
"expression": "ternary",
"condition": "{{item.type === 'CUSTOMER'}}",
"trueValue": "flex-start",
"falseValue": "flex-end"
},
"backgroundColor": {
"expression": "ternary",
"condition": "{{item.type === 'CUSTOMER'}}",
"trueValue": "primary",
"falseValue": "secondary"
},
"color": "white",
"padding": 8,
"borderRadius": 8,
"maxWidth": "80%",
"marginTop": 8
}
}
},
{
"name": "Text",
"props": {
"textContent": "item.timestamp",
"expression": true,
"type": "dateTime",
"format": "DD-MM-YYYY hh:mm a"
}
},
{
"name": "Text",
"props": {
"textContent": "item.label",
"expression": true,
"fixedLength": 2,
"style": {
"fontSize": "h3",
"fontWeight": "bold",
"marginTop": 16
}
}
}
]
}
]
}
```
---