UNPKG

rn-dynamic-ui-render

Version:
383 lines (323 loc) β€’ 12.5 kB
# πŸ“¦ 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 } } } ] } ] } ``` ---