@schema-gui/rn
v0.1.0
Published
React Native renderer implementation for shema-gui core library
Readme
@schema-gui/rn
React Native рендерер для декларативного рендерингу UI на основі JSON схем
📋 Зміст
- Вступ
- Встановлення
- Швидкий старт
- API
- Підтримувані компоненти
- Відмінності від Web рендерера
- Приклади
- Стилізація
- Події
- Детальна документація
Вступ
@schema-gui/rn - це React Native реалізація UIRendererEngine для бібліотеки @schema-gui/core. Вона дозволяє використовувати ті самі JSON схеми для створення UI в React Native додатках.
Основні можливості
- Кросплатформенність - одна схема для iOS та Android
- Нативні компоненти - використання React Native компонентів замість HTML
- Повна сумісність - підтримка всіх можливостей core бібліотеки
- Type-safe - повна типізація TypeScript
Архітектура
JSON Schema → UIRenderer → UIRendererEngineReactNative → React Native ComponentsВстановлення
npm install @schema-gui/rn @schema-gui/coreабо
yarn add @schema-gui/rn @schema-gui/coreЗалежності
- React Native 0.81+
- React 19+
- TypeScript 5+
@schema-gui/core
Швидкий старт
Базовий приклад
import { UIRenderer } from '@schema-gui/core';
import { UIRendererEngineReactNative } from '@schema-gui/rn';
import { useState } from 'react';
import { SafeAreaView } from 'react-native';
const schema = {
type: "view",
style: {
padding: 20,
backgroundColor: "#1E1E1E"
},
children: [
{
type: "text",
text: "Hello, {name}!",
style: {
fontSize: 24,
color: "#FFFFFF",
fontWeight: "600"
}
},
{
type: "text",
text: "Age: {age}",
style: {
fontSize: 16,
color: "#CCCCCC",
marginTop: 10
}
}
]
};
const data = {
name: "John",
age: 30
};
function App() {
const [state, setState] = useState({});
const setStateValue = (variable: string, value: unknown) => {
setState({ ...state, [variable]: value });
};
const renderEngine = new UIRendererEngineReactNative();
return (
<SafeAreaView style={{ flex: 1 }}>
<UIRenderer
schema={schema}
data={data}
renderEngine={renderEngine}
state={state}
setStateValue={setStateValue}
/>
</SafeAreaView>
);
}API
UIRendererEngineReactNative
React Native реалізація рендерера.
import { UIRendererEngineReactNative } from '@schema-gui/rn';
const renderEngine = new UIRendererEngineReactNative();Використання з UIRenderer
import { UIRenderer } from '@schema-gui/core';
import { UIRendererEngineReactNative } from '@schema-gui/rn';
<UIRenderer
schema={schema}
data={data}
renderEngine={new UIRendererEngineReactNative()}
state={state}
setStateValue={setStateValue}
/>Підтримувані компоненти
Базові компоненти
| Тип в схемі | React Native компонент | Опис |
|------------|------------------------|------|
| container | View | Контейнер для групування елементів |
| view | View | Основний контейнер |
| text | Text | Текстовий елемент |
| image / img | Image | Зображення |
| button | Button | Кнопка |
| text_input | TextInput | Поле вводу тексту |
| switch | Switch | Перемикач |
| activity_indicator | ActivityIndicator | Індикатор завантаження |
| scroll_view | ScrollView | Прокручуваний контейнер |
| modal | Modal | Модальне вікно |
| keyboard_avoiding_view | KeyboardAvoidingView | Контейнер з обробкою клавіатури |
| image_background | ImageBackground | Фонове зображення |
| status_bar | StatusBar | Статус бар |
Touchable компоненти
| Тип в схемі | React Native компонент | Опис |
|------------|------------------------|------|
| pressable | Pressable | Натискається елемент (рекомендовано) |
| touchable_opacity | TouchableOpacity | Натискається з ефектом прозорості |
| touchable_highlight | TouchableHighlight | Натискається з підсвічуванням |
| touchable_without_feedback | TouchableWithoutFeedback | Натискається без візуального ефекту |
Приклад використання
const schema = {
type: "view",
children: [
{
type: "text",
text: "Hello World"
},
{
type: "image",
src: "{imageUrl}",
style: {
width: 100,
height: 100
}
},
{
type: "pressable",
events: {
onPress: {
actionType: "setState",
variable: "$state.pressed",
value: "true"
}
},
children: [
{
type: "text",
text: "Press me"
}
]
}
]
};Відмінності від Web рендерера
1. Компоненти
Web: HTML елементи (div, span, button, тощо)
React Native: Нативні компоненти (View, Text, Pressable, тощо)
2. Стилі
Web: CSS властивості (camelCase)
React Native: React Native StyleSheet (camelCase, але з обмеженнями)
Відмінності:
- React Native не підтримує всі CSS властивості
- Використовується
StyleSheet.create()для оптимізації - Деякі властивості мають інші назви (наприклад,
flexDirectionзамістьflex-direction)
3. Події
Web: onClick, onChange, тощо
React Native: onPress, onChangeText, тощо
Відображення:
onClick→onPress(для touchable компонентів)onChange→onChangeText(для TextInput)
4. Зображення
Web: <img src="url" />
React Native: <Image source={{ uri: "url" }} />
Рендерер автоматично конвертує src в source: { uri: src }.
5. className
React Native рендерер підтримує className для інтеграції з NativeWind або іншими CSS-in-JS рішеннями. Анімаційні класи (як animate-*, transition-*, duration-*) автоматично фільтруються.
Приклади
Приклад 1: Простий список
const schema = {
type: "scroll_view",
style: {
flex: 1
},
children: [
{
type: "view",
iterate: {
source: "items",
limit: 10
},
style: {
padding: 15,
borderBottomWidth: 1,
borderBottomColor: "#333"
},
children: [
{
type: "text",
text: "{$item.name}",
style: {
fontSize: 16,
color: "#000000"
}
}
]
}
]
};
const data = {
items: [
{ name: "Item 1" },
{ name: "Item 2" },
{ name: "Item 3" }
]
};Приклад 2: Форма з вводом
const schema = {
type: "view",
style: {
padding: 20
},
children: [
{
type: "text",
text: "Name:",
style: {
fontSize: 16,
marginBottom: 5
}
},
{
type: "text_input",
value: "{$state.name}",
placeholder: "Enter your name",
events: {
onChangeText: {
actionType: "setState",
variable: "$state.name",
value: "value"
}
},
style: {
borderWidth: 1,
borderColor: "#CCCCCC",
borderRadius: 8,
padding: 10,
marginBottom: 20
}
},
{
type: "text",
text: "Hello, {$state.name}!",
condition: {
key: "$state.name",
operator: "!==",
value: ""
},
style: {
fontSize: 18,
color: "#1E1E1E"
}
}
]
};Приклад 3: Модальне вікно
const schema = {
type: "view",
children: [
{
type: "pressable",
events: {
onPress: {
actionType: "setState",
variable: "$state.showModal",
value: "true"
}
},
style: {
padding: 15,
backgroundColor: "#1E1E1E",
borderRadius: 8
},
children: [
{
type: "text",
text: "Open Modal",
style: {
color: "#FFFFFF",
fontSize: 16
}
}
]
},
{
type: "modal",
visible: "{$state.showModal}",
transparent: true,
animationType: "fade",
events: {
onRequestClose: {
actionType: "setState",
variable: "$state.showModal",
value: "false"
}
},
children: [
{
type: "view",
style: {
flex: 1,
justifyContent: "center",
alignItems: "center",
backgroundColor: "rgba(0, 0, 0, 0.5)"
},
children: [
{
type: "view",
style: {
backgroundColor: "#FFFFFF",
padding: 30,
borderRadius: 12,
minWidth: 300
},
children: [
{
type: "text",
text: "Modal Title",
style: {
fontSize: 24,
fontWeight: "600",
marginBottom: 15
}
},
{
type: "text",
text: "Modal content goes here",
style: {
fontSize: 16,
marginBottom: 20
}
},
{
type: "pressable",
events: {
onPress: {
actionType: "setState",
variable: "$state.showModal",
value: "false"
}
},
style: {
padding: 12,
backgroundColor: "#1E1E1E",
borderRadius: 8,
alignItems: "center"
},
children: [
{
type: "text",
text: "Close",
style: {
color: "#FFFFFF",
fontSize: 16
}
}
]
}
]
}
]
}
]
}
]
};Приклад 4: Список з кнопками
const schema = {
type: "scroll_view",
style: {
flex: 1
},
children: [
{
type: "view",
iterate: {
source: "todos"
},
style: {
flexDirection: "row",
padding: 15,
borderBottomWidth: 1,
borderBottomColor: "#E0E0E0",
alignItems: "center"
},
children: [
{
type: "text",
text: "{$item.title}",
style: {
flex: 1,
fontSize: 16
}
},
{
type: "switch",
value: "{$item.completed}",
events: {
onValueChange: {
actionType: "code",
code: `
const updatedTodos = data.todos.map(todo =>
todo.id === item.id
? { ...todo, completed: value }
: todo
);
setStateValue('todos', updatedTodos);
`
}
}
}
]
}
]
};Приклад 5: Зображення
const schema = {
type: "view",
children: [
{
type: "image",
src: "{imageUrl}",
style: {
width: 200,
height: 200,
borderRadius: 10
}
}
]
};Примітка: React Native автоматично конвертує src в source: { uri: src }.
Стилізація
React Native StyleSheet
Стилі в React Native використовують об'єктний синтаксис, сумісний з React.CSSProperties, але з обмеженнями:
{
type: "view",
style: {
flex: 1,
padding: 20,
backgroundColor: "#1E1E1E",
borderRadius: 8,
flexDirection: "column",
alignItems: "center",
justifyContent: "center"
}
}Умовні стилі
Підтримуються умовні стилі як у web версії:
{
type: "text",
text: "Status",
style: {
color: {
condition: {
key: "status",
operator: "===",
value: "active"
},
true: "#00C853",
false: "#D50000"
}
}
}className для NativeWind
Якщо ви використовуєте NativeWind, можете використовувати className:
{
type: "view",
className: "flex-1 bg-gray-100 p-4"
}Примітка: Анімаційні класи (як animate-*, transition-*) автоматично фільтруються.
Події
Підтримувані події
React Native рендерер підтримує стандартні React Native події:
| Подія | Компоненти | Опис |
|------|------------|------|
| onPress | Pressable, TouchableOpacity, TouchableHighlight, Button | Натискання |
| onChangeText | TextInput | Зміна тексту |
| onValueChange | Switch | Зміна значення перемикача |
| onRequestClose | Modal | Запит на закриття модального вікна |
| onFocus | TextInput | Фокус на полі вводу |
| onBlur | TextInput | Втрата фокусу |
Автоматичне відображення
Рендерер автоматично конвертує web події в React Native:
onClick→onPress(для touchable компонентів)onChange→onChangeText(для TextInput)
Приклад з подіями
{
type: "view",
children: [
{
type: "pressable",
events: {
onPress: {
actionType: "code",
code: `
console.log('Button pressed!', data, state);
setStateValue('counter', (state.counter || 0) + 1);
`
}
},
style: {
padding: 15,
backgroundColor: "#1E1E1E",
borderRadius: 8
},
children: [
{
type: "text",
text: "Count: {$state.counter}",
style: {
color: "#FFFFFF"
}
}
]
},
{
type: "text_input",
value: "{$state.input}",
placeholder: "Enter text",
events: {
onChangeText: {
actionType: "setState",
variable: "$state.input",
value: "value"
}
},
style: {
borderWidth: 1,
borderColor: "#CCCCCC",
borderRadius: 8,
padding: 10,
marginTop: 10
}
}
]
}Детальна документація
Для детальної інформації про створення UI схем, інтерполяцію, форматування, умови, ітерацію та інші можливості дивіться:
- Core README - Повна документація по створенню схем
Всі можливості core бібліотеки працюють з React Native рендерером:
- ✅ Інтерполяція змінних (
{variable},{$item},{$state}) - ✅ Форматування (number, volume, datetime, time)
- ✅ Умови (condition)
- ✅ Ітерація (iterate)
- ✅ Обчислення в text та стилях
- ✅ Умовні стилі
- ✅ Події (setState та code)
- ✅ Модальні вікна
Особливості React Native
1. Flexbox за замовчуванням
React Native використовує Flexbox за замовчуванням. display: flex не потрібно вказувати.
2. Відсутність деяких CSS властивостей
Деякі CSS властивості не підтримуються в React Native:
display: grid→ використовуйтеflexDirectionтаflexWrapdisplay: table→ використовуйтеViewзflexDirection: "row"- CSS селектори → використовуйте умовні стилі
3. Текстові елементи
В React Native текст повинен бути всередині <Text> компонента:
// ✅ Правильно
{
type: "view",
children: [
{
type: "text",
text: "Hello"
}
]
}
// ❌ Неправильно (не працює в React Native)
{
type: "view",
text: "Hello" // Текст не може бути прямим дочірнім View
}4. Зображення
React Native вимагає вказати розміри для зображень:
{
type: "image",
src: "{imageUrl}",
style: {
width: 100, // Обов'язково
height: 100 // Обов'язково
}
}5. Безпечні зони
Використовуйте SafeAreaView для обгортання всього контенту:
import { SafeAreaView } from 'react-native';
<SafeAreaView style={{ flex: 1 }}>
<UIRenderer
schema={schema}
data={data}
renderEngine={new UIRendererEngineReactNative()}
state={state}
setStateValue={setStateValue}
/>
</SafeAreaView>Найкращі практики
1. Використання ScrollView для довгого контенту
{
type: "scroll_view",
style: {
flex: 1
},
children: [
// Ваш контент
]
}2. Оптимізація списків
Для великих списків використовуйте limit в ітерації:
{
iterate: {
source: "items",
limit: 20 // Обмежте кількість елементів
}
}3. Використання Pressable замість TouchableOpacity
Pressable - це сучасний компонент з кращою підтримкою:
{
type: "pressable", // ✅ Рекомендовано
// замість
type: "touchable_opacity" // ⚠️ Застаріло
}4. Обробка клавіатури
Використовуйте KeyboardAvoidingView для форм:
{
type: "keyboard_avoiding_view",
style: {
flex: 1
},
children: [
// Форма з TextInput
]
}