@json-render/react-native 0.8.0 → 0.9.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 +21 -0
- package/dist/index.d.mts +49 -14
- package/dist/index.d.ts +49 -14
- package/dist/index.js +134 -70
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +160 -94
- package/dist/index.mjs.map +1 -1
- package/package.json +5 -4
package/README.md
CHANGED
|
@@ -214,6 +214,26 @@ const systemPrompt = catalog.prompt({
|
|
|
214
214
|
});
|
|
215
215
|
```
|
|
216
216
|
|
|
217
|
+
## External Store (Controlled Mode)
|
|
218
|
+
|
|
219
|
+
For full control over state, pass a `StateStore` to bypass the internal state and wire json-render to any state management library (Redux, Zustand, XState, etc.):
|
|
220
|
+
|
|
221
|
+
```tsx
|
|
222
|
+
import { createStateStore, type StateStore } from "@json-render/react-native";
|
|
223
|
+
|
|
224
|
+
// Use the built-in store outside of React
|
|
225
|
+
const store = createStateStore({ count: 0 });
|
|
226
|
+
|
|
227
|
+
<StateProvider store={store}>
|
|
228
|
+
{children}
|
|
229
|
+
</StateProvider>
|
|
230
|
+
|
|
231
|
+
// Mutate from anywhere — React will re-render automatically:
|
|
232
|
+
store.set("/count", 1);
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
When `store` is provided, `initialState` and `onStateChange` are ignored. The store is the single source of truth. The same `store` prop is available on `createRenderer`, `JSONUIProvider`, and `StateProvider`.
|
|
236
|
+
|
|
217
237
|
## Hooks
|
|
218
238
|
|
|
219
239
|
| Hook | Purpose |
|
|
@@ -227,3 +247,4 @@ const systemPrompt = catalog.prompt({
|
|
|
227
247
|
| `useAction(name)` | Get a single action dispatch function |
|
|
228
248
|
| `useUIStream(options)` | Stream specs from an API endpoint |
|
|
229
249
|
| `createStandardActionHandlers(options)` | Create handlers for standard actions |
|
|
250
|
+
| `createStateStore(initialState)` | Create a framework-agnostic in-memory `StateStore` |
|
package/dist/index.d.mts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
2
|
import { ReactNode, ComponentType } from 'react';
|
|
3
|
-
import { StateModel, VisibilityCondition, VisibilityContext, ActionHandler, ResolvedAction, ActionBinding, ActionConfirm, ValidationFunction, ValidationResult, ValidationConfig, Catalog, InferCatalogComponents, InferComponentProps, InferCatalogActions, InferActionParams, UIElement, SchemaDefinition, Spec, FlatElement } from '@json-render/core';
|
|
4
|
-
export { Spec, StateModel } from '@json-render/core';
|
|
3
|
+
import { StateStore, StateModel, VisibilityCondition, VisibilityContext, ActionHandler, ResolvedAction, ActionBinding, ActionConfirm, ValidationFunction, ValidationResult, ValidationConfig, Catalog, InferCatalogComponents, InferComponentProps, InferCatalogActions, InferActionParams, UIElement, SchemaDefinition, Spec, FlatElement } from '@json-render/core';
|
|
4
|
+
export { Spec, StateModel, StateStore, createStateStore } from '@json-render/core';
|
|
5
5
|
export { ElementTreeSchema, ElementTreeSpec, ReactNativeSchema, ReactNativeSpec, elementTreeSchema, schema } from './schema.mjs';
|
|
6
6
|
export { ActionDefinition, ComponentDefinition, standardActionDefinitions, standardComponentDefinitions } from './catalog.mjs';
|
|
7
7
|
import 'zod';
|
|
@@ -18,21 +18,40 @@ interface StateContextValue {
|
|
|
18
18
|
set: (path: string, value: unknown) => void;
|
|
19
19
|
/** Update multiple values at once */
|
|
20
20
|
update: (updates: Record<string, unknown>) => void;
|
|
21
|
+
/** Return the live state snapshot from the underlying store (not the React render snapshot). */
|
|
22
|
+
getSnapshot: () => StateModel;
|
|
21
23
|
}
|
|
22
24
|
/**
|
|
23
25
|
* Props for StateProvider
|
|
24
26
|
*/
|
|
25
27
|
interface StateProviderProps {
|
|
26
|
-
/**
|
|
28
|
+
/**
|
|
29
|
+
* External store that owns the state. When provided, the provider operates
|
|
30
|
+
* in **controlled mode** — `initialState` and `onStateChange` are ignored
|
|
31
|
+
* and the store is the single source of truth.
|
|
32
|
+
*/
|
|
33
|
+
store?: StateStore;
|
|
34
|
+
/** Initial state model (used only in uncontrolled mode) */
|
|
27
35
|
initialState?: StateModel;
|
|
28
|
-
/**
|
|
29
|
-
|
|
36
|
+
/**
|
|
37
|
+
* Callback when state changes (used only in uncontrolled mode).
|
|
38
|
+
* Called once per `set` or `update` with all changed entries.
|
|
39
|
+
*/
|
|
40
|
+
onStateChange?: (changes: Array<{
|
|
41
|
+
path: string;
|
|
42
|
+
value: unknown;
|
|
43
|
+
}>) => void;
|
|
30
44
|
children: ReactNode;
|
|
31
45
|
}
|
|
32
46
|
/**
|
|
33
|
-
* Provider for state model context
|
|
47
|
+
* Provider for state model context.
|
|
48
|
+
*
|
|
49
|
+
* Supports two modes:
|
|
50
|
+
* - **Controlled**: pass a `store` prop (e.g. backed by Redux / Zustand).
|
|
51
|
+
* - **Uncontrolled** (default): omit `store` and optionally pass
|
|
52
|
+
* `initialState` / `onStateChange`.
|
|
34
53
|
*/
|
|
35
|
-
declare function StateProvider({ initialState, onStateChange, children, }: StateProviderProps): react_jsx_runtime.JSX.Element;
|
|
54
|
+
declare function StateProvider({ store: externalStore, initialState, onStateChange, children, }: StateProviderProps): react_jsx_runtime.JSX.Element;
|
|
36
55
|
/**
|
|
37
56
|
* Hook to access the state context
|
|
38
57
|
*/
|
|
@@ -391,7 +410,12 @@ interface JSONUIProviderProps {
|
|
|
391
410
|
* Custom components are merged with (and override) standard components.
|
|
392
411
|
*/
|
|
393
412
|
registry?: ComponentRegistry;
|
|
394
|
-
/**
|
|
413
|
+
/**
|
|
414
|
+
* External store (controlled mode). When provided, `initialState` and
|
|
415
|
+
* `onStateChange` are ignored.
|
|
416
|
+
*/
|
|
417
|
+
store?: StateStore;
|
|
418
|
+
/** Initial state model (uncontrolled mode) */
|
|
395
419
|
initialState?: Record<string, unknown>;
|
|
396
420
|
/** Action handlers */
|
|
397
421
|
handlers?: Record<string, (params: Record<string, unknown>) => Promise<unknown> | unknown>;
|
|
@@ -399,14 +423,17 @@ interface JSONUIProviderProps {
|
|
|
399
423
|
navigate?: (path: string) => void;
|
|
400
424
|
/** Custom validation functions */
|
|
401
425
|
validationFunctions?: Record<string, (value: unknown, args?: Record<string, unknown>) => boolean>;
|
|
402
|
-
/** Callback when state changes */
|
|
403
|
-
onStateChange?: (
|
|
426
|
+
/** Callback when state changes (uncontrolled mode) */
|
|
427
|
+
onStateChange?: (changes: Array<{
|
|
428
|
+
path: string;
|
|
429
|
+
value: unknown;
|
|
430
|
+
}>) => void;
|
|
404
431
|
children: ReactNode;
|
|
405
432
|
}
|
|
406
433
|
/**
|
|
407
434
|
* Combined provider for all JSONUI contexts
|
|
408
435
|
*/
|
|
409
|
-
declare function JSONUIProvider({ registry, initialState, handlers, navigate, validationFunctions, onStateChange, children, }: JSONUIProviderProps): react_jsx_runtime.JSX.Element;
|
|
436
|
+
declare function JSONUIProvider({ registry, store, initialState, handlers, navigate, validationFunctions, onStateChange, children, }: JSONUIProviderProps): react_jsx_runtime.JSX.Element;
|
|
410
437
|
/**
|
|
411
438
|
* Result returned by defineRegistry
|
|
412
439
|
*/
|
|
@@ -463,12 +490,20 @@ declare function defineRegistry<C extends Catalog>(_catalog: C, options: {
|
|
|
463
490
|
interface CreateRendererProps {
|
|
464
491
|
/** The spec to render (AI-generated JSON) */
|
|
465
492
|
spec: Spec | null;
|
|
466
|
-
/**
|
|
493
|
+
/**
|
|
494
|
+
* External store (controlled mode). When provided, `state` and
|
|
495
|
+
* `onStateChange` are ignored.
|
|
496
|
+
*/
|
|
497
|
+
store?: StateStore;
|
|
498
|
+
/** State context for dynamic values (uncontrolled mode) */
|
|
467
499
|
state?: Record<string, unknown>;
|
|
468
500
|
/** Action handler */
|
|
469
501
|
onAction?: (actionName: string, params?: Record<string, unknown>) => void;
|
|
470
|
-
/** Callback when state changes (
|
|
471
|
-
onStateChange?: (
|
|
502
|
+
/** Callback when state changes (uncontrolled mode) */
|
|
503
|
+
onStateChange?: (changes: Array<{
|
|
504
|
+
path: string;
|
|
505
|
+
value: unknown;
|
|
506
|
+
}>) => void;
|
|
472
507
|
/** Whether the spec is currently loading/streaming */
|
|
473
508
|
loading?: boolean;
|
|
474
509
|
/** Fallback component for unknown types */
|
package/dist/index.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
2
|
import { ReactNode, ComponentType } from 'react';
|
|
3
|
-
import { StateModel, VisibilityCondition, VisibilityContext, ActionHandler, ResolvedAction, ActionBinding, ActionConfirm, ValidationFunction, ValidationResult, ValidationConfig, Catalog, InferCatalogComponents, InferComponentProps, InferCatalogActions, InferActionParams, UIElement, SchemaDefinition, Spec, FlatElement } from '@json-render/core';
|
|
4
|
-
export { Spec, StateModel } from '@json-render/core';
|
|
3
|
+
import { StateStore, StateModel, VisibilityCondition, VisibilityContext, ActionHandler, ResolvedAction, ActionBinding, ActionConfirm, ValidationFunction, ValidationResult, ValidationConfig, Catalog, InferCatalogComponents, InferComponentProps, InferCatalogActions, InferActionParams, UIElement, SchemaDefinition, Spec, FlatElement } from '@json-render/core';
|
|
4
|
+
export { Spec, StateModel, StateStore, createStateStore } from '@json-render/core';
|
|
5
5
|
export { ElementTreeSchema, ElementTreeSpec, ReactNativeSchema, ReactNativeSpec, elementTreeSchema, schema } from './schema.js';
|
|
6
6
|
export { ActionDefinition, ComponentDefinition, standardActionDefinitions, standardComponentDefinitions } from './catalog.js';
|
|
7
7
|
import 'zod';
|
|
@@ -18,21 +18,40 @@ interface StateContextValue {
|
|
|
18
18
|
set: (path: string, value: unknown) => void;
|
|
19
19
|
/** Update multiple values at once */
|
|
20
20
|
update: (updates: Record<string, unknown>) => void;
|
|
21
|
+
/** Return the live state snapshot from the underlying store (not the React render snapshot). */
|
|
22
|
+
getSnapshot: () => StateModel;
|
|
21
23
|
}
|
|
22
24
|
/**
|
|
23
25
|
* Props for StateProvider
|
|
24
26
|
*/
|
|
25
27
|
interface StateProviderProps {
|
|
26
|
-
/**
|
|
28
|
+
/**
|
|
29
|
+
* External store that owns the state. When provided, the provider operates
|
|
30
|
+
* in **controlled mode** — `initialState` and `onStateChange` are ignored
|
|
31
|
+
* and the store is the single source of truth.
|
|
32
|
+
*/
|
|
33
|
+
store?: StateStore;
|
|
34
|
+
/** Initial state model (used only in uncontrolled mode) */
|
|
27
35
|
initialState?: StateModel;
|
|
28
|
-
/**
|
|
29
|
-
|
|
36
|
+
/**
|
|
37
|
+
* Callback when state changes (used only in uncontrolled mode).
|
|
38
|
+
* Called once per `set` or `update` with all changed entries.
|
|
39
|
+
*/
|
|
40
|
+
onStateChange?: (changes: Array<{
|
|
41
|
+
path: string;
|
|
42
|
+
value: unknown;
|
|
43
|
+
}>) => void;
|
|
30
44
|
children: ReactNode;
|
|
31
45
|
}
|
|
32
46
|
/**
|
|
33
|
-
* Provider for state model context
|
|
47
|
+
* Provider for state model context.
|
|
48
|
+
*
|
|
49
|
+
* Supports two modes:
|
|
50
|
+
* - **Controlled**: pass a `store` prop (e.g. backed by Redux / Zustand).
|
|
51
|
+
* - **Uncontrolled** (default): omit `store` and optionally pass
|
|
52
|
+
* `initialState` / `onStateChange`.
|
|
34
53
|
*/
|
|
35
|
-
declare function StateProvider({ initialState, onStateChange, children, }: StateProviderProps): react_jsx_runtime.JSX.Element;
|
|
54
|
+
declare function StateProvider({ store: externalStore, initialState, onStateChange, children, }: StateProviderProps): react_jsx_runtime.JSX.Element;
|
|
36
55
|
/**
|
|
37
56
|
* Hook to access the state context
|
|
38
57
|
*/
|
|
@@ -391,7 +410,12 @@ interface JSONUIProviderProps {
|
|
|
391
410
|
* Custom components are merged with (and override) standard components.
|
|
392
411
|
*/
|
|
393
412
|
registry?: ComponentRegistry;
|
|
394
|
-
/**
|
|
413
|
+
/**
|
|
414
|
+
* External store (controlled mode). When provided, `initialState` and
|
|
415
|
+
* `onStateChange` are ignored.
|
|
416
|
+
*/
|
|
417
|
+
store?: StateStore;
|
|
418
|
+
/** Initial state model (uncontrolled mode) */
|
|
395
419
|
initialState?: Record<string, unknown>;
|
|
396
420
|
/** Action handlers */
|
|
397
421
|
handlers?: Record<string, (params: Record<string, unknown>) => Promise<unknown> | unknown>;
|
|
@@ -399,14 +423,17 @@ interface JSONUIProviderProps {
|
|
|
399
423
|
navigate?: (path: string) => void;
|
|
400
424
|
/** Custom validation functions */
|
|
401
425
|
validationFunctions?: Record<string, (value: unknown, args?: Record<string, unknown>) => boolean>;
|
|
402
|
-
/** Callback when state changes */
|
|
403
|
-
onStateChange?: (
|
|
426
|
+
/** Callback when state changes (uncontrolled mode) */
|
|
427
|
+
onStateChange?: (changes: Array<{
|
|
428
|
+
path: string;
|
|
429
|
+
value: unknown;
|
|
430
|
+
}>) => void;
|
|
404
431
|
children: ReactNode;
|
|
405
432
|
}
|
|
406
433
|
/**
|
|
407
434
|
* Combined provider for all JSONUI contexts
|
|
408
435
|
*/
|
|
409
|
-
declare function JSONUIProvider({ registry, initialState, handlers, navigate, validationFunctions, onStateChange, children, }: JSONUIProviderProps): react_jsx_runtime.JSX.Element;
|
|
436
|
+
declare function JSONUIProvider({ registry, store, initialState, handlers, navigate, validationFunctions, onStateChange, children, }: JSONUIProviderProps): react_jsx_runtime.JSX.Element;
|
|
410
437
|
/**
|
|
411
438
|
* Result returned by defineRegistry
|
|
412
439
|
*/
|
|
@@ -463,12 +490,20 @@ declare function defineRegistry<C extends Catalog>(_catalog: C, options: {
|
|
|
463
490
|
interface CreateRendererProps {
|
|
464
491
|
/** The spec to render (AI-generated JSON) */
|
|
465
492
|
spec: Spec | null;
|
|
466
|
-
/**
|
|
493
|
+
/**
|
|
494
|
+
* External store (controlled mode). When provided, `state` and
|
|
495
|
+
* `onStateChange` are ignored.
|
|
496
|
+
*/
|
|
497
|
+
store?: StateStore;
|
|
498
|
+
/** State context for dynamic values (uncontrolled mode) */
|
|
467
499
|
state?: Record<string, unknown>;
|
|
468
500
|
/** Action handler */
|
|
469
501
|
onAction?: (actionName: string, params?: Record<string, unknown>) => void;
|
|
470
|
-
/** Callback when state changes (
|
|
471
|
-
onStateChange?: (
|
|
502
|
+
/** Callback when state changes (uncontrolled mode) */
|
|
503
|
+
onStateChange?: (changes: Array<{
|
|
504
|
+
path: string;
|
|
505
|
+
value: unknown;
|
|
506
|
+
}>) => void;
|
|
472
507
|
/** Whether the spec is currently loading/streaming */
|
|
473
508
|
loading?: boolean;
|
|
474
509
|
/** Fallback component for unknown types */
|
package/dist/index.js
CHANGED
|
@@ -40,6 +40,7 @@ __export(index_exports, {
|
|
|
40
40
|
VisibilityProvider: () => VisibilityProvider,
|
|
41
41
|
createRenderer: () => createRenderer,
|
|
42
42
|
createStandardActionHandlers: () => createStandardActionHandlers,
|
|
43
|
+
createStateStore: () => import_core8.createStateStore,
|
|
43
44
|
defineRegistry: () => defineRegistry,
|
|
44
45
|
elementTreeSchema: () => elementTreeSchema,
|
|
45
46
|
flatToTree: () => flatToTree,
|
|
@@ -62,68 +63,104 @@ __export(index_exports, {
|
|
|
62
63
|
});
|
|
63
64
|
module.exports = __toCommonJS(index_exports);
|
|
64
65
|
|
|
65
|
-
//
|
|
66
|
+
// ../react-state/dist/index.mjs
|
|
66
67
|
var import_react = require("react");
|
|
67
68
|
var import_core = require("@json-render/core");
|
|
69
|
+
var import_store_utils = require("@json-render/core/store-utils");
|
|
68
70
|
var import_jsx_runtime = require("react/jsx-runtime");
|
|
69
71
|
var StateContext = (0, import_react.createContext)(null);
|
|
72
|
+
function computeInitialFlat(isControlled, initialState) {
|
|
73
|
+
if (isControlled) return null;
|
|
74
|
+
if (Object.keys(initialState).length === 0) return {};
|
|
75
|
+
return (0, import_store_utils.flattenToPointers)(initialState);
|
|
76
|
+
}
|
|
70
77
|
function StateProvider({
|
|
78
|
+
store: externalStore,
|
|
71
79
|
initialState = {},
|
|
72
80
|
onStateChange,
|
|
73
81
|
children
|
|
74
82
|
}) {
|
|
75
|
-
const
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
83
|
+
const internalStoreRef = (0, import_react.useRef)(void 0);
|
|
84
|
+
if (!externalStore && !internalStoreRef.current) {
|
|
85
|
+
internalStoreRef.current = (0, import_core.createStateStore)(initialState);
|
|
86
|
+
}
|
|
87
|
+
const store = externalStore ?? internalStoreRef.current;
|
|
88
|
+
const storeRef = (0, import_react.useRef)(store);
|
|
89
|
+
storeRef.current = store;
|
|
90
|
+
const isControlledRef = (0, import_react.useRef)(!!externalStore);
|
|
91
|
+
isControlledRef.current = !!externalStore;
|
|
92
|
+
const initialModeRef = (0, import_react.useRef)(externalStore ? "controlled" : "uncontrolled");
|
|
93
|
+
const modeWarnedRef = (0, import_react.useRef)(false);
|
|
94
|
+
if (process.env.NODE_ENV !== "production") {
|
|
95
|
+
const currentMode = externalStore ? "controlled" : "uncontrolled";
|
|
96
|
+
if (currentMode !== initialModeRef.current && !modeWarnedRef.current) {
|
|
97
|
+
modeWarnedRef.current = true;
|
|
98
|
+
console.warn(
|
|
99
|
+
`StateProvider: switching from ${initialModeRef.current} to ${currentMode} mode is not supported.`
|
|
100
|
+
);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
const prevInitialStateRef = (0, import_react.useRef)(initialState);
|
|
104
|
+
const prevFlatRef = (0, import_react.useRef)(
|
|
105
|
+
computeInitialFlat(!!externalStore, initialState)
|
|
106
|
+
);
|
|
79
107
|
(0, import_react.useEffect)(() => {
|
|
80
|
-
|
|
81
|
-
if (
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
108
|
+
if (externalStore) return;
|
|
109
|
+
if (initialState === prevInitialStateRef.current) return;
|
|
110
|
+
prevInitialStateRef.current = initialState;
|
|
111
|
+
const nextFlat = initialState && Object.keys(initialState).length > 0 ? (0, import_store_utils.flattenToPointers)(initialState) : {};
|
|
112
|
+
const prevFlat = prevFlatRef.current ?? {};
|
|
113
|
+
const allKeys = /* @__PURE__ */ new Set([
|
|
114
|
+
...Object.keys(prevFlat),
|
|
115
|
+
...Object.keys(nextFlat)
|
|
116
|
+
]);
|
|
117
|
+
const updates = {};
|
|
118
|
+
for (const key of allKeys) {
|
|
119
|
+
if (prevFlat[key] !== nextFlat[key]) {
|
|
120
|
+
updates[key] = key in nextFlat ? nextFlat[key] : void 0;
|
|
85
121
|
}
|
|
86
122
|
}
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
);
|
|
92
|
-
const
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
(0, import_core.setByPath)(next, path, value2);
|
|
97
|
-
return next;
|
|
98
|
-
});
|
|
99
|
-
onStateChange?.(path, value2);
|
|
100
|
-
},
|
|
101
|
-
[onStateChange]
|
|
123
|
+
prevFlatRef.current = nextFlat;
|
|
124
|
+
if (Object.keys(updates).length > 0) {
|
|
125
|
+
store.update(updates);
|
|
126
|
+
}
|
|
127
|
+
}, [externalStore, initialState, store]);
|
|
128
|
+
const state = (0, import_react.useSyncExternalStore)(
|
|
129
|
+
store.subscribe,
|
|
130
|
+
store.getSnapshot,
|
|
131
|
+
store.getServerSnapshot ?? store.getSnapshot
|
|
102
132
|
);
|
|
103
|
-
const
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
133
|
+
const onStateChangeRef = (0, import_react.useRef)(onStateChange);
|
|
134
|
+
onStateChangeRef.current = onStateChange;
|
|
135
|
+
const set = (0, import_react.useCallback)((path, value2) => {
|
|
136
|
+
const s = storeRef.current;
|
|
137
|
+
const prev = s.getSnapshot();
|
|
138
|
+
s.set(path, value2);
|
|
139
|
+
if (!isControlledRef.current && s.getSnapshot() !== prev) {
|
|
140
|
+
onStateChangeRef.current?.([{ path, value: value2 }]);
|
|
141
|
+
}
|
|
142
|
+
}, []);
|
|
143
|
+
const update = (0, import_react.useCallback)((updates) => {
|
|
144
|
+
const s = storeRef.current;
|
|
145
|
+
const prev = s.getSnapshot();
|
|
146
|
+
s.update(updates);
|
|
147
|
+
if (!isControlledRef.current && s.getSnapshot() !== prev) {
|
|
148
|
+
const changes = [];
|
|
149
|
+
for (const [path, value2] of Object.entries(updates)) {
|
|
150
|
+
if ((0, import_core.getByPath)(prev, path) !== value2) {
|
|
151
|
+
changes.push({ path, value: value2 });
|
|
110
152
|
}
|
|
111
|
-
return next;
|
|
112
|
-
});
|
|
113
|
-
for (const [path, value2] of entries) {
|
|
114
|
-
onStateChange?.(path, value2);
|
|
115
153
|
}
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
154
|
+
if (changes.length > 0) {
|
|
155
|
+
onStateChangeRef.current?.(changes);
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
}, []);
|
|
159
|
+
const get = (0, import_react.useCallback)((path) => storeRef.current.get(path), []);
|
|
160
|
+
const getSnapshot = (0, import_react.useCallback)(() => storeRef.current.getSnapshot(), []);
|
|
119
161
|
const value = (0, import_react.useMemo)(
|
|
120
|
-
() => ({
|
|
121
|
-
|
|
122
|
-
get,
|
|
123
|
-
set,
|
|
124
|
-
update
|
|
125
|
-
}),
|
|
126
|
-
[state, get, set, update]
|
|
162
|
+
() => ({ state, get, set, update, getSnapshot }),
|
|
163
|
+
[state, get, set, update, getSnapshot]
|
|
127
164
|
);
|
|
128
165
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(StateContext.Provider, { value, children });
|
|
129
166
|
}
|
|
@@ -226,7 +263,7 @@ function ActionProvider({
|
|
|
226
263
|
navigate,
|
|
227
264
|
children
|
|
228
265
|
}) {
|
|
229
|
-
const {
|
|
266
|
+
const { get, set, getSnapshot } = useStateStore();
|
|
230
267
|
const [handlers, setHandlers] = (0, import_react3.useState)(initialHandlers);
|
|
231
268
|
const [loadingActions, setLoadingActions] = (0, import_react3.useState)(/* @__PURE__ */ new Set());
|
|
232
269
|
const [pendingConfirmation, setPendingConfirmation] = (0, import_react3.useState)(null);
|
|
@@ -238,7 +275,7 @@ function ActionProvider({
|
|
|
238
275
|
);
|
|
239
276
|
const execute = (0, import_react3.useCallback)(
|
|
240
277
|
async (binding) => {
|
|
241
|
-
const resolved = (0, import_core3.resolveAction)(binding,
|
|
278
|
+
const resolved = (0, import_core3.resolveAction)(binding, getSnapshot());
|
|
242
279
|
if (resolved.action === "setState" && resolved.params) {
|
|
243
280
|
const statePath = resolved.params.statePath;
|
|
244
281
|
const value2 = resolved.params.value;
|
|
@@ -361,7 +398,7 @@ function ActionProvider({
|
|
|
361
398
|
});
|
|
362
399
|
}
|
|
363
400
|
},
|
|
364
|
-
[
|
|
401
|
+
[handlers, get, set, getSnapshot, navigate]
|
|
365
402
|
);
|
|
366
403
|
const confirm = (0, import_react3.useCallback)(() => {
|
|
367
404
|
pendingConfirmation?.resolve();
|
|
@@ -762,6 +799,9 @@ var schema = (0, import_core5.defineSchema)(
|
|
|
762
799
|
);
|
|
763
800
|
var elementTreeSchema = schema;
|
|
764
801
|
|
|
802
|
+
// src/index.ts
|
|
803
|
+
var import_core8 = require("@json-render/core");
|
|
804
|
+
|
|
765
805
|
// src/renderer.tsx
|
|
766
806
|
var import_react7 = __toESM(require("react"));
|
|
767
807
|
var import_core7 = require("@json-render/core");
|
|
@@ -1994,6 +2034,7 @@ var ElementRenderer = import_react7.default.memo(function ElementRenderer2({
|
|
|
1994
2034
|
const repeatScope = useRepeatScope();
|
|
1995
2035
|
const { ctx } = useVisibility();
|
|
1996
2036
|
const { execute } = useActions();
|
|
2037
|
+
const { getSnapshot } = useStateStore();
|
|
1997
2038
|
const fullCtx = (0, import_react7.useMemo)(
|
|
1998
2039
|
() => repeatScope ? {
|
|
1999
2040
|
...ctx,
|
|
@@ -2006,23 +2047,27 @@ var ElementRenderer = import_react7.default.memo(function ElementRenderer2({
|
|
|
2006
2047
|
const isVisible = element.visible === void 0 ? true : (0, import_core7.evaluateVisibility)(element.visible, fullCtx);
|
|
2007
2048
|
const onBindings = element.on;
|
|
2008
2049
|
const emit = (0, import_react7.useCallback)(
|
|
2009
|
-
(eventName) => {
|
|
2050
|
+
async (eventName) => {
|
|
2010
2051
|
const binding = onBindings?.[eventName];
|
|
2011
2052
|
if (!binding) return;
|
|
2012
2053
|
const actionBindings = Array.isArray(binding) ? binding : [binding];
|
|
2013
2054
|
for (const b of actionBindings) {
|
|
2014
2055
|
if (!b.params) {
|
|
2015
|
-
execute(b);
|
|
2056
|
+
await execute(b);
|
|
2016
2057
|
continue;
|
|
2017
2058
|
}
|
|
2059
|
+
const liveCtx = {
|
|
2060
|
+
...fullCtx,
|
|
2061
|
+
stateModel: getSnapshot()
|
|
2062
|
+
};
|
|
2018
2063
|
const resolved = {};
|
|
2019
2064
|
for (const [key, val] of Object.entries(b.params)) {
|
|
2020
|
-
resolved[key] = (0, import_core7.resolveActionParam)(val,
|
|
2065
|
+
resolved[key] = (0, import_core7.resolveActionParam)(val, liveCtx);
|
|
2021
2066
|
}
|
|
2022
|
-
execute({ ...b, params: resolved });
|
|
2067
|
+
await execute({ ...b, params: resolved });
|
|
2023
2068
|
}
|
|
2024
2069
|
},
|
|
2025
|
-
[onBindings, execute, fullCtx]
|
|
2070
|
+
[onBindings, execute, fullCtx, getSnapshot]
|
|
2026
2071
|
);
|
|
2027
2072
|
if (!isVisible) {
|
|
2028
2073
|
return null;
|
|
@@ -2160,6 +2205,7 @@ function Renderer({
|
|
|
2160
2205
|
}
|
|
2161
2206
|
function JSONUIProvider({
|
|
2162
2207
|
registry,
|
|
2208
|
+
store,
|
|
2163
2209
|
initialState,
|
|
2164
2210
|
handlers,
|
|
2165
2211
|
navigate,
|
|
@@ -2167,10 +2213,18 @@ function JSONUIProvider({
|
|
|
2167
2213
|
onStateChange,
|
|
2168
2214
|
children
|
|
2169
2215
|
}) {
|
|
2170
|
-
return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
2171
|
-
|
|
2172
|
-
|
|
2173
|
-
|
|
2216
|
+
return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
2217
|
+
StateProvider,
|
|
2218
|
+
{
|
|
2219
|
+
store,
|
|
2220
|
+
initialState,
|
|
2221
|
+
onStateChange,
|
|
2222
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(VisibilityProvider, { children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(ActionProvider, { handlers, navigate, children: /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(ValidationProvider, { customFunctions: validationFunctions, children: [
|
|
2223
|
+
children,
|
|
2224
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(ConfirmationDialogManager, {})
|
|
2225
|
+
] }) }) })
|
|
2226
|
+
}
|
|
2227
|
+
);
|
|
2174
2228
|
}
|
|
2175
2229
|
function ConfirmationDialogManager() {
|
|
2176
2230
|
const { pendingConfirmation, confirm, cancel } = useActions();
|
|
@@ -2235,6 +2289,7 @@ function createRenderer(catalog, components) {
|
|
|
2235
2289
|
const registry = components;
|
|
2236
2290
|
return function CatalogRenderer({
|
|
2237
2291
|
spec,
|
|
2292
|
+
store,
|
|
2238
2293
|
state,
|
|
2239
2294
|
onAction,
|
|
2240
2295
|
onStateChange,
|
|
@@ -2250,18 +2305,26 @@ function createRenderer(catalog, components) {
|
|
|
2250
2305
|
has: () => true
|
|
2251
2306
|
}
|
|
2252
2307
|
) : void 0;
|
|
2253
|
-
return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
2254
|
-
|
|
2255
|
-
|
|
2256
|
-
|
|
2257
|
-
|
|
2258
|
-
|
|
2259
|
-
|
|
2260
|
-
|
|
2261
|
-
|
|
2262
|
-
|
|
2263
|
-
|
|
2264
|
-
|
|
2308
|
+
return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
2309
|
+
StateProvider,
|
|
2310
|
+
{
|
|
2311
|
+
store,
|
|
2312
|
+
initialState: state,
|
|
2313
|
+
onStateChange,
|
|
2314
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(VisibilityProvider, { children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(ActionProvider, { handlers: actionHandlers, children: /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(ValidationProvider, { children: [
|
|
2315
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
2316
|
+
Renderer,
|
|
2317
|
+
{
|
|
2318
|
+
spec,
|
|
2319
|
+
registry,
|
|
2320
|
+
loading,
|
|
2321
|
+
fallback
|
|
2322
|
+
}
|
|
2323
|
+
),
|
|
2324
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(ConfirmationDialogManager, {})
|
|
2325
|
+
] }) }) })
|
|
2326
|
+
}
|
|
2327
|
+
);
|
|
2265
2328
|
};
|
|
2266
2329
|
}
|
|
2267
2330
|
|
|
@@ -2671,6 +2734,7 @@ var standardActionDefinitions = {
|
|
|
2671
2734
|
VisibilityProvider,
|
|
2672
2735
|
createRenderer,
|
|
2673
2736
|
createStandardActionHandlers,
|
|
2737
|
+
createStateStore,
|
|
2674
2738
|
defineRegistry,
|
|
2675
2739
|
elementTreeSchema,
|
|
2676
2740
|
flatToTree,
|