ai-design-system 0.1.43 → 0.1.45
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/components/blocks/AIConversation/AIConversation.tsx +2 -2
- package/components/{composites → blocks}/PromptInput/PromptInput.stories.tsx +77 -2
- package/components/{composites → blocks}/PromptInput/PromptInput.tsx +9 -38
- package/components/blocks/PromptInput/index.ts +3 -0
- package/components/blocks/index.ts +3 -0
- package/components/composites/ApprovalCard/ApprovalCard.stories.tsx +115 -0
- package/components/composites/ApprovalCard/ApprovalCard.tsx +533 -0
- package/components/composites/ApprovalCard/index.ts +2 -0
- package/components/composites/Confirmation/Confirmation.stories.tsx +1 -1
- package/components/composites/ToolCallDisplay/ToolCallDisplay.tsx +1 -5
- package/components/composites/index.ts +4 -3
- package/components/features/RefinementPanel/RefinementPanel.mocks.ts +39 -0
- package/components/features/RefinementPanel/RefinementPanel.stories.tsx +147 -1
- package/components/features/RefinementPanel/RefinementPanel.tsx +111 -33
- package/components/features/RefinementPanel/index.ts +3 -0
- package/components/features/RefinementPanel/useRefinementPanel.d.ts +19 -0
- package/components/features/RefinementPanel/useRefinementPanel.mock.ts +77 -35
- package/components/index.ts +2 -1
- package/dist/index.cjs +540 -57
- package/dist/index.cjs.map +1 -1
- package/dist/index.css +88 -0
- package/dist/index.d.ts +130 -82
- package/dist/index.js +541 -59
- package/dist/index.js.map +1 -1
- package/package.json +7 -7
- package/components/composites/PromptInput/index.ts +0 -8
|
@@ -142,8 +142,8 @@ export const AIConversation = React.memo<AIConversationProps>(
|
|
|
142
142
|
message={{
|
|
143
143
|
id: subAgent.id,
|
|
144
144
|
name: subAgent.subAgentName,
|
|
145
|
-
description:
|
|
146
|
-
content: typeof subAgent.
|
|
145
|
+
description: undefined,
|
|
146
|
+
content: `**Task:** ${typeof subAgent.input === 'string' ? subAgent.input : JSON.stringify(subAgent.input)}${subAgent.output ? `\n\n**Output:** ${typeof subAgent.output === 'string' ? subAgent.output : JSON.stringify(subAgent.output)}` : ''}`,
|
|
147
147
|
status: subAgent.status,
|
|
148
148
|
toolCalls: [],
|
|
149
149
|
}}
|
|
@@ -61,7 +61,7 @@ export const ControlledState: Story = {
|
|
|
61
61
|
placeholder="Type something (controlled mode)"
|
|
62
62
|
onSubmit={(message) => {
|
|
63
63
|
setSubmittedMessages((prev) => [...prev, message.text || ""]);
|
|
64
|
-
setValue("");
|
|
64
|
+
setValue("");
|
|
65
65
|
}}
|
|
66
66
|
/>
|
|
67
67
|
|
|
@@ -164,7 +164,6 @@ export const CustomSubmitHandler: Story = {
|
|
|
164
164
|
disabled={isSubmitting}
|
|
165
165
|
onSubmit={async (message) => {
|
|
166
166
|
setIsSubmitting(true);
|
|
167
|
-
// Simulate async processing
|
|
168
167
|
await new Promise((resolve) => setTimeout(resolve, 2000));
|
|
169
168
|
setLastSubmitted(message.text || "");
|
|
170
169
|
setIsSubmitting(false);
|
|
@@ -198,3 +197,79 @@ export const NoAttachmentUI: Story = {
|
|
|
198
197
|
},
|
|
199
198
|
},
|
|
200
199
|
};
|
|
200
|
+
|
|
201
|
+
/**
|
|
202
|
+
* Dialog replacement — static content
|
|
203
|
+
* Shows PromptInput rendering a dialog instead of the input when `dialog` is set.
|
|
204
|
+
* The dialog content replaces the input entirely; no input is shown.
|
|
205
|
+
*/
|
|
206
|
+
export const WithDialog: Story = {
|
|
207
|
+
args: {
|
|
208
|
+
placeholder: "This should not appear — dialog is active",
|
|
209
|
+
onSubmit: (message) => {
|
|
210
|
+
console.log("Submitted:", message);
|
|
211
|
+
},
|
|
212
|
+
dialog: (
|
|
213
|
+
<div className="rounded-lg border border-border bg-card p-6 text-center text-sm text-muted-foreground">
|
|
214
|
+
<p className="font-medium text-foreground">Dialog Content</p>
|
|
215
|
+
<p className="mt-1">This replaces the prompt input when the <code>dialog</code> prop is set.</p>
|
|
216
|
+
</div>
|
|
217
|
+
),
|
|
218
|
+
},
|
|
219
|
+
parameters: {
|
|
220
|
+
docs: {
|
|
221
|
+
description: {
|
|
222
|
+
story:
|
|
223
|
+
"When the `dialog` prop is set, PromptInput renders that ReactNode instead of the input form. This is used by features like RefinementPanel to show file reviews or HITL approval cards in place of the input.",
|
|
224
|
+
},
|
|
225
|
+
},
|
|
226
|
+
},
|
|
227
|
+
};
|
|
228
|
+
|
|
229
|
+
/**
|
|
230
|
+
* Dialog replacement — interactive toggle
|
|
231
|
+
* Demonstrates switching between input mode and dialog mode.
|
|
232
|
+
*/
|
|
233
|
+
export const ToggleDialog: Story = {
|
|
234
|
+
render: () => {
|
|
235
|
+
const [showDialog, setShowDialog] = useState(false);
|
|
236
|
+
|
|
237
|
+
return (
|
|
238
|
+
<div className="space-y-4">
|
|
239
|
+
<div className="rounded-md border border-border bg-muted p-4">
|
|
240
|
+
<label className="flex items-center gap-2">
|
|
241
|
+
<input
|
|
242
|
+
type="checkbox"
|
|
243
|
+
checked={showDialog}
|
|
244
|
+
onChange={(e) => setShowDialog(e.target.checked)}
|
|
245
|
+
/>
|
|
246
|
+
<span className="text-sm">Show dialog (replaces input)</span>
|
|
247
|
+
</label>
|
|
248
|
+
</div>
|
|
249
|
+
|
|
250
|
+
<PromptInput
|
|
251
|
+
placeholder="Type a message..."
|
|
252
|
+
onSubmit={(message) => {
|
|
253
|
+
console.log("Submitted:", message);
|
|
254
|
+
}}
|
|
255
|
+
dialog={
|
|
256
|
+
showDialog ? (
|
|
257
|
+
<div className="rounded-lg border border-border bg-card p-6 text-center text-sm text-muted-foreground">
|
|
258
|
+
<p className="font-medium text-foreground">Dialog Active</p>
|
|
259
|
+
<p className="mt-1">Uncheck the toggle above to return to input mode.</p>
|
|
260
|
+
</div>
|
|
261
|
+
) : undefined
|
|
262
|
+
}
|
|
263
|
+
/>
|
|
264
|
+
</div>
|
|
265
|
+
);
|
|
266
|
+
},
|
|
267
|
+
parameters: {
|
|
268
|
+
docs: {
|
|
269
|
+
description: {
|
|
270
|
+
story:
|
|
271
|
+
"Interactive demonstration of the dialog replacement. Toggle the checkbox to switch between showing the prompt input and showing dialog content. This is the same pattern RefinementPanel uses for file review and HITL approval states.",
|
|
272
|
+
},
|
|
273
|
+
},
|
|
274
|
+
},
|
|
275
|
+
};
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
|
|
3
3
|
import * as React from "react";
|
|
4
|
+
import type { ReactNode } from "react";
|
|
4
5
|
import {
|
|
5
6
|
PromptInput as AIPromptInput,
|
|
6
7
|
PromptInputBody,
|
|
@@ -14,52 +15,22 @@ import {
|
|
|
14
15
|
} from "@/components/ai-elements/prompt-input";
|
|
15
16
|
import type { FormEvent } from "react";
|
|
16
17
|
|
|
17
|
-
/**
|
|
18
|
-
* PromptInput Block
|
|
19
|
-
*
|
|
20
|
-
* A thin wrapper around the PromptInput AI element that hides attachment functionality.
|
|
21
|
-
* This block provides a simplified prompt input interface focused on text-only input.
|
|
22
|
-
*
|
|
23
|
-
* Features:
|
|
24
|
-
* - Controlled and uncontrolled state support
|
|
25
|
-
* - Disabled state (blocks submission, keeps textarea editable)
|
|
26
|
-
* - Custom placeholder text
|
|
27
|
-
* - No attachment UI (compositional hiding)
|
|
28
|
-
*/
|
|
29
|
-
|
|
30
18
|
export interface PromptInputBlockProps
|
|
31
19
|
extends Omit<
|
|
32
20
|
AIPromptInputProps,
|
|
33
21
|
"accept" | "multiple" | "maxFiles" | "maxFileSize" | "globalDrop" | "syncHiddenInput" | "onSubmit" | "onChange"
|
|
34
22
|
> {
|
|
35
|
-
/**
|
|
36
|
-
* Blocks form submission when true. Textarea remains editable for drafts.
|
|
37
|
-
*/
|
|
38
23
|
disabled?: boolean;
|
|
39
|
-
/**
|
|
40
|
-
* Placeholder text for the textarea input
|
|
41
|
-
*/
|
|
42
24
|
placeholder?: string;
|
|
43
|
-
/**
|
|
44
|
-
* Controlled state value (when provided with onChange)
|
|
45
|
-
*/
|
|
46
25
|
value?: string;
|
|
47
|
-
/**
|
|
48
|
-
* Controlled state change handler (when provided with value)
|
|
49
|
-
*/
|
|
50
26
|
onChange?: (value: string) => void;
|
|
51
|
-
/**
|
|
52
|
-
* Submit handler called when form is submitted
|
|
53
|
-
*/
|
|
54
27
|
onSubmit: (
|
|
55
28
|
message: PromptInputMessage,
|
|
56
29
|
event: FormEvent<HTMLFormElement>
|
|
57
30
|
) => void | Promise<void>;
|
|
31
|
+
dialog?: ReactNode;
|
|
58
32
|
}
|
|
59
33
|
|
|
60
|
-
/**
|
|
61
|
-
* PromptInput component - text-only prompt input without attachments
|
|
62
|
-
*/
|
|
63
34
|
export const PromptInput = React.memo<PromptInputBlockProps>(
|
|
64
35
|
({
|
|
65
36
|
disabled = false,
|
|
@@ -67,9 +38,9 @@ export const PromptInput = React.memo<PromptInputBlockProps>(
|
|
|
67
38
|
value,
|
|
68
39
|
onChange,
|
|
69
40
|
onSubmit,
|
|
41
|
+
dialog,
|
|
70
42
|
...props
|
|
71
43
|
}) => {
|
|
72
|
-
// Handle form submission with disabled state
|
|
73
44
|
const handleSubmit = React.useCallback(
|
|
74
45
|
(message: PromptInputMessage, event: FormEvent<HTMLFormElement>) => {
|
|
75
46
|
if (disabled) {
|
|
@@ -81,10 +52,8 @@ export const PromptInput = React.memo<PromptInputBlockProps>(
|
|
|
81
52
|
[disabled, onSubmit]
|
|
82
53
|
);
|
|
83
54
|
|
|
84
|
-
// Controlled mode: wrap in PromptInputProvider
|
|
85
55
|
const isControlled = value !== undefined && onChange !== undefined;
|
|
86
56
|
|
|
87
|
-
// Handle controlled state change
|
|
88
57
|
const handleControlledChange = React.useCallback(
|
|
89
58
|
(e: React.ChangeEvent<HTMLTextAreaElement>) => {
|
|
90
59
|
if (onChange) {
|
|
@@ -94,26 +63,28 @@ export const PromptInput = React.memo<PromptInputBlockProps>(
|
|
|
94
63
|
[onChange]
|
|
95
64
|
);
|
|
96
65
|
|
|
97
|
-
|
|
66
|
+
if (dialog) {
|
|
67
|
+
return <>{dialog}</>;
|
|
68
|
+
}
|
|
69
|
+
|
|
98
70
|
const promptInputContent = (
|
|
99
71
|
<AIPromptInput onSubmit={handleSubmit} {...props}>
|
|
100
72
|
<PromptInputBody>
|
|
101
73
|
<PromptInputTextarea
|
|
102
74
|
placeholder={placeholder}
|
|
103
|
-
disabled={false}
|
|
75
|
+
disabled={false}
|
|
104
76
|
onChange={isControlled ? handleControlledChange : undefined}
|
|
105
77
|
/>
|
|
106
78
|
</PromptInputBody>
|
|
107
79
|
<PromptInputFooter>
|
|
108
80
|
<PromptInputTools>
|
|
109
|
-
{
|
|
81
|
+
{}
|
|
110
82
|
</PromptInputTools>
|
|
111
83
|
<PromptInputSubmit disabled={disabled} />
|
|
112
84
|
</PromptInputFooter>
|
|
113
85
|
</AIPromptInput>
|
|
114
86
|
);
|
|
115
87
|
|
|
116
|
-
// Wrap in provider for controlled mode
|
|
117
88
|
if (isControlled) {
|
|
118
89
|
return (
|
|
119
90
|
<PromptInputProvider initialInput={value}>
|
|
@@ -10,6 +10,9 @@ export type { DocumentEditorWithCommentsProps } from './DocumentEditorWithCommen
|
|
|
10
10
|
export { FileChangeQueue } from './FileChangeQueue'
|
|
11
11
|
export type { FileChangeQueueProps } from './FileChangeQueue'
|
|
12
12
|
|
|
13
|
+
export { PromptInput } from './PromptInput'
|
|
14
|
+
export type { PromptInputBlockProps } from './PromptInput'
|
|
15
|
+
|
|
13
16
|
// Blocks
|
|
14
17
|
export * from './LayoutProvider'
|
|
15
18
|
export * from './SectionLayout'
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from "@storybook/react";
|
|
2
|
+
import { ApprovalCard } from "./ApprovalCard";
|
|
3
|
+
import { fn } from "@storybook/test";
|
|
4
|
+
|
|
5
|
+
const meta: Meta<typeof ApprovalCard> = {
|
|
6
|
+
title: "Composites/ApprovalCard",
|
|
7
|
+
component: ApprovalCard,
|
|
8
|
+
parameters: {
|
|
9
|
+
layout: "centered",
|
|
10
|
+
},
|
|
11
|
+
args: {
|
|
12
|
+
onApprove: fn(),
|
|
13
|
+
onReject: fn(),
|
|
14
|
+
onEdit: fn(),
|
|
15
|
+
isProcessing: false,
|
|
16
|
+
},
|
|
17
|
+
} satisfies Meta<typeof ApprovalCard>;
|
|
18
|
+
|
|
19
|
+
export default meta;
|
|
20
|
+
type Story = StoryObj<typeof ApprovalCard>;
|
|
21
|
+
|
|
22
|
+
export const Default: Story = {
|
|
23
|
+
args: {
|
|
24
|
+
actionRequest: {
|
|
25
|
+
name: "send_email",
|
|
26
|
+
description: "Review email before sending to team",
|
|
27
|
+
args: {
|
|
28
|
+
to: "team@acme.com",
|
|
29
|
+
subject: "Q4 Results",
|
|
30
|
+
body: "Revenue grew 15% this quarter.",
|
|
31
|
+
},
|
|
32
|
+
},
|
|
33
|
+
reviewConfig: {
|
|
34
|
+
allowedDecisions: ["approve", "edit", "reject"],
|
|
35
|
+
},
|
|
36
|
+
},
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
export const SimpleApprovalOnly: Story = {
|
|
40
|
+
args: {
|
|
41
|
+
actionRequest: {
|
|
42
|
+
name: "publish_content",
|
|
43
|
+
description: "Publish video narration to production database",
|
|
44
|
+
args: {
|
|
45
|
+
document_id: "doc_123",
|
|
46
|
+
environment: "production",
|
|
47
|
+
},
|
|
48
|
+
},
|
|
49
|
+
reviewConfig: {
|
|
50
|
+
allowedDecisions: ["approve", "reject"],
|
|
51
|
+
},
|
|
52
|
+
},
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
export const MultilineArguments: Story = {
|
|
56
|
+
args: {
|
|
57
|
+
actionRequest: {
|
|
58
|
+
name: "apply_patch",
|
|
59
|
+
description: "Approve and apply code patch to target repository",
|
|
60
|
+
args: {
|
|
61
|
+
patch: `diff --git a/src/index.ts b/src/index.ts
|
|
62
|
+
index 83a2d78..d3345f1 100644
|
|
63
|
+
--- a/src/index.ts
|
|
64
|
+
+++ b/src/index.ts
|
|
65
|
+
@@ -10,3 +10,4 @@
|
|
66
|
+
export function hello() {
|
|
67
|
+
- console.log("hello");
|
|
68
|
+
+ console.log("hello world!");
|
|
69
|
+
}`,
|
|
70
|
+
author: "AI Developer Agent",
|
|
71
|
+
},
|
|
72
|
+
},
|
|
73
|
+
reviewConfig: {
|
|
74
|
+
allowedDecisions: ["approve", "edit", "reject"],
|
|
75
|
+
},
|
|
76
|
+
},
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
export const InteractiveQuestion: Story = {
|
|
80
|
+
args: {
|
|
81
|
+
actionRequest: {
|
|
82
|
+
name: "ask_question",
|
|
83
|
+
args: {
|
|
84
|
+
question: "Where in the workflow timeline should the SEO review step run?",
|
|
85
|
+
options: [
|
|
86
|
+
"(Recommended) Before the main human content approval, so the editor can see the SEO recommendations and scores when reviewing the script.",
|
|
87
|
+
"After the main human content approval, so that the general content is finalized first before being tuned for SEO."
|
|
88
|
+
],
|
|
89
|
+
is_multi_select: false
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
};
|
|
94
|
+
|
|
95
|
+
export const MultiQuestionPoll: Story = {
|
|
96
|
+
args: {
|
|
97
|
+
actionRequest: {
|
|
98
|
+
name: "ask_question",
|
|
99
|
+
args: {
|
|
100
|
+
questions: [
|
|
101
|
+
{
|
|
102
|
+
question: "Choose preferred publication channel:",
|
|
103
|
+
options: ["YouTube", "Vimeo", "TikTok", "Instagram Reels"],
|
|
104
|
+
is_multi_select: false
|
|
105
|
+
},
|
|
106
|
+
{
|
|
107
|
+
question: "Which departments need to sign off on budget?",
|
|
108
|
+
options: ["Marketing", "Finance", "Legal", "Operations"],
|
|
109
|
+
is_multi_select: true
|
|
110
|
+
}
|
|
111
|
+
]
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
};
|