autoui-react 0.0.5-alpha → 0.1.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/README.md +6 -52
- package/dist/index.css +0 -10
- package/dist/index.css.map +1 -1
- package/dist/index.d.mts +87 -140
- package/dist/index.d.ts +87 -140
- package/dist/index.js +504 -2511
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +496 -2471
- package/dist/index.mjs.map +1 -1
- package/package.json +9 -48
package/dist/index.mjs
CHANGED
|
@@ -1,112 +1,24 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { twMerge } from 'tailwind-merge';
|
|
3
|
-
import { Slot } from '@radix-ui/react-slot';
|
|
4
|
-
import { cva } from 'class-variance-authority';
|
|
5
|
-
import { jsx, jsxs } from 'react/jsx-runtime';
|
|
6
|
-
import React, { useState, useEffect, useRef, useCallback, useReducer } from 'react';
|
|
7
|
-
import { createOpenAI } from '@ai-sdk/openai';
|
|
8
|
-
import { generateObject } from 'ai';
|
|
1
|
+
import { useState, useEffect, useRef, useCallback, useReducer } from 'react';
|
|
9
2
|
import { z } from 'zod';
|
|
10
|
-
import
|
|
11
|
-
import { XIcon, ChevronDownIcon, CheckIcon, ChevronUpIcon, CircleIcon } from 'lucide-react';
|
|
12
|
-
import * as SelectPrimitive from '@radix-ui/react-select';
|
|
13
|
-
import * as CheckboxPrimitive from '@radix-ui/react-checkbox';
|
|
14
|
-
import * as RadioGroupPrimitive from '@radix-ui/react-radio-group';
|
|
15
|
-
import * as TabsPrimitive from '@radix-ui/react-tabs';
|
|
16
|
-
import * as LabelPrimitive from '@radix-ui/react-label';
|
|
17
|
-
|
|
18
|
-
var __defProp = Object.defineProperty;
|
|
19
|
-
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
20
|
-
var __esm = (fn, res) => function __init() {
|
|
21
|
-
return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
|
|
22
|
-
};
|
|
23
|
-
var __export = (target, all) => {
|
|
24
|
-
for (var name in all)
|
|
25
|
-
__defProp(target, name, { get: all[name], enumerable: true });
|
|
26
|
-
};
|
|
27
|
-
function cn(...inputs) {
|
|
28
|
-
return twMerge(clsx(inputs));
|
|
29
|
-
}
|
|
30
|
-
var init_utils = __esm({
|
|
31
|
-
"src/lib/utils.ts"() {
|
|
32
|
-
}
|
|
33
|
-
});
|
|
34
|
-
|
|
35
|
-
// components/ui/button.tsx
|
|
36
|
-
var button_exports = {};
|
|
37
|
-
__export(button_exports, {
|
|
38
|
-
Button: () => Button2,
|
|
39
|
-
buttonVariants: () => buttonVariants
|
|
40
|
-
});
|
|
41
|
-
function Button2({
|
|
42
|
-
className,
|
|
43
|
-
variant,
|
|
44
|
-
size,
|
|
45
|
-
asChild = false,
|
|
46
|
-
...props
|
|
47
|
-
}) {
|
|
48
|
-
const Comp = asChild ? Slot : "button";
|
|
49
|
-
return /* @__PURE__ */ jsx(
|
|
50
|
-
Comp,
|
|
51
|
-
{
|
|
52
|
-
"data-slot": "button",
|
|
53
|
-
className: cn(buttonVariants({ variant, size, className })),
|
|
54
|
-
...props
|
|
55
|
-
}
|
|
56
|
-
);
|
|
57
|
-
}
|
|
58
|
-
var buttonVariants;
|
|
59
|
-
var init_button = __esm({
|
|
60
|
-
"components/ui/button.tsx"() {
|
|
61
|
-
init_utils();
|
|
62
|
-
buttonVariants = cva(
|
|
63
|
-
"inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-all disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4 shrink-0 [&_svg]:shrink-0 outline-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive",
|
|
64
|
-
{
|
|
65
|
-
variants: {
|
|
66
|
-
variant: {
|
|
67
|
-
default: "bg-primary text-primary-foreground shadow-xs hover:bg-primary/90",
|
|
68
|
-
destructive: "bg-destructive text-white shadow-xs hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 dark:bg-destructive/60",
|
|
69
|
-
outline: "border bg-background shadow-xs hover:bg-accent hover:text-accent-foreground dark:bg-input/30 dark:border-input dark:hover:bg-input/50",
|
|
70
|
-
secondary: "bg-secondary text-secondary-foreground shadow-xs hover:bg-secondary/80",
|
|
71
|
-
ghost: "hover:bg-accent hover:text-accent-foreground dark:hover:bg-accent/50",
|
|
72
|
-
link: "text-primary underline-offset-4 hover:underline"
|
|
73
|
-
},
|
|
74
|
-
size: {
|
|
75
|
-
default: "h-9 px-4 py-2 has-[>svg]:px-3",
|
|
76
|
-
sm: "h-8 rounded-md gap-1.5 px-3 has-[>svg]:px-2.5",
|
|
77
|
-
lg: "h-10 rounded-md px-6 has-[>svg]:px-4",
|
|
78
|
-
icon: "size-9"
|
|
79
|
-
}
|
|
80
|
-
},
|
|
81
|
-
defaultVariants: {
|
|
82
|
-
variant: "default",
|
|
83
|
-
size: "default"
|
|
84
|
-
}
|
|
85
|
-
}
|
|
86
|
-
);
|
|
87
|
-
}
|
|
88
|
-
});
|
|
3
|
+
import { jsxs, jsx } from 'react/jsx-runtime';
|
|
89
4
|
|
|
90
5
|
// src/core/reducer.ts
|
|
91
6
|
function cloneNode(node) {
|
|
92
7
|
return {
|
|
93
8
|
...node,
|
|
94
|
-
props: node.props ? { ...node.props } :
|
|
95
|
-
bindings: node.bindings ? { ...node.bindings } :
|
|
96
|
-
events: node.events ? { ...node.events } :
|
|
97
|
-
children: node.children
|
|
9
|
+
props: node.props ? { ...node.props } : void 0,
|
|
10
|
+
bindings: node.bindings ? { ...node.bindings } : void 0,
|
|
11
|
+
events: node.events ? { ...node.events } : void 0,
|
|
12
|
+
children: node.children?.map((child) => cloneNode(child))
|
|
98
13
|
};
|
|
99
14
|
}
|
|
100
15
|
function findNodeById(tree, nodeId) {
|
|
101
|
-
if (!tree)
|
|
102
|
-
|
|
103
|
-
if (tree.id === nodeId)
|
|
104
|
-
return tree;
|
|
16
|
+
if (!tree) return void 0;
|
|
17
|
+
if (tree.id === nodeId) return tree;
|
|
105
18
|
if (tree.children) {
|
|
106
19
|
for (const child of tree.children) {
|
|
107
20
|
const found = findNodeById(child, nodeId);
|
|
108
|
-
if (found)
|
|
109
|
-
return found;
|
|
21
|
+
if (found) return found;
|
|
110
22
|
}
|
|
111
23
|
}
|
|
112
24
|
return void 0;
|
|
@@ -121,15 +33,13 @@ function updateNodeById(tree, nodeId, updater) {
|
|
|
121
33
|
if (node.children) {
|
|
122
34
|
for (const child of node.children) {
|
|
123
35
|
const path2 = findPath(child, id, newPath);
|
|
124
|
-
if (path2)
|
|
125
|
-
return path2;
|
|
36
|
+
if (path2) return path2;
|
|
126
37
|
}
|
|
127
38
|
}
|
|
128
39
|
return null;
|
|
129
40
|
}
|
|
130
41
|
const path = findPath(result, nodeId);
|
|
131
|
-
if (!path)
|
|
132
|
-
return result;
|
|
42
|
+
if (!path) return result;
|
|
133
43
|
const nodeToUpdate = path[path.length - 1];
|
|
134
44
|
const updatedNode = updater(nodeToUpdate);
|
|
135
45
|
if (path.length === 1) {
|
|
@@ -138,14 +48,18 @@ function updateNodeById(tree, nodeId, updater) {
|
|
|
138
48
|
const parent = path[path.length - 2];
|
|
139
49
|
const updatedParent = {
|
|
140
50
|
...parent,
|
|
141
|
-
children: parent.children
|
|
51
|
+
children: parent.children?.map(
|
|
142
52
|
(child) => child.id === nodeId ? updatedNode : child
|
|
143
|
-
)
|
|
53
|
+
)
|
|
144
54
|
};
|
|
145
55
|
if (path.length === 2) {
|
|
146
56
|
return updatedParent;
|
|
147
57
|
}
|
|
148
|
-
return updateNodeById(
|
|
58
|
+
return updateNodeById(
|
|
59
|
+
result,
|
|
60
|
+
parent.id,
|
|
61
|
+
() => updatedParent
|
|
62
|
+
);
|
|
149
63
|
}
|
|
150
64
|
function replaceNodeById(tree, nodeId, newNode) {
|
|
151
65
|
return updateNodeById(tree, nodeId, () => newNode);
|
|
@@ -172,8 +86,7 @@ function removeNodeById(tree, nodeId) {
|
|
|
172
86
|
}
|
|
173
87
|
for (const child of node.children) {
|
|
174
88
|
const parent2 = findParent(child, id);
|
|
175
|
-
if (parent2)
|
|
176
|
-
return parent2;
|
|
89
|
+
if (parent2) return parent2;
|
|
177
90
|
}
|
|
178
91
|
}
|
|
179
92
|
return null;
|
|
@@ -183,11 +96,10 @@ function removeNodeById(tree, nodeId) {
|
|
|
183
96
|
throw new Error("Cannot remove root node");
|
|
184
97
|
}
|
|
185
98
|
const parent = findParent(result, nodeId);
|
|
186
|
-
if (!parent)
|
|
187
|
-
return result;
|
|
99
|
+
if (!parent) return result;
|
|
188
100
|
return updateNodeById(result, parent.id, (node) => ({
|
|
189
101
|
...node,
|
|
190
|
-
children: node.children
|
|
102
|
+
children: node.children?.filter((child) => child.id !== nodeId)
|
|
191
103
|
}));
|
|
192
104
|
}
|
|
193
105
|
function uiReducer(state, action) {
|
|
@@ -204,7 +116,7 @@ function uiReducer(state, action) {
|
|
|
204
116
|
...state,
|
|
205
117
|
layout: action.node,
|
|
206
118
|
loading: false,
|
|
207
|
-
error:
|
|
119
|
+
error: void 0
|
|
208
120
|
};
|
|
209
121
|
}
|
|
210
122
|
case "PARTIAL_UPDATE": {
|
|
@@ -213,7 +125,7 @@ function uiReducer(state, action) {
|
|
|
213
125
|
...state,
|
|
214
126
|
layout: action.node,
|
|
215
127
|
loading: false,
|
|
216
|
-
error:
|
|
128
|
+
error: void 0
|
|
217
129
|
};
|
|
218
130
|
}
|
|
219
131
|
if (action.nodeId === "root" || action.nodeId === state.layout.id) {
|
|
@@ -221,23 +133,19 @@ function uiReducer(state, action) {
|
|
|
221
133
|
...state,
|
|
222
134
|
layout: action.node,
|
|
223
135
|
loading: false,
|
|
224
|
-
error:
|
|
136
|
+
error: void 0
|
|
225
137
|
};
|
|
226
138
|
}
|
|
227
139
|
return {
|
|
228
140
|
...state,
|
|
229
141
|
layout: replaceNodeById(state.layout, action.nodeId, action.node),
|
|
230
142
|
loading: false,
|
|
231
|
-
error:
|
|
143
|
+
error: void 0
|
|
232
144
|
};
|
|
233
145
|
}
|
|
234
146
|
case "ADD_NODE": {
|
|
235
147
|
if (!state.layout) {
|
|
236
|
-
return
|
|
237
|
-
...state,
|
|
238
|
-
error: "Cannot add node: Layout is empty.",
|
|
239
|
-
loading: false
|
|
240
|
-
};
|
|
148
|
+
return state;
|
|
241
149
|
}
|
|
242
150
|
return {
|
|
243
151
|
...state,
|
|
@@ -245,41 +153,21 @@ function uiReducer(state, action) {
|
|
|
245
153
|
state.layout,
|
|
246
154
|
action.parentId,
|
|
247
155
|
action.node,
|
|
248
|
-
action.index
|
|
156
|
+
action.index
|
|
249
157
|
),
|
|
250
158
|
loading: false,
|
|
251
|
-
error:
|
|
159
|
+
error: void 0
|
|
252
160
|
};
|
|
253
161
|
}
|
|
254
162
|
case "REMOVE_NODE": {
|
|
255
163
|
if (!state.layout) {
|
|
256
|
-
return
|
|
257
|
-
...state,
|
|
258
|
-
error: "Cannot remove node: Layout is empty.",
|
|
259
|
-
loading: false
|
|
260
|
-
};
|
|
261
|
-
}
|
|
262
|
-
try {
|
|
263
|
-
return {
|
|
264
|
-
...state,
|
|
265
|
-
layout: removeNodeById(state.layout, action.nodeId),
|
|
266
|
-
loading: false,
|
|
267
|
-
error: null
|
|
268
|
-
};
|
|
269
|
-
} catch (e) {
|
|
270
|
-
const errorMessage = e instanceof Error ? e.message : "Failed to remove node.";
|
|
271
|
-
return {
|
|
272
|
-
...state,
|
|
273
|
-
error: errorMessage,
|
|
274
|
-
loading: false
|
|
275
|
-
};
|
|
164
|
+
return state;
|
|
276
165
|
}
|
|
277
|
-
}
|
|
278
|
-
case "ERROR": {
|
|
279
166
|
return {
|
|
280
167
|
...state,
|
|
281
|
-
|
|
282
|
-
loading: false
|
|
168
|
+
layout: removeNodeById(state.layout, action.nodeId),
|
|
169
|
+
loading: false,
|
|
170
|
+
error: void 0
|
|
283
171
|
};
|
|
284
172
|
}
|
|
285
173
|
case "LOADING": {
|
|
@@ -288,84 +176,23 @@ function uiReducer(state, action) {
|
|
|
288
176
|
loading: action.isLoading
|
|
289
177
|
};
|
|
290
178
|
}
|
|
179
|
+
case "ERROR": {
|
|
180
|
+
return {
|
|
181
|
+
...state,
|
|
182
|
+
error: action.message,
|
|
183
|
+
loading: false
|
|
184
|
+
};
|
|
185
|
+
}
|
|
291
186
|
default:
|
|
292
187
|
return state;
|
|
293
188
|
}
|
|
294
189
|
}
|
|
295
190
|
var initialState = {
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
history: [],
|
|
299
|
-
error: null
|
|
191
|
+
loading: true,
|
|
192
|
+
history: []
|
|
300
193
|
};
|
|
301
194
|
|
|
302
195
|
// src/core/action-router.ts
|
|
303
|
-
var UI_GUIDANCE_BASE = `
|
|
304
|
-
UI Guidance:
|
|
305
|
-
1. Create a focused interface that directly addresses the goal
|
|
306
|
-
2. Use appropriate UI patterns (lists, forms, details, etc.)
|
|
307
|
-
3. Include navigation between related views when needed
|
|
308
|
-
4. Keep the interface simple and intuitive
|
|
309
|
-
5. Bind to schema data where appropriate
|
|
310
|
-
6. Provide event handlers for user interactions - make sure to always include both action and target properties`;
|
|
311
|
-
var LIST_BINDING_GUIDANCE = `7. **CRITICAL:** For \`ListView\` or \`Table\` nodes, the \`data\` binding key **MUST** point to the *exact path* of the data *array* within the context.`;
|
|
312
|
-
var LIST_BINDING_EXAMPLE = `Example: If the context has \`{ tasks: { data: [...] } }\`, the binding **MUST** be \`{ "bindings": { "data": "tasks.data" } }\`. If the context has \`{ userList: [...] }\`, the binding **MUST** be \`{ "bindings": { "data": "userList" } }\`. **NEVER** bind to the parent object containing the array (e.g., DO NOT USE \`{ "bindings": { "data": "tasks" } }\`).`;
|
|
313
|
-
var COMMON_UI_GUIDANCE = UI_GUIDANCE_BASE + "\n" + // Add a newline separator
|
|
314
|
-
LIST_BINDING_GUIDANCE + // Add the specific list binding rule
|
|
315
|
-
"\n" + // Add a newline separator
|
|
316
|
-
LIST_BINDING_EXAMPLE;
|
|
317
|
-
function processTemplate(template, values) {
|
|
318
|
-
return template.replace(/\${(.*?)}/g, (match, key) => {
|
|
319
|
-
const trimmedKey = key.trim();
|
|
320
|
-
return trimmedKey in values ? String(values[trimmedKey]) : match;
|
|
321
|
-
});
|
|
322
|
-
}
|
|
323
|
-
function buildPrompt(input, promptTemplate, templateValues) {
|
|
324
|
-
const { schema, goal, history, userContext } = input;
|
|
325
|
-
const schemaInfo = Object.entries(schema).map(([tableName, tableSchema]) => {
|
|
326
|
-
const schemaString = typeof tableSchema === "object" && tableSchema !== null ? JSON.stringify(tableSchema) : String(tableSchema);
|
|
327
|
-
return `Table: ${tableName}
|
|
328
|
-
Schema: ${schemaString}`;
|
|
329
|
-
}).join("\n\n");
|
|
330
|
-
const recentEvents = history && history.length > 0 ? history.slice(-5).map(
|
|
331
|
-
(event) => `Event: ${event.type} on node ${event.nodeId}${event.payload ? ` with payload ${JSON.stringify(event.payload)}` : ""}`
|
|
332
|
-
).join("\n") : "No recent events";
|
|
333
|
-
const userContextSection = userContext ? `
|
|
334
|
-
|
|
335
|
-
User Context:
|
|
336
|
-
${JSON.stringify(userContext)}` : "";
|
|
337
|
-
if (promptTemplate && templateValues) {
|
|
338
|
-
const fullTemplateValues = {
|
|
339
|
-
...templateValues,
|
|
340
|
-
schemaInfo,
|
|
341
|
-
recentEvents,
|
|
342
|
-
userContextString: userContextSection.trim(),
|
|
343
|
-
// Use trimmed version
|
|
344
|
-
commonUIGuidance: COMMON_UI_GUIDANCE,
|
|
345
|
-
goal
|
|
346
|
-
// Ensure goal is always available to templates
|
|
347
|
-
};
|
|
348
|
-
return processTemplate(promptTemplate, fullTemplateValues);
|
|
349
|
-
}
|
|
350
|
-
const interactionDescription = history && history.length > 0 ? `The user's last action was: ${history[history.length - 1].type} on node ${history[history.length - 1].nodeId}` : "The user initiated the session for the goal";
|
|
351
|
-
return `
|
|
352
|
-
You are an expert UI generator.
|
|
353
|
-
Create a user interface that achieves the following goal: "${goal}".
|
|
354
|
-
${interactionDescription}.
|
|
355
|
-
|
|
356
|
-
Available data schema:
|
|
357
|
-
${schemaInfo}
|
|
358
|
-
|
|
359
|
-
Recent user interactions:
|
|
360
|
-
${recentEvents}${userContextSection}
|
|
361
|
-
|
|
362
|
-
Generate a complete UI specification in JSON format that matches the following TypeScript type:
|
|
363
|
-
type UISpecNode = { id: string; node_type: string; props?: Record<string, unknown>; bindings?: Record<string, unknown>; events?: Record<string, { action: string; target: string; payload?: Record<string, unknown>; }>; children?: UISpecNode[]; };
|
|
364
|
-
${COMMON_UI_GUIDANCE}
|
|
365
|
-
|
|
366
|
-
Respond ONLY with the JSON UI specification and no other text.
|
|
367
|
-
`;
|
|
368
|
-
}
|
|
369
196
|
var ActionType = /* @__PURE__ */ ((ActionType2) => {
|
|
370
197
|
ActionType2["FULL_REFRESH"] = "FULL_REFRESH";
|
|
371
198
|
ActionType2["UPDATE_NODE"] = "UPDATE_NODE";
|
|
@@ -400,39 +227,19 @@ var ActionRouter = class {
|
|
|
400
227
|
* @returns Route resolution or null if no match
|
|
401
228
|
*/
|
|
402
229
|
resolveRoute(event, schema, layout, dataContext, goal, userContext) {
|
|
403
|
-
console.log(
|
|
404
|
-
`[ActionRouter Debug] resolveRoute called for event type: ${event.type}`
|
|
405
|
-
);
|
|
406
230
|
const routes = this.routes[event.type] || [];
|
|
407
|
-
console.log(
|
|
408
|
-
`[ActionRouter Debug] Found ${routes.length} routes for ${event.type}`
|
|
409
|
-
);
|
|
410
231
|
if (routes.length === 0) {
|
|
411
|
-
|
|
412
|
-
`[ActionRouter Debug] No specific route found for ${event.type}, using default FULL_REFRESH.`
|
|
413
|
-
);
|
|
414
|
-
const defaultPlannerInput = {
|
|
415
|
-
schema,
|
|
416
|
-
goal,
|
|
417
|
-
history: [event],
|
|
418
|
-
userContext: userContext || null
|
|
419
|
-
};
|
|
420
|
-
const defaultPrompt = buildPrompt(
|
|
421
|
-
defaultPlannerInput,
|
|
422
|
-
void 0,
|
|
423
|
-
void 0
|
|
424
|
-
);
|
|
425
|
-
const defaultResolution = {
|
|
232
|
+
return {
|
|
426
233
|
actionType: "FULL_REFRESH" /* FULL_REFRESH */,
|
|
427
234
|
targetNodeId: layout?.id || "root",
|
|
428
|
-
plannerInput:
|
|
429
|
-
|
|
235
|
+
plannerInput: {
|
|
236
|
+
schema,
|
|
237
|
+
goal,
|
|
238
|
+
history: [event],
|
|
239
|
+
userContext
|
|
240
|
+
},
|
|
241
|
+
prompt: `Generate a new UI for the goal: "${goal}". The user just triggered: ${event.type} on node ${event.nodeId}`
|
|
430
242
|
};
|
|
431
|
-
console.log(
|
|
432
|
-
"[ActionRouter Debug] Default Resolution:",
|
|
433
|
-
defaultResolution
|
|
434
|
-
);
|
|
435
|
-
return defaultResolution;
|
|
436
243
|
}
|
|
437
244
|
const sourceNode = layout ? findNodeById(layout, event.nodeId) : void 0;
|
|
438
245
|
const nodeConfig = sourceNode?.events?.[event.type];
|
|
@@ -445,7 +252,6 @@ var ActionRouter = class {
|
|
|
445
252
|
if (!matchingRoute) {
|
|
446
253
|
matchingRoute = routes[0];
|
|
447
254
|
}
|
|
448
|
-
console.log("[ActionRouter Debug] Matching Route Config:", matchingRoute);
|
|
449
255
|
const targetNodeId = nodeConfig?.target || matchingRoute.targetNodeId || event.nodeId;
|
|
450
256
|
const additionalContext = {};
|
|
451
257
|
if (matchingRoute.contextKeys) {
|
|
@@ -479,35 +285,23 @@ var ActionRouter = class {
|
|
|
479
285
|
...additionalContext
|
|
480
286
|
}
|
|
481
287
|
};
|
|
482
|
-
const
|
|
483
|
-
goal,
|
|
484
|
-
eventType: event.type,
|
|
485
|
-
nodeId: event.nodeId,
|
|
486
|
-
targetNodeId,
|
|
487
|
-
actionType: matchingRoute.actionType,
|
|
488
|
-
...userContext || {},
|
|
489
|
-
// Spread the original userContext (passed to resolveRoute)
|
|
490
|
-
...additionalContext
|
|
491
|
-
// Spread additionalContext afterwards (can override userContext keys)
|
|
492
|
-
};
|
|
493
|
-
console.log("[ActionRouter Debug] Template Values:", templateValues);
|
|
494
|
-
const finalPrompt = buildPrompt(
|
|
495
|
-
plannerInput2,
|
|
288
|
+
const prompt = this.processTemplate(
|
|
496
289
|
matchingRoute.promptTemplate,
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
290
|
+
{
|
|
291
|
+
goal,
|
|
292
|
+
eventType: event.type,
|
|
293
|
+
nodeId: event.nodeId,
|
|
294
|
+
targetNodeId,
|
|
295
|
+
actionType: matchingRoute.actionType,
|
|
296
|
+
...additionalContext
|
|
297
|
+
}
|
|
500
298
|
);
|
|
501
|
-
|
|
502
|
-
const finalResolution = {
|
|
299
|
+
return {
|
|
503
300
|
actionType: matchingRoute.actionType,
|
|
504
301
|
targetNodeId,
|
|
505
302
|
plannerInput: plannerInput2,
|
|
506
|
-
prompt
|
|
507
|
-
// Use the generated prompt
|
|
303
|
+
prompt
|
|
508
304
|
};
|
|
509
|
-
console.log("[ActionRouter Debug] Final Resolution:", finalResolution);
|
|
510
|
-
return finalResolution;
|
|
511
305
|
}
|
|
512
306
|
/**
|
|
513
307
|
* Process a prompt template with variables
|
|
@@ -525,11 +319,8 @@ function createDefaultRouter() {
|
|
|
525
319
|
const router = new ActionRouter();
|
|
526
320
|
router.registerRoute("CLICK", {
|
|
527
321
|
actionType: "FULL_REFRESH" /* FULL_REFRESH */,
|
|
528
|
-
targetNodeId: "root"
|
|
529
|
-
|
|
530
|
-
router.registerRoute("INIT", {
|
|
531
|
-
actionType: "FULL_REFRESH" /* FULL_REFRESH */,
|
|
532
|
-
targetNodeId: "root"
|
|
322
|
+
targetNodeId: "root",
|
|
323
|
+
promptTemplate: 'Generate a new UI for the goal: "${goal}". The user just clicked on node ${nodeId}'
|
|
533
324
|
});
|
|
534
325
|
router.registerRoute("CLICK", {
|
|
535
326
|
actionType: "SHOW_DETAIL" /* SHOW_DETAIL */,
|
|
@@ -559,31 +350,7 @@ function createDefaultRouter() {
|
|
|
559
350
|
});
|
|
560
351
|
return router;
|
|
561
352
|
}
|
|
562
|
-
var componentType = z.enum([
|
|
563
|
-
// Layout components
|
|
564
|
-
"Container",
|
|
565
|
-
"Card",
|
|
566
|
-
"Header",
|
|
567
|
-
// Input components
|
|
568
|
-
"Button",
|
|
569
|
-
"Input",
|
|
570
|
-
"Select",
|
|
571
|
-
"Textarea",
|
|
572
|
-
"Checkbox",
|
|
573
|
-
"RadioGroup",
|
|
574
|
-
// Data display components
|
|
575
|
-
"ListView",
|
|
576
|
-
"Detail",
|
|
577
|
-
"Tabs",
|
|
578
|
-
"Dialog",
|
|
579
|
-
// Typography
|
|
580
|
-
"Heading",
|
|
581
|
-
"Text"
|
|
582
|
-
]);
|
|
583
|
-
|
|
584
|
-
// src/schema/ui.ts
|
|
585
353
|
var uiEventType = z.enum([
|
|
586
|
-
"INIT",
|
|
587
354
|
"CLICK",
|
|
588
355
|
"CHANGE",
|
|
589
356
|
"SUBMIT",
|
|
@@ -595,62 +362,27 @@ var uiEventType = z.enum([
|
|
|
595
362
|
var uiEvent = z.object({
|
|
596
363
|
type: uiEventType,
|
|
597
364
|
nodeId: z.string(),
|
|
598
|
-
timestamp: z.number().
|
|
599
|
-
payload: z.record(z.
|
|
600
|
-
});
|
|
601
|
-
z.enum(["AI_RESPONSE", "ERROR"]);
|
|
602
|
-
var runtimeRecord = z.record(z.any()).nullable();
|
|
603
|
-
var openAISimplifiedValue = z.string().nullable();
|
|
604
|
-
var openAIRecordSimplifiedNullable = z.record(openAISimplifiedValue).nullable();
|
|
605
|
-
var openAIEventPayloadSimplifiedNullable = z.record(openAISimplifiedValue).nullable();
|
|
606
|
-
var openAIBaseNode = z.object({
|
|
607
|
-
id: z.string().describe("Unique identifier for the UI node."),
|
|
608
|
-
node_type: componentType.describe(
|
|
609
|
-
"The type of UI component (e.g., Container, Text, Button, ListView)."
|
|
610
|
-
),
|
|
611
|
-
props: openAIRecordSimplifiedNullable.describe(
|
|
612
|
-
'Component-specific properties (attributes). Values should be strings or null. E.g., for Header use { "title": "My Title" }; for Text use { "text": "My Text" }.'
|
|
613
|
-
),
|
|
614
|
-
bindings: openAIRecordSimplifiedNullable.describe(
|
|
615
|
-
'Data bindings map context paths to component props. Values are paths (e.g., "user.name") or templates (e.g., "{{item.title}}"). **CRITICAL for ListView/Table:** the `data` key MUST point to the *exact array path* (e.g., { "data": "tasks.data" } or { "data": "userList" }), NOT the parent object.'
|
|
616
|
-
),
|
|
617
|
-
events: z.record(
|
|
618
|
-
z.string(),
|
|
619
|
-
z.object({
|
|
620
|
-
action: z.string(),
|
|
621
|
-
target: z.string(),
|
|
622
|
-
payload: openAIEventPayloadSimplifiedNullable
|
|
623
|
-
})
|
|
624
|
-
).nullable(),
|
|
625
|
-
// Entire events object is nullable
|
|
626
|
-
children: z.null()
|
|
627
|
-
// Base children are null. When extended, it will be an array or null.
|
|
365
|
+
timestamp: z.number().optional(),
|
|
366
|
+
payload: z.record(z.any()).optional()
|
|
628
367
|
});
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
var
|
|
634
|
-
children: z.array(openAINodeL3).nullable()
|
|
635
|
-
});
|
|
636
|
-
var openAIUISpec = openAIBaseNode.extend({
|
|
637
|
-
children: z.array(openAINodeL2).nullable()
|
|
638
|
-
});
|
|
639
|
-
var uiSpecNode = z.object({
|
|
368
|
+
z.enum([
|
|
369
|
+
"AI_RESPONSE",
|
|
370
|
+
"ERROR"
|
|
371
|
+
]);
|
|
372
|
+
var uiSpecNode = z.lazy(() => z.object({
|
|
640
373
|
id: z.string(),
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
).
|
|
652
|
-
|
|
653
|
-
});
|
|
374
|
+
type: z.string(),
|
|
375
|
+
// e.g., "ListView", "Button", "TextField"
|
|
376
|
+
props: z.record(z.any()).optional(),
|
|
377
|
+
bindings: z.record(z.any()).optional(),
|
|
378
|
+
// Data bindings
|
|
379
|
+
events: z.record(z.string(), z.object({
|
|
380
|
+
action: z.string(),
|
|
381
|
+
target: z.string().optional(),
|
|
382
|
+
payload: z.record(z.any()).optional()
|
|
383
|
+
})).optional(),
|
|
384
|
+
children: z.array(uiSpecNode).optional()
|
|
385
|
+
}));
|
|
654
386
|
z.discriminatedUnion("type", [
|
|
655
387
|
z.object({
|
|
656
388
|
type: z.literal("UI_EVENT"),
|
|
@@ -669,7 +401,7 @@ z.discriminatedUnion("type", [
|
|
|
669
401
|
type: z.literal("ADD_NODE"),
|
|
670
402
|
parentId: z.string(),
|
|
671
403
|
node: uiSpecNode,
|
|
672
|
-
index: z.number().
|
|
404
|
+
index: z.number().optional()
|
|
673
405
|
}),
|
|
674
406
|
z.object({
|
|
675
407
|
type: z.literal("REMOVE_NODE"),
|
|
@@ -685,16 +417,16 @@ z.discriminatedUnion("type", [
|
|
|
685
417
|
})
|
|
686
418
|
]);
|
|
687
419
|
z.object({
|
|
688
|
-
layout: uiSpecNode.
|
|
420
|
+
layout: uiSpecNode.optional(),
|
|
689
421
|
loading: z.boolean(),
|
|
690
422
|
history: z.array(uiEvent),
|
|
691
|
-
error: z.string().
|
|
423
|
+
error: z.string().optional()
|
|
692
424
|
});
|
|
693
425
|
z.object({
|
|
694
426
|
schema: z.record(z.unknown()),
|
|
695
427
|
goal: z.string(),
|
|
696
|
-
history: z.array(uiEvent).
|
|
697
|
-
userContext: z.record(z.unknown()).
|
|
428
|
+
history: z.array(uiEvent).optional(),
|
|
429
|
+
userContext: z.record(z.unknown()).optional()
|
|
698
430
|
});
|
|
699
431
|
|
|
700
432
|
// src/core/system-events.ts
|
|
@@ -720,7 +452,7 @@ var SystemEventManager = class {
|
|
|
720
452
|
}
|
|
721
453
|
/**
|
|
722
454
|
* Register a listener for a specific system event type
|
|
723
|
-
*
|
|
455
|
+
*
|
|
724
456
|
* @param eventType - The system event type to listen for
|
|
725
457
|
* @param listener - The listener function
|
|
726
458
|
* @returns Function to unregister the listener
|
|
@@ -740,7 +472,7 @@ var SystemEventManager = class {
|
|
|
740
472
|
}
|
|
741
473
|
/**
|
|
742
474
|
* Emit a system event to all registered listeners
|
|
743
|
-
*
|
|
475
|
+
*
|
|
744
476
|
* @param event - The system event to emit
|
|
745
477
|
*/
|
|
746
478
|
async emit(event) {
|
|
@@ -760,917 +492,257 @@ function createSystemEvent(type, data) {
|
|
|
760
492
|
}
|
|
761
493
|
|
|
762
494
|
// src/env.ts
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
//
|
|
767
|
-
|
|
768
|
-
// Simplified NODE_ENV assignment
|
|
769
|
-
OPENAI_API_KEY: rawApiKeyFromEnv || ""
|
|
770
|
-
};
|
|
495
|
+
({
|
|
496
|
+
MOCK_PLANNER: import.meta.env?.VITE_MOCK_PLANNER || "1",
|
|
497
|
+
NODE_ENV: import.meta.env?.MODE || "development"
|
|
498
|
+
// Add other environment variables as needed
|
|
499
|
+
});
|
|
771
500
|
|
|
772
501
|
// src/core/planner.ts
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
});
|
|
502
|
+
function buildPrompt(input, targetNodeId, customPrompt) {
|
|
503
|
+
const { schema, goal, history, userContext } = input;
|
|
504
|
+
const schemaInfo = Object.entries(schema).map(([tableName, tableSchema]) => {
|
|
505
|
+
return `Table: ${tableName}
|
|
506
|
+
Schema: ${JSON.stringify(tableSchema)}`;
|
|
507
|
+
}).join("\n\n");
|
|
508
|
+
const recentEvents = history?.slice(-5).map(
|
|
509
|
+
(event) => `Event: ${event.type} on node ${event.nodeId}${event.payload ? ` with payload ${JSON.stringify(event.payload)}` : ""}`
|
|
510
|
+
).join("\n") || "No recent events";
|
|
511
|
+
const userContextSection = userContext ? `
|
|
512
|
+
|
|
513
|
+
User Context:
|
|
514
|
+
${JSON.stringify(userContext)}` : "";
|
|
515
|
+
return `
|
|
516
|
+
You are an expert UI generator.
|
|
517
|
+
Create a user interface that achieves the following goal: "${goal}"
|
|
518
|
+
|
|
519
|
+
Available data schema:
|
|
520
|
+
${schemaInfo}
|
|
521
|
+
|
|
522
|
+
Recent user interactions:
|
|
523
|
+
${recentEvents}${userContextSection}
|
|
524
|
+
|
|
525
|
+
Generate a complete UI specification in JSON format that matches the following TypeScript type:
|
|
526
|
+
type UISpecNode = {
|
|
527
|
+
id: string;
|
|
528
|
+
type: string;
|
|
529
|
+
props?: Record<string, any>;
|
|
530
|
+
bindings?: Record<string, any>;
|
|
531
|
+
events?: Record<string, { action: string; target?: string; payload?: Record<string, any>; }>;
|
|
532
|
+
children?: UISpecNode[];
|
|
779
533
|
};
|
|
534
|
+
|
|
535
|
+
UI Guidance:
|
|
536
|
+
1. Create a focused interface that directly addresses the goal
|
|
537
|
+
2. Use appropriate UI patterns (lists, forms, details, etc.)
|
|
538
|
+
3. Include navigation between related views when needed
|
|
539
|
+
4. Keep the interface simple and intuitive
|
|
540
|
+
5. Bind to schema data where appropriate
|
|
541
|
+
6. Provide event handlers for user interactions
|
|
542
|
+
|
|
543
|
+
Respond ONLY with the JSON UI specification and no other text.
|
|
544
|
+
`;
|
|
545
|
+
}
|
|
780
546
|
function mockPlanner(input, targetNodeId, customPrompt) {
|
|
781
|
-
if (customPrompt) {
|
|
782
|
-
console.log("mockPlanner received customPrompt:", customPrompt);
|
|
783
|
-
}
|
|
784
|
-
const taskSchema = input.schema.tasks;
|
|
785
|
-
const taskData = taskSchema?.sampleData || [
|
|
786
|
-
{
|
|
787
|
-
id: "1",
|
|
788
|
-
title: "Example Task 1",
|
|
789
|
-
description: "This is a sample task",
|
|
790
|
-
status: "pending",
|
|
791
|
-
priority: "medium"
|
|
792
|
-
},
|
|
793
|
-
{
|
|
794
|
-
id: "2",
|
|
795
|
-
title: "Example Task 2",
|
|
796
|
-
description: "Another sample task",
|
|
797
|
-
status: "completed",
|
|
798
|
-
priority: "high"
|
|
799
|
-
}
|
|
800
|
-
];
|
|
801
547
|
const mockNode = {
|
|
802
548
|
id: targetNodeId || "root",
|
|
803
|
-
|
|
804
|
-
props: {
|
|
805
|
-
className: "p-4 space-y-6"
|
|
806
|
-
},
|
|
807
|
-
bindings: null,
|
|
808
|
-
events: null,
|
|
549
|
+
type: "Container",
|
|
550
|
+
props: { title: "Mock UI" },
|
|
809
551
|
children: [
|
|
810
552
|
{
|
|
811
|
-
id: "
|
|
812
|
-
|
|
813
|
-
props: {
|
|
814
|
-
title: "Task Management Dashboard",
|
|
815
|
-
className: "mb-4"
|
|
816
|
-
},
|
|
817
|
-
bindings: null,
|
|
818
|
-
events: null,
|
|
819
|
-
children: null
|
|
820
|
-
},
|
|
821
|
-
{
|
|
822
|
-
id: "main-content",
|
|
823
|
-
node_type: "Container",
|
|
824
|
-
props: {
|
|
825
|
-
className: "grid grid-cols-1 gap-6 md:grid-cols-3"
|
|
826
|
-
},
|
|
827
|
-
bindings: null,
|
|
828
|
-
events: null,
|
|
829
|
-
children: [
|
|
830
|
-
{
|
|
831
|
-
id: "tasks-container",
|
|
832
|
-
node_type: "Container",
|
|
833
|
-
props: {
|
|
834
|
-
className: "md:col-span-2"
|
|
835
|
-
},
|
|
836
|
-
bindings: null,
|
|
837
|
-
events: null,
|
|
838
|
-
children: [
|
|
839
|
-
{
|
|
840
|
-
id: "list-heading",
|
|
841
|
-
node_type: "Container",
|
|
842
|
-
props: {
|
|
843
|
-
className: "flex justify-between items-center mb-4"
|
|
844
|
-
},
|
|
845
|
-
bindings: null,
|
|
846
|
-
events: null,
|
|
847
|
-
children: [
|
|
848
|
-
{
|
|
849
|
-
id: "list-title",
|
|
850
|
-
node_type: "Header",
|
|
851
|
-
props: {
|
|
852
|
-
title: "Tasks",
|
|
853
|
-
className: "border-none p-0 m-0"
|
|
854
|
-
},
|
|
855
|
-
bindings: null,
|
|
856
|
-
events: null,
|
|
857
|
-
children: null
|
|
858
|
-
},
|
|
859
|
-
{
|
|
860
|
-
id: "add-task-button",
|
|
861
|
-
node_type: "Button",
|
|
862
|
-
props: {
|
|
863
|
-
label: "Add Task",
|
|
864
|
-
variant: "default"
|
|
865
|
-
},
|
|
866
|
-
bindings: null,
|
|
867
|
-
events: {
|
|
868
|
-
onClick: {
|
|
869
|
-
action: "ADD_TASK",
|
|
870
|
-
target: "tasks-container",
|
|
871
|
-
payload: {}
|
|
872
|
-
}
|
|
873
|
-
},
|
|
874
|
-
children: null
|
|
875
|
-
}
|
|
876
|
-
]
|
|
877
|
-
},
|
|
878
|
-
{
|
|
879
|
-
id: "task-list",
|
|
880
|
-
node_type: "ListView",
|
|
881
|
-
props: {
|
|
882
|
-
selectable: "true"
|
|
883
|
-
},
|
|
884
|
-
bindings: {
|
|
885
|
-
data: "tasks.data",
|
|
886
|
-
fields: JSON.stringify([
|
|
887
|
-
{ key: "id", label: "ID" },
|
|
888
|
-
{ key: "title", label: "Title" },
|
|
889
|
-
{ key: "status", label: "Status" },
|
|
890
|
-
{ key: "priority", label: "Priority" }
|
|
891
|
-
])
|
|
892
|
-
},
|
|
893
|
-
events: {
|
|
894
|
-
onSelect: {
|
|
895
|
-
action: "SELECT_TASK",
|
|
896
|
-
target: "task-detail",
|
|
897
|
-
payload: {
|
|
898
|
-
source: "task-list"
|
|
899
|
-
}
|
|
900
|
-
}
|
|
901
|
-
},
|
|
902
|
-
children: null
|
|
903
|
-
}
|
|
904
|
-
]
|
|
905
|
-
},
|
|
906
|
-
{
|
|
907
|
-
id: "task-detail",
|
|
908
|
-
node_type: "Detail",
|
|
909
|
-
props: {
|
|
910
|
-
title: "Task Details",
|
|
911
|
-
visible: "true"
|
|
912
|
-
},
|
|
913
|
-
bindings: {
|
|
914
|
-
data: JSON.stringify(taskData[0]),
|
|
915
|
-
fields: JSON.stringify([
|
|
916
|
-
{ key: "title", label: "Title", type: "heading" },
|
|
917
|
-
{ key: "description", label: "Description", type: "content" },
|
|
918
|
-
{ key: "status", label: "Status" },
|
|
919
|
-
{ key: "priority", label: "Priority" },
|
|
920
|
-
{ key: "dueDate", label: "Due Date" }
|
|
921
|
-
])
|
|
922
|
-
},
|
|
923
|
-
events: {
|
|
924
|
-
onBack: {
|
|
925
|
-
action: "CLOSE_DETAIL",
|
|
926
|
-
target: "task-detail",
|
|
927
|
-
payload: {}
|
|
928
|
-
}
|
|
929
|
-
},
|
|
930
|
-
children: null
|
|
931
|
-
}
|
|
932
|
-
]
|
|
553
|
+
id: "text-1",
|
|
554
|
+
type: "Text",
|
|
555
|
+
props: { text: "This is a mock UI for testing" }
|
|
933
556
|
}
|
|
934
557
|
]
|
|
935
558
|
};
|
|
936
559
|
return mockNode;
|
|
937
560
|
}
|
|
938
|
-
async function callPlannerLLM(input, openaiApiKey, routeResolution) {
|
|
939
|
-
await systemEvents.emit(
|
|
940
|
-
createSystemEvent("PLAN_START" /* PLAN_START */, { plannerInput: input })
|
|
941
|
-
);
|
|
942
|
-
if (env.MOCK_PLANNER === "1") {
|
|
943
|
-
console.warn(
|
|
944
|
-
`Using mock planner because MOCK_PLANNER environment variable is set to "1".`
|
|
945
|
-
);
|
|
946
|
-
return mockPlanner(input);
|
|
947
|
-
}
|
|
948
|
-
if (!openaiApiKey) {
|
|
949
|
-
console.warn(
|
|
950
|
-
`OpenAI API key was not provided to callPlannerLLM. Falling back to mock planner.`
|
|
951
|
-
);
|
|
952
|
-
return mockPlanner(input);
|
|
953
|
-
}
|
|
954
|
-
const startTime = Date.now();
|
|
955
|
-
const prompt = routeResolution?.prompt;
|
|
956
|
-
if (!prompt) {
|
|
957
|
-
throw new Error("ActionRouter did not provide a prompt to callPlannerLLM.");
|
|
958
|
-
}
|
|
959
|
-
await systemEvents.emit(
|
|
960
|
-
createSystemEvent("PLAN_PROMPT_CREATED" /* PLAN_PROMPT_CREATED */, { prompt })
|
|
961
|
-
);
|
|
962
|
-
try {
|
|
963
|
-
const { object: uiSpec } = await generateObject({
|
|
964
|
-
model: getOpenAIClient(openaiApiKey)("gpt-4o", {
|
|
965
|
-
structuredOutputs: true
|
|
966
|
-
}),
|
|
967
|
-
schema: openAIUISpec,
|
|
968
|
-
messages: [{ role: "user", content: prompt }],
|
|
969
|
-
temperature: 0.2,
|
|
970
|
-
maxTokens: 4e3
|
|
971
|
-
});
|
|
972
|
-
await systemEvents.emit(
|
|
973
|
-
createSystemEvent("PLAN_COMPLETE" /* PLAN_COMPLETE */, {
|
|
974
|
-
layout: uiSpec,
|
|
975
|
-
executionTimeMs: Date.now() - startTime
|
|
976
|
-
})
|
|
977
|
-
);
|
|
978
|
-
return uiSpec;
|
|
979
|
-
} catch (error) {
|
|
980
|
-
console.error("Error calling LLM planner:", error);
|
|
981
|
-
await systemEvents.emit(
|
|
982
|
-
createSystemEvent("PLAN_ERROR" /* PLAN_ERROR */, {
|
|
983
|
-
error: error instanceof Error ? error : new Error(String(error))
|
|
984
|
-
})
|
|
985
|
-
);
|
|
986
|
-
throw error;
|
|
987
|
-
}
|
|
988
|
-
}
|
|
989
|
-
async function processEvent(event, router, schema, layout, dataContext, goal, userContext, openaiApiKey) {
|
|
990
|
-
const routeResolution = await router.resolveRoute(
|
|
991
|
-
event,
|
|
992
|
-
schema,
|
|
993
|
-
layout || null,
|
|
994
|
-
dataContext,
|
|
995
|
-
goal,
|
|
996
|
-
userContext
|
|
997
|
-
);
|
|
998
|
-
if (!routeResolution) {
|
|
999
|
-
throw new Error(
|
|
1000
|
-
`No route found for event type: ${event.type}, node: ${event.nodeId}`
|
|
1001
|
-
);
|
|
1002
|
-
}
|
|
1003
|
-
if (routeResolution.actionType.toString() === "NoOp") {
|
|
1004
|
-
if (!layout)
|
|
1005
|
-
throw new Error("Layout is undefined and action is NoOp");
|
|
1006
|
-
return layout;
|
|
1007
|
-
}
|
|
1008
|
-
const plannerInputForLLM = routeResolution.plannerInput;
|
|
1009
|
-
const newLayout = await callPlannerLLM(
|
|
1010
|
-
plannerInputForLLM,
|
|
1011
|
-
openaiApiKey || "",
|
|
1012
|
-
routeResolution
|
|
1013
|
-
);
|
|
1014
|
-
return newLayout;
|
|
1015
|
-
}
|
|
1016
561
|
|
|
1017
562
|
// src/core/state.ts
|
|
563
|
+
var useChat = (config) => ({
|
|
564
|
+
append: async (message) => {
|
|
565
|
+
},
|
|
566
|
+
data: { content: "{}" },
|
|
567
|
+
isLoading: false,
|
|
568
|
+
error: null,
|
|
569
|
+
stop: () => {
|
|
570
|
+
}
|
|
571
|
+
});
|
|
1018
572
|
function useUIStateEngine({
|
|
1019
573
|
schema,
|
|
1020
574
|
goal,
|
|
1021
|
-
openaiApiKey,
|
|
1022
575
|
userContext,
|
|
1023
576
|
mockMode = false,
|
|
1024
|
-
planningConfig,
|
|
577
|
+
planningConfig = {},
|
|
1025
578
|
router = createDefaultRouter(),
|
|
1026
579
|
dataContext = {},
|
|
1027
580
|
enablePartialUpdates = false
|
|
1028
581
|
}) {
|
|
1029
|
-
if (userContext === null) {
|
|
1030
|
-
console.warn(
|
|
1031
|
-
"useUIStateEngine: userContext was explicitly set to null. This is an allowed but discouraged value. Consider using undefined if you intend to omit the user context."
|
|
1032
|
-
);
|
|
1033
|
-
}
|
|
1034
582
|
const [state, dispatch] = useReducer(uiReducer, initialState);
|
|
1035
|
-
const
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
goal,
|
|
1050
|
-
userContext
|
|
1051
|
-
);
|
|
1052
|
-
if (route) {
|
|
1053
|
-
console.log("Resolved route:", route);
|
|
1054
|
-
actionTypeForDispatch = route.actionType;
|
|
1055
|
-
targetNodeIdForDispatch = route.targetNodeId;
|
|
1056
|
-
systemEvents.emit(
|
|
1057
|
-
createSystemEvent("PLAN_START" /* PLAN_START */, {
|
|
1058
|
-
plannerInput: route.plannerInput
|
|
1059
|
-
})
|
|
1060
|
-
);
|
|
1061
|
-
if (mockMode) {
|
|
1062
|
-
resolvedNode = mockPlanner(
|
|
1063
|
-
route.plannerInput,
|
|
1064
|
-
route.targetNodeId,
|
|
1065
|
-
route.prompt
|
|
1066
|
-
);
|
|
1067
|
-
} else {
|
|
1068
|
-
resolvedNode = await callPlannerLLM(
|
|
1069
|
-
route.plannerInput,
|
|
1070
|
-
openaiApiKey || "",
|
|
1071
|
-
route
|
|
1072
|
-
);
|
|
1073
|
-
}
|
|
1074
|
-
} else {
|
|
1075
|
-
const input = {
|
|
1076
|
-
schema,
|
|
1077
|
-
goal,
|
|
1078
|
-
history: [...state.history, event],
|
|
1079
|
-
userContext
|
|
1080
|
-
};
|
|
1081
|
-
if (mockMode) {
|
|
1082
|
-
resolvedNode = mockPlanner(input);
|
|
1083
|
-
} else {
|
|
1084
|
-
resolvedNode = await callPlannerLLM(
|
|
1085
|
-
input,
|
|
1086
|
-
openaiApiKey || "",
|
|
1087
|
-
void 0
|
|
1088
|
-
);
|
|
1089
|
-
}
|
|
1090
|
-
}
|
|
1091
|
-
} else {
|
|
1092
|
-
const input = {
|
|
1093
|
-
schema,
|
|
1094
|
-
goal,
|
|
1095
|
-
history: [...state.history, event],
|
|
1096
|
-
// event is already in history from UI_EVENT dispatch
|
|
1097
|
-
userContext
|
|
1098
|
-
};
|
|
1099
|
-
if (mockMode) {
|
|
1100
|
-
resolvedNode = mockPlanner(input);
|
|
1101
|
-
} else {
|
|
1102
|
-
resolvedNode = await callPlannerLLM(
|
|
1103
|
-
input,
|
|
1104
|
-
openaiApiKey || "",
|
|
1105
|
-
void 0
|
|
1106
|
-
);
|
|
1107
|
-
}
|
|
1108
|
-
}
|
|
1109
|
-
switch (actionTypeForDispatch) {
|
|
1110
|
-
case "UPDATE_NODE" /* UPDATE_NODE */:
|
|
1111
|
-
case "SHOW_DETAIL" /* SHOW_DETAIL */:
|
|
1112
|
-
case "HIDE_DETAIL" /* HIDE_DETAIL */:
|
|
1113
|
-
case "TOGGLE_STATE" /* TOGGLE_STATE */:
|
|
1114
|
-
case "ADD_DROPDOWN" /* ADD_DROPDOWN */:
|
|
1115
|
-
case "UPDATE_FORM" /* UPDATE_FORM */:
|
|
1116
|
-
case "NAVIGATE" /* NAVIGATE */:
|
|
1117
|
-
dispatch({
|
|
1118
|
-
type: "PARTIAL_UPDATE",
|
|
1119
|
-
nodeId: targetNodeIdForDispatch,
|
|
1120
|
-
node: resolvedNode
|
|
1121
|
-
});
|
|
1122
|
-
break;
|
|
1123
|
-
case "FULL_REFRESH" /* FULL_REFRESH */:
|
|
1124
|
-
default:
|
|
1125
|
-
dispatch({ type: "AI_RESPONSE", node: resolvedNode });
|
|
1126
|
-
break;
|
|
1127
|
-
}
|
|
1128
|
-
} catch (e) {
|
|
1129
|
-
const errorMessage = e instanceof Error ? e.message : String(e);
|
|
1130
|
-
dispatch({ type: "ERROR", message: errorMessage });
|
|
583
|
+
const { append, data, isLoading, error, stop } = useChat();
|
|
584
|
+
const handleEvent = useCallback((event) => {
|
|
585
|
+
dispatch({ type: "UI_EVENT", event });
|
|
586
|
+
if (enablePartialUpdates) {
|
|
587
|
+
const route = router.resolveRoute(
|
|
588
|
+
event,
|
|
589
|
+
schema,
|
|
590
|
+
state.layout,
|
|
591
|
+
dataContext,
|
|
592
|
+
goal,
|
|
593
|
+
userContext
|
|
594
|
+
);
|
|
595
|
+
if (route) {
|
|
596
|
+
console.log("Resolved route:", route);
|
|
1131
597
|
systemEvents.emit(
|
|
1132
|
-
createSystemEvent("
|
|
1133
|
-
|
|
598
|
+
createSystemEvent("PLAN_START" /* PLAN_START */, {
|
|
599
|
+
plannerInput: route.plannerInput
|
|
1134
600
|
})
|
|
1135
601
|
);
|
|
1136
|
-
|
|
1137
|
-
|
|
602
|
+
if (mockMode) {
|
|
603
|
+
const node = mockPlanner(route.plannerInput, route.targetNodeId, route.prompt);
|
|
604
|
+
switch (route.actionType) {
|
|
605
|
+
case "FULL_REFRESH" /* FULL_REFRESH */:
|
|
606
|
+
dispatch({ type: "AI_RESPONSE", node });
|
|
607
|
+
break;
|
|
608
|
+
case "UPDATE_NODE" /* UPDATE_NODE */:
|
|
609
|
+
case "SHOW_DETAIL" /* SHOW_DETAIL */:
|
|
610
|
+
case "HIDE_DETAIL" /* HIDE_DETAIL */:
|
|
611
|
+
case "TOGGLE_STATE" /* TOGGLE_STATE */:
|
|
612
|
+
case "ADD_DROPDOWN" /* ADD_DROPDOWN */:
|
|
613
|
+
case "UPDATE_FORM" /* UPDATE_FORM */:
|
|
614
|
+
case "NAVIGATE" /* NAVIGATE */:
|
|
615
|
+
dispatch({
|
|
616
|
+
type: "PARTIAL_UPDATE",
|
|
617
|
+
nodeId: route.targetNodeId,
|
|
618
|
+
node
|
|
619
|
+
});
|
|
620
|
+
break;
|
|
621
|
+
}
|
|
622
|
+
} else {
|
|
623
|
+
const prompt = route.prompt;
|
|
624
|
+
systemEvents.emit(
|
|
625
|
+
createSystemEvent("PLAN_PROMPT_CREATED" /* PLAN_PROMPT_CREATED */, { prompt })
|
|
626
|
+
);
|
|
627
|
+
append({
|
|
628
|
+
content: prompt,
|
|
629
|
+
role: "user"
|
|
630
|
+
});
|
|
631
|
+
sessionStorage.setItem("currentRoute", JSON.stringify({
|
|
632
|
+
actionType: route.actionType,
|
|
633
|
+
targetNodeId: route.targetNodeId
|
|
634
|
+
}));
|
|
635
|
+
}
|
|
636
|
+
return;
|
|
1138
637
|
}
|
|
1139
|
-
}
|
|
1140
|
-
|
|
1141
|
-
// append, // REMOVE
|
|
1142
|
-
goal,
|
|
638
|
+
}
|
|
639
|
+
const input = {
|
|
1143
640
|
schema,
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
|
|
641
|
+
goal,
|
|
642
|
+
history: [...state.history, event],
|
|
643
|
+
userContext
|
|
644
|
+
};
|
|
645
|
+
if (mockMode) {
|
|
646
|
+
const node = mockPlanner();
|
|
647
|
+
dispatch({ type: "AI_RESPONSE", node });
|
|
648
|
+
} else {
|
|
649
|
+
const prompt = buildPrompt(input);
|
|
650
|
+
append({
|
|
651
|
+
content: prompt,
|
|
652
|
+
role: "user"
|
|
653
|
+
});
|
|
654
|
+
}
|
|
655
|
+
}, [append, goal, schema, state.history, state.layout, stop, userContext, router, mockMode, dataContext, enablePartialUpdates]);
|
|
1158
656
|
useEffect(() => {
|
|
1159
|
-
|
|
1160
|
-
dispatch({ type: "LOADING", isLoading: true });
|
|
657
|
+
{
|
|
1161
658
|
try {
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
|
|
659
|
+
systemEvents.emit(
|
|
660
|
+
createSystemEvent("PLAN_RESPONSE_CHUNK" /* PLAN_RESPONSE_CHUNK */, {
|
|
661
|
+
chunk: data.content,
|
|
662
|
+
isComplete: true
|
|
663
|
+
})
|
|
664
|
+
);
|
|
665
|
+
const jsonMatch = data.content.match(/```(?:json)?\s*([\s\S]*?)\s*```/) || [null, data.content];
|
|
666
|
+
const jsonStr = jsonMatch[1].trim();
|
|
667
|
+
const parsedJson = JSON.parse(jsonStr);
|
|
668
|
+
const validatedNode = uiSpecNode.parse(parsedJson);
|
|
669
|
+
const routeInfoStr = sessionStorage.getItem("currentRoute");
|
|
670
|
+
if (routeInfoStr && enablePartialUpdates) {
|
|
671
|
+
try {
|
|
672
|
+
const routeInfo = JSON.parse(routeInfoStr);
|
|
673
|
+
switch (routeInfo.actionType) {
|
|
674
|
+
case "FULL_REFRESH" /* FULL_REFRESH */:
|
|
675
|
+
dispatch({ type: "AI_RESPONSE", node: validatedNode });
|
|
676
|
+
break;
|
|
677
|
+
case "UPDATE_NODE" /* UPDATE_NODE */:
|
|
678
|
+
case "SHOW_DETAIL" /* SHOW_DETAIL */:
|
|
679
|
+
case "HIDE_DETAIL" /* HIDE_DETAIL */:
|
|
680
|
+
case "TOGGLE_STATE" /* TOGGLE_STATE */:
|
|
681
|
+
case "ADD_DROPDOWN" /* ADD_DROPDOWN */:
|
|
682
|
+
case "UPDATE_FORM" /* UPDATE_FORM */:
|
|
683
|
+
case "NAVIGATE" /* NAVIGATE */:
|
|
684
|
+
dispatch({
|
|
685
|
+
type: "PARTIAL_UPDATE",
|
|
686
|
+
nodeId: routeInfo.targetNodeId,
|
|
687
|
+
node: validatedNode
|
|
688
|
+
});
|
|
689
|
+
break;
|
|
690
|
+
default:
|
|
691
|
+
dispatch({ type: "AI_RESPONSE", node: validatedNode });
|
|
692
|
+
}
|
|
693
|
+
sessionStorage.removeItem("currentRoute");
|
|
694
|
+
} catch (e) {
|
|
695
|
+
console.error("Error parsing route info:", e);
|
|
696
|
+
dispatch({ type: "AI_RESPONSE", node: validatedNode });
|
|
1195
697
|
}
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
plannerInput: route.plannerInput
|
|
1199
|
-
})
|
|
1200
|
-
);
|
|
1201
|
-
node = await callPlannerLLM(
|
|
1202
|
-
route.plannerInput,
|
|
1203
|
-
// Use plannerInput from the resolved route
|
|
1204
|
-
openaiApiKey || "",
|
|
1205
|
-
route
|
|
1206
|
-
// Pass the entire route object
|
|
1207
|
-
);
|
|
698
|
+
} else {
|
|
699
|
+
dispatch({ type: "AI_RESPONSE", node: validatedNode });
|
|
1208
700
|
}
|
|
1209
|
-
dispatch({ type: "AI_RESPONSE", node });
|
|
1210
|
-
} catch (e) {
|
|
1211
|
-
const errorMessage = e instanceof Error ? e.message : String(e);
|
|
1212
|
-
dispatch({ type: "ERROR", message: errorMessage });
|
|
1213
701
|
systemEvents.emit(
|
|
1214
|
-
|
|
702
|
+
createSystemEvent("PLAN_COMPLETE" /* PLAN_COMPLETE */, {
|
|
703
|
+
layout: validatedNode,
|
|
704
|
+
executionTimeMs: 0
|
|
705
|
+
// Not available here
|
|
706
|
+
})
|
|
707
|
+
);
|
|
708
|
+
} catch (parseError) {
|
|
709
|
+
console.error("Failed to parse LLM response:", parseError);
|
|
710
|
+
dispatch({
|
|
711
|
+
type: "ERROR",
|
|
712
|
+
message: "Failed to parse LLM response"
|
|
713
|
+
});
|
|
714
|
+
systemEvents.emit(
|
|
1215
715
|
createSystemEvent("PLAN_ERROR" /* PLAN_ERROR */, {
|
|
1216
|
-
error:
|
|
716
|
+
error: parseError instanceof Error ? parseError : new Error("Parse error")
|
|
1217
717
|
})
|
|
1218
718
|
);
|
|
1219
|
-
} finally {
|
|
1220
|
-
dispatch({ type: "LOADING", isLoading: false });
|
|
1221
719
|
}
|
|
720
|
+
}
|
|
721
|
+
}, [data.content, error, isLoading, enablePartialUpdates]);
|
|
722
|
+
useEffect(() => {
|
|
723
|
+
const input = {
|
|
724
|
+
schema,
|
|
725
|
+
goal,
|
|
726
|
+
history: [],
|
|
727
|
+
userContext
|
|
1222
728
|
};
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
|
|
729
|
+
if (mockMode) {
|
|
730
|
+
const node = mockPlanner();
|
|
731
|
+
dispatch({ type: "AI_RESPONSE", node });
|
|
732
|
+
} else {
|
|
733
|
+
const prompt = buildPrompt(input);
|
|
734
|
+
append({
|
|
735
|
+
content: prompt,
|
|
736
|
+
role: "user"
|
|
737
|
+
});
|
|
738
|
+
}
|
|
739
|
+
}, [append, goal, schema, userContext, mockMode]);
|
|
740
|
+
return {
|
|
741
|
+
state,
|
|
1227
742
|
dispatch,
|
|
1228
743
|
handleEvent
|
|
1229
744
|
};
|
|
1230
745
|
}
|
|
1231
|
-
|
|
1232
|
-
// src/adapters/shadcn.tsx
|
|
1233
|
-
init_utils();
|
|
1234
|
-
|
|
1235
|
-
// components/ui/dialog.tsx
|
|
1236
|
-
init_utils();
|
|
1237
|
-
function Dialog({
|
|
1238
|
-
...props
|
|
1239
|
-
}) {
|
|
1240
|
-
return /* @__PURE__ */ jsx(DialogPrimitive.Root, { "data-slot": "dialog", ...props });
|
|
1241
|
-
}
|
|
1242
|
-
function DialogPortal({
|
|
1243
|
-
...props
|
|
1244
|
-
}) {
|
|
1245
|
-
return /* @__PURE__ */ jsx(DialogPrimitive.Portal, { "data-slot": "dialog-portal", ...props });
|
|
1246
|
-
}
|
|
1247
|
-
function DialogOverlay({
|
|
1248
|
-
className,
|
|
1249
|
-
...props
|
|
1250
|
-
}) {
|
|
1251
|
-
return /* @__PURE__ */ jsx(
|
|
1252
|
-
DialogPrimitive.Overlay,
|
|
1253
|
-
{
|
|
1254
|
-
"data-slot": "dialog-overlay",
|
|
1255
|
-
className: cn(
|
|
1256
|
-
"data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 fixed inset-0 z-50 bg-black/50",
|
|
1257
|
-
className
|
|
1258
|
-
),
|
|
1259
|
-
...props
|
|
1260
|
-
}
|
|
1261
|
-
);
|
|
1262
|
-
}
|
|
1263
|
-
function DialogContent({
|
|
1264
|
-
className,
|
|
1265
|
-
children,
|
|
1266
|
-
...props
|
|
1267
|
-
}) {
|
|
1268
|
-
return /* @__PURE__ */ jsxs(DialogPortal, { "data-slot": "dialog-portal", children: [
|
|
1269
|
-
/* @__PURE__ */ jsx(DialogOverlay, {}),
|
|
1270
|
-
/* @__PURE__ */ jsxs(
|
|
1271
|
-
DialogPrimitive.Content,
|
|
1272
|
-
{
|
|
1273
|
-
"data-slot": "dialog-content",
|
|
1274
|
-
className: cn(
|
|
1275
|
-
"bg-background data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 fixed top-[50%] left-[50%] z-50 grid w-full max-w-[calc(100%-2rem)] translate-x-[-50%] translate-y-[-50%] gap-4 rounded-lg border p-6 shadow-lg duration-200 sm:max-w-lg",
|
|
1276
|
-
className
|
|
1277
|
-
),
|
|
1278
|
-
...props,
|
|
1279
|
-
children: [
|
|
1280
|
-
children,
|
|
1281
|
-
/* @__PURE__ */ jsxs(DialogPrimitive.Close, { className: "ring-offset-background focus:ring-ring data-[state=open]:bg-accent data-[state=open]:text-muted-foreground absolute top-4 right-4 rounded-xs opacity-70 transition-opacity hover:opacity-100 focus:ring-2 focus:ring-offset-2 focus:outline-hidden disabled:pointer-events-none [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4", children: [
|
|
1282
|
-
/* @__PURE__ */ jsx(XIcon, {}),
|
|
1283
|
-
/* @__PURE__ */ jsx("span", { className: "sr-only", children: "Close" })
|
|
1284
|
-
] })
|
|
1285
|
-
]
|
|
1286
|
-
}
|
|
1287
|
-
)
|
|
1288
|
-
] });
|
|
1289
|
-
}
|
|
1290
|
-
function DialogHeader({ className, ...props }) {
|
|
1291
|
-
return /* @__PURE__ */ jsx(
|
|
1292
|
-
"div",
|
|
1293
|
-
{
|
|
1294
|
-
"data-slot": "dialog-header",
|
|
1295
|
-
className: cn("flex flex-col gap-2 text-center sm:text-left", className),
|
|
1296
|
-
...props
|
|
1297
|
-
}
|
|
1298
|
-
);
|
|
1299
|
-
}
|
|
1300
|
-
function DialogTitle({
|
|
1301
|
-
className,
|
|
1302
|
-
...props
|
|
1303
|
-
}) {
|
|
1304
|
-
return /* @__PURE__ */ jsx(
|
|
1305
|
-
DialogPrimitive.Title,
|
|
1306
|
-
{
|
|
1307
|
-
"data-slot": "dialog-title",
|
|
1308
|
-
className: cn("text-lg leading-none font-semibold", className),
|
|
1309
|
-
...props
|
|
1310
|
-
}
|
|
1311
|
-
);
|
|
1312
|
-
}
|
|
1313
|
-
function DialogDescription({
|
|
1314
|
-
className,
|
|
1315
|
-
...props
|
|
1316
|
-
}) {
|
|
1317
|
-
return /* @__PURE__ */ jsx(
|
|
1318
|
-
DialogPrimitive.Description,
|
|
1319
|
-
{
|
|
1320
|
-
"data-slot": "dialog-description",
|
|
1321
|
-
className: cn("text-muted-foreground text-sm", className),
|
|
1322
|
-
...props
|
|
1323
|
-
}
|
|
1324
|
-
);
|
|
1325
|
-
}
|
|
1326
|
-
|
|
1327
|
-
// components/ui/card.tsx
|
|
1328
|
-
init_utils();
|
|
1329
|
-
function Card({ className, ...props }) {
|
|
1330
|
-
return /* @__PURE__ */ jsx(
|
|
1331
|
-
"div",
|
|
1332
|
-
{
|
|
1333
|
-
"data-slot": "card",
|
|
1334
|
-
className: cn(
|
|
1335
|
-
"bg-card text-card-foreground flex flex-col gap-6 rounded-xl border py-6 shadow-sm",
|
|
1336
|
-
className
|
|
1337
|
-
),
|
|
1338
|
-
...props
|
|
1339
|
-
}
|
|
1340
|
-
);
|
|
1341
|
-
}
|
|
1342
|
-
function CardContent({ className, ...props }) {
|
|
1343
|
-
return /* @__PURE__ */ jsx(
|
|
1344
|
-
"div",
|
|
1345
|
-
{
|
|
1346
|
-
"data-slot": "card-content",
|
|
1347
|
-
className: cn("px-6", className),
|
|
1348
|
-
...props
|
|
1349
|
-
}
|
|
1350
|
-
);
|
|
1351
|
-
}
|
|
1352
|
-
|
|
1353
|
-
// components/ui/input.tsx
|
|
1354
|
-
init_utils();
|
|
1355
|
-
function Input({ className, type, ...props }) {
|
|
1356
|
-
return /* @__PURE__ */ jsx(
|
|
1357
|
-
"input",
|
|
1358
|
-
{
|
|
1359
|
-
type,
|
|
1360
|
-
"data-slot": "input",
|
|
1361
|
-
className: cn(
|
|
1362
|
-
"file:text-foreground placeholder:text-muted-foreground selection:bg-primary selection:text-primary-foreground dark:bg-input/30 border-input flex h-9 w-full min-w-0 rounded-md border bg-transparent px-3 py-1 text-base shadow-xs transition-[color,box-shadow] outline-none file:inline-flex file:h-7 file:border-0 file:bg-transparent file:text-sm file:font-medium disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-50 md:text-sm",
|
|
1363
|
-
"focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px]",
|
|
1364
|
-
"aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive",
|
|
1365
|
-
className
|
|
1366
|
-
),
|
|
1367
|
-
...props
|
|
1368
|
-
}
|
|
1369
|
-
);
|
|
1370
|
-
}
|
|
1371
|
-
|
|
1372
|
-
// components/ui/textarea.tsx
|
|
1373
|
-
init_utils();
|
|
1374
|
-
function Textarea({ className, ...props }) {
|
|
1375
|
-
return /* @__PURE__ */ jsx(
|
|
1376
|
-
"textarea",
|
|
1377
|
-
{
|
|
1378
|
-
"data-slot": "textarea",
|
|
1379
|
-
className: cn(
|
|
1380
|
-
"border-input placeholder:text-muted-foreground focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive dark:bg-input/30 flex field-sizing-content min-h-16 w-full rounded-md border bg-transparent px-3 py-2 text-base shadow-xs transition-[color,box-shadow] outline-none focus-visible:ring-[3px] disabled:cursor-not-allowed disabled:opacity-50 md:text-sm",
|
|
1381
|
-
className
|
|
1382
|
-
),
|
|
1383
|
-
...props
|
|
1384
|
-
}
|
|
1385
|
-
);
|
|
1386
|
-
}
|
|
1387
|
-
|
|
1388
|
-
// components/ui/select.tsx
|
|
1389
|
-
init_utils();
|
|
1390
|
-
function Select({
|
|
1391
|
-
...props
|
|
1392
|
-
}) {
|
|
1393
|
-
return /* @__PURE__ */ jsx(SelectPrimitive.Root, { "data-slot": "select", ...props });
|
|
1394
|
-
}
|
|
1395
|
-
function SelectValue({
|
|
1396
|
-
...props
|
|
1397
|
-
}) {
|
|
1398
|
-
return /* @__PURE__ */ jsx(SelectPrimitive.Value, { "data-slot": "select-value", ...props });
|
|
1399
|
-
}
|
|
1400
|
-
function SelectTrigger({
|
|
1401
|
-
className,
|
|
1402
|
-
size = "default",
|
|
1403
|
-
children,
|
|
1404
|
-
...props
|
|
1405
|
-
}) {
|
|
1406
|
-
return /* @__PURE__ */ jsxs(
|
|
1407
|
-
SelectPrimitive.Trigger,
|
|
1408
|
-
{
|
|
1409
|
-
"data-slot": "select-trigger",
|
|
1410
|
-
"data-size": size,
|
|
1411
|
-
className: cn(
|
|
1412
|
-
"border-input data-[placeholder]:text-muted-foreground [&_svg:not([class*='text-'])]:text-muted-foreground focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive dark:bg-input/30 dark:hover:bg-input/50 flex w-fit items-center justify-between gap-2 rounded-md border bg-transparent px-3 py-2 text-sm whitespace-nowrap shadow-xs transition-[color,box-shadow] outline-none focus-visible:ring-[3px] disabled:cursor-not-allowed disabled:opacity-50 data-[size=default]:h-9 data-[size=sm]:h-8 *:data-[slot=select-value]:line-clamp-1 *:data-[slot=select-value]:flex *:data-[slot=select-value]:items-center *:data-[slot=select-value]:gap-2 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
|
|
1413
|
-
className
|
|
1414
|
-
),
|
|
1415
|
-
...props,
|
|
1416
|
-
children: [
|
|
1417
|
-
children,
|
|
1418
|
-
/* @__PURE__ */ jsx(SelectPrimitive.Icon, { asChild: true, children: /* @__PURE__ */ jsx(ChevronDownIcon, { className: "size-4 opacity-50" }) })
|
|
1419
|
-
]
|
|
1420
|
-
}
|
|
1421
|
-
);
|
|
1422
|
-
}
|
|
1423
|
-
function SelectContent({
|
|
1424
|
-
className,
|
|
1425
|
-
children,
|
|
1426
|
-
position = "popper",
|
|
1427
|
-
...props
|
|
1428
|
-
}) {
|
|
1429
|
-
return /* @__PURE__ */ jsx(SelectPrimitive.Portal, { children: /* @__PURE__ */ jsxs(
|
|
1430
|
-
SelectPrimitive.Content,
|
|
1431
|
-
{
|
|
1432
|
-
"data-slot": "select-content",
|
|
1433
|
-
className: cn(
|
|
1434
|
-
"bg-popover text-popover-foreground data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 relative z-50 max-h-(--radix-select-content-available-height) min-w-[8rem] origin-(--radix-select-content-transform-origin) overflow-x-hidden overflow-y-auto rounded-md border shadow-md",
|
|
1435
|
-
position === "popper" && "data-[side=bottom]:translate-y-1 data-[side=left]:-translate-x-1 data-[side=right]:translate-x-1 data-[side=top]:-translate-y-1",
|
|
1436
|
-
className
|
|
1437
|
-
),
|
|
1438
|
-
position,
|
|
1439
|
-
...props,
|
|
1440
|
-
children: [
|
|
1441
|
-
/* @__PURE__ */ jsx(SelectScrollUpButton, {}),
|
|
1442
|
-
/* @__PURE__ */ jsx(
|
|
1443
|
-
SelectPrimitive.Viewport,
|
|
1444
|
-
{
|
|
1445
|
-
className: cn(
|
|
1446
|
-
"p-1",
|
|
1447
|
-
position === "popper" && "h-[var(--radix-select-trigger-height)] w-full min-w-[var(--radix-select-trigger-width)] scroll-my-1"
|
|
1448
|
-
),
|
|
1449
|
-
children
|
|
1450
|
-
}
|
|
1451
|
-
),
|
|
1452
|
-
/* @__PURE__ */ jsx(SelectScrollDownButton, {})
|
|
1453
|
-
]
|
|
1454
|
-
}
|
|
1455
|
-
) });
|
|
1456
|
-
}
|
|
1457
|
-
function SelectItem({
|
|
1458
|
-
className,
|
|
1459
|
-
children,
|
|
1460
|
-
...props
|
|
1461
|
-
}) {
|
|
1462
|
-
return /* @__PURE__ */ jsxs(
|
|
1463
|
-
SelectPrimitive.Item,
|
|
1464
|
-
{
|
|
1465
|
-
"data-slot": "select-item",
|
|
1466
|
-
className: cn(
|
|
1467
|
-
"focus:bg-accent focus:text-accent-foreground [&_svg:not([class*='text-'])]:text-muted-foreground relative flex w-full cursor-default items-center gap-2 rounded-sm py-1.5 pr-8 pl-2 text-sm outline-hidden select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4 *:[span]:last:flex *:[span]:last:items-center *:[span]:last:gap-2",
|
|
1468
|
-
className
|
|
1469
|
-
),
|
|
1470
|
-
...props,
|
|
1471
|
-
children: [
|
|
1472
|
-
/* @__PURE__ */ jsx("span", { className: "absolute right-2 flex size-3.5 items-center justify-center", children: /* @__PURE__ */ jsx(SelectPrimitive.ItemIndicator, { children: /* @__PURE__ */ jsx(CheckIcon, { className: "size-4" }) }) }),
|
|
1473
|
-
/* @__PURE__ */ jsx(SelectPrimitive.ItemText, { children })
|
|
1474
|
-
]
|
|
1475
|
-
}
|
|
1476
|
-
);
|
|
1477
|
-
}
|
|
1478
|
-
function SelectScrollUpButton({
|
|
1479
|
-
className,
|
|
1480
|
-
...props
|
|
1481
|
-
}) {
|
|
1482
|
-
return /* @__PURE__ */ jsx(
|
|
1483
|
-
SelectPrimitive.ScrollUpButton,
|
|
1484
|
-
{
|
|
1485
|
-
"data-slot": "select-scroll-up-button",
|
|
1486
|
-
className: cn(
|
|
1487
|
-
"flex cursor-default items-center justify-center py-1",
|
|
1488
|
-
className
|
|
1489
|
-
),
|
|
1490
|
-
...props,
|
|
1491
|
-
children: /* @__PURE__ */ jsx(ChevronUpIcon, { className: "size-4" })
|
|
1492
|
-
}
|
|
1493
|
-
);
|
|
1494
|
-
}
|
|
1495
|
-
function SelectScrollDownButton({
|
|
1496
|
-
className,
|
|
1497
|
-
...props
|
|
1498
|
-
}) {
|
|
1499
|
-
return /* @__PURE__ */ jsx(
|
|
1500
|
-
SelectPrimitive.ScrollDownButton,
|
|
1501
|
-
{
|
|
1502
|
-
"data-slot": "select-scroll-down-button",
|
|
1503
|
-
className: cn(
|
|
1504
|
-
"flex cursor-default items-center justify-center py-1",
|
|
1505
|
-
className
|
|
1506
|
-
),
|
|
1507
|
-
...props,
|
|
1508
|
-
children: /* @__PURE__ */ jsx(ChevronDownIcon, { className: "size-4" })
|
|
1509
|
-
}
|
|
1510
|
-
);
|
|
1511
|
-
}
|
|
1512
|
-
|
|
1513
|
-
// components/ui/checkbox.tsx
|
|
1514
|
-
init_utils();
|
|
1515
|
-
function Checkbox({
|
|
1516
|
-
className,
|
|
1517
|
-
...props
|
|
1518
|
-
}) {
|
|
1519
|
-
return /* @__PURE__ */ jsx(
|
|
1520
|
-
CheckboxPrimitive.Root,
|
|
1521
|
-
{
|
|
1522
|
-
"data-slot": "checkbox",
|
|
1523
|
-
className: cn(
|
|
1524
|
-
"peer border-input dark:bg-input/30 data-[state=checked]:bg-primary data-[state=checked]:text-primary-foreground dark:data-[state=checked]:bg-primary data-[state=checked]:border-primary focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive size-4 shrink-0 rounded-[4px] border shadow-xs transition-shadow outline-none focus-visible:ring-[3px] disabled:cursor-not-allowed disabled:opacity-50",
|
|
1525
|
-
className
|
|
1526
|
-
),
|
|
1527
|
-
...props,
|
|
1528
|
-
children: /* @__PURE__ */ jsx(
|
|
1529
|
-
CheckboxPrimitive.Indicator,
|
|
1530
|
-
{
|
|
1531
|
-
"data-slot": "checkbox-indicator",
|
|
1532
|
-
className: "flex items-center justify-center text-current transition-none",
|
|
1533
|
-
children: /* @__PURE__ */ jsx(CheckIcon, { className: "size-3.5" })
|
|
1534
|
-
}
|
|
1535
|
-
)
|
|
1536
|
-
}
|
|
1537
|
-
);
|
|
1538
|
-
}
|
|
1539
|
-
|
|
1540
|
-
// components/ui/radio-group.tsx
|
|
1541
|
-
init_utils();
|
|
1542
|
-
function RadioGroup({
|
|
1543
|
-
className,
|
|
1544
|
-
...props
|
|
1545
|
-
}) {
|
|
1546
|
-
return /* @__PURE__ */ jsx(
|
|
1547
|
-
RadioGroupPrimitive.Root,
|
|
1548
|
-
{
|
|
1549
|
-
"data-slot": "radio-group",
|
|
1550
|
-
className: cn("grid gap-3", className),
|
|
1551
|
-
...props
|
|
1552
|
-
}
|
|
1553
|
-
);
|
|
1554
|
-
}
|
|
1555
|
-
function RadioGroupItem({
|
|
1556
|
-
className,
|
|
1557
|
-
...props
|
|
1558
|
-
}) {
|
|
1559
|
-
return /* @__PURE__ */ jsx(
|
|
1560
|
-
RadioGroupPrimitive.Item,
|
|
1561
|
-
{
|
|
1562
|
-
"data-slot": "radio-group-item",
|
|
1563
|
-
className: cn(
|
|
1564
|
-
"border-input text-primary focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive dark:bg-input/30 aspect-square size-4 shrink-0 rounded-full border shadow-xs transition-[color,box-shadow] outline-none focus-visible:ring-[3px] disabled:cursor-not-allowed disabled:opacity-50",
|
|
1565
|
-
className
|
|
1566
|
-
),
|
|
1567
|
-
...props,
|
|
1568
|
-
children: /* @__PURE__ */ jsx(
|
|
1569
|
-
RadioGroupPrimitive.Indicator,
|
|
1570
|
-
{
|
|
1571
|
-
"data-slot": "radio-group-indicator",
|
|
1572
|
-
className: "relative flex items-center justify-center",
|
|
1573
|
-
children: /* @__PURE__ */ jsx(CircleIcon, { className: "fill-primary absolute top-1/2 left-1/2 size-2 -translate-x-1/2 -translate-y-1/2" })
|
|
1574
|
-
}
|
|
1575
|
-
)
|
|
1576
|
-
}
|
|
1577
|
-
);
|
|
1578
|
-
}
|
|
1579
|
-
|
|
1580
|
-
// components/ui/tabs.tsx
|
|
1581
|
-
init_utils();
|
|
1582
|
-
function Tabs({
|
|
1583
|
-
className,
|
|
1584
|
-
...props
|
|
1585
|
-
}) {
|
|
1586
|
-
return /* @__PURE__ */ jsx(
|
|
1587
|
-
TabsPrimitive.Root,
|
|
1588
|
-
{
|
|
1589
|
-
"data-slot": "tabs",
|
|
1590
|
-
className: cn("flex flex-col gap-2", className),
|
|
1591
|
-
...props
|
|
1592
|
-
}
|
|
1593
|
-
);
|
|
1594
|
-
}
|
|
1595
|
-
function TabsList({
|
|
1596
|
-
className,
|
|
1597
|
-
...props
|
|
1598
|
-
}) {
|
|
1599
|
-
return /* @__PURE__ */ jsx(
|
|
1600
|
-
TabsPrimitive.List,
|
|
1601
|
-
{
|
|
1602
|
-
"data-slot": "tabs-list",
|
|
1603
|
-
className: cn(
|
|
1604
|
-
"bg-muted text-muted-foreground inline-flex h-9 w-fit items-center justify-center rounded-lg p-[3px]",
|
|
1605
|
-
className
|
|
1606
|
-
),
|
|
1607
|
-
...props
|
|
1608
|
-
}
|
|
1609
|
-
);
|
|
1610
|
-
}
|
|
1611
|
-
function TabsTrigger({
|
|
1612
|
-
className,
|
|
1613
|
-
...props
|
|
1614
|
-
}) {
|
|
1615
|
-
return /* @__PURE__ */ jsx(
|
|
1616
|
-
TabsPrimitive.Trigger,
|
|
1617
|
-
{
|
|
1618
|
-
"data-slot": "tabs-trigger",
|
|
1619
|
-
className: cn(
|
|
1620
|
-
"data-[state=active]:bg-background dark:data-[state=active]:text-foreground focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:outline-ring dark:data-[state=active]:border-input dark:data-[state=active]:bg-input/30 text-foreground dark:text-muted-foreground inline-flex h-[calc(100%-1px)] flex-1 items-center justify-center gap-1.5 rounded-md border border-transparent px-2 py-1 text-sm font-medium whitespace-nowrap transition-[color,box-shadow] focus-visible:ring-[3px] focus-visible:outline-1 disabled:pointer-events-none disabled:opacity-50 data-[state=active]:shadow-sm [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
|
|
1621
|
-
className
|
|
1622
|
-
),
|
|
1623
|
-
...props
|
|
1624
|
-
}
|
|
1625
|
-
);
|
|
1626
|
-
}
|
|
1627
|
-
function TabsContent({
|
|
1628
|
-
className,
|
|
1629
|
-
...props
|
|
1630
|
-
}) {
|
|
1631
|
-
return /* @__PURE__ */ jsx(
|
|
1632
|
-
TabsPrimitive.Content,
|
|
1633
|
-
{
|
|
1634
|
-
"data-slot": "tabs-content",
|
|
1635
|
-
className: cn("flex-1 outline-none", className),
|
|
1636
|
-
...props
|
|
1637
|
-
}
|
|
1638
|
-
);
|
|
1639
|
-
}
|
|
1640
|
-
|
|
1641
|
-
// components/ui/label.tsx
|
|
1642
|
-
init_utils();
|
|
1643
|
-
function Label2({
|
|
1644
|
-
className,
|
|
1645
|
-
...props
|
|
1646
|
-
}) {
|
|
1647
|
-
return /* @__PURE__ */ jsx(
|
|
1648
|
-
LabelPrimitive.Root,
|
|
1649
|
-
{
|
|
1650
|
-
"data-slot": "label",
|
|
1651
|
-
className: cn(
|
|
1652
|
-
"flex items-center gap-2 text-sm leading-none font-medium select-none group-data-[disabled=true]:pointer-events-none group-data-[disabled=true]:opacity-50 peer-disabled:cursor-not-allowed peer-disabled:opacity-50",
|
|
1653
|
-
className
|
|
1654
|
-
),
|
|
1655
|
-
...props
|
|
1656
|
-
}
|
|
1657
|
-
);
|
|
1658
|
-
}
|
|
1659
|
-
var parseStyleString = (styleString) => {
|
|
1660
|
-
if (typeof styleString !== "string") {
|
|
1661
|
-
return typeof styleString === "object" ? styleString : {};
|
|
1662
|
-
}
|
|
1663
|
-
const style = {};
|
|
1664
|
-
styleString.split(";").forEach((declaration) => {
|
|
1665
|
-
const [property, value] = declaration.split(":");
|
|
1666
|
-
if (property && value) {
|
|
1667
|
-
const camelCasedProperty = property.trim().replace(/-([a-z])/g, (g) => g[1].toUpperCase());
|
|
1668
|
-
style[camelCasedProperty] = value.trim();
|
|
1669
|
-
}
|
|
1670
|
-
});
|
|
1671
|
-
return style;
|
|
1672
|
-
};
|
|
1673
|
-
var isArrayOf = (guard) => (arr) => Array.isArray(arr) && arr.every(guard);
|
|
1674
746
|
var ShimmerBlock = () => /* @__PURE__ */ jsx("div", { className: "w-full h-8 bg-gray-200 animate-pulse rounded" });
|
|
1675
747
|
var ShimmerTable = ({ rows = 3 }) => /* @__PURE__ */ jsxs("div", { className: "w-full space-y-2", children: [
|
|
1676
748
|
/* @__PURE__ */ jsx("div", { className: "w-full h-10 bg-gray-200 animate-pulse rounded" }),
|
|
@@ -1684,696 +756,117 @@ var ShimmerCard = () => /* @__PURE__ */ jsxs("div", { className: "w-full p-4 spa
|
|
|
1684
756
|
/* @__PURE__ */ jsx("div", { className: "w-5/6 h-4 bg-gray-200 animate-pulse rounded" })
|
|
1685
757
|
] })
|
|
1686
758
|
] });
|
|
1687
|
-
var Container = (props) => /* @__PURE__ */ jsx("div", { className: `
|
|
1688
|
-
var Header = ({
|
|
1689
|
-
title,
|
|
1690
|
-
className
|
|
1691
|
-
}) => /* @__PURE__ */ jsx(
|
|
1692
|
-
"header",
|
|
1693
|
-
{
|
|
1694
|
-
className: `py-4 px-6 border-b border-gray-300 mb-4 bg-gray-50 dark:bg-gray-800 ${className || ""}`,
|
|
1695
|
-
children: /* @__PURE__ */ jsx("h1", { className: "text-xl font-semibold text-gray-800 dark:text-white", children: title })
|
|
1696
|
-
}
|
|
1697
|
-
);
|
|
759
|
+
var Container = (props) => /* @__PURE__ */ jsx("div", { className: `w-full ${props.className || ""}`, style: props.style, children: props.children });
|
|
760
|
+
var Header = ({ title }) => /* @__PURE__ */ jsx("header", { className: "py-4 px-6 border-b mb-4", children: /* @__PURE__ */ jsx("h1", { className: "text-xl font-semibold", children: title }) });
|
|
1698
761
|
var Button = ({ onClick, children, variant = "default" }) => /* @__PURE__ */ jsx(
|
|
1699
762
|
"button",
|
|
1700
763
|
{
|
|
1701
|
-
className: `px-4 py-2 rounded
|
|
1702
|
-
onClick
|
|
764
|
+
className: `px-4 py-2 rounded font-medium ${variant === "default" ? "bg-blue-600 text-white" : variant === "outline" ? "border border-gray-300 text-gray-700" : "bg-red-600 text-white"}`,
|
|
765
|
+
onClick,
|
|
1703
766
|
children
|
|
1704
767
|
}
|
|
1705
768
|
);
|
|
769
|
+
var Table = ({ items = [], fields = [], onSelect, selectable }) => /* @__PURE__ */ jsx("div", { className: "w-full border rounded-lg overflow-hidden", children: /* @__PURE__ */ jsxs("table", { className: "w-full", children: [
|
|
770
|
+
/* @__PURE__ */ jsx("thead", { className: "bg-gray-50", children: /* @__PURE__ */ jsx("tr", { children: fields.map((field) => /* @__PURE__ */ jsx("th", { className: "px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider", children: field.label }, field.key)) }) }),
|
|
771
|
+
/* @__PURE__ */ jsx("tbody", { className: "bg-white divide-y divide-gray-200", children: items.map((item, index) => /* @__PURE__ */ jsx(
|
|
772
|
+
"tr",
|
|
773
|
+
{
|
|
774
|
+
onClick: () => selectable && onSelect && onSelect(item),
|
|
775
|
+
className: selectable ? "cursor-pointer hover:bg-gray-50" : "",
|
|
776
|
+
children: fields.map((field) => /* @__PURE__ */ jsx("td", { className: "px-6 py-4 whitespace-nowrap text-sm text-gray-500", children: item[field.key] }, field.key))
|
|
777
|
+
},
|
|
778
|
+
index
|
|
779
|
+
)) })
|
|
780
|
+
] }) });
|
|
1706
781
|
var Detail = ({ data, fields = [], title, visible = true, onBack }) => {
|
|
1707
|
-
if (!visible)
|
|
1708
|
-
|
|
1709
|
-
|
|
1710
|
-
|
|
1711
|
-
title && /* @__PURE__ */ jsx("h2", { className: "text-lg font-medium text-gray-800 dark:text-white", children: title }),
|
|
782
|
+
if (!visible) return null;
|
|
783
|
+
return /* @__PURE__ */ jsxs("div", { className: "w-full border rounded-lg p-6 space-y-4", children: [
|
|
784
|
+
/* @__PURE__ */ jsxs("div", { className: "flex justify-between items-center", children: [
|
|
785
|
+
title && /* @__PURE__ */ jsx("h2", { className: "text-lg font-medium", children: title }),
|
|
1712
786
|
onBack && /* @__PURE__ */ jsx(Button, { variant: "outline", onClick: onBack, children: "Back" })
|
|
1713
787
|
] }),
|
|
1714
788
|
/* @__PURE__ */ jsx("div", { className: "space-y-4", children: fields.map((field) => {
|
|
1715
789
|
if (field.type === "heading") {
|
|
1716
|
-
return /* @__PURE__ */ jsx(
|
|
1717
|
-
"h3",
|
|
1718
|
-
{
|
|
1719
|
-
className: "text-xl font-semibold text-gray-800 dark:text-white",
|
|
1720
|
-
children: data?.[field.key] ?? ""
|
|
1721
|
-
},
|
|
1722
|
-
field.key
|
|
1723
|
-
);
|
|
790
|
+
return /* @__PURE__ */ jsx("h3", { className: "text-xl font-semibold", children: data?.[field.key] }, field.key);
|
|
1724
791
|
}
|
|
1725
792
|
if (field.type === "content") {
|
|
1726
|
-
return /* @__PURE__ */ jsx(
|
|
1727
|
-
"div",
|
|
1728
|
-
{
|
|
1729
|
-
className: "text-sm text-gray-700 dark:text-gray-300",
|
|
1730
|
-
children: data?.[field.key] ?? ""
|
|
1731
|
-
},
|
|
1732
|
-
field.key
|
|
1733
|
-
);
|
|
793
|
+
return /* @__PURE__ */ jsx("div", { className: "text-sm text-gray-700", children: data?.[field.key] }, field.key);
|
|
1734
794
|
}
|
|
1735
|
-
return /* @__PURE__ */ jsxs(
|
|
1736
|
-
"
|
|
1737
|
-
{
|
|
1738
|
-
|
|
1739
|
-
children: [
|
|
1740
|
-
field.label && /* @__PURE__ */ jsx("span", { className: "text-xs text-gray-600 dark:text-gray-400 font-medium", children: field.label }),
|
|
1741
|
-
/* @__PURE__ */ jsx("span", { className: "text-sm text-gray-800 dark:text-gray-200", children: data?.[field.key] ?? "" })
|
|
1742
|
-
]
|
|
1743
|
-
},
|
|
1744
|
-
field.key
|
|
1745
|
-
);
|
|
795
|
+
return /* @__PURE__ */ jsxs("div", { className: "flex flex-col", children: [
|
|
796
|
+
field.label && /* @__PURE__ */ jsx("span", { className: "text-xs text-gray-500", children: field.label }),
|
|
797
|
+
/* @__PURE__ */ jsx("span", { className: "text-sm", children: data?.[field.key] })
|
|
798
|
+
] }, field.key);
|
|
1746
799
|
}) })
|
|
1747
800
|
] });
|
|
1748
801
|
};
|
|
1749
|
-
var
|
|
1750
|
-
|
|
1751
|
-
|
|
1752
|
-
|
|
1753
|
-
|
|
1754
|
-
|
|
1755
|
-
|
|
1756
|
-
|
|
1757
|
-
};
|
|
1758
|
-
var isObject = (value) => typeof value === "object" && value !== null;
|
|
1759
|
-
var isString = (value) => typeof value === "string";
|
|
1760
|
-
var isBoolean = (value) => typeof value === "boolean";
|
|
1761
|
-
var isButtonVariant = (value) => isString(value) && ["default", "outline", "destructive"].includes(value);
|
|
1762
|
-
var getSafeBinding = (bindings, key, validator, defaultValue) => {
|
|
1763
|
-
if (bindings && typeof bindings === "object" && key in bindings) {
|
|
1764
|
-
const value = bindings[key];
|
|
1765
|
-
if (validator(value)) {
|
|
1766
|
-
return value;
|
|
1767
|
-
}
|
|
1768
|
-
}
|
|
1769
|
-
return defaultValue;
|
|
1770
|
-
};
|
|
1771
|
-
var isReactNode = (value) => {
|
|
1772
|
-
return typeof value === "string" || typeof value === "number" || typeof value === "boolean" || value === null || typeof value === "undefined" || typeof value === "object" && value !== null && "$$typeof" in value;
|
|
1773
|
-
};
|
|
1774
|
-
var isRecordWithReactNodeValues = (value) => isObject(value) && Object.values(value).every(isReactNode);
|
|
1775
|
-
var isSelectOptionObject = (item) => isObject(item) && isString(item.value) && isString(item.label);
|
|
1776
|
-
var isTabObject = (item) => (
|
|
1777
|
-
// Allow content to be optional initially
|
|
1778
|
-
isObject(item) && isString(item.value) && isString(item.label) && (item.content === void 0 || isUISpecNode(item.content))
|
|
1779
|
-
);
|
|
1780
|
-
var isUISpecNode = (value) => {
|
|
1781
|
-
if (!isObject(value))
|
|
1782
|
-
return false;
|
|
1783
|
-
return isString(value.id) && isString(value.node_type);
|
|
1784
|
-
};
|
|
1785
|
-
var isDetailFieldObject = (item) => isObject(item) && isString(item.key) && isString(item.label) && (item.type === void 0 || isString(item.type));
|
|
1786
|
-
var createEventHandler = (node, eventName, uiEventType2, processEvent2) => {
|
|
1787
|
-
const eventConfig = node.events?.[uiEventType2];
|
|
1788
|
-
if (!processEvent2 || !eventConfig)
|
|
1789
|
-
return void 0;
|
|
1790
|
-
return (eventPayload) => {
|
|
1791
|
-
const fullEvent = {
|
|
1792
|
-
type: uiEventType2,
|
|
1793
|
-
nodeId: node.id,
|
|
1794
|
-
timestamp: Date.now(),
|
|
1795
|
-
payload: {
|
|
1796
|
-
...eventConfig.payload || {},
|
|
1797
|
-
...eventPayload || {}
|
|
1798
|
-
}
|
|
1799
|
-
};
|
|
1800
|
-
processEvent2(fullEvent);
|
|
802
|
+
var createEventHandler = (node, eventName) => {
|
|
803
|
+
const eventConfig = node.events?.[eventName];
|
|
804
|
+
if (!eventConfig) return void 0;
|
|
805
|
+
return () => {
|
|
806
|
+
console.log(`Event triggered: ${eventName} on node ${node.id}`, {
|
|
807
|
+
action: eventConfig.action,
|
|
808
|
+
target: eventConfig.target,
|
|
809
|
+
payload: eventConfig.payload
|
|
810
|
+
});
|
|
1801
811
|
};
|
|
1802
812
|
};
|
|
1803
813
|
var adapterMap = {
|
|
1804
|
-
Container: (node,
|
|
1805
|
-
|
|
1806
|
-
|
|
1807
|
-
|
|
1808
|
-
// Use React.cloneElement to add the key prop to the element returned by renderNode
|
|
1809
|
-
React.cloneElement(renderNode(child, processEvent2), { key: child.id })
|
|
1810
|
-
)
|
|
1811
|
-
);
|
|
1812
|
-
const style = typeof styleProp === "string" ? parseStyleString(styleProp) : styleProp;
|
|
1813
|
-
return /* @__PURE__ */ jsxs(
|
|
1814
|
-
"div",
|
|
1815
|
-
{
|
|
1816
|
-
className: cn("autoui-container", className),
|
|
1817
|
-
style,
|
|
1818
|
-
...restProps,
|
|
1819
|
-
"data-id": node.id,
|
|
1820
|
-
children: [
|
|
1821
|
-
(() => {
|
|
1822
|
-
console.log(
|
|
1823
|
-
`[Adapter Debug] Rendering Container: id=${node.id}, props=`,
|
|
1824
|
-
node.props
|
|
1825
|
-
);
|
|
1826
|
-
return null;
|
|
1827
|
-
})(),
|
|
1828
|
-
children
|
|
1829
|
-
]
|
|
1830
|
-
},
|
|
1831
|
-
key
|
|
1832
|
-
);
|
|
1833
|
-
},
|
|
1834
|
-
Header: (node) => /* @__PURE__ */ jsx(
|
|
1835
|
-
Header,
|
|
814
|
+
Container: (node) => /* @__PURE__ */ jsx(Container, { style: node.props?.style, className: node.props?.className, children: node.children?.map((child) => renderNode(child)) }),
|
|
815
|
+
Header: (node) => /* @__PURE__ */ jsx(Header, { title: node.props?.title || "Untitled" }),
|
|
816
|
+
Button: (node) => /* @__PURE__ */ jsx(
|
|
817
|
+
Button,
|
|
1836
818
|
{
|
|
1837
|
-
|
|
1838
|
-
|
|
819
|
+
variant: node.props?.variant,
|
|
820
|
+
onClick: createEventHandler(node, "onClick"),
|
|
821
|
+
children: node.props?.label || "Button"
|
|
1839
822
|
}
|
|
1840
823
|
),
|
|
1841
|
-
|
|
1842
|
-
|
|
824
|
+
ListView: (node) => /* @__PURE__ */ jsx(
|
|
825
|
+
Table,
|
|
1843
826
|
{
|
|
1844
|
-
|
|
1845
|
-
|
|
1846
|
-
|
|
827
|
+
items: node.bindings?.items || [],
|
|
828
|
+
fields: node.bindings?.fields || [],
|
|
829
|
+
selectable: node.props?.selectable,
|
|
830
|
+
onSelect: createEventHandler(node, "onSelect")
|
|
1847
831
|
}
|
|
1848
832
|
),
|
|
1849
|
-
|
|
1850
|
-
|
|
1851
|
-
|
|
1852
|
-
|
|
1853
|
-
|
|
1854
|
-
node.props
|
|
1855
|
-
|
|
1856
|
-
|
|
1857
|
-
(child) => React.cloneElement(renderNode(child, processEvent2), { key: child.id })
|
|
1858
|
-
);
|
|
1859
|
-
return /* @__PURE__ */ jsx(
|
|
1860
|
-
"div",
|
|
1861
|
-
{
|
|
1862
|
-
className: cn(
|
|
1863
|
-
"autoui-listview-container space-y-2",
|
|
1864
|
-
className
|
|
1865
|
-
),
|
|
1866
|
-
style,
|
|
1867
|
-
...restProps,
|
|
1868
|
-
"data-id": node.id,
|
|
1869
|
-
children
|
|
1870
|
-
},
|
|
1871
|
-
key
|
|
1872
|
-
);
|
|
1873
|
-
},
|
|
1874
|
-
Detail: (node, processEvent2) => {
|
|
1875
|
-
const data = getSafeBinding(
|
|
1876
|
-
node.bindings,
|
|
1877
|
-
"data",
|
|
1878
|
-
isRecordWithReactNodeValues,
|
|
1879
|
-
{}
|
|
1880
|
-
);
|
|
1881
|
-
const fields = getSafeBinding(
|
|
1882
|
-
node.bindings,
|
|
1883
|
-
"fields",
|
|
1884
|
-
isArrayOf(isDetailFieldObject),
|
|
1885
|
-
[]
|
|
1886
|
-
);
|
|
1887
|
-
const title = getSafeProp(node.props, "title", isString, "");
|
|
1888
|
-
const visible = getSafeProp(node.props, "visible", isBoolean, true);
|
|
1889
|
-
return /* @__PURE__ */ jsx(
|
|
1890
|
-
Detail,
|
|
1891
|
-
{
|
|
1892
|
-
data,
|
|
1893
|
-
fields,
|
|
1894
|
-
title,
|
|
1895
|
-
visible,
|
|
1896
|
-
onBack: createEventHandler(node, "onBack", "CLICK", processEvent2)
|
|
1897
|
-
}
|
|
1898
|
-
);
|
|
1899
|
-
},
|
|
1900
|
-
Card: (node, processEvent2) => {
|
|
1901
|
-
const { className, style: styleProp, key, ...restProps } = node.props || {};
|
|
1902
|
-
const children = node.children?.map(
|
|
1903
|
-
(child) => React.cloneElement(renderNode(child, processEvent2), { key: child.id })
|
|
1904
|
-
);
|
|
1905
|
-
const style = typeof styleProp === "string" ? parseStyleString(styleProp) : styleProp;
|
|
1906
|
-
return /* @__PURE__ */ jsx(
|
|
1907
|
-
Card,
|
|
1908
|
-
{
|
|
1909
|
-
className: cn("autoui-card", className),
|
|
1910
|
-
style,
|
|
1911
|
-
...restProps,
|
|
1912
|
-
"data-id": node.id,
|
|
1913
|
-
children: /* @__PURE__ */ jsxs(CardContent, { className: "p-0", children: [
|
|
1914
|
-
" ",
|
|
1915
|
-
children
|
|
1916
|
-
] })
|
|
1917
|
-
},
|
|
1918
|
-
key
|
|
1919
|
-
);
|
|
1920
|
-
},
|
|
1921
|
-
Input: (node, processEvent2) => {
|
|
1922
|
-
const name = getSafeProp(node.props, "name", isString, "inputName");
|
|
1923
|
-
const label = getSafeProp(node.props, "label", isString, "");
|
|
1924
|
-
const value = getSafeBinding(node.bindings, "value", isString, "");
|
|
1925
|
-
const placeholder = getSafeProp(node.props, "placeholder", isString, "");
|
|
1926
|
-
const disabled = getSafeProp(node.props, "disabled", isBoolean, false);
|
|
1927
|
-
const className = getSafeProp(node.props, "className", isString, "");
|
|
1928
|
-
const handleChange = (e) => {
|
|
1929
|
-
const handler = createEventHandler(
|
|
1930
|
-
node,
|
|
1931
|
-
"onChange",
|
|
1932
|
-
"CHANGE",
|
|
1933
|
-
processEvent2
|
|
1934
|
-
);
|
|
1935
|
-
if (handler)
|
|
1936
|
-
handler({ value: e.target.value });
|
|
1937
|
-
};
|
|
1938
|
-
const handleFocus = () => {
|
|
1939
|
-
const handler = createEventHandler(
|
|
1940
|
-
node,
|
|
1941
|
-
"onFocus",
|
|
1942
|
-
"FOCUS",
|
|
1943
|
-
processEvent2
|
|
1944
|
-
);
|
|
1945
|
-
if (handler)
|
|
1946
|
-
handler({});
|
|
1947
|
-
};
|
|
1948
|
-
const handleBlur = () => {
|
|
1949
|
-
const handler = createEventHandler(node, "onBlur", "BLUR", processEvent2);
|
|
1950
|
-
if (handler)
|
|
1951
|
-
handler({});
|
|
1952
|
-
};
|
|
1953
|
-
return /* @__PURE__ */ jsxs("div", { className: "grid w-full max-w-sm items-center gap-1.5", children: [
|
|
1954
|
-
label && /* @__PURE__ */ jsx(Label2, { htmlFor: name, children: label }),
|
|
1955
|
-
/* @__PURE__ */ jsx(
|
|
1956
|
-
Input,
|
|
1957
|
-
{
|
|
1958
|
-
id: name,
|
|
1959
|
-
name,
|
|
1960
|
-
placeholder,
|
|
1961
|
-
disabled,
|
|
1962
|
-
value,
|
|
1963
|
-
onChange: handleChange,
|
|
1964
|
-
onFocus: handleFocus,
|
|
1965
|
-
onBlur: handleBlur,
|
|
1966
|
-
className
|
|
1967
|
-
}
|
|
1968
|
-
)
|
|
1969
|
-
] });
|
|
1970
|
-
},
|
|
1971
|
-
Select: (node, processEvent2) => {
|
|
1972
|
-
const name = getSafeProp(node.props, "name", isString, "selectName");
|
|
1973
|
-
const label = getSafeProp(node.props, "label", isString, "");
|
|
1974
|
-
const placeholder = getSafeProp(
|
|
1975
|
-
node.props,
|
|
1976
|
-
"placeholder",
|
|
1977
|
-
isString,
|
|
1978
|
-
"Select..."
|
|
1979
|
-
);
|
|
1980
|
-
const disabled = getSafeProp(node.props, "disabled", isBoolean, false);
|
|
1981
|
-
const value = getSafeBinding(node.bindings, "value", isString, "");
|
|
1982
|
-
const options = getSafeBinding(
|
|
1983
|
-
node.bindings,
|
|
1984
|
-
"options",
|
|
1985
|
-
isArrayOf(isSelectOptionObject),
|
|
1986
|
-
[]
|
|
1987
|
-
);
|
|
1988
|
-
const className = getSafeProp(node.props, "className", isString, "");
|
|
1989
|
-
const handleValueChange = (selectedValue) => {
|
|
1990
|
-
const handler = createEventHandler(
|
|
1991
|
-
node,
|
|
1992
|
-
"onValueChange",
|
|
1993
|
-
"CHANGE",
|
|
1994
|
-
processEvent2
|
|
1995
|
-
);
|
|
1996
|
-
if (handler)
|
|
1997
|
-
handler({ value: selectedValue });
|
|
1998
|
-
};
|
|
1999
|
-
return /* @__PURE__ */ jsxs(
|
|
2000
|
-
"div",
|
|
2001
|
-
{
|
|
2002
|
-
className: cn("grid w-full max-w-sm items-center gap-1.5", className),
|
|
2003
|
-
children: [
|
|
2004
|
-
label && /* @__PURE__ */ jsx(Label2, { htmlFor: name, children: label }),
|
|
2005
|
-
/* @__PURE__ */ jsxs(
|
|
2006
|
-
Select,
|
|
2007
|
-
{
|
|
2008
|
-
name,
|
|
2009
|
-
value,
|
|
2010
|
-
onValueChange: handleValueChange,
|
|
2011
|
-
disabled,
|
|
2012
|
-
children: [
|
|
2013
|
-
/* @__PURE__ */ jsx(SelectTrigger, { id: name, children: /* @__PURE__ */ jsx(SelectValue, { placeholder }) }),
|
|
2014
|
-
/* @__PURE__ */ jsx(SelectContent, { children: options.map((option) => /* @__PURE__ */ jsx(SelectItem, { value: option.value, children: option.label }, option.value)) })
|
|
2015
|
-
]
|
|
2016
|
-
}
|
|
2017
|
-
)
|
|
2018
|
-
]
|
|
2019
|
-
}
|
|
2020
|
-
);
|
|
2021
|
-
},
|
|
2022
|
-
Textarea: (node, processEvent2) => {
|
|
2023
|
-
const { key, ...propsWithoutKey } = node.props || {};
|
|
2024
|
-
const name = getSafeProp(propsWithoutKey, "name", isString, "textareaName");
|
|
2025
|
-
const label = getSafeProp(propsWithoutKey, "label", isString, "");
|
|
2026
|
-
const placeholder = getSafeProp(
|
|
2027
|
-
propsWithoutKey,
|
|
2028
|
-
"placeholder",
|
|
2029
|
-
isString,
|
|
2030
|
-
""
|
|
2031
|
-
);
|
|
2032
|
-
const disabled = getSafeProp(propsWithoutKey, "disabled", isBoolean, false);
|
|
2033
|
-
const rows = getSafeProp(
|
|
2034
|
-
propsWithoutKey,
|
|
2035
|
-
"rows",
|
|
2036
|
-
(v) => typeof v === "number",
|
|
2037
|
-
3
|
|
2038
|
-
);
|
|
2039
|
-
const value = getSafeBinding(node.bindings, "value", isString, "");
|
|
2040
|
-
const className = getSafeProp(propsWithoutKey, "className", isString, "");
|
|
2041
|
-
const handleChange = (e) => {
|
|
2042
|
-
const handler = createEventHandler(
|
|
2043
|
-
node,
|
|
2044
|
-
"onChange",
|
|
2045
|
-
"CHANGE",
|
|
2046
|
-
processEvent2
|
|
2047
|
-
);
|
|
2048
|
-
if (handler)
|
|
2049
|
-
handler({ value: e.target.value });
|
|
2050
|
-
};
|
|
2051
|
-
const handleFocus = () => {
|
|
2052
|
-
const handler = createEventHandler(
|
|
2053
|
-
node,
|
|
2054
|
-
"onFocus",
|
|
2055
|
-
"FOCUS",
|
|
2056
|
-
processEvent2
|
|
2057
|
-
);
|
|
2058
|
-
if (handler)
|
|
2059
|
-
handler({});
|
|
2060
|
-
};
|
|
2061
|
-
const handleBlur = () => {
|
|
2062
|
-
const handler = createEventHandler(node, "onBlur", "BLUR", processEvent2);
|
|
2063
|
-
if (handler)
|
|
2064
|
-
handler({});
|
|
2065
|
-
};
|
|
2066
|
-
return /* @__PURE__ */ jsxs("div", { className: "grid w-full gap-1.5", children: [
|
|
2067
|
-
label && /* @__PURE__ */ jsx(Label2, { htmlFor: name, children: label }),
|
|
2068
|
-
/* @__PURE__ */ jsx(
|
|
2069
|
-
Textarea,
|
|
2070
|
-
{
|
|
2071
|
-
id: name,
|
|
2072
|
-
name,
|
|
2073
|
-
placeholder,
|
|
2074
|
-
disabled,
|
|
2075
|
-
rows,
|
|
2076
|
-
value,
|
|
2077
|
-
onChange: handleChange,
|
|
2078
|
-
onFocus: handleFocus,
|
|
2079
|
-
onBlur: handleBlur,
|
|
2080
|
-
className
|
|
2081
|
-
}
|
|
2082
|
-
)
|
|
2083
|
-
] }, key);
|
|
2084
|
-
},
|
|
2085
|
-
Checkbox: (node, processEvent2) => {
|
|
2086
|
-
const { key, ...propsWithoutKey } = node.props || {};
|
|
2087
|
-
const name = getSafeProp(propsWithoutKey, "name", isString, "checkboxName");
|
|
2088
|
-
const label = getSafeProp(propsWithoutKey, "label", isString, "");
|
|
2089
|
-
const checked = getSafeBinding(node.bindings, "checked", isBoolean, false);
|
|
2090
|
-
const disabled = getSafeProp(propsWithoutKey, "disabled", isBoolean, false);
|
|
2091
|
-
const className = getSafeProp(propsWithoutKey, "className", isString, "");
|
|
2092
|
-
const handleCheckedChange = (isChecked) => {
|
|
2093
|
-
if (typeof isChecked === "boolean") {
|
|
2094
|
-
const handler = createEventHandler(
|
|
2095
|
-
node,
|
|
2096
|
-
"onCheckedChange",
|
|
2097
|
-
"CHANGE",
|
|
2098
|
-
processEvent2
|
|
2099
|
-
);
|
|
2100
|
-
if (handler)
|
|
2101
|
-
handler({ checked: isChecked });
|
|
2102
|
-
}
|
|
2103
|
-
};
|
|
2104
|
-
return /* @__PURE__ */ jsxs(
|
|
2105
|
-
"div",
|
|
2106
|
-
{
|
|
2107
|
-
className: cn("flex items-center space-x-2", className),
|
|
2108
|
-
children: [
|
|
2109
|
-
/* @__PURE__ */ jsx(
|
|
2110
|
-
Checkbox,
|
|
2111
|
-
{
|
|
2112
|
-
id: name,
|
|
2113
|
-
name,
|
|
2114
|
-
checked,
|
|
2115
|
-
disabled,
|
|
2116
|
-
onCheckedChange: handleCheckedChange
|
|
2117
|
-
}
|
|
2118
|
-
),
|
|
2119
|
-
label && /* @__PURE__ */ jsx(Label2, { htmlFor: name, className: "cursor-pointer", children: label })
|
|
2120
|
-
]
|
|
2121
|
-
},
|
|
2122
|
-
key
|
|
2123
|
-
);
|
|
2124
|
-
},
|
|
2125
|
-
RadioGroup: (node, processEvent2) => {
|
|
2126
|
-
const { key, ...propsWithoutKey } = node.props || {};
|
|
2127
|
-
const name = getSafeProp(
|
|
2128
|
-
propsWithoutKey,
|
|
2129
|
-
"name",
|
|
2130
|
-
isString,
|
|
2131
|
-
"radioGroupName"
|
|
2132
|
-
);
|
|
2133
|
-
const label = getSafeProp(propsWithoutKey, "label", isString, "");
|
|
2134
|
-
const value = getSafeBinding(node.bindings, "value", isString, "");
|
|
2135
|
-
const options = getSafeBinding(
|
|
2136
|
-
node.bindings,
|
|
2137
|
-
"options",
|
|
2138
|
-
isArrayOf(isSelectOptionObject),
|
|
2139
|
-
[]
|
|
2140
|
-
);
|
|
2141
|
-
const disabled = getSafeProp(propsWithoutKey, "disabled", isBoolean, false);
|
|
2142
|
-
const className = getSafeProp(propsWithoutKey, "className", isString, "");
|
|
2143
|
-
const handleValueChange = (selectedValue) => {
|
|
2144
|
-
const handler = createEventHandler(
|
|
2145
|
-
node,
|
|
2146
|
-
"onValueChange",
|
|
2147
|
-
"CHANGE",
|
|
2148
|
-
processEvent2
|
|
2149
|
-
);
|
|
2150
|
-
if (handler)
|
|
2151
|
-
handler({ value: selectedValue });
|
|
2152
|
-
};
|
|
2153
|
-
return /* @__PURE__ */ jsxs(
|
|
2154
|
-
"div",
|
|
2155
|
-
{
|
|
2156
|
-
className: cn("grid gap-1.5", className),
|
|
2157
|
-
children: [
|
|
2158
|
-
label && /* @__PURE__ */ jsx(Label2, { className: "mb-1", children: label }),
|
|
2159
|
-
/* @__PURE__ */ jsx(
|
|
2160
|
-
RadioGroup,
|
|
2161
|
-
{
|
|
2162
|
-
name,
|
|
2163
|
-
value,
|
|
2164
|
-
onValueChange: handleValueChange,
|
|
2165
|
-
disabled,
|
|
2166
|
-
className: "flex flex-col space-y-1",
|
|
2167
|
-
children: options.map((option) => /* @__PURE__ */ jsxs("div", { className: "flex items-center space-x-2", children: [
|
|
2168
|
-
/* @__PURE__ */ jsx(
|
|
2169
|
-
RadioGroupItem,
|
|
2170
|
-
{
|
|
2171
|
-
value: option.value,
|
|
2172
|
-
id: `${name}-${option.value}`
|
|
2173
|
-
}
|
|
2174
|
-
),
|
|
2175
|
-
/* @__PURE__ */ jsx(
|
|
2176
|
-
Label2,
|
|
2177
|
-
{
|
|
2178
|
-
htmlFor: `${name}-${option.value}`,
|
|
2179
|
-
className: "cursor-pointer",
|
|
2180
|
-
children: option.label
|
|
2181
|
-
}
|
|
2182
|
-
)
|
|
2183
|
-
] }, option.value))
|
|
2184
|
-
}
|
|
2185
|
-
)
|
|
2186
|
-
]
|
|
2187
|
-
},
|
|
2188
|
-
key
|
|
2189
|
-
);
|
|
2190
|
-
},
|
|
2191
|
-
Tabs: (node, processEvent2) => {
|
|
2192
|
-
const { key, ...propsWithoutKey } = node.props || {};
|
|
2193
|
-
const rawTabs = getSafeBinding(
|
|
2194
|
-
node.bindings,
|
|
2195
|
-
"tabs",
|
|
2196
|
-
isArrayOf(isTabObject),
|
|
2197
|
-
[]
|
|
2198
|
-
);
|
|
2199
|
-
const defaultValue = getSafeProp(
|
|
2200
|
-
propsWithoutKey,
|
|
2201
|
-
"defaultValue",
|
|
2202
|
-
isString,
|
|
2203
|
-
rawTabs[0]?.value || ""
|
|
2204
|
-
);
|
|
2205
|
-
const className = getSafeProp(propsWithoutKey, "className", isString, "");
|
|
2206
|
-
const handleValueChange = (value) => {
|
|
2207
|
-
const handler = createEventHandler(
|
|
2208
|
-
node,
|
|
2209
|
-
"onValueChange",
|
|
2210
|
-
"CHANGE",
|
|
2211
|
-
processEvent2
|
|
2212
|
-
);
|
|
2213
|
-
if (handler)
|
|
2214
|
-
handler({ value });
|
|
2215
|
-
};
|
|
2216
|
-
return /* @__PURE__ */ jsxs(
|
|
2217
|
-
Tabs,
|
|
2218
|
-
{
|
|
2219
|
-
defaultValue,
|
|
2220
|
-
onValueChange: handleValueChange,
|
|
2221
|
-
className: cn("autoui-tabs w-full", className),
|
|
2222
|
-
"data-id": node.id,
|
|
2223
|
-
children: [
|
|
2224
|
-
/* @__PURE__ */ jsx(TabsList, { children: rawTabs.map((tab) => /* @__PURE__ */ jsx(TabsTrigger, { value: tab.value, children: tab.label }, tab.value)) }),
|
|
2225
|
-
rawTabs.map((tab) => /* @__PURE__ */ jsx(TabsContent, { value: tab.value, children: tab.content ? renderNode(tab.content, processEvent2) : null }, tab.value))
|
|
2226
|
-
]
|
|
2227
|
-
},
|
|
2228
|
-
key
|
|
2229
|
-
);
|
|
2230
|
-
},
|
|
2231
|
-
Dialog: (node, processEvent2) => {
|
|
2232
|
-
const isOpen = getSafeBinding(
|
|
2233
|
-
node.bindings,
|
|
2234
|
-
"open",
|
|
2235
|
-
isBoolean,
|
|
2236
|
-
getSafeProp(node.props, "open", isBoolean, false)
|
|
2237
|
-
);
|
|
2238
|
-
const {
|
|
2239
|
-
title,
|
|
2240
|
-
description,
|
|
2241
|
-
className,
|
|
2242
|
-
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
2243
|
-
style: _styleProp,
|
|
2244
|
-
key,
|
|
2245
|
-
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
2246
|
-
open: _openProp,
|
|
2247
|
-
...restProps
|
|
2248
|
-
} = node.props || {};
|
|
2249
|
-
const children = node.children?.map(
|
|
2250
|
-
(child) => React.cloneElement(renderNode(child, processEvent2), { key: child.id })
|
|
2251
|
-
);
|
|
2252
|
-
const handleOpenChange = (open) => {
|
|
2253
|
-
if (!open) {
|
|
2254
|
-
const handler = createEventHandler(
|
|
2255
|
-
node,
|
|
2256
|
-
"onClose",
|
|
2257
|
-
// Assumed event name in UISpec
|
|
2258
|
-
"CLICK",
|
|
2259
|
-
// Use CLICK as the event type for closing dialogs
|
|
2260
|
-
processEvent2
|
|
2261
|
-
);
|
|
2262
|
-
if (handler) {
|
|
2263
|
-
handler({});
|
|
2264
|
-
}
|
|
2265
|
-
}
|
|
2266
|
-
};
|
|
2267
|
-
console.log(
|
|
2268
|
-
`[Adapter Debug] Rendering Dialog: id=${node.id}, props=`,
|
|
2269
|
-
node.props,
|
|
2270
|
-
`isOpen=${isOpen}`
|
|
2271
|
-
);
|
|
2272
|
-
return /* @__PURE__ */ jsx(
|
|
2273
|
-
Dialog,
|
|
2274
|
-
{
|
|
2275
|
-
open: isOpen,
|
|
2276
|
-
onOpenChange: handleOpenChange,
|
|
2277
|
-
children: /* @__PURE__ */ jsxs(
|
|
2278
|
-
DialogContent,
|
|
2279
|
-
{
|
|
2280
|
-
className: cn("autoui-dialog-content", className),
|
|
2281
|
-
...restProps,
|
|
2282
|
-
"data-id": node.id,
|
|
2283
|
-
children: [
|
|
2284
|
-
(title || description) && /* @__PURE__ */ jsxs(DialogHeader, { children: [
|
|
2285
|
-
title && /* @__PURE__ */ jsx(DialogTitle, { children: title }),
|
|
2286
|
-
description && /* @__PURE__ */ jsx(DialogDescription, { children: description })
|
|
2287
|
-
] }),
|
|
2288
|
-
children
|
|
2289
|
-
]
|
|
2290
|
-
}
|
|
2291
|
-
)
|
|
2292
|
-
},
|
|
2293
|
-
key
|
|
2294
|
-
);
|
|
2295
|
-
},
|
|
2296
|
-
Heading: (node) => {
|
|
2297
|
-
const { className, style: styleProp, key, ...restProps } = node.props || {};
|
|
2298
|
-
const text = getSafeProp(node.props, "text", isString, "Heading");
|
|
2299
|
-
let level = getSafeProp(
|
|
2300
|
-
node.props,
|
|
2301
|
-
"level",
|
|
2302
|
-
(v) => typeof v === "number" && v >= 1 && v <= 6,
|
|
2303
|
-
2
|
|
2304
|
-
);
|
|
2305
|
-
if (typeof level !== "number" || level < 1 || level > 6) {
|
|
2306
|
-
level = 2;
|
|
833
|
+
Detail: (node) => /* @__PURE__ */ jsx(
|
|
834
|
+
Detail,
|
|
835
|
+
{
|
|
836
|
+
data: node.bindings?.data,
|
|
837
|
+
fields: node.bindings?.fields || [],
|
|
838
|
+
title: node.props?.title,
|
|
839
|
+
visible: node.props?.visible !== false,
|
|
840
|
+
onBack: createEventHandler(node, "onBack")
|
|
2307
841
|
}
|
|
2308
|
-
|
|
2309
|
-
const style = typeof styleProp === "string" ? parseStyleString(styleProp) : styleProp;
|
|
2310
|
-
const headingStyles = {
|
|
2311
|
-
1: "scroll-m-20 text-4xl font-extrabold tracking-tight lg:text-5xl",
|
|
2312
|
-
2: "scroll-m-20 border-b pb-2 text-3xl font-semibold tracking-tight first:mt-0",
|
|
2313
|
-
3: "scroll-m-20 text-2xl font-semibold tracking-tight",
|
|
2314
|
-
4: "scroll-m-20 text-xl font-semibold tracking-tight"
|
|
2315
|
-
// Add styles for h5, h6 if needed, using text-lg, text-base etc.
|
|
2316
|
-
}[level] || "text-lg font-semibold";
|
|
2317
|
-
return /* @__PURE__ */ jsx(
|
|
2318
|
-
Tag,
|
|
2319
|
-
{
|
|
2320
|
-
className: cn(headingStyles, className),
|
|
2321
|
-
style,
|
|
2322
|
-
...restProps,
|
|
2323
|
-
children: text
|
|
2324
|
-
},
|
|
2325
|
-
key
|
|
2326
|
-
);
|
|
2327
|
-
},
|
|
2328
|
-
Text: (node) => {
|
|
2329
|
-
const { className, style: styleProp, key, ...restProps } = node.props || {};
|
|
2330
|
-
const text = getSafeProp(node.props, "text", isString, "Some text");
|
|
2331
|
-
const style = typeof styleProp === "string" ? parseStyleString(styleProp) : styleProp;
|
|
2332
|
-
return /* @__PURE__ */ jsx(
|
|
2333
|
-
"p",
|
|
2334
|
-
{
|
|
2335
|
-
className: cn("leading-7", className),
|
|
2336
|
-
style,
|
|
2337
|
-
...restProps,
|
|
2338
|
-
children: text
|
|
2339
|
-
},
|
|
2340
|
-
key
|
|
2341
|
-
);
|
|
2342
|
-
}
|
|
842
|
+
)
|
|
2343
843
|
};
|
|
2344
|
-
function renderNode(node
|
|
2345
|
-
const
|
|
2346
|
-
if (
|
|
2347
|
-
return
|
|
2348
|
-
}
|
|
2349
|
-
|
|
2350
|
-
|
|
2351
|
-
|
|
2352
|
-
|
|
2353
|
-
|
|
2354
|
-
|
|
844
|
+
function renderNode(node) {
|
|
845
|
+
const Component = adapterMap[node.type];
|
|
846
|
+
if (Component) {
|
|
847
|
+
return Component(node);
|
|
848
|
+
}
|
|
849
|
+
return /* @__PURE__ */ jsxs("div", { className: "p-2 border border-red-300 rounded", children: [
|
|
850
|
+
/* @__PURE__ */ jsxs("p", { className: "text-sm text-red-500", children: [
|
|
851
|
+
"Unsupported component: ",
|
|
852
|
+
node.type
|
|
853
|
+
] }),
|
|
854
|
+
node.children?.map((child) => renderNode(child))
|
|
855
|
+
] });
|
|
2355
856
|
}
|
|
2356
|
-
|
|
2357
|
-
var MAX_CACHE_SIZE = 10;
|
|
2358
|
-
var CACHE_TTL = 5e3;
|
|
2359
|
-
async function renderNode2(node, adapter = "shadcn", processEvent2) {
|
|
857
|
+
async function renderNode2(node, adapter = "shadcn") {
|
|
2360
858
|
const startTime = Date.now();
|
|
2361
|
-
const nodeId = node.id;
|
|
2362
|
-
const cachedItem = renderedNodesCache.get(nodeId);
|
|
2363
|
-
if (cachedItem && startTime - cachedItem.timestamp < CACHE_TTL) {
|
|
2364
|
-
return cachedItem.element;
|
|
2365
|
-
}
|
|
2366
859
|
await systemEvents.emit(
|
|
2367
860
|
createSystemEvent("RENDER_START" /* RENDER_START */, { layout: node })
|
|
2368
861
|
);
|
|
2369
862
|
let result;
|
|
2370
863
|
switch (adapter) {
|
|
2371
864
|
case "shadcn":
|
|
2372
|
-
result = renderNode(node
|
|
865
|
+
result = renderNode(node);
|
|
2373
866
|
break;
|
|
2374
867
|
default:
|
|
2375
868
|
console.warn(`Unsupported adapter: ${adapter}, falling back to shadcn`);
|
|
2376
|
-
result = renderNode(node
|
|
869
|
+
result = renderNode(node);
|
|
2377
870
|
}
|
|
2378
871
|
await systemEvents.emit(
|
|
2379
872
|
createSystemEvent("RENDER_COMPLETE" /* RENDER_COMPLETE */, {
|
|
@@ -2381,23 +874,13 @@ async function renderNode2(node, adapter = "shadcn", processEvent2) {
|
|
|
2381
874
|
renderTimeMs: Date.now() - startTime
|
|
2382
875
|
})
|
|
2383
876
|
);
|
|
2384
|
-
renderedNodesCache.set(nodeId, {
|
|
2385
|
-
element: result,
|
|
2386
|
-
timestamp: startTime
|
|
2387
|
-
});
|
|
2388
|
-
if (renderedNodesCache.size > MAX_CACHE_SIZE) {
|
|
2389
|
-
const oldestKey = [...renderedNodesCache.entries()].sort(
|
|
2390
|
-
([, a], [, b]) => a.timestamp - b.timestamp
|
|
2391
|
-
)[0][0];
|
|
2392
|
-
renderedNodesCache.delete(oldestKey);
|
|
2393
|
-
}
|
|
2394
877
|
return result;
|
|
2395
878
|
}
|
|
2396
879
|
function renderShimmer(node, adapter = "shadcn") {
|
|
2397
880
|
if (!node) {
|
|
2398
881
|
return /* @__PURE__ */ jsx(ShimmerBlock, {});
|
|
2399
882
|
}
|
|
2400
|
-
switch (node.
|
|
883
|
+
switch (node.type) {
|
|
2401
884
|
case "ListView":
|
|
2402
885
|
return /* @__PURE__ */ jsx(ShimmerTable, { rows: 3 });
|
|
2403
886
|
case "Detail":
|
|
@@ -2410,16 +893,6 @@ function renderShimmer(node, adapter = "shadcn") {
|
|
|
2410
893
|
}
|
|
2411
894
|
|
|
2412
895
|
// src/core/bindings.ts
|
|
2413
|
-
var bindingsCache = /* @__PURE__ */ new Map();
|
|
2414
|
-
var MAX_CACHE_SIZE2 = 50;
|
|
2415
|
-
var CACHE_TTL2 = 2e3;
|
|
2416
|
-
var nodeCacheTimestamps = /* @__PURE__ */ new Map();
|
|
2417
|
-
function hashDataContext(context) {
|
|
2418
|
-
return JSON.stringify(context);
|
|
2419
|
-
}
|
|
2420
|
-
function createCacheKey(nodeId, context) {
|
|
2421
|
-
return `${nodeId}:${hashDataContext(context)}`;
|
|
2422
|
-
}
|
|
2423
896
|
function getValueByPath(context, path) {
|
|
2424
897
|
const parts = path.split(".");
|
|
2425
898
|
let current = context;
|
|
@@ -2435,265 +908,68 @@ function getValueByPath(context, path) {
|
|
|
2435
908
|
return current;
|
|
2436
909
|
}
|
|
2437
910
|
function setValueByPath(context, path, value) {
|
|
2438
|
-
if (!path) {
|
|
2439
|
-
return context;
|
|
2440
|
-
}
|
|
2441
911
|
const result = { ...context };
|
|
2442
912
|
const parts = path.split(".");
|
|
2443
913
|
let current = result;
|
|
2444
914
|
for (let i = 0; i < parts.length - 1; i++) {
|
|
2445
915
|
const part = parts[i];
|
|
2446
|
-
if (
|
|
2447
|
-
|
|
2448
|
-
`setValueByPath: Cannot traverse path "${path}". Parent segment "${parts[i - 1] || "(root)"}" is not an object.`
|
|
2449
|
-
);
|
|
2450
|
-
return context;
|
|
916
|
+
if (!(part in current) || current[part] === null || current[part] === void 0) {
|
|
917
|
+
current[part] = {};
|
|
2451
918
|
}
|
|
2452
|
-
|
|
2453
|
-
|
|
2454
|
-
|
|
2455
|
-
currentAsObject[part] = {};
|
|
2456
|
-
} else if (typeof nextPartValue !== "object") {
|
|
2457
|
-
console.warn(
|
|
2458
|
-
`setValueByPath: Cannot create nested path "${path}". Segment "${part}" is not an object.`
|
|
2459
|
-
);
|
|
2460
|
-
return context;
|
|
2461
|
-
} else {
|
|
2462
|
-
currentAsObject[part] = { ...nextPartValue };
|
|
919
|
+
current = current[part];
|
|
920
|
+
if (typeof current !== "object") {
|
|
921
|
+
current = {};
|
|
2463
922
|
}
|
|
2464
|
-
current = currentAsObject[part];
|
|
2465
923
|
}
|
|
2466
924
|
const lastPart = parts[parts.length - 1];
|
|
2467
|
-
|
|
2468
|
-
current[lastPart] = value;
|
|
2469
|
-
} else {
|
|
2470
|
-
console.warn(
|
|
2471
|
-
`setValueByPath: Could not set value for path "${path}". Final segment parent is not an object.`
|
|
2472
|
-
);
|
|
2473
|
-
return context;
|
|
2474
|
-
}
|
|
925
|
+
current[lastPart] = value;
|
|
2475
926
|
return result;
|
|
2476
927
|
}
|
|
2477
|
-
function processBinding(binding, context
|
|
928
|
+
function processBinding(binding, context) {
|
|
2478
929
|
if (typeof binding === "string") {
|
|
2479
|
-
|
|
2480
|
-
const pathInsideExact = exactMatchArr ? exactMatchArr[1].trim() : null;
|
|
2481
|
-
if (pathInsideExact !== null && !pathInsideExact.includes("{{") && !pathInsideExact.includes("}}")) {
|
|
2482
|
-
const pathToResolve = pathInsideExact;
|
|
2483
|
-
let resolvedValue = void 0;
|
|
2484
|
-
console.log(
|
|
2485
|
-
`[processBinding Debug] Processing EXACT template: "${binding}", Path: "${pathToResolve}", Has itemData: ${!!itemData}`
|
|
2486
|
-
);
|
|
2487
|
-
if (itemData) {
|
|
2488
|
-
try {
|
|
2489
|
-
console.log(
|
|
2490
|
-
`[processBinding Debug] itemData content (EXACT):`,
|
|
2491
|
-
JSON.parse(JSON.stringify(itemData))
|
|
2492
|
-
);
|
|
2493
|
-
} catch {
|
|
2494
|
-
}
|
|
2495
|
-
}
|
|
2496
|
-
if ((pathToResolve.startsWith("item.") || pathToResolve.startsWith("row.")) && itemData) {
|
|
2497
|
-
if (pathToResolve.startsWith("item.")) {
|
|
2498
|
-
resolvedValue = getValueByPath(itemData, pathToResolve.substring(5));
|
|
2499
|
-
} else {
|
|
2500
|
-
resolvedValue = getValueByPath(itemData, pathToResolve.substring(4));
|
|
2501
|
-
}
|
|
2502
|
-
} else if (itemData && pathToResolve in itemData) {
|
|
2503
|
-
resolvedValue = getValueByPath(itemData, pathToResolve);
|
|
2504
|
-
}
|
|
2505
|
-
if (resolvedValue === void 0) {
|
|
2506
|
-
resolvedValue = getValueByPath(context, pathToResolve);
|
|
2507
|
-
}
|
|
2508
|
-
return resolvedValue;
|
|
2509
|
-
} else if (binding.includes("{{") && binding.includes("}}")) {
|
|
2510
|
-
console.log(
|
|
2511
|
-
`[processBinding Debug] Processing EMBEDDED templates: "${binding}", Has itemData: ${!!itemData}`
|
|
2512
|
-
);
|
|
2513
|
-
if (itemData) {
|
|
2514
|
-
try {
|
|
2515
|
-
console.log(
|
|
2516
|
-
`[processBinding Debug] itemData content (EMBEDDED):`,
|
|
2517
|
-
JSON.parse(JSON.stringify(itemData))
|
|
2518
|
-
);
|
|
2519
|
-
} catch {
|
|
2520
|
-
}
|
|
2521
|
-
}
|
|
2522
|
-
const resolvedString = binding.replaceAll(
|
|
2523
|
-
/{{(.*?)}}/g,
|
|
2524
|
-
// Non-greedy match inside braces
|
|
2525
|
-
(match, path) => {
|
|
2526
|
-
const trimmedPath = path.trim();
|
|
2527
|
-
let resolvedValue = void 0;
|
|
2528
|
-
if ((trimmedPath.startsWith("item.") || trimmedPath.startsWith("row.")) && itemData) {
|
|
2529
|
-
if (trimmedPath.startsWith("item.")) {
|
|
2530
|
-
resolvedValue = getValueByPath(
|
|
2531
|
-
itemData,
|
|
2532
|
-
trimmedPath.substring(5)
|
|
2533
|
-
);
|
|
2534
|
-
} else {
|
|
2535
|
-
resolvedValue = getValueByPath(
|
|
2536
|
-
itemData,
|
|
2537
|
-
trimmedPath.substring(4)
|
|
2538
|
-
);
|
|
2539
|
-
}
|
|
2540
|
-
} else if (itemData && trimmedPath in itemData) {
|
|
2541
|
-
resolvedValue = getValueByPath(itemData, trimmedPath);
|
|
2542
|
-
}
|
|
2543
|
-
if (resolvedValue === void 0) {
|
|
2544
|
-
resolvedValue = getValueByPath(context, trimmedPath);
|
|
2545
|
-
}
|
|
2546
|
-
return resolvedValue === null || resolvedValue === void 0 ? "" : String(resolvedValue);
|
|
2547
|
-
}
|
|
2548
|
-
);
|
|
2549
|
-
return resolvedString;
|
|
2550
|
-
} else {
|
|
2551
|
-
const pathToResolve = binding;
|
|
2552
|
-
let resolvedValue = void 0;
|
|
2553
|
-
console.log(
|
|
2554
|
-
`[processBinding Debug] Processing PATH string: "${pathToResolve}", Has itemData: ${!!itemData}`
|
|
2555
|
-
);
|
|
2556
|
-
if (itemData && !pathToResolve.includes(".") && pathToResolve in itemData) {
|
|
2557
|
-
resolvedValue = getValueByPath(itemData, pathToResolve);
|
|
2558
|
-
}
|
|
2559
|
-
if (resolvedValue === void 0) {
|
|
2560
|
-
resolvedValue = getValueByPath(context, pathToResolve);
|
|
2561
|
-
}
|
|
2562
|
-
return resolvedValue;
|
|
2563
|
-
}
|
|
930
|
+
return getValueByPath(context, binding);
|
|
2564
931
|
}
|
|
2565
932
|
if (Array.isArray(binding)) {
|
|
2566
|
-
return binding.map((item) => processBinding(item, context
|
|
933
|
+
return binding.map((item) => processBinding(item, context));
|
|
2567
934
|
}
|
|
2568
935
|
if (binding !== null && typeof binding === "object") {
|
|
2569
936
|
const result = {};
|
|
2570
937
|
for (const [key, value] of Object.entries(binding)) {
|
|
2571
|
-
result[key] = processBinding(value, context
|
|
938
|
+
result[key] = processBinding(value, context);
|
|
2572
939
|
}
|
|
2573
940
|
return result;
|
|
2574
941
|
}
|
|
2575
942
|
return binding;
|
|
2576
943
|
}
|
|
2577
|
-
async function resolveBindings(node, context
|
|
2578
|
-
|
|
2579
|
-
|
|
2580
|
-
|
|
2581
|
-
const cachedNode = bindingsCache.get(cacheKey);
|
|
2582
|
-
const cachedTimestamp = nodeCacheTimestamps.get(cacheKey);
|
|
2583
|
-
if (cachedNode && cachedTimestamp && currentTime - cachedTimestamp < CACHE_TTL2) {
|
|
2584
|
-
return cachedNode;
|
|
2585
|
-
}
|
|
2586
|
-
if (!itemData) {
|
|
2587
|
-
await systemEvents.emit(
|
|
2588
|
-
createSystemEvent("BINDING_RESOLUTION_START" /* BINDING_RESOLUTION_START */, {
|
|
2589
|
-
layout: node
|
|
2590
|
-
})
|
|
2591
|
-
);
|
|
2592
|
-
}
|
|
944
|
+
async function resolveBindings(node, context) {
|
|
945
|
+
await systemEvents.emit(
|
|
946
|
+
createSystemEvent("BINDING_RESOLUTION_START" /* BINDING_RESOLUTION_START */, { layout: node })
|
|
947
|
+
);
|
|
2593
948
|
const result = {
|
|
2594
949
|
...node,
|
|
2595
|
-
props: node.props ?
|
|
2596
|
-
events: node.events ?
|
|
2597
|
-
bindings: node.bindings ? JSON.parse(JSON.stringify(node.bindings)) : null,
|
|
2598
|
-
children: null
|
|
2599
|
-
// Initialize children to null
|
|
950
|
+
props: node.props ? { ...node.props } : void 0,
|
|
951
|
+
events: node.events ? { ...node.events } : void 0
|
|
2600
952
|
};
|
|
2601
|
-
const resolvedBindings = {};
|
|
2602
953
|
if (node.bindings) {
|
|
2603
|
-
for (const [key,
|
|
2604
|
-
const
|
|
2605
|
-
|
|
2606
|
-
|
|
2607
|
-
if (!result.props)
|
|
954
|
+
for (const [key, binding] of Object.entries(node.bindings)) {
|
|
955
|
+
const value = processBinding(binding, context);
|
|
956
|
+
if (value !== void 0) {
|
|
957
|
+
if (!result.props) {
|
|
2608
958
|
result.props = {};
|
|
2609
|
-
result.props[key] = resolvedValue;
|
|
2610
|
-
}
|
|
2611
|
-
}
|
|
2612
|
-
}
|
|
2613
|
-
result.bindings = null;
|
|
2614
|
-
if (node.events) {
|
|
2615
|
-
result.events = processBinding(
|
|
2616
|
-
node.events,
|
|
2617
|
-
context,
|
|
2618
|
-
itemData
|
|
2619
|
-
);
|
|
2620
|
-
} else {
|
|
2621
|
-
result.events = null;
|
|
2622
|
-
}
|
|
2623
|
-
const dataBindingValue = resolvedBindings["data"] ?? resolvedBindings["items"];
|
|
2624
|
-
if ((node.node_type === "ListView" || node.node_type === "Table") && Array.isArray(dataBindingValue) && node.children && node.children.length > 0) {
|
|
2625
|
-
const templateChild = node.children[0];
|
|
2626
|
-
const mappedChildren = await Promise.all(
|
|
2627
|
-
dataBindingValue.map(async (currentItemData, index) => {
|
|
2628
|
-
try {
|
|
2629
|
-
if (typeof currentItemData !== "object" || currentItemData === null) {
|
|
2630
|
-
console.warn(
|
|
2631
|
-
`List item at index ${index} for node ${node.id} is not an object:`,
|
|
2632
|
-
currentItemData
|
|
2633
|
-
);
|
|
2634
|
-
return null;
|
|
2635
|
-
}
|
|
2636
|
-
const currentItemAsRecord = currentItemData;
|
|
2637
|
-
const itemId = currentItemAsRecord.id;
|
|
2638
|
-
const instanceId = `${templateChild.id}-${itemId || index}`;
|
|
2639
|
-
const childNodeInstance = JSON.parse(
|
|
2640
|
-
JSON.stringify(templateChild)
|
|
2641
|
-
);
|
|
2642
|
-
childNodeInstance.id = instanceId;
|
|
2643
|
-
const resolvedChild = await resolveBindings(
|
|
2644
|
-
childNodeInstance,
|
|
2645
|
-
context,
|
|
2646
|
-
currentItemAsRecord
|
|
2647
|
-
);
|
|
2648
|
-
if (!resolvedChild.props)
|
|
2649
|
-
resolvedChild.props = {};
|
|
2650
|
-
resolvedChild.props.key = itemId || `${node.id}-item-${index}`;
|
|
2651
|
-
return resolvedChild;
|
|
2652
|
-
} catch (error) {
|
|
2653
|
-
console.error(
|
|
2654
|
-
`[resolveBindings Error] Error processing item at index ${index} for node ${node.id}:`,
|
|
2655
|
-
error,
|
|
2656
|
-
"Item Data:",
|
|
2657
|
-
currentItemData
|
|
2658
|
-
);
|
|
2659
|
-
return null;
|
|
2660
959
|
}
|
|
2661
|
-
|
|
2662
|
-
);
|
|
2663
|
-
result.children = mappedChildren.filter(
|
|
2664
|
-
(child) => child !== null
|
|
2665
|
-
);
|
|
2666
|
-
} else if (node.children && node.children.length > 0) {
|
|
2667
|
-
result.children = await Promise.all(
|
|
2668
|
-
node.children.map((child) => resolveBindings(child, context, itemData))
|
|
2669
|
-
);
|
|
2670
|
-
} else {
|
|
2671
|
-
result.children = [];
|
|
2672
|
-
}
|
|
2673
|
-
if (!itemData) {
|
|
2674
|
-
await systemEvents.emit(
|
|
2675
|
-
createSystemEvent("BINDING_RESOLUTION_COMPLETE" /* BINDING_RESOLUTION_COMPLETE */, {
|
|
2676
|
-
originalLayout: node,
|
|
2677
|
-
resolvedLayout: result
|
|
2678
|
-
})
|
|
2679
|
-
);
|
|
2680
|
-
}
|
|
2681
|
-
bindingsCache.set(cacheKey, result);
|
|
2682
|
-
nodeCacheTimestamps.set(cacheKey, currentTime);
|
|
2683
|
-
if (bindingsCache.size > MAX_CACHE_SIZE2) {
|
|
2684
|
-
let oldestKey = null;
|
|
2685
|
-
let oldestTimestamp = currentTime;
|
|
2686
|
-
for (const [key, timestamp] of nodeCacheTimestamps.entries()) {
|
|
2687
|
-
if (timestamp < oldestTimestamp) {
|
|
2688
|
-
oldestTimestamp = timestamp;
|
|
2689
|
-
oldestKey = key;
|
|
960
|
+
result.props[key] = value;
|
|
2690
961
|
}
|
|
2691
962
|
}
|
|
2692
|
-
if (oldestKey) {
|
|
2693
|
-
bindingsCache.delete(oldestKey);
|
|
2694
|
-
nodeCacheTimestamps.delete(oldestKey);
|
|
2695
|
-
}
|
|
2696
963
|
}
|
|
964
|
+
if (node.children) {
|
|
965
|
+
result.children = await Promise.all(node.children.map((child) => resolveBindings(child, context)));
|
|
966
|
+
}
|
|
967
|
+
await systemEvents.emit(
|
|
968
|
+
createSystemEvent("BINDING_RESOLUTION_COMPLETE" /* BINDING_RESOLUTION_COMPLETE */, {
|
|
969
|
+
originalLayout: node,
|
|
970
|
+
resolvedLayout: result
|
|
971
|
+
})
|
|
972
|
+
);
|
|
2697
973
|
return result;
|
|
2698
974
|
}
|
|
2699
975
|
function executeAction(action, targetId, payload, context = {}, layoutTree) {
|
|
@@ -2716,6 +992,7 @@ function executeAction(action, targetId, payload, context = {}, layoutTree) {
|
|
|
2716
992
|
}
|
|
2717
993
|
break;
|
|
2718
994
|
}
|
|
995
|
+
// Add more actions as needed
|
|
2719
996
|
default:
|
|
2720
997
|
console.warn(`Unknown action: ${action}`);
|
|
2721
998
|
}
|
|
@@ -2729,7 +1006,7 @@ var EventManager = class {
|
|
|
2729
1006
|
}
|
|
2730
1007
|
/**
|
|
2731
1008
|
* Register a hook for specific event types
|
|
2732
|
-
*
|
|
1009
|
+
*
|
|
2733
1010
|
* @param eventTypes - Event types to register for, or 'all' for all events
|
|
2734
1011
|
* @param hook - Hook function to execute
|
|
2735
1012
|
* @returns Unregister function
|
|
@@ -2762,7 +1039,7 @@ var EventManager = class {
|
|
|
2762
1039
|
}
|
|
2763
1040
|
/**
|
|
2764
1041
|
* Process an event through all registered hooks
|
|
2765
|
-
*
|
|
1042
|
+
*
|
|
2766
1043
|
* @param event - The UI event to process
|
|
2767
1044
|
* @returns Whether the default action should proceed
|
|
2768
1045
|
*/
|
|
@@ -2783,15 +1060,13 @@ var EventManager = class {
|
|
|
2783
1060
|
if (this.hooks.all) {
|
|
2784
1061
|
for (const hook of this.hooks.all) {
|
|
2785
1062
|
await hook(context);
|
|
2786
|
-
if (propagationStopped)
|
|
2787
|
-
break;
|
|
1063
|
+
if (propagationStopped) break;
|
|
2788
1064
|
}
|
|
2789
1065
|
}
|
|
2790
1066
|
if (!propagationStopped && this.hooks[event.type]) {
|
|
2791
1067
|
for (const hook of this.hooks[event.type] || []) {
|
|
2792
1068
|
await hook(context);
|
|
2793
|
-
if (propagationStopped)
|
|
2794
|
-
break;
|
|
1069
|
+
if (propagationStopped) break;
|
|
2795
1070
|
}
|
|
2796
1071
|
}
|
|
2797
1072
|
return !defaultPrevented;
|
|
@@ -2808,45 +1083,6 @@ function createEventHook(eventTypes, hook, options) {
|
|
|
2808
1083
|
}
|
|
2809
1084
|
};
|
|
2810
1085
|
}
|
|
2811
|
-
|
|
2812
|
-
// src/core/component-detection.ts
|
|
2813
|
-
function areShadcnComponentsAvailable() {
|
|
2814
|
-
try {
|
|
2815
|
-
init_button();
|
|
2816
|
-
return true;
|
|
2817
|
-
} catch (error) {
|
|
2818
|
-
return false;
|
|
2819
|
-
}
|
|
2820
|
-
}
|
|
2821
|
-
function getMissingComponentsMessage() {
|
|
2822
|
-
return `Missing required shadcn components. Please run:
|
|
2823
|
-
> npm run setup-shadcn`;
|
|
2824
|
-
}
|
|
2825
|
-
function correctListBindingsRecursive(node, dataContext) {
|
|
2826
|
-
const correctedNode = JSON.parse(JSON.stringify(node));
|
|
2827
|
-
if ((correctedNode.node_type === "ListView" || correctedNode.node_type === "Table") && correctedNode.bindings?.data) {
|
|
2828
|
-
const bindingPath = correctedNode.bindings.data;
|
|
2829
|
-
if (typeof bindingPath === "string") {
|
|
2830
|
-
const pathSegments = bindingPath.split(".");
|
|
2831
|
-
const mainKey = pathSegments[0];
|
|
2832
|
-
if (pathSegments.length === 1) {
|
|
2833
|
-
const potentialDataContextEntry = dataContext[mainKey];
|
|
2834
|
-
if (potentialDataContextEntry && typeof potentialDataContextEntry === "object" && potentialDataContextEntry !== null && "data" in potentialDataContextEntry && Array.isArray(potentialDataContextEntry.data)) {
|
|
2835
|
-
correctedNode.bindings.data = `${mainKey}.data`;
|
|
2836
|
-
console.log(
|
|
2837
|
-
`[AutoUI Debug] Corrected list binding for node '${correctedNode.id}': from '${mainKey}' to '${mainKey}.data'`
|
|
2838
|
-
);
|
|
2839
|
-
}
|
|
2840
|
-
}
|
|
2841
|
-
}
|
|
2842
|
-
}
|
|
2843
|
-
if (correctedNode.children) {
|
|
2844
|
-
correctedNode.children = correctedNode.children.map(
|
|
2845
|
-
(child) => correctListBindingsRecursive(child, dataContext)
|
|
2846
|
-
);
|
|
2847
|
-
}
|
|
2848
|
-
return correctedNode;
|
|
2849
|
-
}
|
|
2850
1086
|
var AutoUI = ({
|
|
2851
1087
|
schema,
|
|
2852
1088
|
goal,
|
|
@@ -2856,34 +1092,24 @@ var AutoUI = ({
|
|
|
2856
1092
|
eventHooks,
|
|
2857
1093
|
systemEventHooks,
|
|
2858
1094
|
debugMode = false,
|
|
2859
|
-
mockMode =
|
|
1095
|
+
mockMode = true,
|
|
1096
|
+
databaseConfig,
|
|
2860
1097
|
planningConfig,
|
|
2861
1098
|
integration = {},
|
|
2862
1099
|
scope = {},
|
|
2863
|
-
enablePartialUpdates = false
|
|
2864
|
-
openaiApiKey
|
|
1100
|
+
enablePartialUpdates = false
|
|
2865
1101
|
}) => {
|
|
2866
|
-
const [schemaAdapterInstance] = useState(null);
|
|
1102
|
+
const [schemaAdapterInstance, setSchemaAdapterInstance] = useState(null);
|
|
2867
1103
|
const [dataContext, setDataContext] = useState({});
|
|
2868
|
-
const [componentsAvailable, setComponentsAvailable] = useState(true);
|
|
2869
1104
|
const effectiveSchema = schema;
|
|
2870
1105
|
const scopedGoal = goal;
|
|
2871
|
-
useEffect(() => {
|
|
2872
|
-
if (componentAdapter === "shadcn") {
|
|
2873
|
-
setComponentsAvailable(areShadcnComponentsAvailable());
|
|
2874
|
-
}
|
|
2875
|
-
}, [componentAdapter]);
|
|
2876
1106
|
useEffect(() => {
|
|
2877
1107
|
const unregisters = [];
|
|
2878
1108
|
if (systemEventHooks) {
|
|
2879
1109
|
Object.entries(systemEventHooks).forEach(([eventType, hooks]) => {
|
|
2880
|
-
if (!hooks)
|
|
2881
|
-
return;
|
|
1110
|
+
if (!hooks) return;
|
|
2882
1111
|
hooks.forEach((hook) => {
|
|
2883
|
-
const unregister = systemEvents.on(
|
|
2884
|
-
eventType,
|
|
2885
|
-
hook
|
|
2886
|
-
);
|
|
1112
|
+
const unregister = systemEvents.on(eventType, hook);
|
|
2887
1113
|
unregisters.push(unregister);
|
|
2888
1114
|
});
|
|
2889
1115
|
});
|
|
@@ -2892,9 +1118,7 @@ var AutoUI = ({
|
|
|
2892
1118
|
const debugHook = (event) => {
|
|
2893
1119
|
console.debug(`[AutoUI Debug] System Event:`, event);
|
|
2894
1120
|
};
|
|
2895
|
-
Object.values(SystemEventType).
|
|
2896
|
-
(eventType) => eventType !== "RENDER_START" /* RENDER_START */ && eventType !== "BINDING_RESOLUTION_START" /* BINDING_RESOLUTION_START */
|
|
2897
|
-
).forEach((eventType) => {
|
|
1121
|
+
Object.values(SystemEventType).forEach((eventType) => {
|
|
2898
1122
|
const unregister = systemEvents.on(eventType, debugHook);
|
|
2899
1123
|
unregisters.push(unregister);
|
|
2900
1124
|
});
|
|
@@ -2933,162 +1157,88 @@ var AutoUI = ({
|
|
|
2933
1157
|
planningConfig,
|
|
2934
1158
|
router: void 0,
|
|
2935
1159
|
dataContext,
|
|
2936
|
-
enablePartialUpdates
|
|
2937
|
-
openaiApiKey
|
|
1160
|
+
enablePartialUpdates
|
|
2938
1161
|
});
|
|
2939
1162
|
const eventManagerRef = useRef(new EventManager());
|
|
2940
1163
|
useEffect(() => {
|
|
2941
|
-
if (!eventHooks)
|
|
2942
|
-
return;
|
|
1164
|
+
if (!eventHooks) return;
|
|
2943
1165
|
const unregisters = [];
|
|
2944
1166
|
if (eventHooks.all) {
|
|
2945
|
-
const unregister = eventManagerRef.current.register(
|
|
2946
|
-
|
|
2947
|
-
|
|
2948
|
-
|
|
2949
|
-
await hook(ctx);
|
|
2950
|
-
if (ctx.isPropagationStopped())
|
|
2951
|
-
break;
|
|
2952
|
-
}
|
|
1167
|
+
const unregister = eventManagerRef.current.register("all", async (ctx) => {
|
|
1168
|
+
for (const hook of eventHooks.all || []) {
|
|
1169
|
+
await hook(ctx);
|
|
1170
|
+
if (ctx.isPropagationStopped()) break;
|
|
2953
1171
|
}
|
|
2954
|
-
);
|
|
1172
|
+
});
|
|
2955
1173
|
unregisters.push(unregister);
|
|
2956
1174
|
}
|
|
2957
1175
|
Object.entries(eventHooks).forEach(([type, hooks]) => {
|
|
2958
|
-
if (type === "all" || !hooks)
|
|
2959
|
-
|
|
2960
|
-
|
|
2961
|
-
|
|
2962
|
-
|
|
2963
|
-
for (const hook of hooks) {
|
|
2964
|
-
await hook(ctx);
|
|
2965
|
-
if (ctx.isPropagationStopped())
|
|
2966
|
-
break;
|
|
2967
|
-
}
|
|
1176
|
+
if (type === "all" || !hooks) return;
|
|
1177
|
+
const unregister = eventManagerRef.current.register([type], async (ctx) => {
|
|
1178
|
+
for (const hook of hooks) {
|
|
1179
|
+
await hook(ctx);
|
|
1180
|
+
if (ctx.isPropagationStopped()) break;
|
|
2968
1181
|
}
|
|
2969
|
-
);
|
|
1182
|
+
});
|
|
2970
1183
|
unregisters.push(unregister);
|
|
2971
1184
|
});
|
|
2972
1185
|
return () => {
|
|
2973
1186
|
unregisters.forEach((unregister) => unregister());
|
|
2974
1187
|
};
|
|
2975
1188
|
}, [eventHooks]);
|
|
2976
|
-
|
|
2977
|
-
|
|
2978
|
-
|
|
2979
|
-
|
|
2980
|
-
|
|
2981
|
-
|
|
2982
|
-
|
|
2983
|
-
|
|
2984
|
-
|
|
2985
|
-
|
|
2986
|
-
|
|
2987
|
-
|
|
2988
|
-
|
|
2989
|
-
|
|
2990
|
-
|
|
2991
|
-
|
|
2992
|
-
for (const child of node.children) {
|
|
2993
|
-
const found = findNodeById2(child, id);
|
|
2994
|
-
if (found)
|
|
2995
|
-
return found;
|
|
2996
|
-
}
|
|
1189
|
+
useCallback(async (event) => {
|
|
1190
|
+
const shouldProceed = await eventManagerRef.current.processEvent(event);
|
|
1191
|
+
if (onEvent) {
|
|
1192
|
+
onEvent(event);
|
|
1193
|
+
}
|
|
1194
|
+
if (!shouldProceed) {
|
|
1195
|
+
console.info("Event processing was prevented by hooks", event);
|
|
1196
|
+
return;
|
|
1197
|
+
}
|
|
1198
|
+
const findNodeById2 = (node, id) => {
|
|
1199
|
+
if (!node) return void 0;
|
|
1200
|
+
if (node.id === id) return node;
|
|
1201
|
+
if (node.children) {
|
|
1202
|
+
for (const child of node.children) {
|
|
1203
|
+
const found = findNodeById2(child, id);
|
|
1204
|
+
if (found) return found;
|
|
2997
1205
|
}
|
|
2998
|
-
return void 0;
|
|
2999
|
-
};
|
|
3000
|
-
const sourceNode = findNodeById2(state.layout, event.nodeId);
|
|
3001
|
-
if (!sourceNode) {
|
|
3002
|
-
console.warn(`Node not found for event: ${event.nodeId}`);
|
|
3003
|
-
handleEvent(event);
|
|
3004
|
-
return;
|
|
3005
1206
|
}
|
|
3006
|
-
|
|
3007
|
-
|
|
3008
|
-
|
|
3009
|
-
|
|
3010
|
-
|
|
3011
|
-
handleEvent(event);
|
|
3012
|
-
return;
|
|
3013
|
-
}
|
|
3014
|
-
const newContext = executeAction(
|
|
3015
|
-
eventConfig.action,
|
|
3016
|
-
eventConfig.target || "",
|
|
3017
|
-
// Provide empty string as fallback if target is null
|
|
3018
|
-
{
|
|
3019
|
-
...eventConfig.payload,
|
|
3020
|
-
...event.payload
|
|
3021
|
-
},
|
|
3022
|
-
dataContext,
|
|
3023
|
-
state.layout || void 0
|
|
3024
|
-
);
|
|
3025
|
-
setDataContext(newContext);
|
|
1207
|
+
return void 0;
|
|
1208
|
+
};
|
|
1209
|
+
const sourceNode = findNodeById2(state.layout, event.nodeId);
|
|
1210
|
+
if (!sourceNode) {
|
|
1211
|
+
console.warn(`Node not found for event: ${event.nodeId}`);
|
|
3026
1212
|
handleEvent(event);
|
|
3027
|
-
|
|
3028
|
-
[dataContext, handleEvent, onEvent, state.layout]
|
|
3029
|
-
);
|
|
3030
|
-
const [resolvedLayout, setResolvedLayout] = useState(
|
|
3031
|
-
void 0
|
|
3032
|
-
);
|
|
3033
|
-
const [renderedNode, setRenderedNode] = useState(
|
|
3034
|
-
null
|
|
3035
|
-
);
|
|
3036
|
-
const resolveLayoutBindings = useCallback(async () => {
|
|
3037
|
-
if (state.layout && dataContext) {
|
|
3038
|
-
console.log(
|
|
3039
|
-
"[AutoUI Debug] DataContext before resolving bindings:",
|
|
3040
|
-
JSON.stringify(dataContext, null, 2)
|
|
3041
|
-
);
|
|
3042
|
-
console.log(
|
|
3043
|
-
"[AutoUI Debug] Raw layout before resolving (from planner):",
|
|
3044
|
-
JSON.stringify(state.layout, null, 2)
|
|
3045
|
-
);
|
|
3046
|
-
const correctedLayout = correctListBindingsRecursive(
|
|
3047
|
-
state.layout,
|
|
3048
|
-
dataContext
|
|
3049
|
-
);
|
|
3050
|
-
console.log(
|
|
3051
|
-
"[AutoUI Debug] Layout after binding correction (before resolving):",
|
|
3052
|
-
JSON.stringify(correctedLayout, null, 2)
|
|
3053
|
-
);
|
|
3054
|
-
const resolved = await resolveBindings(correctedLayout, dataContext);
|
|
3055
|
-
setResolvedLayout(resolved);
|
|
3056
|
-
console.log(
|
|
3057
|
-
"[AutoUI Debug] Resolved layout after bindings:",
|
|
3058
|
-
JSON.stringify(resolved, null, 2)
|
|
3059
|
-
);
|
|
3060
|
-
} else {
|
|
3061
|
-
setResolvedLayout(void 0);
|
|
1213
|
+
return;
|
|
3062
1214
|
}
|
|
3063
|
-
|
|
1215
|
+
const eventConfig = sourceNode.events?.[event.type];
|
|
1216
|
+
if (!eventConfig) {
|
|
1217
|
+
console.warn(`No event config found for ${event.type} on node ${event.nodeId}`);
|
|
1218
|
+
handleEvent(event);
|
|
1219
|
+
return;
|
|
1220
|
+
}
|
|
1221
|
+
const newContext = executeAction(
|
|
1222
|
+
eventConfig.action,
|
|
1223
|
+
eventConfig.target,
|
|
1224
|
+
{
|
|
1225
|
+
...eventConfig.payload,
|
|
1226
|
+
...event.payload
|
|
1227
|
+
},
|
|
1228
|
+
dataContext,
|
|
1229
|
+
state.layout
|
|
1230
|
+
);
|
|
1231
|
+
setDataContext(newContext);
|
|
1232
|
+
handleEvent(event);
|
|
1233
|
+
}, [dataContext, handleEvent, onEvent, state.layout]);
|
|
1234
|
+
const [resolvedLayout, setResolvedLayout] = useState(void 0);
|
|
3064
1235
|
useEffect(() => {
|
|
3065
|
-
|
|
3066
|
-
|
|
3067
|
-
const renderResolvedLayout = useCallback(async () => {
|
|
3068
|
-
if (resolvedLayout) {
|
|
3069
|
-
try {
|
|
3070
|
-
const rendered = await renderNode2(
|
|
3071
|
-
resolvedLayout,
|
|
3072
|
-
componentAdapter,
|
|
3073
|
-
processEvent2
|
|
3074
|
-
);
|
|
3075
|
-
setRenderedNode(rendered);
|
|
3076
|
-
} catch (err) {
|
|
3077
|
-
console.error("Error rendering node:", err);
|
|
3078
|
-
}
|
|
1236
|
+
if (state.layout) {
|
|
1237
|
+
resolveBindings(state.layout, dataContext).then((resolved) => setResolvedLayout(resolved)).catch((err) => console.error("Error resolving bindings:", err));
|
|
3079
1238
|
} else {
|
|
3080
|
-
|
|
1239
|
+
setResolvedLayout(void 0);
|
|
3081
1240
|
}
|
|
3082
|
-
}, [
|
|
3083
|
-
useEffect(() => {
|
|
3084
|
-
renderResolvedLayout();
|
|
3085
|
-
}, [renderResolvedLayout]);
|
|
3086
|
-
if (!componentsAvailable) {
|
|
3087
|
-
return /* @__PURE__ */ jsxs("div", { className: "autoui-error p-4 border border-red-300 bg-red-50 text-red-700 rounded", children: [
|
|
3088
|
-
/* @__PURE__ */ jsx("p", { className: "font-medium", children: "Component Library Not Found" }),
|
|
3089
|
-
/* @__PURE__ */ jsx("p", { className: "text-sm whitespace-pre-line", children: getMissingComponentsMessage() })
|
|
3090
|
-
] });
|
|
3091
|
-
}
|
|
1241
|
+
}, [state.layout, dataContext]);
|
|
3092
1242
|
return /* @__PURE__ */ jsxs(
|
|
3093
1243
|
"div",
|
|
3094
1244
|
{
|
|
@@ -3105,24 +1255,11 @@ var AutoUI = ({
|
|
|
3105
1255
|
] }) })
|
|
3106
1256
|
) : (
|
|
3107
1257
|
// Render the resolved layout
|
|
3108
|
-
/* @__PURE__ */ jsx("div", { className: "autoui-content", children:
|
|
1258
|
+
/* @__PURE__ */ jsx("div", { className: "autoui-content", children: renderNode2(resolvedLayout, componentAdapter) })
|
|
3109
1259
|
),
|
|
3110
|
-
state.error && /* @__PURE__ */ jsxs("div", { className: "autoui-error
|
|
3111
|
-
/* @__PURE__ */ jsx("p", { className: "autoui-error-title
|
|
3112
|
-
/* @__PURE__ */ jsx("p", { className: "autoui-error-message
|
|
3113
|
-
!mockMode && /* @__PURE__ */ jsxs("div", { className: "mt-4 text-sm text-red-600 dark:text-red-300", children: [
|
|
3114
|
-
/* @__PURE__ */ jsx("p", { children: "This could be because:" }),
|
|
3115
|
-
/* @__PURE__ */ jsxs("ul", { className: "list-disc pl-5 mt-2", children: [
|
|
3116
|
-
/* @__PURE__ */ jsx("li", { children: "Your OpenAI API key is missing or invalid" }),
|
|
3117
|
-
/* @__PURE__ */ jsx("li", { children: "The OpenAI service is experiencing issues" }),
|
|
3118
|
-
/* @__PURE__ */ jsx("li", { children: "Your API rate limit has been exceeded" })
|
|
3119
|
-
] }),
|
|
3120
|
-
/* @__PURE__ */ jsxs("p", { className: "mt-2", children: [
|
|
3121
|
-
"Try setting ",
|
|
3122
|
-
/* @__PURE__ */ jsx("code", { children: "mockMode=true" }),
|
|
3123
|
-
" to use sample data instead."
|
|
3124
|
-
] })
|
|
3125
|
-
] })
|
|
1260
|
+
state.error && /* @__PURE__ */ jsxs("div", { className: "autoui-error", children: [
|
|
1261
|
+
/* @__PURE__ */ jsx("p", { className: "autoui-error-title", children: "Error generating UI" }),
|
|
1262
|
+
/* @__PURE__ */ jsx("p", { className: "autoui-error-message", children: state.error })
|
|
3126
1263
|
] })
|
|
3127
1264
|
]
|
|
3128
1265
|
}
|
|
@@ -3175,26 +1312,26 @@ var DrizzleAdapter = class {
|
|
|
3175
1312
|
*/
|
|
3176
1313
|
mapDataType(drizzleType) {
|
|
3177
1314
|
const typeMap = {
|
|
3178
|
-
serial: "integer",
|
|
3179
|
-
integer: "integer",
|
|
3180
|
-
int: "integer",
|
|
3181
|
-
bigint: "integer",
|
|
3182
|
-
text: "string",
|
|
3183
|
-
varchar: "string",
|
|
3184
|
-
char: "string",
|
|
3185
|
-
boolean: "boolean",
|
|
3186
|
-
bool: "boolean",
|
|
3187
|
-
timestamp: "datetime",
|
|
3188
|
-
timestamptz: "datetime",
|
|
3189
|
-
date: "date",
|
|
3190
|
-
time: "time",
|
|
3191
|
-
json: "object",
|
|
3192
|
-
jsonb: "object",
|
|
3193
|
-
real: "number",
|
|
3194
|
-
float: "number",
|
|
3195
|
-
double: "number",
|
|
3196
|
-
numeric: "number",
|
|
3197
|
-
decimal: "number"
|
|
1315
|
+
"serial": "integer",
|
|
1316
|
+
"integer": "integer",
|
|
1317
|
+
"int": "integer",
|
|
1318
|
+
"bigint": "integer",
|
|
1319
|
+
"text": "string",
|
|
1320
|
+
"varchar": "string",
|
|
1321
|
+
"char": "string",
|
|
1322
|
+
"boolean": "boolean",
|
|
1323
|
+
"bool": "boolean",
|
|
1324
|
+
"timestamp": "datetime",
|
|
1325
|
+
"timestamptz": "datetime",
|
|
1326
|
+
"date": "date",
|
|
1327
|
+
"time": "time",
|
|
1328
|
+
"json": "object",
|
|
1329
|
+
"jsonb": "object",
|
|
1330
|
+
"real": "number",
|
|
1331
|
+
"float": "number",
|
|
1332
|
+
"double": "number",
|
|
1333
|
+
"numeric": "number",
|
|
1334
|
+
"decimal": "number"
|
|
3198
1335
|
};
|
|
3199
1336
|
return typeMap[drizzleType.toLowerCase()] || "string";
|
|
3200
1337
|
}
|
|
@@ -3237,122 +1374,10 @@ function createSchemaAdapter(options) {
|
|
|
3237
1374
|
case "custom":
|
|
3238
1375
|
return options.adapter;
|
|
3239
1376
|
default:
|
|
3240
|
-
throw new Error(
|
|
3241
|
-
`Unsupported schema adapter type: ${options.type}`
|
|
3242
|
-
);
|
|
1377
|
+
throw new Error(`Unsupported schema adapter type: ${options.type}`);
|
|
3243
1378
|
}
|
|
3244
1379
|
}
|
|
3245
1380
|
|
|
3246
|
-
|
|
3247
|
-
|
|
3248
|
-
console.warn(
|
|
3249
|
-
"generateComponent is a placeholder and will be implemented in a future version"
|
|
3250
|
-
);
|
|
3251
|
-
return `<div>Generated Component for: ${prompt}</div>`;
|
|
3252
|
-
};
|
|
3253
|
-
var generateUIDescription = async (prompt) => {
|
|
3254
|
-
console.warn(
|
|
3255
|
-
"generateUIDescription is a placeholder and will be implemented in a future version"
|
|
3256
|
-
);
|
|
3257
|
-
return `Description for ${prompt}`;
|
|
3258
|
-
};
|
|
3259
|
-
var generateUIComponent = async (prompt) => {
|
|
3260
|
-
console.warn(
|
|
3261
|
-
"generateUIComponent is a placeholder and will be implemented in a future version"
|
|
3262
|
-
);
|
|
3263
|
-
return `<div>Generated UI Component for: ${prompt}</div>`;
|
|
3264
|
-
};
|
|
3265
|
-
function usePlanner(options) {
|
|
3266
|
-
const {
|
|
3267
|
-
schema,
|
|
3268
|
-
goal,
|
|
3269
|
-
openaiApiKey,
|
|
3270
|
-
userContext,
|
|
3271
|
-
initialLayout,
|
|
3272
|
-
mockMode: optionsMockMode
|
|
3273
|
-
} = options;
|
|
3274
|
-
const [layout, setLayout] = useState(
|
|
3275
|
-
initialLayout || void 0
|
|
3276
|
-
);
|
|
3277
|
-
const [loading, setLoading] = useState(false);
|
|
3278
|
-
const [error, setError] = useState(null);
|
|
3279
|
-
const router = options.router || createDefaultRouter();
|
|
3280
|
-
const dataContext = {};
|
|
3281
|
-
const initialFetchAttempted = useRef(false);
|
|
3282
|
-
const mockMode = optionsMockMode || !openaiApiKey;
|
|
3283
|
-
const generateInitialLayout = useCallback(async () => {
|
|
3284
|
-
setLoading(true);
|
|
3285
|
-
setError(null);
|
|
3286
|
-
try {
|
|
3287
|
-
const plannerInput2 = {
|
|
3288
|
-
schema,
|
|
3289
|
-
goal,
|
|
3290
|
-
userContext: userContext || null,
|
|
3291
|
-
history: null
|
|
3292
|
-
};
|
|
3293
|
-
let generatedLayout;
|
|
3294
|
-
if (mockMode) {
|
|
3295
|
-
console.warn(
|
|
3296
|
-
"Using mock planner in usePlanner hook (mockMode enabled or API key missing)."
|
|
3297
|
-
);
|
|
3298
|
-
generatedLayout = mockPlanner(plannerInput2);
|
|
3299
|
-
} else {
|
|
3300
|
-
generatedLayout = await callPlannerLLM(
|
|
3301
|
-
plannerInput2,
|
|
3302
|
-
openaiApiKey,
|
|
3303
|
-
void 0
|
|
3304
|
-
);
|
|
3305
|
-
}
|
|
3306
|
-
setLayout(generatedLayout);
|
|
3307
|
-
} catch (err) {
|
|
3308
|
-
setError(err instanceof Error ? err : new Error(String(err)));
|
|
3309
|
-
} finally {
|
|
3310
|
-
setLoading(false);
|
|
3311
|
-
}
|
|
3312
|
-
}, [schema, goal, userContext, openaiApiKey, mockMode]);
|
|
3313
|
-
const handleEvent = useCallback(
|
|
3314
|
-
async (event) => {
|
|
3315
|
-
if (!layout) {
|
|
3316
|
-
setError(new Error("Cannot handle event - no layout exists"));
|
|
3317
|
-
return;
|
|
3318
|
-
}
|
|
3319
|
-
setLoading(true);
|
|
3320
|
-
setError(null);
|
|
3321
|
-
try {
|
|
3322
|
-
const updatedLayout = await processEvent(
|
|
3323
|
-
event,
|
|
3324
|
-
router,
|
|
3325
|
-
schema,
|
|
3326
|
-
layout,
|
|
3327
|
-
dataContext,
|
|
3328
|
-
goal,
|
|
3329
|
-
userContext,
|
|
3330
|
-
openaiApiKey
|
|
3331
|
-
);
|
|
3332
|
-
setLayout(updatedLayout);
|
|
3333
|
-
} catch (err) {
|
|
3334
|
-
setError(err instanceof Error ? err : new Error(String(err)));
|
|
3335
|
-
} finally {
|
|
3336
|
-
setLoading(false);
|
|
3337
|
-
}
|
|
3338
|
-
},
|
|
3339
|
-
[layout, router, schema, dataContext, goal, userContext, openaiApiKey]
|
|
3340
|
-
);
|
|
3341
|
-
useEffect(() => {
|
|
3342
|
-
if (options.initialLayout === void 0 && layout === void 0 && !initialFetchAttempted.current) {
|
|
3343
|
-
initialFetchAttempted.current = true;
|
|
3344
|
-
generateInitialLayout();
|
|
3345
|
-
}
|
|
3346
|
-
}, [options.initialLayout, layout, generateInitialLayout]);
|
|
3347
|
-
return {
|
|
3348
|
-
layout,
|
|
3349
|
-
loading,
|
|
3350
|
-
error,
|
|
3351
|
-
handleEvent,
|
|
3352
|
-
generateInitialLayout
|
|
3353
|
-
};
|
|
3354
|
-
}
|
|
3355
|
-
|
|
3356
|
-
export { ActionRouter, ActionType, AutoUI, DrizzleAdapter, SystemEventType, createDefaultRouter, createEventHook, createSchemaAdapter, createSystemEvent, generateComponent, generateUIComponent, generateUIDescription, systemEvents, uiEvent, uiEventType, uiSpecNode, usePlanner };
|
|
3357
|
-
//# sourceMappingURL=out.js.map
|
|
1381
|
+
export { ActionRouter, ActionType, AutoUI, DrizzleAdapter, SystemEventType, createDefaultRouter, createEventHook, createSchemaAdapter, createSystemEvent, systemEvents, uiEvent, uiEventType, uiSpecNode };
|
|
1382
|
+
//# sourceMappingURL=index.mjs.map
|
|
3358
1383
|
//# sourceMappingURL=index.mjs.map
|