autoui-react 0.0.4-alpha → 0.0.5-alpha
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.d.mts +38 -18
- package/dist/index.d.ts +38 -18
- package/dist/index.js +1568 -298
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +1473 -227
- package/dist/index.mjs.map +1 -1
- package/package.json +5 -1
package/dist/index.mjs
CHANGED
|
@@ -7,6 +7,13 @@ import React, { useState, useEffect, useRef, useCallback, useReducer } from 'rea
|
|
|
7
7
|
import { createOpenAI } from '@ai-sdk/openai';
|
|
8
8
|
import { generateObject } from 'ai';
|
|
9
9
|
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';
|
|
10
17
|
|
|
11
18
|
var __defProp = Object.defineProperty;
|
|
12
19
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
@@ -293,6 +300,72 @@ var initialState = {
|
|
|
293
300
|
};
|
|
294
301
|
|
|
295
302
|
// 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
|
+
}
|
|
296
369
|
var ActionType = /* @__PURE__ */ ((ActionType2) => {
|
|
297
370
|
ActionType2["FULL_REFRESH"] = "FULL_REFRESH";
|
|
298
371
|
ActionType2["UPDATE_NODE"] = "UPDATE_NODE";
|
|
@@ -327,19 +400,39 @@ var ActionRouter = class {
|
|
|
327
400
|
* @returns Route resolution or null if no match
|
|
328
401
|
*/
|
|
329
402
|
resolveRoute(event, schema, layout, dataContext, goal, userContext) {
|
|
403
|
+
console.log(
|
|
404
|
+
`[ActionRouter Debug] resolveRoute called for event type: ${event.type}`
|
|
405
|
+
);
|
|
330
406
|
const routes = this.routes[event.type] || [];
|
|
407
|
+
console.log(
|
|
408
|
+
`[ActionRouter Debug] Found ${routes.length} routes for ${event.type}`
|
|
409
|
+
);
|
|
331
410
|
if (routes.length === 0) {
|
|
332
|
-
|
|
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 = {
|
|
333
426
|
actionType: "FULL_REFRESH" /* FULL_REFRESH */,
|
|
334
427
|
targetNodeId: layout?.id || "root",
|
|
335
|
-
plannerInput:
|
|
336
|
-
|
|
337
|
-
goal,
|
|
338
|
-
history: [event],
|
|
339
|
-
userContext: userContext || null
|
|
340
|
-
},
|
|
341
|
-
prompt: `Generate a new UI for the goal: "${goal}". The user just triggered: ${event.type} on node ${event.nodeId}`
|
|
428
|
+
plannerInput: defaultPlannerInput,
|
|
429
|
+
prompt: defaultPrompt
|
|
342
430
|
};
|
|
431
|
+
console.log(
|
|
432
|
+
"[ActionRouter Debug] Default Resolution:",
|
|
433
|
+
defaultResolution
|
|
434
|
+
);
|
|
435
|
+
return defaultResolution;
|
|
343
436
|
}
|
|
344
437
|
const sourceNode = layout ? findNodeById(layout, event.nodeId) : void 0;
|
|
345
438
|
const nodeConfig = sourceNode?.events?.[event.type];
|
|
@@ -352,6 +445,7 @@ var ActionRouter = class {
|
|
|
352
445
|
if (!matchingRoute) {
|
|
353
446
|
matchingRoute = routes[0];
|
|
354
447
|
}
|
|
448
|
+
console.log("[ActionRouter Debug] Matching Route Config:", matchingRoute);
|
|
355
449
|
const targetNodeId = nodeConfig?.target || matchingRoute.targetNodeId || event.nodeId;
|
|
356
450
|
const additionalContext = {};
|
|
357
451
|
if (matchingRoute.contextKeys) {
|
|
@@ -396,16 +490,24 @@ var ActionRouter = class {
|
|
|
396
490
|
...additionalContext
|
|
397
491
|
// Spread additionalContext afterwards (can override userContext keys)
|
|
398
492
|
};
|
|
399
|
-
|
|
493
|
+
console.log("[ActionRouter Debug] Template Values:", templateValues);
|
|
494
|
+
const finalPrompt = buildPrompt(
|
|
495
|
+
plannerInput2,
|
|
400
496
|
matchingRoute.promptTemplate,
|
|
497
|
+
// Pass template if it exists (can be undefined)
|
|
401
498
|
templateValues
|
|
499
|
+
// Pass templateValues (used only if promptTemplate exists)
|
|
402
500
|
);
|
|
403
|
-
|
|
501
|
+
console.log("[ActionRouter Debug] Generated Prompt:", finalPrompt);
|
|
502
|
+
const finalResolution = {
|
|
404
503
|
actionType: matchingRoute.actionType,
|
|
405
504
|
targetNodeId,
|
|
406
505
|
plannerInput: plannerInput2,
|
|
407
|
-
prompt
|
|
506
|
+
prompt: finalPrompt
|
|
507
|
+
// Use the generated prompt
|
|
408
508
|
};
|
|
509
|
+
console.log("[ActionRouter Debug] Final Resolution:", finalResolution);
|
|
510
|
+
return finalResolution;
|
|
409
511
|
}
|
|
410
512
|
/**
|
|
411
513
|
* Process a prompt template with variables
|
|
@@ -423,8 +525,11 @@ function createDefaultRouter() {
|
|
|
423
525
|
const router = new ActionRouter();
|
|
424
526
|
router.registerRoute("CLICK", {
|
|
425
527
|
actionType: "FULL_REFRESH" /* FULL_REFRESH */,
|
|
426
|
-
targetNodeId: "root"
|
|
427
|
-
|
|
528
|
+
targetNodeId: "root"
|
|
529
|
+
});
|
|
530
|
+
router.registerRoute("INIT", {
|
|
531
|
+
actionType: "FULL_REFRESH" /* FULL_REFRESH */,
|
|
532
|
+
targetNodeId: "root"
|
|
428
533
|
});
|
|
429
534
|
router.registerRoute("CLICK", {
|
|
430
535
|
actionType: "SHOW_DETAIL" /* SHOW_DETAIL */,
|
|
@@ -454,7 +559,31 @@ function createDefaultRouter() {
|
|
|
454
559
|
});
|
|
455
560
|
return router;
|
|
456
561
|
}
|
|
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
|
|
457
585
|
var uiEventType = z.enum([
|
|
586
|
+
"INIT",
|
|
458
587
|
"CLICK",
|
|
459
588
|
"CHANGE",
|
|
460
589
|
"SUBMIT",
|
|
@@ -475,12 +604,16 @@ var openAISimplifiedValue = z.string().nullable();
|
|
|
475
604
|
var openAIRecordSimplifiedNullable = z.record(openAISimplifiedValue).nullable();
|
|
476
605
|
var openAIEventPayloadSimplifiedNullable = z.record(openAISimplifiedValue).nullable();
|
|
477
606
|
var openAIBaseNode = z.object({
|
|
478
|
-
id: z.string(),
|
|
479
|
-
node_type:
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
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
|
+
),
|
|
484
617
|
events: z.record(
|
|
485
618
|
z.string(),
|
|
486
619
|
z.object({
|
|
@@ -628,67 +761,22 @@ function createSystemEvent(type, data) {
|
|
|
628
761
|
|
|
629
762
|
// src/env.ts
|
|
630
763
|
var rawApiKeyFromEnv = process.env.VITE_OPENAI_API_KEY;
|
|
631
|
-
var defaultApiKeyLiteral = "sk-proj-literal-default-for-debug-in-env-ts";
|
|
632
764
|
var env = {
|
|
633
|
-
MOCK_PLANNER: process.env.VITE_MOCK_PLANNER || "
|
|
765
|
+
MOCK_PLANNER: process.env.VITE_MOCK_PLANNER || "0",
|
|
634
766
|
// Simplified MOCK_PLANNER assignment
|
|
635
|
-
NODE_ENV: process.env.VITE_NODE_ENV || "
|
|
767
|
+
NODE_ENV: process.env.VITE_NODE_ENV || "production",
|
|
636
768
|
// Simplified NODE_ENV assignment
|
|
637
|
-
OPENAI_API_KEY: rawApiKeyFromEnv
|
|
769
|
+
OPENAI_API_KEY: rawApiKeyFromEnv || ""
|
|
638
770
|
};
|
|
639
771
|
|
|
640
772
|
// src/core/planner.ts
|
|
641
|
-
var
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
const schemaInfo = Object.entries(schema).map(([tableName, tableSchema]) => {
|
|
648
|
-
return `Table: ${tableName}
|
|
649
|
-
Schema: ${JSON.stringify(tableSchema)}`;
|
|
650
|
-
}).join("\n\n");
|
|
651
|
-
const recentEvents = history?.slice(-5).map(
|
|
652
|
-
(event) => `Event: ${event.type} on node ${event.nodeId}${event.payload ? ` with payload ${JSON.stringify(event.payload)}` : ""}`
|
|
653
|
-
).join("\n") || "No recent events";
|
|
654
|
-
const userContextSection = userContext ? `
|
|
655
|
-
|
|
656
|
-
User Context:
|
|
657
|
-
${JSON.stringify(userContext)}` : "";
|
|
658
|
-
if (customPrompt) {
|
|
659
|
-
return customPrompt;
|
|
660
|
-
}
|
|
661
|
-
return `
|
|
662
|
-
You are an expert UI generator.
|
|
663
|
-
Create a user interface that achieves the following goal: "${goal}"
|
|
664
|
-
|
|
665
|
-
Available data schema:
|
|
666
|
-
${schemaInfo}
|
|
667
|
-
|
|
668
|
-
Recent user interactions:
|
|
669
|
-
${recentEvents}${userContextSection}
|
|
670
|
-
|
|
671
|
-
Generate a complete UI specification in JSON format that matches the following TypeScript type:
|
|
672
|
-
type UISpecNode = {
|
|
673
|
-
id: string;
|
|
674
|
-
node_type: string;
|
|
675
|
-
props?: Record<string, unknown>;
|
|
676
|
-
bindings?: Record<string, unknown>;
|
|
677
|
-
events?: Record<string, { action: string; target: string; payload?: Record<string, unknown>; }>;
|
|
678
|
-
children?: UISpecNode[];
|
|
773
|
+
var getOpenAIClient = (apiKey) => {
|
|
774
|
+
return createOpenAI({
|
|
775
|
+
apiKey,
|
|
776
|
+
// Use the provided key directly
|
|
777
|
+
compatibility: "strict"
|
|
778
|
+
});
|
|
679
779
|
};
|
|
680
|
-
|
|
681
|
-
UI Guidance:
|
|
682
|
-
1. Create a focused interface that directly addresses the goal
|
|
683
|
-
2. Use appropriate UI patterns (lists, forms, details, etc.)
|
|
684
|
-
3. Include navigation between related views when needed
|
|
685
|
-
4. Keep the interface simple and intuitive
|
|
686
|
-
5. Bind to schema data where appropriate
|
|
687
|
-
6. Provide event handlers for user interactions - make sure to always include both action and target properties
|
|
688
|
-
|
|
689
|
-
Respond ONLY with the JSON UI specification and no other text.
|
|
690
|
-
`;
|
|
691
|
-
}
|
|
692
780
|
function mockPlanner(input, targetNodeId, customPrompt) {
|
|
693
781
|
if (customPrompt) {
|
|
694
782
|
console.log("mockPlanner received customPrompt:", customPrompt);
|
|
@@ -794,7 +882,7 @@ function mockPlanner(input, targetNodeId, customPrompt) {
|
|
|
794
882
|
selectable: "true"
|
|
795
883
|
},
|
|
796
884
|
bindings: {
|
|
797
|
-
|
|
885
|
+
data: "tasks.data",
|
|
798
886
|
fields: JSON.stringify([
|
|
799
887
|
{ key: "id", label: "ID" },
|
|
800
888
|
{ key: "title", label: "Title" },
|
|
@@ -847,24 +935,35 @@ function mockPlanner(input, targetNodeId, customPrompt) {
|
|
|
847
935
|
};
|
|
848
936
|
return mockNode;
|
|
849
937
|
}
|
|
850
|
-
async function callPlannerLLM(input, routeResolution) {
|
|
938
|
+
async function callPlannerLLM(input, openaiApiKey, routeResolution) {
|
|
851
939
|
await systemEvents.emit(
|
|
852
940
|
createSystemEvent("PLAN_START" /* PLAN_START */, { plannerInput: input })
|
|
853
941
|
);
|
|
854
|
-
if (env.MOCK_PLANNER === "1"
|
|
942
|
+
if (env.MOCK_PLANNER === "1") {
|
|
855
943
|
console.warn(
|
|
856
|
-
|
|
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.`
|
|
857
951
|
);
|
|
858
952
|
return mockPlanner(input);
|
|
859
953
|
}
|
|
860
954
|
const startTime = Date.now();
|
|
861
|
-
const prompt = routeResolution?.prompt
|
|
955
|
+
const prompt = routeResolution?.prompt;
|
|
956
|
+
if (!prompt) {
|
|
957
|
+
throw new Error("ActionRouter did not provide a prompt to callPlannerLLM.");
|
|
958
|
+
}
|
|
862
959
|
await systemEvents.emit(
|
|
863
960
|
createSystemEvent("PLAN_PROMPT_CREATED" /* PLAN_PROMPT_CREATED */, { prompt })
|
|
864
961
|
);
|
|
865
962
|
try {
|
|
866
963
|
const { object: uiSpec } = await generateObject({
|
|
867
|
-
model:
|
|
964
|
+
model: getOpenAIClient(openaiApiKey)("gpt-4o", {
|
|
965
|
+
structuredOutputs: true
|
|
966
|
+
}),
|
|
868
967
|
schema: openAIUISpec,
|
|
869
968
|
messages: [{ role: "user", content: prompt }],
|
|
870
969
|
temperature: 0.2,
|
|
@@ -887,7 +986,7 @@ async function callPlannerLLM(input, routeResolution) {
|
|
|
887
986
|
throw error;
|
|
888
987
|
}
|
|
889
988
|
}
|
|
890
|
-
async function processEvent(event, router, schema, layout, dataContext, goal, userContext) {
|
|
989
|
+
async function processEvent(event, router, schema, layout, dataContext, goal, userContext, openaiApiKey) {
|
|
891
990
|
const routeResolution = await router.resolveRoute(
|
|
892
991
|
event,
|
|
893
992
|
schema,
|
|
@@ -907,7 +1006,11 @@ async function processEvent(event, router, schema, layout, dataContext, goal, us
|
|
|
907
1006
|
return layout;
|
|
908
1007
|
}
|
|
909
1008
|
const plannerInputForLLM = routeResolution.plannerInput;
|
|
910
|
-
const newLayout = await callPlannerLLM(
|
|
1009
|
+
const newLayout = await callPlannerLLM(
|
|
1010
|
+
plannerInputForLLM,
|
|
1011
|
+
openaiApiKey || "",
|
|
1012
|
+
routeResolution
|
|
1013
|
+
);
|
|
911
1014
|
return newLayout;
|
|
912
1015
|
}
|
|
913
1016
|
|
|
@@ -915,6 +1018,7 @@ async function processEvent(event, router, schema, layout, dataContext, goal, us
|
|
|
915
1018
|
function useUIStateEngine({
|
|
916
1019
|
schema,
|
|
917
1020
|
goal,
|
|
1021
|
+
openaiApiKey,
|
|
918
1022
|
userContext,
|
|
919
1023
|
mockMode = false,
|
|
920
1024
|
planningConfig,
|
|
@@ -961,7 +1065,11 @@ function useUIStateEngine({
|
|
|
961
1065
|
route.prompt
|
|
962
1066
|
);
|
|
963
1067
|
} else {
|
|
964
|
-
resolvedNode = await callPlannerLLM(
|
|
1068
|
+
resolvedNode = await callPlannerLLM(
|
|
1069
|
+
route.plannerInput,
|
|
1070
|
+
openaiApiKey || "",
|
|
1071
|
+
route
|
|
1072
|
+
);
|
|
965
1073
|
}
|
|
966
1074
|
} else {
|
|
967
1075
|
const input = {
|
|
@@ -973,7 +1081,11 @@ function useUIStateEngine({
|
|
|
973
1081
|
if (mockMode) {
|
|
974
1082
|
resolvedNode = mockPlanner(input);
|
|
975
1083
|
} else {
|
|
976
|
-
resolvedNode = await callPlannerLLM(
|
|
1084
|
+
resolvedNode = await callPlannerLLM(
|
|
1085
|
+
input,
|
|
1086
|
+
openaiApiKey || "",
|
|
1087
|
+
void 0
|
|
1088
|
+
);
|
|
977
1089
|
}
|
|
978
1090
|
}
|
|
979
1091
|
} else {
|
|
@@ -987,7 +1099,11 @@ function useUIStateEngine({
|
|
|
987
1099
|
if (mockMode) {
|
|
988
1100
|
resolvedNode = mockPlanner(input);
|
|
989
1101
|
} else {
|
|
990
|
-
resolvedNode = await callPlannerLLM(
|
|
1102
|
+
resolvedNode = await callPlannerLLM(
|
|
1103
|
+
input,
|
|
1104
|
+
openaiApiKey || "",
|
|
1105
|
+
void 0
|
|
1106
|
+
);
|
|
991
1107
|
}
|
|
992
1108
|
}
|
|
993
1109
|
switch (actionTypeForDispatch) {
|
|
@@ -1033,6 +1149,7 @@ function useUIStateEngine({
|
|
|
1033
1149
|
router,
|
|
1034
1150
|
mockMode,
|
|
1035
1151
|
dataContext,
|
|
1152
|
+
openaiApiKey,
|
|
1036
1153
|
enablePartialUpdates,
|
|
1037
1154
|
dispatch
|
|
1038
1155
|
// Add dispatch
|
|
@@ -1046,13 +1163,48 @@ function useUIStateEngine({
|
|
|
1046
1163
|
schema,
|
|
1047
1164
|
goal,
|
|
1048
1165
|
history: [],
|
|
1166
|
+
// Initial history is empty
|
|
1049
1167
|
userContext
|
|
1050
1168
|
};
|
|
1051
1169
|
let node;
|
|
1052
1170
|
if (mockMode) {
|
|
1053
1171
|
node = mockPlanner(input);
|
|
1054
1172
|
} else {
|
|
1055
|
-
|
|
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.");
|
|
1195
|
+
}
|
|
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
|
+
);
|
|
1056
1208
|
}
|
|
1057
1209
|
dispatch({ type: "AI_RESPONSE", node });
|
|
1058
1210
|
} catch (e) {
|
|
@@ -1069,34 +1221,456 @@ function useUIStateEngine({
|
|
|
1069
1221
|
}
|
|
1070
1222
|
};
|
|
1071
1223
|
initialFetch();
|
|
1072
|
-
}, [goal, schema, userContext, mockMode, dispatch]);
|
|
1224
|
+
}, [goal, schema, userContext, mockMode, dispatch, openaiApiKey]);
|
|
1073
1225
|
return {
|
|
1074
1226
|
state,
|
|
1075
1227
|
dispatch,
|
|
1076
1228
|
handleEvent
|
|
1077
1229
|
};
|
|
1078
1230
|
}
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
"
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
"
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
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);
|
|
1100
1674
|
var ShimmerBlock = () => /* @__PURE__ */ jsx("div", { className: "w-full h-8 bg-gray-200 animate-pulse rounded" });
|
|
1101
1675
|
var ShimmerTable = ({ rows = 3 }) => /* @__PURE__ */ jsxs("div", { className: "w-full space-y-2", children: [
|
|
1102
1676
|
/* @__PURE__ */ jsx("div", { className: "w-full h-10 bg-gray-200 animate-pulse rounded" }),
|
|
@@ -1125,36 +1699,10 @@ var Button = ({ onClick, children, variant = "default" }) => /* @__PURE__ */ jsx
|
|
|
1125
1699
|
"button",
|
|
1126
1700
|
{
|
|
1127
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"}`,
|
|
1128
|
-
onClick,
|
|
1702
|
+
onClick: () => onClick?.(),
|
|
1129
1703
|
children
|
|
1130
1704
|
}
|
|
1131
1705
|
);
|
|
1132
|
-
var Table = ({ items = [], fields = [], onSelect, selectable }) => /* @__PURE__ */ jsx("div", { className: "w-full border border-gray-300 dark:border-gray-700 rounded-lg overflow-hidden shadow-sm", children: /* @__PURE__ */ jsxs("table", { className: "w-full", children: [
|
|
1133
|
-
/* @__PURE__ */ jsx("thead", { className: "bg-gray-100 dark:bg-gray-800 border-b border-gray-300 dark:border-gray-700", children: /* @__PURE__ */ jsx("tr", { children: fields.map((field) => /* @__PURE__ */ jsx(
|
|
1134
|
-
"th",
|
|
1135
|
-
{
|
|
1136
|
-
className: "px-6 py-3 text-left text-xs font-medium text-gray-700 dark:text-gray-300 uppercase tracking-wider",
|
|
1137
|
-
children: field.label
|
|
1138
|
-
},
|
|
1139
|
-
field.key
|
|
1140
|
-
)) }) }),
|
|
1141
|
-
/* @__PURE__ */ jsx("tbody", { className: "bg-white dark:bg-gray-900 divide-y divide-gray-200 dark:divide-gray-700", children: items.map((item, index) => /* @__PURE__ */ jsx(
|
|
1142
|
-
"tr",
|
|
1143
|
-
{
|
|
1144
|
-
onClick: () => selectable && onSelect && onSelect(item),
|
|
1145
|
-
className: selectable ? "cursor-pointer hover:bg-gray-100 dark:hover:bg-gray-800" : "",
|
|
1146
|
-
children: fields.map((field) => /* @__PURE__ */ jsx(
|
|
1147
|
-
"td",
|
|
1148
|
-
{
|
|
1149
|
-
className: "px-6 py-4 whitespace-nowrap text-sm text-gray-800 dark:text-gray-300",
|
|
1150
|
-
children: item[field.key] ?? ""
|
|
1151
|
-
},
|
|
1152
|
-
field.key
|
|
1153
|
-
))
|
|
1154
|
-
},
|
|
1155
|
-
index
|
|
1156
|
-
)) })
|
|
1157
|
-
] }) });
|
|
1158
1706
|
var Detail = ({ data, fields = [], title, visible = true, onBack }) => {
|
|
1159
1707
|
if (!visible)
|
|
1160
1708
|
return null;
|
|
@@ -1210,7 +1758,6 @@ var getSafeProp = (props, key, validator, defaultValue) => {
|
|
|
1210
1758
|
var isObject = (value) => typeof value === "object" && value !== null;
|
|
1211
1759
|
var isString = (value) => typeof value === "string";
|
|
1212
1760
|
var isBoolean = (value) => typeof value === "boolean";
|
|
1213
|
-
var isCSSProperties = (value) => isObject(value);
|
|
1214
1761
|
var isButtonVariant = (value) => isString(value) && ["default", "outline", "destructive"].includes(value);
|
|
1215
1762
|
var getSafeBinding = (bindings, key, validator, defaultValue) => {
|
|
1216
1763
|
if (bindings && typeof bindings === "object" && key in bindings) {
|
|
@@ -1221,12 +1768,20 @@ var getSafeBinding = (bindings, key, validator, defaultValue) => {
|
|
|
1221
1768
|
}
|
|
1222
1769
|
return defaultValue;
|
|
1223
1770
|
};
|
|
1224
|
-
var isArrayOf = (itemValidator) => (arr) => Array.isArray(arr) && arr.every(itemValidator);
|
|
1225
1771
|
var isReactNode = (value) => {
|
|
1226
1772
|
return typeof value === "string" || typeof value === "number" || typeof value === "boolean" || value === null || typeof value === "undefined" || typeof value === "object" && value !== null && "$$typeof" in value;
|
|
1227
1773
|
};
|
|
1228
1774
|
var isRecordWithReactNodeValues = (value) => isObject(value) && Object.values(value).every(isReactNode);
|
|
1229
|
-
var
|
|
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
|
+
};
|
|
1230
1785
|
var isDetailFieldObject = (item) => isObject(item) && isString(item.key) && isString(item.label) && (item.type === void 0 || isString(item.type));
|
|
1231
1786
|
var createEventHandler = (node, eventName, uiEventType2, processEvent2) => {
|
|
1232
1787
|
const eventConfig = node.events?.[uiEventType2];
|
|
@@ -1246,14 +1801,36 @@ var createEventHandler = (node, eventName, uiEventType2, processEvent2) => {
|
|
|
1246
1801
|
};
|
|
1247
1802
|
};
|
|
1248
1803
|
var adapterMap = {
|
|
1249
|
-
Container: (node, processEvent2) =>
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
|
|
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
|
+
},
|
|
1257
1834
|
Header: (node) => /* @__PURE__ */ jsx(
|
|
1258
1835
|
Header,
|
|
1259
1836
|
{
|
|
@@ -1270,37 +1847,28 @@ var adapterMap = {
|
|
|
1270
1847
|
}
|
|
1271
1848
|
),
|
|
1272
1849
|
ListView: (node, processEvent2) => {
|
|
1273
|
-
const
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
|
|
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
|
|
1278
1855
|
);
|
|
1279
|
-
const
|
|
1280
|
-
|
|
1281
|
-
"fields",
|
|
1282
|
-
isArrayOf(isFieldObject),
|
|
1283
|
-
[]
|
|
1856
|
+
const children = node.children?.map(
|
|
1857
|
+
(child) => React.cloneElement(renderNode(child, processEvent2), { key: child.id })
|
|
1284
1858
|
);
|
|
1285
|
-
const selectable = getSafeProp(node.props, "selectable", isBoolean, false);
|
|
1286
1859
|
return /* @__PURE__ */ jsx(
|
|
1287
|
-
|
|
1860
|
+
"div",
|
|
1288
1861
|
{
|
|
1289
|
-
|
|
1290
|
-
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
if (handler) {
|
|
1300
|
-
handler({ selectedItem: item });
|
|
1301
|
-
}
|
|
1302
|
-
}
|
|
1303
|
-
}
|
|
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
|
|
1304
1872
|
);
|
|
1305
1873
|
},
|
|
1306
1874
|
Detail: (node, processEvent2) => {
|
|
@@ -1328,6 +1896,449 @@ var adapterMap = {
|
|
|
1328
1896
|
onBack: createEventHandler(node, "onBack", "CLICK", processEvent2)
|
|
1329
1897
|
}
|
|
1330
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;
|
|
2307
|
+
}
|
|
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
|
+
);
|
|
1331
2342
|
}
|
|
1332
2343
|
};
|
|
1333
2344
|
function renderNode(node, processEvent2) {
|
|
@@ -1424,99 +2435,261 @@ function getValueByPath(context, path) {
|
|
|
1424
2435
|
return current;
|
|
1425
2436
|
}
|
|
1426
2437
|
function setValueByPath(context, path, value) {
|
|
2438
|
+
if (!path) {
|
|
2439
|
+
return context;
|
|
2440
|
+
}
|
|
1427
2441
|
const result = { ...context };
|
|
1428
2442
|
const parts = path.split(".");
|
|
1429
|
-
if (parts.length === 0)
|
|
1430
|
-
return result;
|
|
1431
2443
|
let current = result;
|
|
1432
2444
|
for (let i = 0; i < parts.length - 1; i++) {
|
|
1433
2445
|
const part = parts[i];
|
|
1434
2446
|
if (typeof current !== "object" || current === null) {
|
|
1435
|
-
console.
|
|
2447
|
+
console.warn(
|
|
2448
|
+
`setValueByPath: Cannot traverse path "${path}". Parent segment "${parts[i - 1] || "(root)"}" is not an object.`
|
|
2449
|
+
);
|
|
1436
2450
|
return context;
|
|
1437
2451
|
}
|
|
1438
2452
|
const currentAsObject = current;
|
|
1439
|
-
|
|
2453
|
+
const nextPartValue = currentAsObject[part];
|
|
2454
|
+
if (nextPartValue === void 0 || nextPartValue === null) {
|
|
1440
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 };
|
|
1441
2463
|
}
|
|
1442
2464
|
current = currentAsObject[part];
|
|
1443
2465
|
}
|
|
1444
2466
|
const lastPart = parts[parts.length - 1];
|
|
1445
2467
|
if (typeof current === "object" && current !== null) {
|
|
1446
2468
|
current[lastPart] = value;
|
|
1447
|
-
} else if (parts.length === 1 && typeof result === "object" && result !== null) {
|
|
1448
|
-
result[lastPart] = value;
|
|
1449
2469
|
} else {
|
|
1450
2470
|
console.warn(
|
|
1451
|
-
`setValueByPath: Could not set value for path "${path}". Final segment
|
|
2471
|
+
`setValueByPath: Could not set value for path "${path}". Final segment parent is not an object.`
|
|
1452
2472
|
);
|
|
1453
2473
|
return context;
|
|
1454
2474
|
}
|
|
1455
2475
|
return result;
|
|
1456
2476
|
}
|
|
1457
|
-
function processBinding(binding, context) {
|
|
2477
|
+
function processBinding(binding, context, itemData) {
|
|
1458
2478
|
if (typeof binding === "string") {
|
|
1459
|
-
|
|
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
|
+
}
|
|
1460
2564
|
}
|
|
1461
2565
|
if (Array.isArray(binding)) {
|
|
1462
|
-
return binding.map((item) => processBinding(item, context));
|
|
2566
|
+
return binding.map((item) => processBinding(item, context, itemData));
|
|
1463
2567
|
}
|
|
1464
2568
|
if (binding !== null && typeof binding === "object") {
|
|
1465
2569
|
const result = {};
|
|
1466
2570
|
for (const [key, value] of Object.entries(binding)) {
|
|
1467
|
-
result[key] = processBinding(value, context);
|
|
2571
|
+
result[key] = processBinding(value, context, itemData);
|
|
1468
2572
|
}
|
|
1469
2573
|
return result;
|
|
1470
2574
|
}
|
|
1471
2575
|
return binding;
|
|
1472
2576
|
}
|
|
1473
|
-
async function resolveBindings(node, context) {
|
|
2577
|
+
async function resolveBindings(node, context, itemData) {
|
|
2578
|
+
const effectiveContext = itemData ? { ...context, item: itemData } : context;
|
|
1474
2579
|
const currentTime = Date.now();
|
|
1475
|
-
const cacheKey = createCacheKey(node.id,
|
|
2580
|
+
const cacheKey = createCacheKey(node.id, effectiveContext);
|
|
1476
2581
|
const cachedNode = bindingsCache.get(cacheKey);
|
|
1477
2582
|
const cachedTimestamp = nodeCacheTimestamps.get(cacheKey);
|
|
1478
2583
|
if (cachedNode && cachedTimestamp && currentTime - cachedTimestamp < CACHE_TTL2) {
|
|
1479
2584
|
return cachedNode;
|
|
1480
2585
|
}
|
|
1481
|
-
|
|
1482
|
-
|
|
1483
|
-
|
|
1484
|
-
|
|
1485
|
-
|
|
2586
|
+
if (!itemData) {
|
|
2587
|
+
await systemEvents.emit(
|
|
2588
|
+
createSystemEvent("BINDING_RESOLUTION_START" /* BINDING_RESOLUTION_START */, {
|
|
2589
|
+
layout: node
|
|
2590
|
+
})
|
|
2591
|
+
);
|
|
2592
|
+
}
|
|
1486
2593
|
const result = {
|
|
1487
2594
|
...node,
|
|
1488
|
-
props: node.props ?
|
|
1489
|
-
events: node.events ?
|
|
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
|
|
1490
2600
|
};
|
|
2601
|
+
const resolvedBindings = {};
|
|
1491
2602
|
if (node.bindings) {
|
|
1492
|
-
for (const [key,
|
|
1493
|
-
const
|
|
1494
|
-
|
|
1495
|
-
|
|
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)
|
|
1496
2608
|
result.props = {};
|
|
1497
|
-
|
|
1498
|
-
result.props[key] = value;
|
|
2609
|
+
result.props[key] = resolvedValue;
|
|
1499
2610
|
}
|
|
1500
2611
|
}
|
|
1501
2612
|
}
|
|
1502
|
-
|
|
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
|
+
}
|
|
2661
|
+
})
|
|
2662
|
+
);
|
|
2663
|
+
result.children = mappedChildren.filter(
|
|
2664
|
+
(child) => child !== null
|
|
2665
|
+
);
|
|
2666
|
+
} else if (node.children && node.children.length > 0) {
|
|
1503
2667
|
result.children = await Promise.all(
|
|
1504
|
-
node.children.map((child) => resolveBindings(child, context))
|
|
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
|
+
})
|
|
1505
2679
|
);
|
|
1506
2680
|
}
|
|
1507
|
-
await systemEvents.emit(
|
|
1508
|
-
createSystemEvent("BINDING_RESOLUTION_COMPLETE" /* BINDING_RESOLUTION_COMPLETE */, {
|
|
1509
|
-
originalLayout: node,
|
|
1510
|
-
resolvedLayout: result
|
|
1511
|
-
})
|
|
1512
|
-
);
|
|
1513
2681
|
bindingsCache.set(cacheKey, result);
|
|
1514
2682
|
nodeCacheTimestamps.set(cacheKey, currentTime);
|
|
1515
2683
|
if (bindingsCache.size > MAX_CACHE_SIZE2) {
|
|
1516
|
-
|
|
1517
|
-
|
|
1518
|
-
|
|
1519
|
-
|
|
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;
|
|
2690
|
+
}
|
|
2691
|
+
}
|
|
2692
|
+
if (oldestKey) {
|
|
1520
2693
|
bindingsCache.delete(oldestKey);
|
|
1521
2694
|
nodeCacheTimestamps.delete(oldestKey);
|
|
1522
2695
|
}
|
|
@@ -1649,6 +2822,31 @@ function getMissingComponentsMessage() {
|
|
|
1649
2822
|
return `Missing required shadcn components. Please run:
|
|
1650
2823
|
> npm run setup-shadcn`;
|
|
1651
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
|
+
}
|
|
1652
2850
|
var AutoUI = ({
|
|
1653
2851
|
schema,
|
|
1654
2852
|
goal,
|
|
@@ -1658,11 +2856,12 @@ var AutoUI = ({
|
|
|
1658
2856
|
eventHooks,
|
|
1659
2857
|
systemEventHooks,
|
|
1660
2858
|
debugMode = false,
|
|
1661
|
-
mockMode =
|
|
2859
|
+
mockMode = false,
|
|
1662
2860
|
planningConfig,
|
|
1663
2861
|
integration = {},
|
|
1664
2862
|
scope = {},
|
|
1665
|
-
enablePartialUpdates = false
|
|
2863
|
+
enablePartialUpdates = false,
|
|
2864
|
+
openaiApiKey
|
|
1666
2865
|
}) => {
|
|
1667
2866
|
const [schemaAdapterInstance] = useState(null);
|
|
1668
2867
|
const [dataContext, setDataContext] = useState({});
|
|
@@ -1734,7 +2933,8 @@ var AutoUI = ({
|
|
|
1734
2933
|
planningConfig,
|
|
1735
2934
|
router: void 0,
|
|
1736
2935
|
dataContext,
|
|
1737
|
-
enablePartialUpdates
|
|
2936
|
+
enablePartialUpdates,
|
|
2937
|
+
openaiApiKey
|
|
1738
2938
|
});
|
|
1739
2939
|
const eventManagerRef = useRef(new EventManager());
|
|
1740
2940
|
useEffect(() => {
|
|
@@ -1834,13 +3034,29 @@ var AutoUI = ({
|
|
|
1834
3034
|
null
|
|
1835
3035
|
);
|
|
1836
3036
|
const resolveLayoutBindings = useCallback(async () => {
|
|
1837
|
-
if (state.layout) {
|
|
1838
|
-
|
|
1839
|
-
|
|
1840
|
-
|
|
1841
|
-
|
|
1842
|
-
|
|
1843
|
-
|
|
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
|
+
);
|
|
1844
3060
|
} else {
|
|
1845
3061
|
setResolvedLayout(void 0);
|
|
1846
3062
|
}
|
|
@@ -2047,12 +3263,23 @@ var generateUIComponent = async (prompt) => {
|
|
|
2047
3263
|
return `<div>Generated UI Component for: ${prompt}</div>`;
|
|
2048
3264
|
};
|
|
2049
3265
|
function usePlanner(options) {
|
|
2050
|
-
const {
|
|
2051
|
-
|
|
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
|
+
);
|
|
2052
3277
|
const [loading, setLoading] = useState(false);
|
|
2053
3278
|
const [error, setError] = useState(null);
|
|
2054
|
-
const router =
|
|
3279
|
+
const router = options.router || createDefaultRouter();
|
|
2055
3280
|
const dataContext = {};
|
|
3281
|
+
const initialFetchAttempted = useRef(false);
|
|
3282
|
+
const mockMode = optionsMockMode || !openaiApiKey;
|
|
2056
3283
|
const generateInitialLayout = useCallback(async () => {
|
|
2057
3284
|
setLoading(true);
|
|
2058
3285
|
setError(null);
|
|
@@ -2063,14 +3290,26 @@ function usePlanner(options) {
|
|
|
2063
3290
|
userContext: userContext || null,
|
|
2064
3291
|
history: null
|
|
2065
3292
|
};
|
|
2066
|
-
|
|
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
|
+
}
|
|
2067
3306
|
setLayout(generatedLayout);
|
|
2068
3307
|
} catch (err) {
|
|
2069
3308
|
setError(err instanceof Error ? err : new Error(String(err)));
|
|
2070
3309
|
} finally {
|
|
2071
3310
|
setLoading(false);
|
|
2072
3311
|
}
|
|
2073
|
-
}, [schema, goal, userContext]);
|
|
3312
|
+
}, [schema, goal, userContext, openaiApiKey, mockMode]);
|
|
2074
3313
|
const handleEvent = useCallback(
|
|
2075
3314
|
async (event) => {
|
|
2076
3315
|
if (!layout) {
|
|
@@ -2087,7 +3326,8 @@ function usePlanner(options) {
|
|
|
2087
3326
|
layout,
|
|
2088
3327
|
dataContext,
|
|
2089
3328
|
goal,
|
|
2090
|
-
userContext
|
|
3329
|
+
userContext,
|
|
3330
|
+
openaiApiKey
|
|
2091
3331
|
);
|
|
2092
3332
|
setLayout(updatedLayout);
|
|
2093
3333
|
} catch (err) {
|
|
@@ -2096,8 +3336,14 @@ function usePlanner(options) {
|
|
|
2096
3336
|
setLoading(false);
|
|
2097
3337
|
}
|
|
2098
3338
|
},
|
|
2099
|
-
[layout, router, schema, dataContext, goal, userContext]
|
|
3339
|
+
[layout, router, schema, dataContext, goal, userContext, openaiApiKey]
|
|
2100
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]);
|
|
2101
3347
|
return {
|
|
2102
3348
|
layout,
|
|
2103
3349
|
loading,
|