@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/dist/index.js ADDED
@@ -0,0 +1,796 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __export = (target, all) => {
9
+ for (var name in all)
10
+ __defProp(target, name, { get: all[name], enumerable: true });
11
+ };
12
+ var __copyProps = (to, from, except, desc) => {
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (let key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(to, key) && key !== except)
16
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
+ }
18
+ return to;
19
+ };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
28
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
+
30
+ // src/index.ts
31
+ var index_exports = {};
32
+ __export(index_exports, {
33
+ ActionProvider: () => ActionProvider,
34
+ ConfirmDialog: () => ConfirmDialog,
35
+ DataProvider: () => DataProvider,
36
+ JSONUIProvider: () => JSONUIProvider,
37
+ Renderer: () => Renderer,
38
+ ValidationProvider: () => ValidationProvider,
39
+ VisibilityProvider: () => VisibilityProvider,
40
+ createRendererFromCatalog: () => createRendererFromCatalog,
41
+ flatToTree: () => flatToTree,
42
+ useAction: () => useAction,
43
+ useActions: () => useActions,
44
+ useData: () => useData,
45
+ useDataBinding: () => useDataBinding,
46
+ useDataValue: () => useDataValue,
47
+ useFieldValidation: () => useFieldValidation,
48
+ useIsVisible: () => useIsVisible,
49
+ useUIStream: () => useUIStream,
50
+ useValidation: () => useValidation,
51
+ useVisibility: () => useVisibility
52
+ });
53
+ module.exports = __toCommonJS(index_exports);
54
+
55
+ // src/contexts/data.tsx
56
+ var import_react = require("react");
57
+ var import_core = require("@json-render/core");
58
+ var import_jsx_runtime = require("react/jsx-runtime");
59
+ var DataContext = (0, import_react.createContext)(null);
60
+ function DataProvider({
61
+ initialData = {},
62
+ authState,
63
+ onDataChange,
64
+ children
65
+ }) {
66
+ const [data, setData] = (0, import_react.useState)(initialData);
67
+ const get = (0, import_react.useCallback)(
68
+ (path) => (0, import_core.getByPath)(data, path),
69
+ [data]
70
+ );
71
+ const set = (0, import_react.useCallback)(
72
+ (path, value2) => {
73
+ setData((prev) => {
74
+ const next = { ...prev };
75
+ (0, import_core.setByPath)(next, path, value2);
76
+ return next;
77
+ });
78
+ onDataChange?.(path, value2);
79
+ },
80
+ [onDataChange]
81
+ );
82
+ const update = (0, import_react.useCallback)(
83
+ (updates) => {
84
+ setData((prev) => {
85
+ const next = { ...prev };
86
+ for (const [path, value2] of Object.entries(updates)) {
87
+ (0, import_core.setByPath)(next, path, value2);
88
+ onDataChange?.(path, value2);
89
+ }
90
+ return next;
91
+ });
92
+ },
93
+ [onDataChange]
94
+ );
95
+ const value = (0, import_react.useMemo)(
96
+ () => ({
97
+ data,
98
+ authState,
99
+ get,
100
+ set,
101
+ update
102
+ }),
103
+ [data, authState, get, set, update]
104
+ );
105
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(DataContext.Provider, { value, children });
106
+ }
107
+ function useData() {
108
+ const ctx = (0, import_react.useContext)(DataContext);
109
+ if (!ctx) {
110
+ throw new Error("useData must be used within a DataProvider");
111
+ }
112
+ return ctx;
113
+ }
114
+ function useDataValue(path) {
115
+ const { get } = useData();
116
+ return get(path);
117
+ }
118
+ function useDataBinding(path) {
119
+ const { get, set } = useData();
120
+ const value = get(path);
121
+ const setValue = (0, import_react.useCallback)(
122
+ (newValue) => set(path, newValue),
123
+ [path, set]
124
+ );
125
+ return [value, setValue];
126
+ }
127
+
128
+ // src/contexts/visibility.tsx
129
+ var import_react2 = require("react");
130
+ var import_core2 = require("@json-render/core");
131
+ var import_jsx_runtime2 = require("react/jsx-runtime");
132
+ var VisibilityContext = (0, import_react2.createContext)(null);
133
+ function VisibilityProvider({ children }) {
134
+ const { data, authState } = useData();
135
+ const ctx = (0, import_react2.useMemo)(
136
+ () => ({
137
+ dataModel: data,
138
+ authState
139
+ }),
140
+ [data, authState]
141
+ );
142
+ const isVisible = (0, import_react2.useMemo)(
143
+ () => (condition) => (0, import_core2.evaluateVisibility)(condition, ctx),
144
+ [ctx]
145
+ );
146
+ const value = (0, import_react2.useMemo)(
147
+ () => ({ isVisible, ctx }),
148
+ [isVisible, ctx]
149
+ );
150
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(VisibilityContext.Provider, { value, children });
151
+ }
152
+ function useVisibility() {
153
+ const ctx = (0, import_react2.useContext)(VisibilityContext);
154
+ if (!ctx) {
155
+ throw new Error("useVisibility must be used within a VisibilityProvider");
156
+ }
157
+ return ctx;
158
+ }
159
+ function useIsVisible(condition) {
160
+ const { isVisible } = useVisibility();
161
+ return isVisible(condition);
162
+ }
163
+
164
+ // src/contexts/actions.tsx
165
+ var import_react3 = require("react");
166
+ var import_core3 = require("@json-render/core");
167
+ var import_jsx_runtime3 = require("react/jsx-runtime");
168
+ var ActionContext = (0, import_react3.createContext)(null);
169
+ function ActionProvider({
170
+ handlers: initialHandlers = {},
171
+ navigate,
172
+ children
173
+ }) {
174
+ const { data, set } = useData();
175
+ const [handlers, setHandlers] = (0, import_react3.useState)(initialHandlers);
176
+ const [loadingActions, setLoadingActions] = (0, import_react3.useState)(/* @__PURE__ */ new Set());
177
+ const [pendingConfirmation, setPendingConfirmation] = (0, import_react3.useState)(null);
178
+ const registerHandler = (0, import_react3.useCallback)((name, handler) => {
179
+ setHandlers((prev) => ({ ...prev, [name]: handler }));
180
+ }, []);
181
+ const execute = (0, import_react3.useCallback)(
182
+ async (action) => {
183
+ const resolved = (0, import_core3.resolveAction)(action, data);
184
+ const handler = handlers[resolved.name];
185
+ if (!handler) {
186
+ console.warn(`No handler registered for action: ${resolved.name}`);
187
+ return;
188
+ }
189
+ if (resolved.confirm) {
190
+ return new Promise((resolve, reject) => {
191
+ setPendingConfirmation({
192
+ action: resolved,
193
+ handler,
194
+ resolve: () => {
195
+ setPendingConfirmation(null);
196
+ resolve();
197
+ },
198
+ reject: () => {
199
+ setPendingConfirmation(null);
200
+ reject(new Error("Action cancelled"));
201
+ }
202
+ });
203
+ }).then(async () => {
204
+ setLoadingActions((prev) => new Set(prev).add(resolved.name));
205
+ try {
206
+ await (0, import_core3.executeAction)({
207
+ action: resolved,
208
+ handler,
209
+ setData: set,
210
+ navigate,
211
+ executeAction: async (name) => {
212
+ const subAction = { name };
213
+ await execute(subAction);
214
+ }
215
+ });
216
+ } finally {
217
+ setLoadingActions((prev) => {
218
+ const next = new Set(prev);
219
+ next.delete(resolved.name);
220
+ return next;
221
+ });
222
+ }
223
+ });
224
+ }
225
+ setLoadingActions((prev) => new Set(prev).add(resolved.name));
226
+ try {
227
+ await (0, import_core3.executeAction)({
228
+ action: resolved,
229
+ handler,
230
+ setData: set,
231
+ navigate,
232
+ executeAction: async (name) => {
233
+ const subAction = { name };
234
+ await execute(subAction);
235
+ }
236
+ });
237
+ } finally {
238
+ setLoadingActions((prev) => {
239
+ const next = new Set(prev);
240
+ next.delete(resolved.name);
241
+ return next;
242
+ });
243
+ }
244
+ },
245
+ [data, handlers, set, navigate]
246
+ );
247
+ const confirm = (0, import_react3.useCallback)(() => {
248
+ pendingConfirmation?.resolve();
249
+ }, [pendingConfirmation]);
250
+ const cancel = (0, import_react3.useCallback)(() => {
251
+ pendingConfirmation?.reject();
252
+ }, [pendingConfirmation]);
253
+ const value = (0, import_react3.useMemo)(
254
+ () => ({
255
+ handlers,
256
+ loadingActions,
257
+ pendingConfirmation,
258
+ execute,
259
+ confirm,
260
+ cancel,
261
+ registerHandler
262
+ }),
263
+ [handlers, loadingActions, pendingConfirmation, execute, confirm, cancel, registerHandler]
264
+ );
265
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(ActionContext.Provider, { value, children });
266
+ }
267
+ function useActions() {
268
+ const ctx = (0, import_react3.useContext)(ActionContext);
269
+ if (!ctx) {
270
+ throw new Error("useActions must be used within an ActionProvider");
271
+ }
272
+ return ctx;
273
+ }
274
+ function useAction(action) {
275
+ const { execute, loadingActions } = useActions();
276
+ const isLoading = loadingActions.has(action.name);
277
+ const executeAction2 = (0, import_react3.useCallback)(() => execute(action), [execute, action]);
278
+ return { execute: executeAction2, isLoading };
279
+ }
280
+ function ConfirmDialog({ confirm, onConfirm, onCancel }) {
281
+ const isDanger = confirm.variant === "danger";
282
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
283
+ "div",
284
+ {
285
+ style: {
286
+ position: "fixed",
287
+ inset: 0,
288
+ backgroundColor: "rgba(0, 0, 0, 0.5)",
289
+ display: "flex",
290
+ alignItems: "center",
291
+ justifyContent: "center",
292
+ zIndex: 50
293
+ },
294
+ onClick: onCancel,
295
+ children: /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
296
+ "div",
297
+ {
298
+ style: {
299
+ backgroundColor: "white",
300
+ borderRadius: "8px",
301
+ padding: "24px",
302
+ maxWidth: "400px",
303
+ width: "100%",
304
+ boxShadow: "0 20px 25px -5px rgba(0, 0, 0, 0.1)"
305
+ },
306
+ onClick: (e) => e.stopPropagation(),
307
+ children: [
308
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
309
+ "h3",
310
+ {
311
+ style: {
312
+ margin: "0 0 8px 0",
313
+ fontSize: "18px",
314
+ fontWeight: 600
315
+ },
316
+ children: confirm.title
317
+ }
318
+ ),
319
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
320
+ "p",
321
+ {
322
+ style: {
323
+ margin: "0 0 24px 0",
324
+ color: "#6b7280"
325
+ },
326
+ children: confirm.message
327
+ }
328
+ ),
329
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
330
+ "div",
331
+ {
332
+ style: {
333
+ display: "flex",
334
+ gap: "12px",
335
+ justifyContent: "flex-end"
336
+ },
337
+ children: [
338
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
339
+ "button",
340
+ {
341
+ onClick: onCancel,
342
+ style: {
343
+ padding: "8px 16px",
344
+ borderRadius: "6px",
345
+ border: "1px solid #d1d5db",
346
+ backgroundColor: "white",
347
+ cursor: "pointer"
348
+ },
349
+ children: confirm.cancelLabel ?? "Cancel"
350
+ }
351
+ ),
352
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
353
+ "button",
354
+ {
355
+ onClick: onConfirm,
356
+ style: {
357
+ padding: "8px 16px",
358
+ borderRadius: "6px",
359
+ border: "none",
360
+ backgroundColor: isDanger ? "#dc2626" : "#3b82f6",
361
+ color: "white",
362
+ cursor: "pointer"
363
+ },
364
+ children: confirm.confirmLabel ?? "Confirm"
365
+ }
366
+ )
367
+ ]
368
+ }
369
+ )
370
+ ]
371
+ }
372
+ )
373
+ }
374
+ );
375
+ }
376
+
377
+ // src/contexts/validation.tsx
378
+ var import_react4 = __toESM(require("react"));
379
+ var import_core4 = require("@json-render/core");
380
+ var import_jsx_runtime4 = require("react/jsx-runtime");
381
+ var ValidationContext = (0, import_react4.createContext)(null);
382
+ function ValidationProvider({
383
+ customFunctions = {},
384
+ children
385
+ }) {
386
+ const { data, authState } = useData();
387
+ const [fieldStates, setFieldStates] = (0, import_react4.useState)({});
388
+ const [fieldConfigs, setFieldConfigs] = (0, import_react4.useState)({});
389
+ const registerField = (0, import_react4.useCallback)((path, config) => {
390
+ setFieldConfigs((prev) => ({ ...prev, [path]: config }));
391
+ }, []);
392
+ const validate = (0, import_react4.useCallback)(
393
+ (path, config) => {
394
+ const value2 = data[path.split("/").filter(Boolean).join(".")];
395
+ const result = (0, import_core4.runValidation)(config, {
396
+ value: value2,
397
+ dataModel: data,
398
+ customFunctions,
399
+ authState
400
+ });
401
+ setFieldStates((prev) => ({
402
+ ...prev,
403
+ [path]: {
404
+ touched: prev[path]?.touched ?? true,
405
+ validated: true,
406
+ result
407
+ }
408
+ }));
409
+ return result;
410
+ },
411
+ [data, customFunctions, authState]
412
+ );
413
+ const touch = (0, import_react4.useCallback)((path) => {
414
+ setFieldStates((prev) => ({
415
+ ...prev,
416
+ [path]: {
417
+ ...prev[path],
418
+ touched: true,
419
+ validated: prev[path]?.validated ?? false,
420
+ result: prev[path]?.result ?? null
421
+ }
422
+ }));
423
+ }, []);
424
+ const clear = (0, import_react4.useCallback)((path) => {
425
+ setFieldStates((prev) => {
426
+ const { [path]: _, ...rest } = prev;
427
+ return rest;
428
+ });
429
+ }, []);
430
+ const validateAll = (0, import_react4.useCallback)(() => {
431
+ let allValid = true;
432
+ for (const [path, config] of Object.entries(fieldConfigs)) {
433
+ const result = validate(path, config);
434
+ if (!result.valid) {
435
+ allValid = false;
436
+ }
437
+ }
438
+ return allValid;
439
+ }, [fieldConfigs, validate]);
440
+ const value = (0, import_react4.useMemo)(
441
+ () => ({
442
+ customFunctions,
443
+ fieldStates,
444
+ validate,
445
+ touch,
446
+ clear,
447
+ validateAll,
448
+ registerField
449
+ }),
450
+ [customFunctions, fieldStates, validate, touch, clear, validateAll, registerField]
451
+ );
452
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(ValidationContext.Provider, { value, children });
453
+ }
454
+ function useValidation() {
455
+ const ctx = (0, import_react4.useContext)(ValidationContext);
456
+ if (!ctx) {
457
+ throw new Error("useValidation must be used within a ValidationProvider");
458
+ }
459
+ return ctx;
460
+ }
461
+ function useFieldValidation(path, config) {
462
+ const {
463
+ fieldStates,
464
+ validate: validateField,
465
+ touch: touchField,
466
+ clear: clearField,
467
+ registerField
468
+ } = useValidation();
469
+ import_react4.default.useEffect(() => {
470
+ if (config) {
471
+ registerField(path, config);
472
+ }
473
+ }, [path, config, registerField]);
474
+ const state = fieldStates[path] ?? {
475
+ touched: false,
476
+ validated: false,
477
+ result: null
478
+ };
479
+ const validate = (0, import_react4.useCallback)(
480
+ () => validateField(path, config ?? { checks: [] }),
481
+ [path, config, validateField]
482
+ );
483
+ const touch = (0, import_react4.useCallback)(() => touchField(path), [path, touchField]);
484
+ const clear = (0, import_react4.useCallback)(() => clearField(path), [path, clearField]);
485
+ return {
486
+ state,
487
+ validate,
488
+ touch,
489
+ clear,
490
+ errors: state.result?.errors ?? [],
491
+ isValid: state.result?.valid ?? true
492
+ };
493
+ }
494
+
495
+ // src/renderer.tsx
496
+ var import_jsx_runtime5 = require("react/jsx-runtime");
497
+ function ElementRenderer({
498
+ element,
499
+ tree,
500
+ registry,
501
+ loading,
502
+ fallback
503
+ }) {
504
+ const isVisible = useIsVisible(element.visible);
505
+ const { execute } = useActions();
506
+ if (!isVisible) {
507
+ return null;
508
+ }
509
+ const Component = registry[element.type] ?? fallback;
510
+ if (!Component) {
511
+ console.warn(`No renderer for component type: ${element.type}`);
512
+ return null;
513
+ }
514
+ const children = element.children?.map((childKey) => {
515
+ const childElement = tree.elements[childKey];
516
+ if (!childElement) {
517
+ return null;
518
+ }
519
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
520
+ ElementRenderer,
521
+ {
522
+ element: childElement,
523
+ tree,
524
+ registry,
525
+ loading,
526
+ fallback
527
+ },
528
+ childKey
529
+ );
530
+ });
531
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
532
+ Component,
533
+ {
534
+ element,
535
+ onAction: execute,
536
+ loading,
537
+ children
538
+ }
539
+ );
540
+ }
541
+ function Renderer({ tree, registry, loading, fallback }) {
542
+ if (!tree || !tree.root) {
543
+ return null;
544
+ }
545
+ const rootElement = tree.elements[tree.root];
546
+ if (!rootElement) {
547
+ return null;
548
+ }
549
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
550
+ ElementRenderer,
551
+ {
552
+ element: rootElement,
553
+ tree,
554
+ registry,
555
+ loading,
556
+ fallback
557
+ }
558
+ );
559
+ }
560
+ function JSONUIProvider({
561
+ registry,
562
+ initialData,
563
+ authState,
564
+ actionHandlers,
565
+ navigate,
566
+ validationFunctions,
567
+ onDataChange,
568
+ children
569
+ }) {
570
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
571
+ DataProvider,
572
+ {
573
+ initialData,
574
+ authState,
575
+ onDataChange,
576
+ children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(VisibilityProvider, { children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(ActionProvider, { handlers: actionHandlers, navigate, children: /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(ValidationProvider, { customFunctions: validationFunctions, children: [
577
+ children,
578
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(ConfirmationDialogManager, {})
579
+ ] }) }) })
580
+ }
581
+ );
582
+ }
583
+ function ConfirmationDialogManager() {
584
+ const { pendingConfirmation, confirm, cancel } = useActions();
585
+ if (!pendingConfirmation?.action.confirm) {
586
+ return null;
587
+ }
588
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
589
+ ConfirmDialog,
590
+ {
591
+ confirm: pendingConfirmation.action.confirm,
592
+ onConfirm: confirm,
593
+ onCancel: cancel
594
+ }
595
+ );
596
+ }
597
+ function createRendererFromCatalog(_catalog, registry) {
598
+ return function CatalogRenderer(props) {
599
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(Renderer, { ...props, registry });
600
+ };
601
+ }
602
+
603
+ // src/hooks.ts
604
+ var import_react5 = require("react");
605
+ var import_core5 = require("@json-render/core");
606
+ function parsePatchLine(line) {
607
+ try {
608
+ const trimmed = line.trim();
609
+ if (!trimmed || trimmed.startsWith("//")) {
610
+ return null;
611
+ }
612
+ return JSON.parse(trimmed);
613
+ } catch {
614
+ return null;
615
+ }
616
+ }
617
+ function applyPatch(tree, patch) {
618
+ const newTree = { ...tree, elements: { ...tree.elements } };
619
+ switch (patch.op) {
620
+ case "set":
621
+ case "add":
622
+ case "replace": {
623
+ if (patch.path === "/root") {
624
+ newTree.root = patch.value;
625
+ return newTree;
626
+ }
627
+ if (patch.path.startsWith("/elements/")) {
628
+ const pathParts = patch.path.slice("/elements/".length).split("/");
629
+ const elementKey = pathParts[0];
630
+ if (!elementKey) return newTree;
631
+ if (pathParts.length === 1) {
632
+ newTree.elements[elementKey] = patch.value;
633
+ } else {
634
+ const element = newTree.elements[elementKey];
635
+ if (element) {
636
+ const propPath = "/" + pathParts.slice(1).join("/");
637
+ const newElement = { ...element };
638
+ (0, import_core5.setByPath)(newElement, propPath, patch.value);
639
+ newTree.elements[elementKey] = newElement;
640
+ }
641
+ }
642
+ }
643
+ break;
644
+ }
645
+ case "remove": {
646
+ if (patch.path.startsWith("/elements/")) {
647
+ const elementKey = patch.path.slice("/elements/".length).split("/")[0];
648
+ if (elementKey) {
649
+ const { [elementKey]: _, ...rest } = newTree.elements;
650
+ newTree.elements = rest;
651
+ }
652
+ }
653
+ break;
654
+ }
655
+ }
656
+ return newTree;
657
+ }
658
+ function useUIStream({
659
+ api,
660
+ onComplete,
661
+ onError
662
+ }) {
663
+ const [tree, setTree] = (0, import_react5.useState)(null);
664
+ const [isStreaming, setIsStreaming] = (0, import_react5.useState)(false);
665
+ const [error, setError] = (0, import_react5.useState)(null);
666
+ const abortControllerRef = (0, import_react5.useRef)(null);
667
+ const clear = (0, import_react5.useCallback)(() => {
668
+ setTree(null);
669
+ setError(null);
670
+ }, []);
671
+ const send = (0, import_react5.useCallback)(
672
+ async (prompt, context) => {
673
+ abortControllerRef.current?.abort();
674
+ abortControllerRef.current = new AbortController();
675
+ setIsStreaming(true);
676
+ setError(null);
677
+ let currentTree = { root: "", elements: {} };
678
+ setTree(currentTree);
679
+ try {
680
+ const response = await fetch(api, {
681
+ method: "POST",
682
+ headers: { "Content-Type": "application/json" },
683
+ body: JSON.stringify({
684
+ prompt,
685
+ context,
686
+ currentTree
687
+ }),
688
+ signal: abortControllerRef.current.signal
689
+ });
690
+ if (!response.ok) {
691
+ throw new Error(`HTTP error: ${response.status}`);
692
+ }
693
+ const reader = response.body?.getReader();
694
+ if (!reader) {
695
+ throw new Error("No response body");
696
+ }
697
+ const decoder = new TextDecoder();
698
+ let buffer = "";
699
+ while (true) {
700
+ const { done, value } = await reader.read();
701
+ if (done) break;
702
+ buffer += decoder.decode(value, { stream: true });
703
+ const lines = buffer.split("\n");
704
+ buffer = lines.pop() ?? "";
705
+ for (const line of lines) {
706
+ const patch = parsePatchLine(line);
707
+ if (patch) {
708
+ currentTree = applyPatch(currentTree, patch);
709
+ setTree({ ...currentTree });
710
+ }
711
+ }
712
+ }
713
+ if (buffer.trim()) {
714
+ const patch = parsePatchLine(buffer);
715
+ if (patch) {
716
+ currentTree = applyPatch(currentTree, patch);
717
+ setTree({ ...currentTree });
718
+ }
719
+ }
720
+ onComplete?.(currentTree);
721
+ } catch (err) {
722
+ if (err.name === "AbortError") {
723
+ return;
724
+ }
725
+ const error2 = err instanceof Error ? err : new Error(String(err));
726
+ setError(error2);
727
+ onError?.(error2);
728
+ } finally {
729
+ setIsStreaming(false);
730
+ }
731
+ },
732
+ [api, onComplete, onError]
733
+ );
734
+ (0, import_react5.useEffect)(() => {
735
+ return () => {
736
+ abortControllerRef.current?.abort();
737
+ };
738
+ }, []);
739
+ return {
740
+ tree,
741
+ isStreaming,
742
+ error,
743
+ send,
744
+ clear
745
+ };
746
+ }
747
+ function flatToTree(elements) {
748
+ const elementMap = {};
749
+ let root = "";
750
+ for (const element of elements) {
751
+ elementMap[element.key] = {
752
+ key: element.key,
753
+ type: element.type,
754
+ props: element.props,
755
+ children: [],
756
+ visible: element.visible
757
+ };
758
+ }
759
+ for (const element of elements) {
760
+ if (element.parentKey) {
761
+ const parent = elementMap[element.parentKey];
762
+ if (parent) {
763
+ if (!parent.children) {
764
+ parent.children = [];
765
+ }
766
+ parent.children.push(element.key);
767
+ }
768
+ } else {
769
+ root = element.key;
770
+ }
771
+ }
772
+ return { root, elements: elementMap };
773
+ }
774
+ // Annotate the CommonJS export names for ESM import in node:
775
+ 0 && (module.exports = {
776
+ ActionProvider,
777
+ ConfirmDialog,
778
+ DataProvider,
779
+ JSONUIProvider,
780
+ Renderer,
781
+ ValidationProvider,
782
+ VisibilityProvider,
783
+ createRendererFromCatalog,
784
+ flatToTree,
785
+ useAction,
786
+ useActions,
787
+ useData,
788
+ useDataBinding,
789
+ useDataValue,
790
+ useFieldValidation,
791
+ useIsVisible,
792
+ useUIStream,
793
+ useValidation,
794
+ useVisibility
795
+ });
796
+ //# sourceMappingURL=index.js.map