@json-render/react 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,238 @@
1
+ # @json-render/react
2
+
3
+ React renderer for @json-render/core - JSON becomes React components.
4
+
5
+ ## Features
6
+
7
+ - **Visibility Filtering**: Components automatically show/hide based on visibility conditions
8
+ - **Action Handling**: Built-in action execution with confirmation dialogs
9
+ - **Validation**: Field validation with error display
10
+ - **Data Binding**: Two-way data binding between UI and data model
11
+ - **Streaming**: Progressive rendering from streamed UI trees
12
+
13
+ ## Installation
14
+
15
+ ```bash
16
+ npm install @json-render/react @json-render/core
17
+ # or
18
+ pnpm add @json-render/react @json-render/core
19
+ ```
20
+
21
+ ## Quick Start
22
+
23
+ ### Basic Setup
24
+
25
+ ```tsx
26
+ import { JSONUIProvider, Renderer, useUIStream } from '@json-render/react';
27
+
28
+ // Define your component registry
29
+ const registry = {
30
+ Card: ({ element, children }) => (
31
+ <div className="card">
32
+ <h3>{element.props.title}</h3>
33
+ {children}
34
+ </div>
35
+ ),
36
+ Button: ({ element, onAction }) => (
37
+ <button onClick={() => onAction?.(element.props.action)}>
38
+ {element.props.label}
39
+ </button>
40
+ ),
41
+ };
42
+
43
+ // Action handlers
44
+ const actionHandlers = {
45
+ submit: async (params) => {
46
+ await api.submit(params);
47
+ },
48
+ export: (params) => {
49
+ download(params.format);
50
+ },
51
+ };
52
+
53
+ function App() {
54
+ const { tree, isStreaming, send, clear } = useUIStream({
55
+ api: '/api/generate',
56
+ });
57
+
58
+ return (
59
+ <JSONUIProvider
60
+ registry={registry}
61
+ initialData={{ user: { name: 'John' } }}
62
+ authState={{ isSignedIn: true }}
63
+ actionHandlers={actionHandlers}
64
+ >
65
+ <input
66
+ placeholder="Describe the UI..."
67
+ onKeyDown={(e) => e.key === 'Enter' && send(e.target.value)}
68
+ />
69
+ <Renderer tree={tree} registry={registry} loading={isStreaming} />
70
+ </JSONUIProvider>
71
+ );
72
+ }
73
+ ```
74
+
75
+ ### Using Contexts Directly
76
+
77
+ ```tsx
78
+ import {
79
+ DataProvider,
80
+ VisibilityProvider,
81
+ ActionProvider,
82
+ ValidationProvider,
83
+ useData,
84
+ useVisibility,
85
+ useActions,
86
+ useFieldValidation,
87
+ } from '@json-render/react';
88
+
89
+ // Data context
90
+ function MyComponent() {
91
+ const { data, get, set } = useData();
92
+ const value = get('/user/name');
93
+
94
+ return (
95
+ <input
96
+ value={value}
97
+ onChange={(e) => set('/user/name', e.target.value)}
98
+ />
99
+ );
100
+ }
101
+
102
+ // Visibility context
103
+ function ConditionalComponent({ visible }) {
104
+ const { isVisible } = useVisibility();
105
+
106
+ if (!isVisible(visible)) {
107
+ return null;
108
+ }
109
+
110
+ return <div>Visible content</div>;
111
+ }
112
+
113
+ // Action context
114
+ function ActionButton({ action }) {
115
+ const { execute, loadingActions } = useActions();
116
+
117
+ return (
118
+ <button
119
+ onClick={() => execute(action)}
120
+ disabled={loadingActions.has(action.name)}
121
+ >
122
+ {action.name}
123
+ </button>
124
+ );
125
+ }
126
+
127
+ // Validation context
128
+ function ValidatedInput({ path, checks }) {
129
+ const { errors, validate, touch } = useFieldValidation(path, { checks });
130
+ const [value, setValue] = useDataBinding(path);
131
+
132
+ return (
133
+ <div>
134
+ <input
135
+ value={value}
136
+ onChange={(e) => setValue(e.target.value)}
137
+ onBlur={() => { touch(); validate(); }}
138
+ />
139
+ {errors.map((err) => <span key={err}>{err}</span>)}
140
+ </div>
141
+ );
142
+ }
143
+ ```
144
+
145
+ ### Streaming UI
146
+
147
+ ```tsx
148
+ import { useUIStream } from '@json-render/react';
149
+
150
+ function StreamingDemo() {
151
+ const {
152
+ tree, // Current UI tree
153
+ isStreaming, // Whether currently streaming
154
+ error, // Error if any
155
+ send, // Send a prompt
156
+ clear, // Clear the tree
157
+ } = useUIStream({
158
+ api: '/api/generate',
159
+ onComplete: (tree) => console.log('Done:', tree),
160
+ onError: (err) => console.error('Error:', err),
161
+ });
162
+
163
+ return (
164
+ <div>
165
+ <button onClick={() => send('Create a dashboard')}>
166
+ Generate
167
+ </button>
168
+ {isStreaming && <span>Generating...</span>}
169
+ {tree && <Renderer tree={tree} registry={registry} />}
170
+ </div>
171
+ );
172
+ }
173
+ ```
174
+
175
+ ## API Reference
176
+
177
+ ### Providers
178
+
179
+ - `JSONUIProvider` - Combined provider for all contexts
180
+ - `DataProvider` - Data model context
181
+ - `VisibilityProvider` - Visibility evaluation context
182
+ - `ActionProvider` - Action execution context
183
+ - `ValidationProvider` - Validation context
184
+
185
+ ### Hooks
186
+
187
+ - `useData()` - Access data model
188
+ - `useDataValue(path)` - Get a single value
189
+ - `useDataBinding(path)` - Two-way binding like useState
190
+ - `useVisibility()` - Access visibility evaluation
191
+ - `useIsVisible(condition)` - Check if condition is visible
192
+ - `useActions()` - Access action execution
193
+ - `useAction(action)` - Execute a specific action
194
+ - `useValidation()` - Access validation context
195
+ - `useFieldValidation(path, config)` - Field-level validation
196
+
197
+ ### Components
198
+
199
+ - `Renderer` - Render a UI tree
200
+ - `ConfirmDialog` - Default confirmation dialog
201
+
202
+ ### Utilities
203
+
204
+ - `useUIStream(options)` - Hook for streaming UI generation
205
+ - `flatToTree(elements)` - Convert flat list to tree
206
+
207
+ ## Component Props
208
+
209
+ Components in your registry receive these props:
210
+
211
+ ```typescript
212
+ interface ComponentRenderProps<P = Record<string, unknown>> {
213
+ element: UIElement<string, P>; // The element definition
214
+ children?: ReactNode; // Rendered children
215
+ onAction?: (action: Action) => void; // Action callback
216
+ loading?: boolean; // Streaming in progress
217
+ }
218
+ ```
219
+
220
+ ## Example Component
221
+
222
+ ```tsx
223
+ function MetricComponent({ element }: ComponentRenderProps) {
224
+ const { label, valuePath, format } = element.props;
225
+ const value = useDataValue(valuePath);
226
+
227
+ const formatted = format === 'currency'
228
+ ? new Intl.NumberFormat('en-US', { style: 'currency', currency: 'USD' }).format(value)
229
+ : String(value);
230
+
231
+ return (
232
+ <div className="metric">
233
+ <span className="label">{label}</span>
234
+ <span className="value">{formatted}</span>
235
+ </div>
236
+ );
237
+ }
238
+ ```
@@ -0,0 +1,315 @@
1
+ import * as react_jsx_runtime from 'react/jsx-runtime';
2
+ import { ReactNode, ComponentType } from 'react';
3
+ import { DataModel, AuthState, VisibilityCondition, VisibilityContext, ActionHandler, ResolvedAction, Action, ActionConfirm, ValidationFunction, ValidationResult, ValidationConfig, UITree, UIElement, Catalog, ComponentDefinition } from '@json-render/core';
4
+
5
+ /**
6
+ * Data context value
7
+ */
8
+ interface DataContextValue {
9
+ /** The current data model */
10
+ data: DataModel;
11
+ /** Auth state for visibility evaluation */
12
+ authState?: AuthState;
13
+ /** Get a value by path */
14
+ get: (path: string) => unknown;
15
+ /** Set a value by path */
16
+ set: (path: string, value: unknown) => void;
17
+ /** Update multiple values at once */
18
+ update: (updates: Record<string, unknown>) => void;
19
+ }
20
+ /**
21
+ * Props for DataProvider
22
+ */
23
+ interface DataProviderProps {
24
+ /** Initial data model */
25
+ initialData?: DataModel;
26
+ /** Auth state */
27
+ authState?: AuthState;
28
+ /** Callback when data changes */
29
+ onDataChange?: (path: string, value: unknown) => void;
30
+ children: ReactNode;
31
+ }
32
+ /**
33
+ * Provider for data model context
34
+ */
35
+ declare function DataProvider({ initialData, authState, onDataChange, children, }: DataProviderProps): react_jsx_runtime.JSX.Element;
36
+ /**
37
+ * Hook to access the data context
38
+ */
39
+ declare function useData(): DataContextValue;
40
+ /**
41
+ * Hook to get a value from the data model
42
+ */
43
+ declare function useDataValue<T>(path: string): T | undefined;
44
+ /**
45
+ * Hook to get and set a value from the data model (like useState)
46
+ */
47
+ declare function useDataBinding<T>(path: string): [T | undefined, (value: T) => void];
48
+
49
+ /**
50
+ * Visibility context value
51
+ */
52
+ interface VisibilityContextValue {
53
+ /** Evaluate a visibility condition */
54
+ isVisible: (condition: VisibilityCondition | undefined) => boolean;
55
+ /** The underlying visibility context */
56
+ ctx: VisibilityContext;
57
+ }
58
+ /**
59
+ * Props for VisibilityProvider
60
+ */
61
+ interface VisibilityProviderProps {
62
+ children: ReactNode;
63
+ }
64
+ /**
65
+ * Provider for visibility evaluation
66
+ */
67
+ declare function VisibilityProvider({ children }: VisibilityProviderProps): react_jsx_runtime.JSX.Element;
68
+ /**
69
+ * Hook to access visibility evaluation
70
+ */
71
+ declare function useVisibility(): VisibilityContextValue;
72
+ /**
73
+ * Hook to check if a condition is visible
74
+ */
75
+ declare function useIsVisible(condition: VisibilityCondition | undefined): boolean;
76
+
77
+ /**
78
+ * Pending confirmation state
79
+ */
80
+ interface PendingConfirmation {
81
+ /** The resolved action */
82
+ action: ResolvedAction;
83
+ /** The action handler */
84
+ handler: ActionHandler;
85
+ /** Resolve callback */
86
+ resolve: () => void;
87
+ /** Reject callback */
88
+ reject: () => void;
89
+ }
90
+ /**
91
+ * Action context value
92
+ */
93
+ interface ActionContextValue {
94
+ /** Registered action handlers */
95
+ handlers: Record<string, ActionHandler>;
96
+ /** Currently loading action names */
97
+ loadingActions: Set<string>;
98
+ /** Pending confirmation dialog */
99
+ pendingConfirmation: PendingConfirmation | null;
100
+ /** Execute an action */
101
+ execute: (action: Action) => Promise<void>;
102
+ /** Confirm the pending action */
103
+ confirm: () => void;
104
+ /** Cancel the pending action */
105
+ cancel: () => void;
106
+ /** Register an action handler */
107
+ registerHandler: (name: string, handler: ActionHandler) => void;
108
+ }
109
+ /**
110
+ * Props for ActionProvider
111
+ */
112
+ interface ActionProviderProps {
113
+ /** Initial action handlers */
114
+ handlers?: Record<string, ActionHandler>;
115
+ /** Navigation function */
116
+ navigate?: (path: string) => void;
117
+ children: ReactNode;
118
+ }
119
+ /**
120
+ * Provider for action execution
121
+ */
122
+ declare function ActionProvider({ handlers: initialHandlers, navigate, children, }: ActionProviderProps): react_jsx_runtime.JSX.Element;
123
+ /**
124
+ * Hook to access action context
125
+ */
126
+ declare function useActions(): ActionContextValue;
127
+ /**
128
+ * Hook to execute an action
129
+ */
130
+ declare function useAction(action: Action): {
131
+ execute: () => Promise<void>;
132
+ isLoading: boolean;
133
+ };
134
+ /**
135
+ * Props for ConfirmDialog component
136
+ */
137
+ interface ConfirmDialogProps {
138
+ /** The confirmation config */
139
+ confirm: ActionConfirm;
140
+ /** Called when confirmed */
141
+ onConfirm: () => void;
142
+ /** Called when cancelled */
143
+ onCancel: () => void;
144
+ }
145
+ /**
146
+ * Default confirmation dialog component
147
+ */
148
+ declare function ConfirmDialog({ confirm, onConfirm, onCancel }: ConfirmDialogProps): react_jsx_runtime.JSX.Element;
149
+
150
+ /**
151
+ * Field validation state
152
+ */
153
+ interface FieldValidationState {
154
+ /** Whether the field has been touched */
155
+ touched: boolean;
156
+ /** Whether the field has been validated */
157
+ validated: boolean;
158
+ /** Validation result */
159
+ result: ValidationResult | null;
160
+ }
161
+ /**
162
+ * Validation context value
163
+ */
164
+ interface ValidationContextValue {
165
+ /** Custom validation functions from catalog */
166
+ customFunctions: Record<string, ValidationFunction>;
167
+ /** Validation state by field path */
168
+ fieldStates: Record<string, FieldValidationState>;
169
+ /** Validate a field */
170
+ validate: (path: string, config: ValidationConfig) => ValidationResult;
171
+ /** Mark field as touched */
172
+ touch: (path: string) => void;
173
+ /** Clear validation for a field */
174
+ clear: (path: string) => void;
175
+ /** Validate all fields */
176
+ validateAll: () => boolean;
177
+ /** Register field config */
178
+ registerField: (path: string, config: ValidationConfig) => void;
179
+ }
180
+ /**
181
+ * Props for ValidationProvider
182
+ */
183
+ interface ValidationProviderProps {
184
+ /** Custom validation functions from catalog */
185
+ customFunctions?: Record<string, ValidationFunction>;
186
+ children: ReactNode;
187
+ }
188
+ /**
189
+ * Provider for validation
190
+ */
191
+ declare function ValidationProvider({ customFunctions, children, }: ValidationProviderProps): react_jsx_runtime.JSX.Element;
192
+ /**
193
+ * Hook to access validation context
194
+ */
195
+ declare function useValidation(): ValidationContextValue;
196
+ /**
197
+ * Hook to get validation state for a field
198
+ */
199
+ declare function useFieldValidation(path: string, config?: ValidationConfig): {
200
+ state: FieldValidationState;
201
+ validate: () => ValidationResult;
202
+ touch: () => void;
203
+ clear: () => void;
204
+ errors: string[];
205
+ isValid: boolean;
206
+ };
207
+
208
+ /**
209
+ * Props passed to component renderers
210
+ */
211
+ interface ComponentRenderProps<P = Record<string, unknown>> {
212
+ /** The element being rendered */
213
+ element: UIElement<string, P>;
214
+ /** Rendered children */
215
+ children?: ReactNode;
216
+ /** Execute an action */
217
+ onAction?: (action: Action) => void;
218
+ /** Whether the parent is loading */
219
+ loading?: boolean;
220
+ }
221
+ /**
222
+ * Component renderer type
223
+ */
224
+ type ComponentRenderer<P = Record<string, unknown>> = ComponentType<ComponentRenderProps<P>>;
225
+ /**
226
+ * Registry of component renderers
227
+ */
228
+ type ComponentRegistry = Record<string, ComponentRenderer<any>>;
229
+ /**
230
+ * Props for the Renderer component
231
+ */
232
+ interface RendererProps {
233
+ /** The UI tree to render */
234
+ tree: UITree | null;
235
+ /** Component registry */
236
+ registry: ComponentRegistry;
237
+ /** Whether the tree is currently loading/streaming */
238
+ loading?: boolean;
239
+ /** Fallback component for unknown types */
240
+ fallback?: ComponentRenderer;
241
+ }
242
+ /**
243
+ * Main renderer component
244
+ */
245
+ declare function Renderer({ tree, registry, loading, fallback }: RendererProps): react_jsx_runtime.JSX.Element | null;
246
+ /**
247
+ * Props for JSONUIProvider
248
+ */
249
+ interface JSONUIProviderProps {
250
+ /** Component registry */
251
+ registry: ComponentRegistry;
252
+ /** Initial data model */
253
+ initialData?: Record<string, unknown>;
254
+ /** Auth state */
255
+ authState?: {
256
+ isSignedIn: boolean;
257
+ user?: Record<string, unknown>;
258
+ };
259
+ /** Action handlers */
260
+ actionHandlers?: Record<string, (params: Record<string, unknown>) => Promise<unknown> | unknown>;
261
+ /** Navigation function */
262
+ navigate?: (path: string) => void;
263
+ /** Custom validation functions */
264
+ validationFunctions?: Record<string, (value: unknown, args?: Record<string, unknown>) => boolean>;
265
+ /** Callback when data changes */
266
+ onDataChange?: (path: string, value: unknown) => void;
267
+ children: ReactNode;
268
+ }
269
+ /**
270
+ * Combined provider for all JSONUI contexts
271
+ */
272
+ declare function JSONUIProvider({ registry, initialData, authState, actionHandlers, navigate, validationFunctions, onDataChange, children, }: JSONUIProviderProps): react_jsx_runtime.JSX.Element;
273
+ /**
274
+ * Helper to create a renderer component from a catalog
275
+ */
276
+ declare function createRendererFromCatalog<C extends Catalog<Record<string, ComponentDefinition>>>(_catalog: C, registry: ComponentRegistry): ComponentType<Omit<RendererProps, 'registry'>>;
277
+
278
+ /**
279
+ * Options for useUIStream
280
+ */
281
+ interface UseUIStreamOptions {
282
+ /** API endpoint */
283
+ api: string;
284
+ /** Callback when complete */
285
+ onComplete?: (tree: UITree) => void;
286
+ /** Callback on error */
287
+ onError?: (error: Error) => void;
288
+ }
289
+ /**
290
+ * Return type for useUIStream
291
+ */
292
+ interface UseUIStreamReturn {
293
+ /** Current UI tree */
294
+ tree: UITree | null;
295
+ /** Whether currently streaming */
296
+ isStreaming: boolean;
297
+ /** Error if any */
298
+ error: Error | null;
299
+ /** Send a prompt to generate UI */
300
+ send: (prompt: string, context?: Record<string, unknown>) => Promise<void>;
301
+ /** Clear the current tree */
302
+ clear: () => void;
303
+ }
304
+ /**
305
+ * Hook for streaming UI generation
306
+ */
307
+ declare function useUIStream({ api, onComplete, onError, }: UseUIStreamOptions): UseUIStreamReturn;
308
+ /**
309
+ * Convert a flat element list to a UITree
310
+ */
311
+ declare function flatToTree(elements: Array<UIElement & {
312
+ parentKey?: string | null;
313
+ }>): UITree;
314
+
315
+ export { type ActionContextValue, ActionProvider, type ActionProviderProps, type ComponentRegistry, type ComponentRenderProps, type ComponentRenderer, ConfirmDialog, type ConfirmDialogProps, type DataContextValue, DataProvider, type DataProviderProps, type FieldValidationState, JSONUIProvider, type JSONUIProviderProps, type PendingConfirmation, Renderer, type RendererProps, type UseUIStreamOptions, type UseUIStreamReturn, type ValidationContextValue, ValidationProvider, type ValidationProviderProps, type VisibilityContextValue, VisibilityProvider, type VisibilityProviderProps, createRendererFromCatalog, flatToTree, useAction, useActions, useData, useDataBinding, useDataValue, useFieldValidation, useIsVisible, useUIStream, useValidation, useVisibility };