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