ai-design-system 0.1.103 → 0.1.104

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.
@@ -360,5 +360,28 @@ export const WithSpeechInput: Story = {
360
360
  },
361
361
  };
362
362
 
363
+ /**
364
+ * Row / Inline Variant
365
+ * Single row where the input box and send button are side-by-side, without tools icons.
366
+ */
367
+ export const RowVariant: Story = {
368
+ args: {
369
+ variant: "row",
370
+ placeholder: "Ask a question or provide instructions...",
371
+ onSubmit: (message) => {
372
+ console.log("Submitted in row mode:", message);
373
+ alert(`Submitted: ${message.text}`);
374
+ },
375
+ },
376
+ parameters: {
377
+ docs: {
378
+ description: {
379
+ story:
380
+ "Compact single-row PromptInput variant where input box and send button are in the same line without toolbar tool icons (attachments, speech mic, etc.).",
381
+ },
382
+ },
383
+ },
384
+ };
385
+
363
386
 
364
387
 
@@ -44,11 +44,14 @@ export interface PromptInputContextProps {
44
44
  modelId?: string;
45
45
  }
46
46
 
47
+ export type PromptInputVariant = "default" | "row" | "inline";
48
+
47
49
  export interface PromptInputBlockProps
48
50
  extends Omit<
49
51
  AIPromptInputProps,
50
52
  "globalDrop" | "syncHiddenInput" | "onSubmit" | "onChange"
