@json-render/react 0.1.0 → 0.4.0
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/LICENSE +201 -0
- package/README.md +253 -175
- package/dist/chunk-IGPI5WNB.mjs +52 -0
- package/dist/chunk-IGPI5WNB.mjs.map +1 -0
- package/dist/index.d.mts +139 -17
- package/dist/index.d.ts +139 -17
- package/dist/index.js +191 -58
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +156 -62
- package/dist/index.mjs.map +1 -1
- package/dist/schema.d.mts +106 -0
- package/dist/schema.d.ts +106 -0
- package/dist/schema.js +77 -0
- package/dist/schema.js.map +1 -0
- package/dist/schema.mjs +9 -0
- package/dist/schema.mjs.map +1 -0
- package/package.json +15 -10
package/dist/index.mjs
CHANGED
|
@@ -1,10 +1,17 @@
|
|
|
1
|
+
import {
|
|
2
|
+
elementTreeSchema,
|
|
3
|
+
schema
|
|
4
|
+
} from "./chunk-IGPI5WNB.mjs";
|
|
5
|
+
|
|
1
6
|
// src/contexts/data.tsx
|
|
2
7
|
import {
|
|
3
8
|
createContext,
|
|
4
9
|
useContext,
|
|
5
10
|
useState,
|
|
6
11
|
useCallback,
|
|
7
|
-
useMemo
|
|
12
|
+
useMemo,
|
|
13
|
+
useEffect,
|
|
14
|
+
useRef
|
|
8
15
|
} from "react";
|
|
9
16
|
import {
|
|
10
17
|
getByPath,
|
|
@@ -19,10 +26,17 @@ function DataProvider({
|
|
|
19
26
|
children
|
|
20
27
|
}) {
|
|
21
28
|
const [data, setData] = useState(initialData);
|
|
22
|
-
const
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
29
|
+
const initialDataJsonRef = useRef(JSON.stringify(initialData));
|
|
30
|
+
useEffect(() => {
|
|
31
|
+
const newJson = JSON.stringify(initialData);
|
|
32
|
+
if (newJson !== initialDataJsonRef.current) {
|
|
33
|
+
initialDataJsonRef.current = newJson;
|
|
34
|
+
if (initialData && Object.keys(initialData).length > 0) {
|
|
35
|
+
setData((prev) => ({ ...prev, ...initialData }));
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
}, [initialData]);
|
|
39
|
+
const get = useCallback((path) => getByPath(data, path), [data]);
|
|
26
40
|
const set = useCallback(
|
|
27
41
|
(path, value2) => {
|
|
28
42
|
setData((prev) => {
|
|
@@ -67,12 +81,12 @@ function useData() {
|
|
|
67
81
|
return ctx;
|
|
68
82
|
}
|
|
69
83
|
function useDataValue(path) {
|
|
70
|
-
const {
|
|
71
|
-
return
|
|
84
|
+
const { data } = useData();
|
|
85
|
+
return getByPath(data, path);
|
|
72
86
|
}
|
|
73
87
|
function useDataBinding(path) {
|
|
74
|
-
const {
|
|
75
|
-
const value =
|
|
88
|
+
const { data, set } = useData();
|
|
89
|
+
const value = getByPath(data, path);
|
|
76
90
|
const setValue = useCallback(
|
|
77
91
|
(newValue) => set(path, newValue),
|
|
78
92
|
[path, set]
|
|
@@ -81,7 +95,11 @@ function useDataBinding(path) {
|
|
|
81
95
|
}
|
|
82
96
|
|
|
83
97
|
// src/contexts/visibility.tsx
|
|
84
|
-
import {
|
|
98
|
+
import {
|
|
99
|
+
createContext as createContext2,
|
|
100
|
+
useContext as useContext2,
|
|
101
|
+
useMemo as useMemo2
|
|
102
|
+
} from "react";
|
|
85
103
|
import {
|
|
86
104
|
evaluateVisibility
|
|
87
105
|
} from "@json-render/core";
|
|
@@ -141,9 +159,12 @@ function ActionProvider({
|
|
|
141
159
|
const [handlers, setHandlers] = useState2(initialHandlers);
|
|
142
160
|
const [loadingActions, setLoadingActions] = useState2(/* @__PURE__ */ new Set());
|
|
143
161
|
const [pendingConfirmation, setPendingConfirmation] = useState2(null);
|
|
144
|
-
const registerHandler = useCallback2(
|
|
145
|
-
|
|
146
|
-
|
|
162
|
+
const registerHandler = useCallback2(
|
|
163
|
+
(name, handler) => {
|
|
164
|
+
setHandlers((prev) => ({ ...prev, [name]: handler }));
|
|
165
|
+
},
|
|
166
|
+
[]
|
|
167
|
+
);
|
|
147
168
|
const execute = useCallback2(
|
|
148
169
|
async (action) => {
|
|
149
170
|
const resolved = resolveAction(action, data);
|
|
@@ -226,7 +247,15 @@ function ActionProvider({
|
|
|
226
247
|
cancel,
|
|
227
248
|
registerHandler
|
|
228
249
|
}),
|
|
229
|
-
[
|
|
250
|
+
[
|
|
251
|
+
handlers,
|
|
252
|
+
loadingActions,
|
|
253
|
+
pendingConfirmation,
|
|
254
|
+
execute,
|
|
255
|
+
confirm,
|
|
256
|
+
cancel,
|
|
257
|
+
registerHandler
|
|
258
|
+
]
|
|
230
259
|
);
|
|
231
260
|
return /* @__PURE__ */ jsx3(ActionContext.Provider, { value, children });
|
|
232
261
|
}
|
|
@@ -243,7 +272,11 @@ function useAction(action) {
|
|
|
243
272
|
const executeAction2 = useCallback2(() => execute(action), [execute, action]);
|
|
244
273
|
return { execute: executeAction2, isLoading };
|
|
245
274
|
}
|
|
246
|
-
function ConfirmDialog({
|
|
275
|
+
function ConfirmDialog({
|
|
276
|
+
confirm,
|
|
277
|
+
onConfirm,
|
|
278
|
+
onCancel
|
|
279
|
+
}) {
|
|
247
280
|
const isDanger = confirm.variant === "danger";
|
|
248
281
|
return /* @__PURE__ */ jsx3(
|
|
249
282
|
"div",
|
|
@@ -360,9 +393,12 @@ function ValidationProvider({
|
|
|
360
393
|
const { data, authState } = useData();
|
|
361
394
|
const [fieldStates, setFieldStates] = useState3({});
|
|
362
395
|
const [fieldConfigs, setFieldConfigs] = useState3({});
|
|
363
|
-
const registerField = useCallback3(
|
|
364
|
-
|
|
365
|
-
|
|
396
|
+
const registerField = useCallback3(
|
|
397
|
+
(path, config) => {
|
|
398
|
+
setFieldConfigs((prev) => ({ ...prev, [path]: config }));
|
|
399
|
+
},
|
|
400
|
+
[]
|
|
401
|
+
);
|
|
366
402
|
const validate = useCallback3(
|
|
367
403
|
(path, config) => {
|
|
368
404
|
const value2 = data[path.split("/").filter(Boolean).join(".")];
|
|
@@ -421,7 +457,15 @@ function ValidationProvider({
|
|
|
421
457
|
validateAll,
|
|
422
458
|
registerField
|
|
423
459
|
}),
|
|
424
|
-
[
|
|
460
|
+
[
|
|
461
|
+
customFunctions,
|
|
462
|
+
fieldStates,
|
|
463
|
+
validate,
|
|
464
|
+
touch,
|
|
465
|
+
clear,
|
|
466
|
+
validateAll,
|
|
467
|
+
registerField
|
|
468
|
+
]
|
|
425
469
|
);
|
|
426
470
|
return /* @__PURE__ */ jsx4(ValidationContext.Provider, { value, children });
|
|
427
471
|
}
|
|
@@ -470,7 +514,7 @@ function useFieldValidation(path, config) {
|
|
|
470
514
|
import { jsx as jsx5, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
471
515
|
function ElementRenderer({
|
|
472
516
|
element,
|
|
473
|
-
|
|
517
|
+
spec,
|
|
474
518
|
registry,
|
|
475
519
|
loading,
|
|
476
520
|
fallback
|
|
@@ -486,7 +530,7 @@ function ElementRenderer({
|
|
|
486
530
|
return null;
|
|
487
531
|
}
|
|
488
532
|
const children = element.children?.map((childKey) => {
|
|
489
|
-
const childElement =
|
|
533
|
+
const childElement = spec.elements[childKey];
|
|
490
534
|
if (!childElement) {
|
|
491
535
|
return null;
|
|
492
536
|
}
|
|
@@ -494,7 +538,7 @@ function ElementRenderer({
|
|
|
494
538
|
ElementRenderer,
|
|
495
539
|
{
|
|
496
540
|
element: childElement,
|
|
497
|
-
|
|
541
|
+
spec,
|
|
498
542
|
registry,
|
|
499
543
|
loading,
|
|
500
544
|
fallback
|
|
@@ -502,21 +546,13 @@ function ElementRenderer({
|
|
|
502
546
|
childKey
|
|
503
547
|
);
|
|
504
548
|
});
|
|
505
|
-
return /* @__PURE__ */ jsx5(
|
|
506
|
-
Component,
|
|
507
|
-
{
|
|
508
|
-
element,
|
|
509
|
-
onAction: execute,
|
|
510
|
-
loading,
|
|
511
|
-
children
|
|
512
|
-
}
|
|
513
|
-
);
|
|
549
|
+
return /* @__PURE__ */ jsx5(Component, { element, onAction: execute, loading, children });
|
|
514
550
|
}
|
|
515
|
-
function Renderer({
|
|
516
|
-
if (!
|
|
551
|
+
function Renderer({ spec, registry, loading, fallback }) {
|
|
552
|
+
if (!spec || !spec.root) {
|
|
517
553
|
return null;
|
|
518
554
|
}
|
|
519
|
-
const rootElement =
|
|
555
|
+
const rootElement = spec.elements[spec.root];
|
|
520
556
|
if (!rootElement) {
|
|
521
557
|
return null;
|
|
522
558
|
}
|
|
@@ -524,7 +560,7 @@ function Renderer({ tree, registry, loading, fallback }) {
|
|
|
524
560
|
ElementRenderer,
|
|
525
561
|
{
|
|
526
562
|
element: rootElement,
|
|
527
|
-
|
|
563
|
+
spec,
|
|
528
564
|
registry,
|
|
529
565
|
loading,
|
|
530
566
|
fallback
|
|
@@ -573,9 +609,49 @@ function createRendererFromCatalog(_catalog, registry) {
|
|
|
573
609
|
return /* @__PURE__ */ jsx5(Renderer, { ...props, registry });
|
|
574
610
|
};
|
|
575
611
|
}
|
|
612
|
+
function createRenderer(catalog, components) {
|
|
613
|
+
const registry = components;
|
|
614
|
+
return function CatalogRenderer({
|
|
615
|
+
spec,
|
|
616
|
+
data,
|
|
617
|
+
onAction,
|
|
618
|
+
onDataChange,
|
|
619
|
+
loading,
|
|
620
|
+
authState,
|
|
621
|
+
fallback
|
|
622
|
+
}) {
|
|
623
|
+
const actionHandlers = onAction ? {
|
|
624
|
+
__default__: (params) => {
|
|
625
|
+
const actionName = params.__actionName__;
|
|
626
|
+
const actionParams = params.__actionParams__;
|
|
627
|
+
return onAction(actionName, actionParams);
|
|
628
|
+
}
|
|
629
|
+
} : void 0;
|
|
630
|
+
return /* @__PURE__ */ jsx5(
|
|
631
|
+
DataProvider,
|
|
632
|
+
{
|
|
633
|
+
initialData: data,
|
|
634
|
+
authState,
|
|
635
|
+
onDataChange,
|
|
636
|
+
children: /* @__PURE__ */ jsx5(VisibilityProvider, { children: /* @__PURE__ */ jsx5(ActionProvider, { handlers: actionHandlers, children: /* @__PURE__ */ jsxs2(ValidationProvider, { children: [
|
|
637
|
+
/* @__PURE__ */ jsx5(
|
|
638
|
+
Renderer,
|
|
639
|
+
{
|
|
640
|
+
spec,
|
|
641
|
+
registry,
|
|
642
|
+
loading,
|
|
643
|
+
fallback
|
|
644
|
+
}
|
|
645
|
+
),
|
|
646
|
+
/* @__PURE__ */ jsx5(ConfirmationDialogManager, {})
|
|
647
|
+
] }) }) })
|
|
648
|
+
}
|
|
649
|
+
);
|
|
650
|
+
};
|
|
651
|
+
}
|
|
576
652
|
|
|
577
653
|
// src/hooks.ts
|
|
578
|
-
import { useState as useState4, useCallback as useCallback4, useRef, useEffect } from "react";
|
|
654
|
+
import { useState as useState4, useCallback as useCallback4, useRef as useRef2, useEffect as useEffect2 } from "react";
|
|
579
655
|
import { setByPath as setByPath2 } from "@json-render/core";
|
|
580
656
|
function parsePatchLine(line) {
|
|
581
657
|
try {
|
|
@@ -588,29 +664,33 @@ function parsePatchLine(line) {
|
|
|
588
664
|
return null;
|
|
589
665
|
}
|
|
590
666
|
}
|
|
591
|
-
function applyPatch(
|
|
592
|
-
const
|
|
667
|
+
function applyPatch(spec, patch) {
|
|
668
|
+
const newSpec = { ...spec, elements: { ...spec.elements } };
|
|
593
669
|
switch (patch.op) {
|
|
594
670
|
case "set":
|
|
595
671
|
case "add":
|
|
596
672
|
case "replace": {
|
|
597
673
|
if (patch.path === "/root") {
|
|
598
|
-
|
|
599
|
-
return
|
|
674
|
+
newSpec.root = patch.value;
|
|
675
|
+
return newSpec;
|
|
600
676
|
}
|
|
601
677
|
if (patch.path.startsWith("/elements/")) {
|
|
602
678
|
const pathParts = patch.path.slice("/elements/".length).split("/");
|
|
603
679
|
const elementKey = pathParts[0];
|
|
604
|
-
if (!elementKey) return
|
|
680
|
+
if (!elementKey) return newSpec;
|
|
605
681
|
if (pathParts.length === 1) {
|
|
606
|
-
|
|
682
|
+
newSpec.elements[elementKey] = patch.value;
|
|
607
683
|
} else {
|
|
608
|
-
const element =
|
|
684
|
+
const element = newSpec.elements[elementKey];
|
|
609
685
|
if (element) {
|
|
610
686
|
const propPath = "/" + pathParts.slice(1).join("/");
|
|
611
687
|
const newElement = { ...element };
|
|
612
|
-
setByPath2(
|
|
613
|
-
|
|
688
|
+
setByPath2(
|
|
689
|
+
newElement,
|
|
690
|
+
propPath,
|
|
691
|
+
patch.value
|
|
692
|
+
);
|
|
693
|
+
newSpec.elements[elementKey] = newElement;
|
|
614
694
|
}
|
|
615
695
|
}
|
|
616
696
|
}
|
|
@@ -620,26 +700,26 @@ function applyPatch(tree, patch) {
|
|
|
620
700
|
if (patch.path.startsWith("/elements/")) {
|
|
621
701
|
const elementKey = patch.path.slice("/elements/".length).split("/")[0];
|
|
622
702
|
if (elementKey) {
|
|
623
|
-
const { [elementKey]: _, ...rest } =
|
|
624
|
-
|
|
703
|
+
const { [elementKey]: _, ...rest } = newSpec.elements;
|
|
704
|
+
newSpec.elements = rest;
|
|
625
705
|
}
|
|
626
706
|
}
|
|
627
707
|
break;
|
|
628
708
|
}
|
|
629
709
|
}
|
|
630
|
-
return
|
|
710
|
+
return newSpec;
|
|
631
711
|
}
|
|
632
712
|
function useUIStream({
|
|
633
713
|
api,
|
|
634
714
|
onComplete,
|
|
635
715
|
onError
|
|
636
716
|
}) {
|
|
637
|
-
const [
|
|
717
|
+
const [spec, setSpec] = useState4(null);
|
|
638
718
|
const [isStreaming, setIsStreaming] = useState4(false);
|
|
639
719
|
const [error, setError] = useState4(null);
|
|
640
|
-
const abortControllerRef =
|
|
720
|
+
const abortControllerRef = useRef2(null);
|
|
641
721
|
const clear = useCallback4(() => {
|
|
642
|
-
|
|
722
|
+
setSpec(null);
|
|
643
723
|
setError(null);
|
|
644
724
|
}, []);
|
|
645
725
|
const send = useCallback4(
|
|
@@ -648,8 +728,9 @@ function useUIStream({
|
|
|
648
728
|
abortControllerRef.current = new AbortController();
|
|
649
729
|
setIsStreaming(true);
|
|
650
730
|
setError(null);
|
|
651
|
-
|
|
652
|
-
|
|
731
|
+
const previousSpec = context?.previousSpec;
|
|
732
|
+
let currentSpec = previousSpec && previousSpec.root ? { ...previousSpec, elements: { ...previousSpec.elements } } : { root: "", elements: {} };
|
|
733
|
+
setSpec(currentSpec);
|
|
653
734
|
try {
|
|
654
735
|
const response = await fetch(api, {
|
|
655
736
|
method: "POST",
|
|
@@ -657,12 +738,22 @@ function useUIStream({
|
|
|
657
738
|
body: JSON.stringify({
|
|
658
739
|
prompt,
|
|
659
740
|
context,
|
|
660
|
-
|
|
741
|
+
currentSpec
|
|
661
742
|
}),
|
|
662
743
|
signal: abortControllerRef.current.signal
|
|
663
744
|
});
|
|
664
745
|
if (!response.ok) {
|
|
665
|
-
|
|
746
|
+
let errorMessage = `HTTP error: ${response.status}`;
|
|
747
|
+
try {
|
|
748
|
+
const errorData = await response.json();
|
|
749
|
+
if (errorData.message) {
|
|
750
|
+
errorMessage = errorData.message;
|
|
751
|
+
} else if (errorData.error) {
|
|
752
|
+
errorMessage = errorData.error;
|
|
753
|
+
}
|
|
754
|
+
} catch {
|
|
755
|
+
}
|
|
756
|
+
throw new Error(errorMessage);
|
|
666
757
|
}
|
|
667
758
|
const reader = response.body?.getReader();
|
|
668
759
|
if (!reader) {
|
|
@@ -679,19 +770,19 @@ function useUIStream({
|
|
|
679
770
|
for (const line of lines) {
|
|
680
771
|
const patch = parsePatchLine(line);
|
|
681
772
|
if (patch) {
|
|
682
|
-
|
|
683
|
-
|
|
773
|
+
currentSpec = applyPatch(currentSpec, patch);
|
|
774
|
+
setSpec({ ...currentSpec });
|
|
684
775
|
}
|
|
685
776
|
}
|
|
686
777
|
}
|
|
687
778
|
if (buffer.trim()) {
|
|
688
779
|
const patch = parsePatchLine(buffer);
|
|
689
780
|
if (patch) {
|
|
690
|
-
|
|
691
|
-
|
|
781
|
+
currentSpec = applyPatch(currentSpec, patch);
|
|
782
|
+
setSpec({ ...currentSpec });
|
|
692
783
|
}
|
|
693
784
|
}
|
|
694
|
-
onComplete?.(
|
|
785
|
+
onComplete?.(currentSpec);
|
|
695
786
|
} catch (err) {
|
|
696
787
|
if (err.name === "AbortError") {
|
|
697
788
|
return;
|
|
@@ -705,13 +796,13 @@ function useUIStream({
|
|
|
705
796
|
},
|
|
706
797
|
[api, onComplete, onError]
|
|
707
798
|
);
|
|
708
|
-
|
|
799
|
+
useEffect2(() => {
|
|
709
800
|
return () => {
|
|
710
801
|
abortControllerRef.current?.abort();
|
|
711
802
|
};
|
|
712
803
|
}, []);
|
|
713
804
|
return {
|
|
714
|
-
|
|
805
|
+
spec,
|
|
715
806
|
isStreaming,
|
|
716
807
|
error,
|
|
717
808
|
send,
|
|
@@ -753,8 +844,11 @@ export {
|
|
|
753
844
|
Renderer,
|
|
754
845
|
ValidationProvider,
|
|
755
846
|
VisibilityProvider,
|
|
847
|
+
createRenderer,
|
|
756
848
|
createRendererFromCatalog,
|
|
849
|
+
elementTreeSchema,
|
|
757
850
|
flatToTree,
|
|
851
|
+
schema,
|
|
758
852
|
useAction,
|
|
759
853
|
useActions,
|
|
760
854
|
useData,
|