@agentuity/workbench 0.0.86 → 0.0.88
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/components/App.d.ts.map +1 -1
- package/dist/components/App.js +18 -2
- package/dist/components/App.js.map +1 -1
- package/dist/components/ai-elements/code-block.d.ts +3 -3
- package/dist/components/ai-elements/code-block.d.ts.map +1 -1
- package/dist/components/ai-elements/code-block.js +29 -7
- package/dist/components/ai-elements/code-block.js.map +1 -1
- package/dist/components/internal/Chat.d.ts +3 -2
- package/dist/components/internal/Chat.d.ts.map +1 -1
- package/dist/components/internal/Chat.js +23 -24
- package/dist/components/internal/Chat.js.map +1 -1
- package/dist/components/internal/InputSection.d.ts +3 -2
- package/dist/components/internal/InputSection.d.ts.map +1 -1
- package/dist/components/internal/InputSection.js +68 -6
- package/dist/components/internal/InputSection.js.map +1 -1
- package/dist/components/internal/MonacoJsonEditor.d.ts +3 -1
- package/dist/components/internal/MonacoJsonEditor.d.ts.map +1 -1
- package/dist/components/internal/MonacoJsonEditor.js +41 -57
- package/dist/components/internal/MonacoJsonEditor.js.map +1 -1
- package/dist/components/internal/Schema.d.ts +1 -2
- package/dist/components/internal/Schema.d.ts.map +1 -1
- package/dist/components/internal/Schema.js +2 -3
- package/dist/components/internal/Schema.js.map +1 -1
- package/dist/components/internal/WorkbenchProvider.d.ts.map +1 -1
- package/dist/components/internal/WorkbenchProvider.js +55 -8
- package/dist/components/internal/WorkbenchProvider.js.map +1 -1
- package/dist/components/ui/button.d.ts +1 -1
- package/dist/components/ui/input-group.js +2 -2
- package/dist/components/ui/input-group.js.map +1 -1
- package/dist/components/ui/input.d.ts.map +1 -1
- package/dist/components/ui/input.js +1 -1
- package/dist/components/ui/input.js.map +1 -1
- package/dist/index.d.ts +3 -5
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -6
- package/dist/index.js.map +1 -1
- package/dist/{styles.css → standalone.css} +206 -1554
- package/package.json +29 -29
- package/src/{styles.css → base.css} +36 -52
- package/src/components/App.tsx +41 -5
- package/src/components/ai-elements/code-block.tsx +42 -10
- package/src/components/internal/Chat.tsx +112 -119
- package/src/components/internal/InputSection.tsx +79 -9
- package/src/components/internal/MonacoJsonEditor.tsx +59 -65
- package/src/components/internal/Schema.tsx +74 -86
- package/src/components/internal/WorkbenchProvider.tsx +69 -10
- package/src/components/ui/input-group.tsx +2 -2
- package/src/components/ui/input.tsx +2 -3
- package/src/index.ts +5 -14
- package/src/integration.css +15 -0
- package/src/standalone.css +25 -0
- package/dist/components/ConnectionStatus.d.ts +0 -7
- package/dist/components/ConnectionStatus.d.ts.map +0 -1
- package/dist/components/ConnectionStatus.js +0 -52
- package/dist/components/ConnectionStatus.js.map +0 -1
- package/dist/components/Inline.d.ts +0 -10
- package/dist/components/Inline.d.ts.map +0 -1
- package/dist/components/Inline.js +0 -11
- package/dist/components/Inline.js.map +0 -1
- package/dist/components/ai-elements/artifact.d.ts +0 -24
- package/dist/components/ai-elements/artifact.d.ts.map +0 -1
- package/dist/components/ai-elements/artifact.js +0 -21
- package/dist/components/ai-elements/artifact.js.map +0 -1
- package/dist/components/ai-elements/branch.d.ts +0 -21
- package/dist/components/ai-elements/branch.d.ts.map +0 -1
- package/dist/components/ai-elements/branch.js +0 -71
- package/dist/components/ai-elements/branch.js.map +0 -1
- package/dist/components/ai-elements/canvas.d.ts +0 -9
- package/dist/components/ai-elements/canvas.d.ts.map +0 -1
- package/dist/components/ai-elements/canvas.js +0 -6
- package/dist/components/ai-elements/canvas.js.map +0 -1
- package/dist/components/ai-elements/chain-of-thought.d.ts +0 -30
- package/dist/components/ai-elements/chain-of-thought.d.ts.map +0 -1
- package/dist/components/ai-elements/chain-of-thought.js +0 -52
- package/dist/components/ai-elements/chain-of-thought.js.map +0 -1
- package/dist/components/ai-elements/confirmation.d.ts +0 -27
- package/dist/components/ai-elements/confirmation.d.ts.map +0 -1
- package/dist/components/ai-elements/confirmation.js +0 -57
- package/dist/components/ai-elements/confirmation.js.map +0 -1
- package/dist/components/ai-elements/connection.d.ts +0 -3
- package/dist/components/ai-elements/connection.d.ts.map +0 -1
- package/dist/components/ai-elements/connection.js +0 -4
- package/dist/components/ai-elements/connection.js.map +0 -1
- package/dist/components/ai-elements/context.d.ts +0 -33
- package/dist/components/ai-elements/context.d.ts.map +0 -1
- package/dist/components/ai-elements/context.js +0 -167
- package/dist/components/ai-elements/context.js.map +0 -1
- package/dist/components/ai-elements/controls.d.ts +0 -5
- package/dist/components/ai-elements/controls.d.ts.map +0 -1
- package/dist/components/ai-elements/controls.js +0 -6
- package/dist/components/ai-elements/controls.js.map +0 -1
- package/dist/components/ai-elements/edge.d.ts +0 -6
- package/dist/components/ai-elements/edge.d.ts.map +0 -1
- package/dist/components/ai-elements/edge.js +0 -83
- package/dist/components/ai-elements/edge.js.map +0 -1
- package/dist/components/ai-elements/image.d.ts +0 -7
- package/dist/components/ai-elements/image.d.ts.map +0 -1
- package/dist/components/ai-elements/image.js +0 -4
- package/dist/components/ai-elements/image.js.map +0 -1
- package/dist/components/ai-elements/inline-citation.d.ts +0 -39
- package/dist/components/ai-elements/inline-citation.d.ts.map +0 -1
- package/dist/components/ai-elements/inline-citation.js +0 -62
- package/dist/components/ai-elements/inline-citation.js.map +0 -1
- package/dist/components/ai-elements/loader.d.ts +0 -6
- package/dist/components/ai-elements/loader.d.ts.map +0 -1
- package/dist/components/ai-elements/loader.js +0 -5
- package/dist/components/ai-elements/loader.js.map +0 -1
- package/dist/components/ai-elements/node.d.ts +0 -22
- package/dist/components/ai-elements/node.d.ts.map +0 -1
- package/dist/components/ai-elements/node.js +0 -12
- package/dist/components/ai-elements/node.js.map +0 -1
- package/dist/components/ai-elements/open-in-chat.d.ts +0 -29
- package/dist/components/ai-elements/open-in-chat.d.ts.map +0 -1
- package/dist/components/ai-elements/open-in-chat.js +0 -97
- package/dist/components/ai-elements/open-in-chat.js.map +0 -1
- package/dist/components/ai-elements/panel.d.ts +0 -6
- package/dist/components/ai-elements/panel.d.ts.map +0 -1
- package/dist/components/ai-elements/panel.js +0 -5
- package/dist/components/ai-elements/panel.js.map +0 -1
- package/dist/components/ai-elements/plan.d.ts +0 -26
- package/dist/components/ai-elements/plan.d.ts.map +0 -1
- package/dist/components/ai-elements/plan.js +0 -32
- package/dist/components/ai-elements/plan.js.map +0 -1
- package/dist/components/ai-elements/queue.d.ts +0 -62
- package/dist/components/ai-elements/queue.d.ts.map +0 -1
- package/dist/components/ai-elements/queue.js +0 -25
- package/dist/components/ai-elements/queue.js.map +0 -1
- package/dist/components/ai-elements/reasoning.d.ts +0 -17
- package/dist/components/ai-elements/reasoning.d.ts.map +0 -1
- package/dist/components/ai-elements/reasoning.js +0 -77
- package/dist/components/ai-elements/reasoning.js.map +0 -1
- package/dist/components/ai-elements/response.d.ts +0 -6
- package/dist/components/ai-elements/response.d.ts.map +0 -1
- package/dist/components/ai-elements/response.js +0 -8
- package/dist/components/ai-elements/response.js.map +0 -1
- package/dist/components/ai-elements/sources.d.ts +0 -13
- package/dist/components/ai-elements/sources.d.ts.map +0 -1
- package/dist/components/ai-elements/sources.js +0 -10
- package/dist/components/ai-elements/sources.js.map +0 -1
- package/dist/components/ai-elements/suggestion.d.ts +0 -11
- package/dist/components/ai-elements/suggestion.d.ts.map +0 -1
- package/dist/components/ai-elements/suggestion.js +0 -13
- package/dist/components/ai-elements/suggestion.js.map +0 -1
- package/dist/components/ai-elements/task.d.ts +0 -15
- package/dist/components/ai-elements/task.d.ts.map +0 -1
- package/dist/components/ai-elements/task.js +0 -11
- package/dist/components/ai-elements/task.js.map +0 -1
- package/dist/components/ai-elements/tool.d.ts +0 -24
- package/dist/components/ai-elements/tool.d.ts.map +0 -1
- package/dist/components/ai-elements/tool.js +0 -47
- package/dist/components/ai-elements/tool.js.map +0 -1
- package/dist/components/ai-elements/toolbar.d.ts +0 -6
- package/dist/components/ai-elements/toolbar.d.ts.map +0 -1
- package/dist/components/ai-elements/toolbar.js +0 -5
- package/dist/components/ai-elements/toolbar.js.map +0 -1
- package/dist/components/ai-elements/web-preview.d.ts +0 -35
- package/dist/components/ai-elements/web-preview.d.ts.map +0 -1
- package/dist/components/ai-elements/web-preview.js +0 -63
- package/dist/components/ai-elements/web-preview.js.map +0 -1
- package/dist/components/ui/alert.d.ts +0 -10
- package/dist/components/ui/alert.d.ts.map +0 -1
- package/dist/components/ui/alert.js +0 -25
- package/dist/components/ui/alert.js.map +0 -1
- package/dist/components/ui/badge.d.ts +0 -10
- package/dist/components/ui/badge.d.ts.map +0 -1
- package/dist/components/ui/badge.js +0 -23
- package/dist/components/ui/badge.js.map +0 -1
- package/dist/components/ui/card.d.ts +0 -10
- package/dist/components/ui/card.d.ts.map +0 -1
- package/dist/components/ui/card.js +0 -25
- package/dist/components/ui/card.js.map +0 -1
- package/dist/components/ui/carousel.d.ts +0 -20
- package/dist/components/ui/carousel.d.ts.map +0 -1
- package/dist/components/ui/carousel.js +0 -92
- package/dist/components/ui/carousel.js.map +0 -1
- package/dist/components/ui/checkbox.d.ts +0 -5
- package/dist/components/ui/checkbox.d.ts.map +0 -1
- package/dist/components/ui/checkbox.js +0 -9
- package/dist/components/ui/checkbox.js.map +0 -1
- package/dist/components/ui/collapsible.d.ts +0 -6
- package/dist/components/ui/collapsible.d.ts.map +0 -1
- package/dist/components/ui/collapsible.js +0 -14
- package/dist/components/ui/collapsible.js.map +0 -1
- package/dist/components/ui/field.d.ts +0 -25
- package/dist/components/ui/field.d.ts.map +0 -1
- package/dist/components/ui/field.js +0 -74
- package/dist/components/ui/field.js.map +0 -1
- package/dist/components/ui/form.d.ts +0 -25
- package/dist/components/ui/form.d.ts.map +0 -1
- package/dist/components/ui/form.js +0 -58
- package/dist/components/ui/form.js.map +0 -1
- package/dist/components/ui/label.d.ts +0 -5
- package/dist/components/ui/label.d.ts.map +0 -1
- package/dist/components/ui/label.js +0 -9
- package/dist/components/ui/label.js.map +0 -1
- package/dist/components/ui/progress.d.ts +0 -5
- package/dist/components/ui/progress.d.ts.map +0 -1
- package/dist/components/ui/progress.js +0 -9
- package/dist/components/ui/progress.js.map +0 -1
- package/dist/components/ui/separator.d.ts +0 -5
- package/dist/components/ui/separator.d.ts.map +0 -1
- package/dist/components/ui/separator.js +0 -9
- package/dist/components/ui/separator.js.map +0 -1
- package/dist/components/ui/switch.d.ts +0 -5
- package/dist/components/ui/switch.d.ts.map +0 -1
- package/dist/components/ui/switch.js +0 -8
- package/dist/components/ui/switch.js.map +0 -1
- package/dist/components/ui/tabs.d.ts +0 -8
- package/dist/components/ui/tabs.d.ts.map +0 -1
- package/dist/components/ui/tabs.js +0 -17
- package/dist/components/ui/tabs.js.map +0 -1
- package/dist/components/ui/toggle.d.ts +0 -10
- package/dist/components/ui/toggle.d.ts.map +0 -1
- package/dist/components/ui/toggle.js +0 -26
- package/dist/components/ui/toggle.js.map +0 -1
- package/dist/components.d.ts +0 -12
- package/dist/components.d.ts.map +0 -1
- package/dist/components.js +0 -13
- package/dist/components.js.map +0 -1
- package/dist/hooks/index.d.ts +0 -7
- package/dist/hooks/index.d.ts.map +0 -1
- package/dist/hooks/index.js +0 -5
- package/dist/hooks/index.js.map +0 -1
- package/dist/hooks/useWorkbenchSchemas.d.ts +0 -56
- package/dist/hooks/useWorkbenchSchemas.d.ts.map +0 -1
- package/dist/hooks/useWorkbenchSchemas.js +0 -63
- package/dist/hooks/useWorkbenchSchemas.js.map +0 -1
- package/src/components/ConnectionStatus.tsx +0 -67
- package/src/components/Inline.tsx +0 -16
- package/src/components/ai-elements/artifact.tsx +0 -118
- package/src/components/ai-elements/branch.tsx +0 -187
- package/src/components/ai-elements/canvas.tsx +0 -24
- package/src/components/ai-elements/chain-of-thought.tsx +0 -198
- package/src/components/ai-elements/confirmation.tsx +0 -119
- package/src/components/ai-elements/connection.tsx +0 -16
- package/src/components/ai-elements/context.tsx +0 -357
- package/src/components/ai-elements/controls.tsx +0 -18
- package/src/components/ai-elements/edge.tsx +0 -131
- package/src/components/ai-elements/image.tsx +0 -16
- package/src/components/ai-elements/inline-citation.tsx +0 -246
- package/src/components/ai-elements/loader.tsx +0 -88
- package/src/components/ai-elements/node.tsx +0 -66
- package/src/components/ai-elements/open-in-chat.tsx +0 -333
- package/src/components/ai-elements/panel.tsx +0 -12
- package/src/components/ai-elements/plan.tsx +0 -123
- package/src/components/ai-elements/queue.tsx +0 -231
- package/src/components/ai-elements/reasoning.tsx +0 -163
- package/src/components/ai-elements/response.tsx +0 -19
- package/src/components/ai-elements/sources.tsx +0 -53
- package/src/components/ai-elements/suggestion.tsx +0 -47
- package/src/components/ai-elements/task.tsx +0 -64
- package/src/components/ai-elements/tool.tsx +0 -136
- package/src/components/ai-elements/toolbar.tsx +0 -13
- package/src/components/ai-elements/web-preview.tsx +0 -238
- package/src/components/ui/alert.tsx +0 -60
- package/src/components/ui/badge.tsx +0 -40
- package/src/components/ui/card.tsx +0 -41
- package/src/components/ui/carousel.tsx +0 -234
- package/src/components/ui/checkbox.tsx +0 -27
- package/src/components/ui/collapsible.tsx +0 -21
- package/src/components/ui/field.tsx +0 -234
- package/src/components/ui/form.tsx +0 -154
- package/src/components/ui/label.tsx +0 -21
- package/src/components/ui/progress.tsx +0 -28
- package/src/components/ui/separator.tsx +0 -28
- package/src/components/ui/switch.tsx +0 -26
- package/src/components/ui/tabs.tsx +0 -52
- package/src/components/ui/toggle.tsx +0 -44
- package/src/components.tsx +0 -29
- package/src/hooks/index.ts +0 -20
- package/src/hooks/useWorkbenchSchemas.ts +0 -69
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import React, { useMemo, useState } from 'react';
|
|
1
|
+
import React, { useMemo, useState, useCallback, useEffect } from 'react';
|
|
2
2
|
import {
|
|
3
3
|
CheckIcon,
|
|
4
4
|
ChevronsUpDownIcon,
|
|
@@ -41,7 +41,8 @@ export interface InputSectionProps {
|
|
|
41
41
|
selectedAgent: string;
|
|
42
42
|
setSelectedAgent: (agentId: string) => void;
|
|
43
43
|
suggestions: string[];
|
|
44
|
-
|
|
44
|
+
isSchemaOpen: boolean;
|
|
45
|
+
onSchemaToggle: () => void;
|
|
45
46
|
}
|
|
46
47
|
|
|
47
48
|
function isSchemaRootObject(schemaJson?: JSONSchema7): boolean {
|
|
@@ -65,10 +66,13 @@ export function InputSection({
|
|
|
65
66
|
selectedAgent,
|
|
66
67
|
setSelectedAgent,
|
|
67
68
|
suggestions,
|
|
68
|
-
|
|
69
|
+
isSchemaOpen,
|
|
70
|
+
onSchemaToggle,
|
|
69
71
|
}: InputSectionProps) {
|
|
70
72
|
const logger = useLogger('InputSection');
|
|
71
73
|
const [agentSelectOpen, setAgentSelectOpen] = useState(false);
|
|
74
|
+
const [isValidInput, setIsValidInput] = useState(true);
|
|
75
|
+
const [monacoHasErrors, setMonacoHasErrors] = useState<boolean | null>(null);
|
|
72
76
|
|
|
73
77
|
const selectedAgentData = Object.values(agents).find(
|
|
74
78
|
(agent) => agent.metadata.agentId === selectedAgent
|
|
@@ -95,10 +99,66 @@ export function InputSection({
|
|
|
95
99
|
return 'string'; // String schema
|
|
96
100
|
}
|
|
97
101
|
return 'none'; // Default to none for other types
|
|
98
|
-
}, [selectedAgentData?.schema.input?.json]);
|
|
102
|
+
}, [selectedAgentData?.schema.input?.json, logger]);
|
|
99
103
|
|
|
100
104
|
const isObjectSchema = inputType === 'object';
|
|
101
105
|
|
|
106
|
+
// Validate JSON input against schema using zod (fallback for non-Monaco cases)
|
|
107
|
+
const validateInput = useCallback(
|
|
108
|
+
(inputValue: string, schema?: JSONSchema7): boolean => {
|
|
109
|
+
if (!schema || !isObjectSchema || !inputValue.trim()) {
|
|
110
|
+
return true; // No validation needed or empty input
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
try {
|
|
114
|
+
// Parse JSON first
|
|
115
|
+
const parsedJson = JSON.parse(inputValue);
|
|
116
|
+
|
|
117
|
+
// Convert schema to zod and validate
|
|
118
|
+
const schemaObject = typeof schema === 'string' ? JSON.parse(schema) : schema;
|
|
119
|
+
const zodSchema = convertJsonSchemaToZod(schemaObject);
|
|
120
|
+
|
|
121
|
+
// Validate with zod
|
|
122
|
+
const result = zodSchema.safeParse(parsedJson);
|
|
123
|
+
return result.success;
|
|
124
|
+
} catch {
|
|
125
|
+
// JSON parse error or schema validation error
|
|
126
|
+
return false;
|
|
127
|
+
}
|
|
128
|
+
},
|
|
129
|
+
[isObjectSchema]
|
|
130
|
+
);
|
|
131
|
+
|
|
132
|
+
// Reset Monaco error state when schema changes
|
|
133
|
+
useEffect(() => {
|
|
134
|
+
if (isObjectSchema) {
|
|
135
|
+
setMonacoHasErrors(null);
|
|
136
|
+
}
|
|
137
|
+
}, [selectedAgentData?.schema?.input?.json, isObjectSchema]);
|
|
138
|
+
|
|
139
|
+
// Update validation state - use Monaco errors if available, otherwise fall back to zod validation
|
|
140
|
+
useEffect(() => {
|
|
141
|
+
if (isObjectSchema) {
|
|
142
|
+
if (monacoHasErrors !== null) {
|
|
143
|
+
// Monaco is handling validation, use its error state
|
|
144
|
+
setIsValidInput(!monacoHasErrors);
|
|
145
|
+
} else {
|
|
146
|
+
// Monaco hasn't reported yet, use zod validation as fallback
|
|
147
|
+
const isValid = validateInput(value, selectedAgentData?.schema?.input?.json);
|
|
148
|
+
setIsValidInput(isValid);
|
|
149
|
+
}
|
|
150
|
+
} else {
|
|
151
|
+
// No schema or not object schema
|
|
152
|
+
setIsValidInput(true);
|
|
153
|
+
}
|
|
154
|
+
}, [
|
|
155
|
+
value,
|
|
156
|
+
selectedAgentData?.schema?.input?.json,
|
|
157
|
+
validateInput,
|
|
158
|
+
isObjectSchema,
|
|
159
|
+
monacoHasErrors,
|
|
160
|
+
]);
|
|
161
|
+
|
|
102
162
|
const handleGenerateSample = () => {
|
|
103
163
|
if (!selectedAgentData?.schema.input?.json || !isObjectSchema) return;
|
|
104
164
|
|
|
@@ -115,6 +175,14 @@ export function InputSection({
|
|
|
115
175
|
}
|
|
116
176
|
};
|
|
117
177
|
|
|
178
|
+
// Memoized submit disabled condition for readability
|
|
179
|
+
const isSubmitDisabled = useMemo(() => {
|
|
180
|
+
if (isLoading) return true;
|
|
181
|
+
if (inputType === 'string' && !value.trim()) return true;
|
|
182
|
+
if (inputType === 'object' && (!isValidInput || !value.trim())) return true;
|
|
183
|
+
return false;
|
|
184
|
+
}, [isLoading, inputType, value, isValidInput]);
|
|
185
|
+
|
|
118
186
|
return (
|
|
119
187
|
<>
|
|
120
188
|
<div className="flex items-center gap-2 py-2 px-3">
|
|
@@ -213,11 +281,11 @@ export function InputSection({
|
|
|
213
281
|
)}
|
|
214
282
|
|
|
215
283
|
<Button
|
|
216
|
-
aria-label=
|
|
284
|
+
aria-label={isSchemaOpen ? 'Hide Schema' : 'View Schema'}
|
|
217
285
|
size="sm"
|
|
218
|
-
variant=
|
|
219
|
-
className=
|
|
220
|
-
onClick={
|
|
286
|
+
variant={isSchemaOpen ? 'default' : 'outline'}
|
|
287
|
+
className={cn('font-normal', isSchemaOpen ? 'bg-primary' : 'bg-none')}
|
|
288
|
+
onClick={onSchemaToggle}
|
|
221
289
|
>
|
|
222
290
|
<FileJson className="size-4" /> Schema
|
|
223
291
|
</Button>
|
|
@@ -234,6 +302,8 @@ export function InputSection({
|
|
|
234
302
|
onChange={onChange}
|
|
235
303
|
schema={selectedAgentData?.schema.input?.json}
|
|
236
304
|
schemaUri={`agentuity://schema/${selectedAgentData?.metadata.id}/input`}
|
|
305
|
+
aria-invalid={!isValidInput}
|
|
306
|
+
onValidationChange={setMonacoHasErrors}
|
|
237
307
|
/>
|
|
238
308
|
);
|
|
239
309
|
|
|
@@ -279,7 +349,7 @@ export function InputSection({
|
|
|
279
349
|
aria-label="Submit"
|
|
280
350
|
size="icon"
|
|
281
351
|
variant="default"
|
|
282
|
-
disabled={
|
|
352
|
+
disabled={isSubmitDisabled}
|
|
283
353
|
onClick={() => {
|
|
284
354
|
logger.debug(
|
|
285
355
|
'🔥 Submit button clicked! inputType:',
|
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
import React, { useEffect, useState } from 'react';
|
|
2
2
|
import Editor, { type Monaco, type OnMount } from '@monaco-editor/react';
|
|
3
3
|
import { useTheme } from '../ui/theme-provider';
|
|
4
|
-
import { bundledThemes } from 'shiki';
|
|
5
4
|
import type { JSONSchema7 } from 'ai';
|
|
5
|
+
import type * as monaco from 'monaco-editor';
|
|
6
|
+
import type { ThemeRegistration } from 'shiki';
|
|
7
|
+
import oneLightModule from '@shikijs/themes/one-light';
|
|
8
|
+
import oneDarkProModule from '@shikijs/themes/one-dark-pro';
|
|
6
9
|
|
|
7
10
|
interface MonacoJsonEditorProps {
|
|
8
11
|
value: string;
|
|
@@ -10,6 +13,8 @@ interface MonacoJsonEditorProps {
|
|
|
10
13
|
schema?: JSONSchema7;
|
|
11
14
|
schemaUri?: string;
|
|
12
15
|
className?: string;
|
|
16
|
+
'aria-invalid'?: boolean;
|
|
17
|
+
onValidationChange?: (hasErrors: boolean) => void;
|
|
13
18
|
}
|
|
14
19
|
|
|
15
20
|
// Convert color value to valid hex for Monaco
|
|
@@ -104,6 +109,8 @@ export function MonacoJsonEditor({
|
|
|
104
109
|
schema,
|
|
105
110
|
schemaUri = 'agentuity://schema/default',
|
|
106
111
|
className = '',
|
|
112
|
+
'aria-invalid': ariaInvalid,
|
|
113
|
+
onValidationChange,
|
|
107
114
|
}: MonacoJsonEditorProps) {
|
|
108
115
|
const { theme } = useTheme();
|
|
109
116
|
const [editorInstance, setEditorInstance] = useState<Parameters<OnMount>[0] | null>(null);
|
|
@@ -120,13 +127,16 @@ export function MonacoJsonEditor({
|
|
|
120
127
|
|
|
121
128
|
// Configure JSON schema when schema or monacoInstance changes
|
|
122
129
|
useEffect(() => {
|
|
123
|
-
if (!monacoInstance || !schema)
|
|
130
|
+
if (!monacoInstance || !schema) {
|
|
131
|
+
return;
|
|
132
|
+
}
|
|
124
133
|
|
|
125
134
|
const schemaObject = typeof schema === 'string' ? JSON.parse(schema) : schema;
|
|
126
135
|
|
|
127
136
|
// Configure Monaco JSON language support for schema validation
|
|
128
137
|
monacoInstance.languages.json.jsonDefaults.setDiagnosticsOptions({
|
|
129
138
|
validate: true,
|
|
139
|
+
allowComments: false,
|
|
130
140
|
schemas: [
|
|
131
141
|
{
|
|
132
142
|
uri: schemaUri,
|
|
@@ -134,6 +144,9 @@ export function MonacoJsonEditor({
|
|
|
134
144
|
schema: schemaObject,
|
|
135
145
|
},
|
|
136
146
|
],
|
|
147
|
+
enableSchemaRequest: true,
|
|
148
|
+
schemaRequest: 'error',
|
|
149
|
+
schemaValidation: 'error',
|
|
137
150
|
});
|
|
138
151
|
}, [monacoInstance, schema, schemaUri]);
|
|
139
152
|
|
|
@@ -148,6 +161,8 @@ export function MonacoJsonEditor({
|
|
|
148
161
|
|
|
149
162
|
return (
|
|
150
163
|
<div
|
|
164
|
+
data-slot="input-group-control"
|
|
165
|
+
aria-invalid={ariaInvalid}
|
|
151
166
|
className={`w-full pl-3 pb-3 [&_.monaco-editor]:!bg-transparent [&_.monaco-editor-background]:!bg-transparent [&_.view-lines]:!bg-transparent [&_.monaco-editor]:!shadow-none [&_.monaco-scrollable-element]:!shadow-none [&_.overflow-guard]:!shadow-none [&_.monaco-scrollable-element>.shadow.top]:!hidden [&_.monaco-editor_.scroll-decoration]:!hidden [&_.shadow.top]:!hidden [&_.scroll-decoration]:!hidden ${className}`}
|
|
152
167
|
style={{ minHeight: '64px', maxHeight: '192px', height: `${editorHeight}px` }}
|
|
153
168
|
>
|
|
@@ -192,7 +207,7 @@ export function MonacoJsonEditor({
|
|
|
192
207
|
},
|
|
193
208
|
padding: { top: 12, bottom: 12 },
|
|
194
209
|
// Additional background transparency options
|
|
195
|
-
renderValidationDecorations: '
|
|
210
|
+
renderValidationDecorations: 'on',
|
|
196
211
|
guides: {
|
|
197
212
|
indentation: false,
|
|
198
213
|
highlightActiveIndentation: false,
|
|
@@ -223,6 +238,35 @@ export function MonacoJsonEditor({
|
|
|
223
238
|
// Update height on content changes
|
|
224
239
|
editor.onDidChangeModelContent(updateHeight);
|
|
225
240
|
|
|
241
|
+
// Listen to validation markers to detect schema errors
|
|
242
|
+
if (onValidationChange) {
|
|
243
|
+
const checkValidationErrors = () => {
|
|
244
|
+
const model = editor.getModel();
|
|
245
|
+
if (model) {
|
|
246
|
+
const markers = monaco.editor.getModelMarkers({ resource: model.uri });
|
|
247
|
+
const hasErrors = markers.some(
|
|
248
|
+
(marker: monaco.editor.IMarker) =>
|
|
249
|
+
marker.severity === monaco.MarkerSeverity.Error
|
|
250
|
+
);
|
|
251
|
+
onValidationChange(hasErrors);
|
|
252
|
+
}
|
|
253
|
+
};
|
|
254
|
+
|
|
255
|
+
// Check on model changes
|
|
256
|
+
editor.onDidChangeModelContent(checkValidationErrors);
|
|
257
|
+
|
|
258
|
+
// Check when markers change
|
|
259
|
+
monaco.editor.onDidChangeMarkers((uris: monaco.Uri[]) => {
|
|
260
|
+
const model = editor.getModel();
|
|
261
|
+
if (model && uris.includes(model.uri)) {
|
|
262
|
+
checkValidationErrors();
|
|
263
|
+
}
|
|
264
|
+
});
|
|
265
|
+
|
|
266
|
+
// Initial check
|
|
267
|
+
setTimeout(checkValidationErrors, 100);
|
|
268
|
+
}
|
|
269
|
+
|
|
226
270
|
// Initial height update
|
|
227
271
|
setTimeout(updateHeight, 0);
|
|
228
272
|
|
|
@@ -286,72 +330,22 @@ export function MonacoJsonEditor({
|
|
|
286
330
|
}
|
|
287
331
|
}, 0);
|
|
288
332
|
}}
|
|
289
|
-
beforeMount={
|
|
333
|
+
beforeMount={(monaco) => {
|
|
290
334
|
setMonacoInstance(monaco);
|
|
291
335
|
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
336
|
+
// Use the same direct theme imports as code-block
|
|
337
|
+
const oneLight = (
|
|
338
|
+
'default' in oneLightModule ? oneLightModule.default : oneLightModule
|
|
339
|
+
) as ThemeRegistration;
|
|
340
|
+
const oneDarkPro = (
|
|
341
|
+
'default' in oneDarkProModule ? oneDarkProModule.default : oneDarkProModule
|
|
342
|
+
) as ThemeRegistration;
|
|
296
343
|
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
oneLightThemeModule.default,
|
|
300
|
-
'one-light'
|
|
301
|
-
);
|
|
302
|
-
monaco.editor.defineTheme('custom-light', lightMonacoTheme);
|
|
303
|
-
}
|
|
344
|
+
const lightMonacoTheme = convertShikiToMonaco(oneLight, 'one-light');
|
|
345
|
+
monaco.editor.defineTheme('custom-light', lightMonacoTheme);
|
|
304
346
|
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
oneDarkProThemeModule.default,
|
|
308
|
-
'one-dark-pro'
|
|
309
|
-
);
|
|
310
|
-
monaco.editor.defineTheme('custom-dark', darkMonacoTheme);
|
|
311
|
-
}
|
|
312
|
-
} catch (error) {
|
|
313
|
-
console.warn(
|
|
314
|
-
'Failed to load Shiki themes, falling back to manual themes:',
|
|
315
|
-
error
|
|
316
|
-
);
|
|
317
|
-
|
|
318
|
-
// Fallback to manual theme definitions
|
|
319
|
-
monaco.editor.defineTheme('custom-light', {
|
|
320
|
-
base: 'vs',
|
|
321
|
-
inherit: true,
|
|
322
|
-
rules: [
|
|
323
|
-
{ token: 'string.key.json', foreground: 'e45649' },
|
|
324
|
-
{ token: 'string.value.json', foreground: '50a14f' },
|
|
325
|
-
{ token: 'number.json', foreground: '986801' },
|
|
326
|
-
{ token: 'keyword.json', foreground: '986801' },
|
|
327
|
-
{ token: 'string', foreground: '50a14f' },
|
|
328
|
-
{ token: 'number', foreground: '986801' },
|
|
329
|
-
{ token: 'keyword', foreground: '986801' },
|
|
330
|
-
],
|
|
331
|
-
colors: {
|
|
332
|
-
'editor.background': '#00000000',
|
|
333
|
-
'editor.foreground': '#383a42',
|
|
334
|
-
},
|
|
335
|
-
});
|
|
336
|
-
|
|
337
|
-
monaco.editor.defineTheme('custom-dark', {
|
|
338
|
-
base: 'vs-dark',
|
|
339
|
-
inherit: true,
|
|
340
|
-
rules: [
|
|
341
|
-
{ token: 'string.key.json', foreground: 'e06c75' },
|
|
342
|
-
{ token: 'string.value.json', foreground: '98c379' },
|
|
343
|
-
{ token: 'number.json', foreground: 'd19a66' },
|
|
344
|
-
{ token: 'keyword.json', foreground: 'c678dd' },
|
|
345
|
-
{ token: 'string', foreground: '98c379' },
|
|
346
|
-
{ token: 'number', foreground: 'd19a66' },
|
|
347
|
-
{ token: 'keyword', foreground: 'c678dd' },
|
|
348
|
-
],
|
|
349
|
-
colors: {
|
|
350
|
-
'editor.background': '#00000000',
|
|
351
|
-
'editor.foreground': '#abb2bf',
|
|
352
|
-
},
|
|
353
|
-
});
|
|
354
|
-
}
|
|
347
|
+
const darkMonacoTheme = convertShikiToMonaco(oneDarkPro, 'one-dark-pro');
|
|
348
|
+
monaco.editor.defineTheme('custom-dark', darkMonacoTheme);
|
|
355
349
|
}}
|
|
356
350
|
/>
|
|
357
351
|
</div>
|
|
@@ -3,109 +3,97 @@ import { X, FileJson } from 'lucide-react';
|
|
|
3
3
|
import { Button } from '../ui/button';
|
|
4
4
|
import { CodeBlock, CodeBlockCopyButton } from '../ai-elements/code-block';
|
|
5
5
|
import { ScrollArea } from '../ui/scroll-area';
|
|
6
|
-
import { cn } from '../../lib/utils';
|
|
7
6
|
import { useWorkbench } from './WorkbenchProvider';
|
|
8
7
|
|
|
9
8
|
export interface SchemaProps {
|
|
10
|
-
open: boolean;
|
|
11
9
|
onOpenChange: (open: boolean) => void;
|
|
12
10
|
}
|
|
13
11
|
|
|
14
|
-
export function Schema({
|
|
12
|
+
export function Schema({ onOpenChange }: SchemaProps) {
|
|
15
13
|
const { agents, selectedAgent, schemasLoading, schemasError } = useWorkbench();
|
|
16
14
|
|
|
17
15
|
const selectedAgentData =
|
|
18
16
|
Object.values(agents).find((agent) => agent.metadata.agentId === selectedAgent) || null;
|
|
19
17
|
|
|
20
18
|
return (
|
|
21
|
-
|
|
22
|
-
{/*
|
|
23
|
-
<div
|
|
24
|
-
className=
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
<div>
|
|
34
|
-
<h2 className="text-lg font-semibold">Schema</h2>
|
|
35
|
-
{selectedAgentData && (
|
|
36
|
-
<p className="text-sm text-muted-foreground">
|
|
37
|
-
{selectedAgentData.metadata.name}
|
|
38
|
-
</p>
|
|
39
|
-
)}
|
|
40
|
-
</div>
|
|
19
|
+
<div className="h-full bg-background border-l border-border flex flex-col">
|
|
20
|
+
{/* Header */}
|
|
21
|
+
<div className="flex items-center justify-between p-4 border-b border-border">
|
|
22
|
+
<div className="flex items-center gap-2">
|
|
23
|
+
<FileJson className="size-5 text-muted-foreground" />
|
|
24
|
+
<div>
|
|
25
|
+
<h2 className="text-lg font-semibold">Schema</h2>
|
|
26
|
+
{selectedAgentData && (
|
|
27
|
+
<p className="text-sm text-muted-foreground">
|
|
28
|
+
{selectedAgentData.metadata.name}
|
|
29
|
+
</p>
|
|
30
|
+
)}
|
|
41
31
|
</div>
|
|
42
|
-
<Button
|
|
43
|
-
variant="ghost"
|
|
44
|
-
size="icon"
|
|
45
|
-
onClick={() => onOpenChange(false)}
|
|
46
|
-
className="size-8"
|
|
47
|
-
>
|
|
48
|
-
<X className="size-4" />
|
|
49
|
-
</Button>
|
|
50
32
|
</div>
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
33
|
+
<Button
|
|
34
|
+
variant="ghost"
|
|
35
|
+
size="icon"
|
|
36
|
+
onClick={() => onOpenChange(false)}
|
|
37
|
+
className="size-8"
|
|
38
|
+
>
|
|
39
|
+
<X className="size-4" />
|
|
40
|
+
</Button>
|
|
41
|
+
</div>
|
|
42
|
+
{/* Content */}
|
|
43
|
+
<ScrollArea className="flex-1">
|
|
44
|
+
<div className="p-6 space-y-6">
|
|
45
|
+
{schemasLoading && (
|
|
46
|
+
<div className="text-center text-muted-foreground py-8">Loading schemas...</div>
|
|
47
|
+
)}
|
|
59
48
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
49
|
+
{schemasError && (
|
|
50
|
+
<div className="rounded-md bg-destructive/10 text-destructive p-4">
|
|
51
|
+
<p className="font-medium">Error loading schemas</p>
|
|
52
|
+
<p className="text-sm mt-1">{schemasError.message}</p>
|
|
53
|
+
</div>
|
|
54
|
+
)}
|
|
66
55
|
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
56
|
+
{!schemasLoading && !schemasError && !selectedAgentData && (
|
|
57
|
+
<div className="text-center text-muted-foreground py-8">
|
|
58
|
+
<p>No schema available for selected agent</p>
|
|
59
|
+
</div>
|
|
60
|
+
)}
|
|
72
61
|
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
</>
|
|
62
|
+
{!schemasLoading && !schemasError && selectedAgentData && (
|
|
63
|
+
<>
|
|
64
|
+
{/* Input Schema */}
|
|
65
|
+
{selectedAgentData.schema.input?.code ? (
|
|
66
|
+
<div className="space-y-2">
|
|
67
|
+
<h3 className="text-sm font-semibold text-muted-foreground uppercase tracking-wide">
|
|
68
|
+
Input Schema
|
|
69
|
+
</h3>
|
|
70
|
+
<CodeBlock
|
|
71
|
+
code={selectedAgentData.schema.input?.code}
|
|
72
|
+
language="typescript"
|
|
73
|
+
>
|
|
74
|
+
<CodeBlockCopyButton />
|
|
75
|
+
</CodeBlock>
|
|
76
|
+
</div>
|
|
77
|
+
) : null}
|
|
78
|
+
{/* Output Schema */}
|
|
79
|
+
{selectedAgentData.schema.output?.code ? (
|
|
80
|
+
<div className="space-y-2">
|
|
81
|
+
<h3 className="text-sm font-semibold text-muted-foreground uppercase tracking-wide">
|
|
82
|
+
Output Schema
|
|
83
|
+
</h3>
|
|
84
|
+
<CodeBlock
|
|
85
|
+
code={selectedAgentData.schema.output?.code}
|
|
86
|
+
language="typescript"
|
|
87
|
+
>
|
|
88
|
+
<CodeBlockCopyButton />
|
|
89
|
+
</CodeBlock>
|
|
90
|
+
</div>
|
|
91
|
+
) : null}
|
|
92
|
+
</>
|
|
93
|
+
)}
|
|
94
|
+
</div>
|
|
95
|
+
</ScrollArea>
|
|
96
|
+
</div>
|
|
109
97
|
);
|
|
110
98
|
}
|
|
111
99
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import React, { createContext, useContext, useEffect, useState } from 'react';
|
|
1
|
+
import React, { createContext, useContext, useEffect, useState, useMemo, useCallback } from 'react';
|
|
2
2
|
import type { UIMessage } from 'ai';
|
|
3
3
|
import type { WorkbenchConfig } from '@agentuity/core/workbench';
|
|
4
4
|
import type { WorkbenchContextType, ConnectionStatus } from '../../types/config';
|
|
@@ -25,6 +25,43 @@ interface WorkbenchProviderProps {
|
|
|
25
25
|
export function WorkbenchProvider({ config, children }: WorkbenchProviderProps) {
|
|
26
26
|
const logger = useLogger('WorkbenchProvider');
|
|
27
27
|
|
|
28
|
+
// Generate project identifier from config for localStorage scoping
|
|
29
|
+
const projectId = useMemo(() => {
|
|
30
|
+
// Use a combination of baseUrl and apiKey hash to create unique project identifier
|
|
31
|
+
const configHash = btoa(
|
|
32
|
+
JSON.stringify({
|
|
33
|
+
route: config.route,
|
|
34
|
+
apiKey: config.apiKey?.substring(0, 8), // Only first 8 chars for uniqueness without exposing key
|
|
35
|
+
})
|
|
36
|
+
)
|
|
37
|
+
.replace(/[^a-zA-Z0-9]/g, '')
|
|
38
|
+
.substring(0, 16);
|
|
39
|
+
return `project_${configHash}`;
|
|
40
|
+
}, [config]);
|
|
41
|
+
|
|
42
|
+
// localStorage utilities scoped by project
|
|
43
|
+
const getStorageKey = useCallback((key: string) => `agentuity_${projectId}_${key}`, [projectId]);
|
|
44
|
+
|
|
45
|
+
const saveSelectedAgent = useCallback(
|
|
46
|
+
(agentId: string) => {
|
|
47
|
+
try {
|
|
48
|
+
localStorage.setItem(getStorageKey('selected_agent'), agentId);
|
|
49
|
+
} catch (error) {
|
|
50
|
+
console.warn('Failed to save selected agent to localStorage:', error);
|
|
51
|
+
}
|
|
52
|
+
},
|
|
53
|
+
[getStorageKey]
|
|
54
|
+
);
|
|
55
|
+
|
|
56
|
+
const loadSelectedAgent = useCallback((): string | null => {
|
|
57
|
+
try {
|
|
58
|
+
return localStorage.getItem(getStorageKey('selected_agent'));
|
|
59
|
+
} catch (error) {
|
|
60
|
+
console.warn('Failed to load selected agent from localStorage:', error);
|
|
61
|
+
return null;
|
|
62
|
+
}
|
|
63
|
+
}, [getStorageKey]);
|
|
64
|
+
|
|
28
65
|
const [messages, setMessages] = useState<UIMessage[]>([]);
|
|
29
66
|
const [selectedAgent, setSelectedAgent] = useState<string>('');
|
|
30
67
|
const [inputMode, setInputMode] = useState<'text' | 'form'>('text');
|
|
@@ -103,15 +140,36 @@ export function WorkbenchProvider({ config, children }: WorkbenchProviderProps)
|
|
|
103
140
|
useEffect(() => {
|
|
104
141
|
if (agents && Object.keys(agents).length > 0 && !selectedAgent) {
|
|
105
142
|
logger.debug('🔍 Available agents:', agents);
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
);
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
143
|
+
|
|
144
|
+
// Try to load previously selected agent from localStorage
|
|
145
|
+
const savedAgentId = loadSelectedAgent();
|
|
146
|
+
logger.debug('💾 Saved agent from localStorage:', savedAgentId);
|
|
147
|
+
|
|
148
|
+
// Check if saved agent still exists in available agents
|
|
149
|
+
const savedAgent = savedAgentId
|
|
150
|
+
? Object.values(agents).find((agent) => agent.metadata.agentId === savedAgentId)
|
|
151
|
+
: null;
|
|
152
|
+
|
|
153
|
+
if (savedAgent && savedAgentId) {
|
|
154
|
+
logger.debug('✅ Restoring saved agent:', savedAgent.metadata.name);
|
|
155
|
+
setSelectedAgent(savedAgentId);
|
|
156
|
+
} else {
|
|
157
|
+
// Fallback to first agent alphabetically
|
|
158
|
+
const sortedAgents = Object.values(agents).sort((a, b) =>
|
|
159
|
+
a.metadata.name.localeCompare(b.metadata.name)
|
|
160
|
+
);
|
|
161
|
+
const firstAgent = sortedAgents[0];
|
|
162
|
+
logger.debug(
|
|
163
|
+
'🎯 No saved agent found, using first agent (alphabetically):',
|
|
164
|
+
firstAgent
|
|
165
|
+
);
|
|
166
|
+
logger.debug('🆔 Setting selectedAgent to:', firstAgent.metadata.agentId);
|
|
167
|
+
setSelectedAgent(firstAgent.metadata.agentId);
|
|
168
|
+
// Save this selection for next time
|
|
169
|
+
saveSelectedAgent(firstAgent.metadata.agentId);
|
|
170
|
+
}
|
|
113
171
|
}
|
|
114
|
-
}, [agents, selectedAgent]);
|
|
172
|
+
}, [agents, selectedAgent, loadSelectedAgent, saveSelectedAgent, logger]);
|
|
115
173
|
|
|
116
174
|
// Fetch suggestions from API if endpoint is provided
|
|
117
175
|
useEffect(() => {
|
|
@@ -279,7 +337,8 @@ export function WorkbenchProvider({ config, children }: WorkbenchProviderProps)
|
|
|
279
337
|
const handleAgentSelect = async (agentId: string) => {
|
|
280
338
|
logger.debug('🔄 handleAgentSelect called with:', agentId);
|
|
281
339
|
setSelectedAgent(agentId);
|
|
282
|
-
//
|
|
340
|
+
// Save selection to localStorage for persistence across sessions
|
|
341
|
+
saveSelectedAgent(agentId);
|
|
283
342
|
};
|
|
284
343
|
|
|
285
344
|
const contextValue: WorkbenchContextType = {
|
|
@@ -26,8 +26,8 @@ function InputGroup({ className, ...props }: React.ComponentProps<'div'>) {
|
|
|
26
26
|
// Focus state.
|
|
27
27
|
'has-[[data-slot=input-group-control]:focus-visible]:border-ring has-[[data-slot=input-group-control]:focus-visible]:ring-ring/50 has-[[data-slot=input-group-control]:focus-visible]:ring-[3px]',
|
|
28
28
|
|
|
29
|
-
// Error state.
|
|
30
|
-
'has-[[data-slot][aria-invalid=true]]:
|
|
29
|
+
// Error state - use destructive theme color.
|
|
30
|
+
'has-[[data-slot][aria-invalid=true]]:border-destructive',
|
|
31
31
|
|
|
32
32
|
className
|
|
33
33
|
)}
|
|
@@ -8,9 +8,8 @@ function Input({ className, type, ...props }: React.ComponentProps<'input'>) {
|
|
|
8
8
|
type={type}
|
|
9
9
|
data-slot="input"
|
|
10
10
|
className={cn(
|
|
11
|
-
'file:text-foreground placeholder:text-muted-foreground selection:bg-primary selection:text-primary-foreground dark:
|
|
12
|
-
'
|
|
13
|
-
'aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive',
|
|
11
|
+
'border-input file:text-foreground placeholder:text-muted-foreground selection:bg-primary selection:text-primary-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 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 focus-visible:ring-[3px] disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-50 md:text-sm',
|
|
12
|
+
'aria-invalid:focus-visible:ring-0',
|
|
14
13
|
className
|
|
15
14
|
)}
|
|
16
15
|
{...props}
|