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