51
53
  > {
54
+ variant?: PromptInputVariant;
52
55
  disabled?: boolean;
53
56
  placeholder?: string;
54
57
  value?: string;
@@ -62,6 +65,7 @@ export interface PromptInputBlockProps
62
65
  onStop?: () => void;
63
66
  context?: PromptInputContextProps | ReactNode;
64
67
  tools?: ReactNode;
68
+ enableAttachments?: boolean;
65
69
  enableSpeech?: boolean;
66
70
  speechProps?: SpeechInputProps;
67
71
  attachIcon?: "paperclip" | "plus";
@@ -69,6 +73,7 @@ export interface PromptInputBlockProps
69
73
 
70
74
  export const PromptInput = React.memo<PromptInputBlockProps>(
71
75
  ({
76
+ variant = "default",
72
77
  disabled = false,
73
78
  placeholder,
74
79
  value,
@@ -79,7 +84,8 @@ export const PromptInput = React.memo<PromptInputBlockProps>(
79
84
  onStop,
80
85
  context,
81
86
  tools,
82
- enableSpeech = true,
87
+ enableAttachments,
88
+ enableSpeech,
83
89
  speechProps,
84
90
  attachIcon = "paperclip",
85
91
  accept = "image/*,audio/*",
@@ -89,6 +95,10 @@ export const PromptInput = React.memo<PromptInputBlockProps>(
89
95
  onError,
90
96
  ...props
91
97
  }) => {
98
+ const isRowVariant = variant === "row" || variant === "inline";
99
+ const showAttachments = enableAttachments ?? !isRowVariant;
100
+ const showSpeech = enableSpeech ?? !isRowVariant;
101
+
92
102
  const existingController = useOptionalPromptInputController();
93
103
 
94
104
  const handleSubmit = React.useCallback(
@@ -122,7 +132,40 @@ export const PromptInput = React.memo<PromptInputBlockProps>(
122
132
 
123
133
  const isStopping = loading && Boolean(onStop);
124
134
 
125
- const promptInputContent = (
135
+ const promptInputContent = isRowVariant ? (
136
+ <AIPromptInput
137
+ onSubmit={handleSubmit}
138
+ accept={accept}
139
+ multiple={multiple}
140
+ maxFiles={maxFiles}
141
+ maxFileSize={maxFileSize}
142
+ onError={onError}
143
+ {...props}
144
+ >
145
+ <PromptInputBody className="contents">
146
+ {showAttachments && <AttachmentPreviews />}
147
+ <PromptInputTextarea
148
+ placeholder={placeholder}
149
+ disabled={disabled}
150
+ onChange={isControlled ? handleControlledChange : undefined}
151
+ className="min-h-9 py-2 px-3 text-sm resize-none border-0 shadow-none focus-visible:ring-0 bg-transparent flex-1 field-sizing-content"
152
+ />
153
+ </PromptInputBody>
154
+ <div className="pr-1.5 shrink-0 flex items-center self-center">
155
+ <PromptInputSubmit
156
+ disabled={disabled || (loading && !onStop)}
157
+ status={loading ? (onStop ? "streaming" : "submitted") : undefined}
158
+ onClick={isStopping ? (e: React.MouseEvent) => { e.preventDefault(); onStop?.(); } : undefined}
159
+ className={cn(
160
+ "h-8 w-8 rounded-lg bg-blue-600 hover:bg-blue-700 text-white transition-colors shrink-0 p-0 flex items-center justify-center cursor-pointer",
161
+ isStopping && "bg-transparent hover:bg-accent"
162
+ )}
163
+ >
164
+ {loading ? undefined : <Icon name="corner-down-left" size="sm" />}
165
+ </PromptInputSubmit>
166
+ </div>
167
+ </AIPromptInput>
168
+ ) : (
126
169
  <AIPromptInput
127
170
  onSubmit={handleSubmit}
128
171
  accept={accept}
@@ -142,8 +185,10 @@ export const PromptInput = React.memo<PromptInputBlockProps>(
142
185
  </PromptInputBody>
143
186
  <PromptInputFooter>
144
187
  <PromptInputTools>
145
- <AttachButton disabled={disabled || loading} icon={attachIcon} />
146
- {enableSpeech && (
188
+ {showAttachments && (
189
+ <AttachButton disabled={disabled || loading} icon={attachIcon} />
190
+ )}
191
+ {showSpeech && (
147
192
  <SpeechInput
148
193
  disabled={disabled || loading}
149
194
  {...speechProps}
@@ -1,5 +1,5 @@
1
1
  export { PromptInput } from "./PromptInput";
2
- export type { PromptInputBlockProps, PromptInputContextProps } from "./PromptInput";
2
+ export type { PromptInputBlockProps, PromptInputContextProps, PromptInputVariant } from "./PromptInput";
3
3
 
4
4
  export { SpeechInput } from "@/components/ai-elements/speech-input";
5
5
  export type { SpeechInputProps } from "@/components/ai-elements/speech-input";
@@ -4,7 +4,7 @@ import * as React from "react";
4
4
  import type { FormEvent } from "react";
5
5
  import { Button } from "@/components/primitives/Button";
6
6
  import { Icon } from "@/components/primitives/Icon";
7
- import { PromptInput } from "@/components/composites/PromptInput";
7
+ import { PromptInput, type PromptInputVariant } from "@/components/composites/PromptInput";
8
8
  import type { PromptInputMessage } from "@/components/ai-elements/prompt-input";
9
9
  import { cn } from "@/lib/utils";
10
10
 
@@ -45,6 +45,8 @@ export interface ScenePlayerProps extends Omit<React.HTMLAttributes<HTMLDivEleme
45
45
  loading?: boolean;
46
46
  onStop?: () => void;
47
47
  enableSpeech?: boolean;
48
+ enableAttachments?: boolean;
49
+ promptInputVariant?: PromptInputVariant;
48
50
  onPublish?: (currentScene: SceneItem, text?: string) => void;
49
51
  publishPlaceholder?: string;
50
52
  onSceneChange?: (sceneIndex: number, scene: SceneItem) => void;
@@ -72,7 +74,9 @@ export const ScenePlayer = React.forwardRef<HTMLDivElement, ScenePlayerProps>(
72
74
  onSubmit,
73
75
  loading = false,
74
76
  onStop,
75
- enableSpeech = true,
77
+ enableSpeech = false,
78
+ enableAttachments = false,
79
+ promptInputVariant = "row",
76
80
  onPublish,
77
81
  publishPlaceholder = "Ask a question or provide instructions...",
78
82
  onSceneChange,
@@ -408,6 +412,7 @@ export const ScenePlayer = React.forwardRef<HTMLDivElement, ScenePlayerProps>(
408
412
  }}
409
413
  >
410
414
  <PromptInput
415
+ variant={promptInputVariant}
411
416
  placeholder={placeholder || publishPlaceholder}
412
417
  value={promptValue}
413
418
  onChange={onPromptValueChange}
@@ -415,6 +420,7 @@ export const ScenePlayer = React.forwardRef<HTMLDivElement, ScenePlayerProps>(
415
420
  loading={loading}
416
421
  onStop={onStop}
417
422
  enableSpeech={enableSpeech}
423
+ enableAttachments={enableAttachments}
418
424
  className="border border-border bg-background shadow-md overflow-hidden rounded-2xl"
419
425
  />
420
426
  </div>
@@ -231,6 +231,7 @@ export {
231
231
  } from './PromptInput'
232
232
  export type {
233
233
  PromptInputBlockProps,
234
+ PromptInputVariant,
234
235
  SpeechInputProps,
235
236
  PromptInputContextProps,
236
237
  PromptInputControllerProps,
@@ -3,7 +3,7 @@
3
3
  import * as React from "react";
4
4
  import { AIConversation } from "@/components/blocks/AIConversation";
5
5
  import { FileChangeQueue } from "@/components/blocks/FileChangeQueue";
6
- import { PromptInput, type PromptInputContextProps } from "@/components/composites/PromptInput";
6
+ import { PromptInput, type PromptInputContextProps, type PromptInputVariant } from "@/components/composites/PromptInput";
7
7
  import { TaskQueue, type TaskItem } from "@/components/composites/TaskQueue";
8
8
  import { ApprovalCard } from "@/components/composites/ApprovalCard";
9
9
  import { cn } from "@/lib/utils";
@@ -194,6 +194,18 @@ export interface ChatPanelProps {
194
194
  * Handler when a task item is clicked (e.g. to inspect terminal output or logs)
195
195
  */
196
196
  onTaskClick?: (task: TaskItem) => void;
197
+ /**
198
+ * Layout variant for PromptInput:
199
+ * - "default": multi-line textarea with toolbar buttons below (attachment, mic)
200
+ * - "row" | "inline": single row where input box and send button are side-by-side without tools icons
201
+ * @default "default"
202
+ */
203
+ promptInputVariant?: PromptInputVariant;
204
+ /**
205
+ * Whether to enable the attachment button in prompt
206
+ * @default true for default variant, false for row variant
207
+ */
208
+ enableAttachments?: boolean;
197
209
  /**
198
210
  * Whether to enable the voice-note microphone button in prompt
199
211
  * @default true
@@ -268,6 +280,8 @@ export const ChatPanel = React.memo<ChatPanelProps>(
268
280
  onTaskRetry,
269
281
  onTaskStopAll,
270
282
  onTaskClick,
283
+ promptInputVariant = "default",
284
+ enableAttachments,
271
285
  enableSpeech = true,
272
286
  showHeader = true,
273
287
  sessionTitle,
@@ -465,6 +479,7 @@ export const ChatPanel = React.memo<ChatPanelProps>(
465
479
  />
466
480
  )}
467
481
  <PromptInput
482
+ variant={promptInputVariant}
468
483
  dialog={dialog}
469
484
  placeholder={placeholder}
470
485
  value={promptValue}
@@ -474,6 +489,7 @@ export const ChatPanel = React.memo<ChatPanelProps>(
474
489
  onStop={onStop}
475
490
  context={context}
476
491
  enableSpeech={enableSpeech}
492
+ enableAttachments={enableAttachments}
477
493
  className={cn(
478
494
  "border border-neutral-600 bg-background shadow-sm overflow-hidden",
479
495
  tasks.length > 0 && !dialog
@@ -53,6 +53,7 @@ export type {
53
53
  AppBreadcrumbProps,
54
54
  BreadcrumbItemData,
55
55
  PromptInputBlockProps,
56
+ PromptInputVariant,
56
57
  PromptInputContextProps,
57
58
  PromptInputControllerProps,
58
59
  AttachmentsContext,
package/dist/index.cjs CHANGED
@@ -6828,6 +6828,7 @@ SpeechInput.displayName = "SpeechInput";
6828
6828
  var PromptInput2 = React3__namespace.memo(
6829
6829
  (_a) => {
6830
6830
  var _b = _a, {
6831
+ variant = "default",
6831
6832
  disabled = false,
6832
6833
  placeholder,
6833
6834
  value,
@@ -6838,7 +6839,8 @@ var PromptInput2 = React3__namespace.memo(
6838
6839
  onStop,
6839
6840
  context,
6840
6841
  tools,
6841
- enableSpeech = true,
6842
+ enableAttachments,
6843
+ enableSpeech,
6842
6844
  speechProps,
6843
6845
  attachIcon = "paperclip",
6844
6846
  accept = "image/*,audio/*",
@@ -6847,6 +6849,7 @@ var PromptInput2 = React3__namespace.memo(
6847
6849
  maxFileSize,
6848
6850
  onError
6849
6851
  } = _b, props = __objRest(_b, [
6852
+ "variant",
6850
6853
  "disabled",
6851
6854
  "placeholder",
6852
6855
  "value",
@@ -6857,6 +6860,7 @@ var PromptInput2 = React3__namespace.memo(
6857
6860
  "onStop",
6858
6861
  "context",
6859
6862
  "tools",
6863
+ "enableAttachments",
6860
6864
  "enableSpeech",
6861
6865
  "speechProps",
6862
6866
  "attachIcon",
@@ -6866,6 +6870,9 @@ var PromptInput2 = React3__namespace.memo(
6866
6870
  "maxFileSize",
6867
6871
  "onError"
6868
6872
  ]);
6873
+ const isRowVariant = variant === "row" || variant === "inline";
6874
+ const showAttachments = enableAttachments != null ? enableAttachments : !isRowVariant;
6875
+ const showSpeech = enableSpeech != null ? enableSpeech : !isRowVariant;
6869
6876
  const existingController = useOptionalPromptInputController();
6870
6877
  const handleSubmit = React3__namespace.useCallback(
6871
6878
  (message, event) => {
@@ -6893,7 +6900,48 @@ var PromptInput2 = React3__namespace.memo(
6893
6900
  return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: dialog });
6894
6901
  }
6895
6902
  const isStopping = loading && Boolean(onStop);
6896
- const promptInputContent = /* @__PURE__ */ jsxRuntime.jsxs(
6903
+ const promptInputContent = isRowVariant ? /* @__PURE__ */ jsxRuntime.jsxs(
6904
+ PromptInput,
6905
+ __spreadProps(__spreadValues({
6906
+ onSubmit: handleSubmit,
6907
+ accept,
6908
+ multiple,
6909
+ maxFiles,
6910
+ maxFileSize,
6911
+ onError
6912
+ }, props), {
6913
+ children: [
6914
+ /* @__PURE__ */ jsxRuntime.jsxs(PromptInputBody, { className: "contents", children: [
6915
+ showAttachments && /* @__PURE__ */ jsxRuntime.jsx(AttachmentPreviews, {}),
6916
+ /* @__PURE__ */ jsxRuntime.jsx(
6917
+ PromptInputTextarea,
6918
+ {
6919
+ placeholder,
6920
+ disabled,
6921
+ onChange: isControlled ? handleControlledChange : void 0,
6922
+ className: "min-h-9 py-2 px-3 text-sm resize-none border-0 shadow-none focus-visible:ring-0 bg-transparent flex-1 field-sizing-content"
6923
+ }
6924
+ )
6925
+ ] }),
6926
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "pr-1.5 shrink-0 flex items-center self-center", children: /* @__PURE__ */ jsxRuntime.jsx(
6927
+ PromptInputSubmit,
6928
+ {
6929
+ disabled: disabled || loading && !onStop,
6930
+ status: loading ? onStop ? "streaming" : "submitted" : void 0,
6931
+ onClick: isStopping ? (e) => {
6932
+ e.preventDefault();
6933
+ onStop == null ? void 0 : onStop();
6934
+ } : void 0,
6935
+ className: cn(
6936
+ "h-8 w-8 rounded-lg bg-blue-600 hover:bg-blue-700 text-white transition-colors shrink-0 p-0 flex items-center justify-center cursor-pointer",
6937
+ isStopping && "bg-transparent hover:bg-accent"
6938
+ ),
6939
+ children: loading ? void 0 : /* @__PURE__ */ jsxRuntime.jsx(Icon, { name: "corner-down-left", size: "sm" })
6940
+ }
6941
+ ) })
6942
+ ]
6943
+ })
6944
+ ) : /* @__PURE__ */ jsxRuntime.jsxs(
6897
6945
  PromptInput,
6898
6946
  __spreadProps(__spreadValues({
6899
6947
  onSubmit: handleSubmit,
@@ -6917,8 +6965,8 @@ var PromptInput2 = React3__namespace.memo(
6917
6965
  ] }),
6918
6966
  /* @__PURE__ */ jsxRuntime.jsxs(PromptInputFooter, { children: [
6919
6967
  /* @__PURE__ */ jsxRuntime.jsxs(PromptInputTools, { children: [
6920
- /* @__PURE__ */ jsxRuntime.jsx(AttachButton, { disabled: disabled || loading, icon: attachIcon }),
6921
- enableSpeech && /* @__PURE__ */ jsxRuntime.jsx(
6968
+ showAttachments && /* @__PURE__ */ jsxRuntime.jsx(AttachButton, { disabled: disabled || loading, icon: attachIcon }),
6969
+ showSpeech && /* @__PURE__ */ jsxRuntime.jsx(
6922
6970
  SpeechInput,
6923
6971
  __spreadValues({
6924
6972
  disabled: disabled || loading
@@ -8065,6 +8113,8 @@ var ChatPanel = React3__namespace.memo(
8065
8113
  onTaskRetry,
8066
8114
  onTaskStopAll,
8067
8115
  onTaskClick,
8116
+ promptInputVariant = "default",
8117
+ enableAttachments,
8068
8118
  enableSpeech = true,
8069
8119
  showHeader = true,
8070
8120
  sessionTitle,
@@ -8232,6 +8282,7 @@ var ChatPanel = React3__namespace.memo(
8232
8282
  /* @__PURE__ */ jsxRuntime.jsx(
8233
8283
  PromptInput2,
8234
8284
  {
8285
+ variant: promptInputVariant,
8235
8286
  dialog,
8236
8287
  placeholder,
8237
8288
  value: promptValue,
@@ -8241,6 +8292,7 @@ var ChatPanel = React3__namespace.memo(
8241
8292
  onStop,
8242
8293
  context,
8243
8294
  enableSpeech,
8295
+ enableAttachments,
8244
8296
  className: cn(
8245
8297
  "border border-neutral-600 bg-background shadow-sm overflow-hidden",
8246
8298
  tasks.length > 0 && !dialog ? "rounded-t-none rounded-b-2xl border-t-0" : "rounded-2xl"
@@ -14596,7 +14648,9 @@ var ScenePlayer = React3__namespace.forwardRef(
14596
14648
  onSubmit,
14597
14649
  loading = false,
14598
14650
  onStop,
14599
- enableSpeech = true,
14651
+ enableSpeech = false,
14652
+ enableAttachments = false,
14653
+ promptInputVariant = "row",
14600
14654
  onPublish,
14601
14655
  publishPlaceholder = "Ask a question or provide instructions...",
14602
14656
  onSceneChange,
@@ -14622,6 +14676,8 @@ var ScenePlayer = React3__namespace.forwardRef(
14622
14676
  "loading",
14623
14677
  "onStop",
14624
14678
  "enableSpeech",
14679
+ "enableAttachments",
14680
+ "promptInputVariant",
14625
14681
  "onPublish",
14626
14682
  "publishPlaceholder",
14627
14683
  "onSceneChange",
@@ -14936,6 +14992,7 @@ var ScenePlayer = React3__namespace.forwardRef(
14936
14992
  children: /* @__PURE__ */ jsxRuntime.jsx(
14937
14993
  PromptInput2,
14938
14994
  {
14995
+ variant: promptInputVariant,
14939
14996
  placeholder: placeholder || publishPlaceholder,
14940
14997
  value: promptValue,
14941
14998
  onChange: onPromptValueChange,
@@ -14943,6 +15000,7 @@ var ScenePlayer = React3__namespace.forwardRef(
14943
15000
  loading,
14944
15001
  onStop,
14945
15002
  enableSpeech,
15003
+ enableAttachments,
14946
15004
  className: "border border-border bg-background shadow-md overflow-hidden rounded-2xl"
14947
15005
  }
14948
15006
  )