feat(app): gate return-key submit icon to new workspace composer
The new-workspace composer is a one-shot "create" submit, not a chat send, so a return-key glyph reads more accurately there than an arrow. Add a submitIcon prop on Composer/MessageInput (defaulting to "arrow") and opt NewWorkspace into "return".
This commit is contained in:
@@ -176,6 +176,7 @@ vi.mock("lucide-react-native", () => {
|
||||
const createIcon = (name: string) => (props: Record<string, unknown>) =>
|
||||
React.createElement("span", { ...props, "data-icon": name });
|
||||
return {
|
||||
ArrowUp: createIcon("ArrowUp"),
|
||||
CornerDownLeft: createIcon("CornerDownLeft"),
|
||||
Square: createIcon("Square"),
|
||||
Pencil: createIcon("Pencil"),
|
||||
|
||||
@@ -100,6 +100,7 @@ interface ComposerProps {
|
||||
allowEmptySubmit?: boolean;
|
||||
/** Optional accessibility label for the primary submit button. */
|
||||
submitButtonAccessibilityLabel?: string;
|
||||
submitIcon?: "arrow" | "return";
|
||||
/** Externally controlled loading state. When true, disables the submit button. */
|
||||
isSubmitLoading?: boolean;
|
||||
submitBehavior?: "clear" | "preserve-and-lock";
|
||||
@@ -142,6 +143,7 @@ export function Composer({
|
||||
hasExternalContent = false,
|
||||
allowEmptySubmit = false,
|
||||
submitButtonAccessibilityLabel,
|
||||
submitIcon = "arrow",
|
||||
isSubmitLoading = false,
|
||||
submitBehavior = "clear",
|
||||
blurOnSubmit = false,
|
||||
@@ -930,6 +932,7 @@ export function Composer({
|
||||
hasExternalContent={hasExternalContent}
|
||||
allowEmptySubmit={allowEmptySubmit}
|
||||
submitButtonAccessibilityLabel={submitButtonAccessibilityLabel}
|
||||
submitIcon={submitIcon}
|
||||
isSubmitDisabled={isProcessing || isSubmitLoading}
|
||||
isSubmitLoading={isProcessing || isSubmitLoading}
|
||||
attachments={selectedAttachments}
|
||||
|
||||
@@ -49,6 +49,7 @@ vi.mock("lucide-react-native", () => {
|
||||
const createIcon = (name: string) => (props: Record<string, unknown>) =>
|
||||
React.createElement("span", { ...props, "data-icon": name });
|
||||
return {
|
||||
ArrowUp: createIcon("ArrowUp"),
|
||||
Mic: createIcon("Mic"),
|
||||
MicOff: createIcon("MicOff"),
|
||||
CornerDownLeft: createIcon("CornerDownLeft"),
|
||||
@@ -226,18 +227,27 @@ afterEach(() => {
|
||||
vi.unstubAllGlobals();
|
||||
});
|
||||
|
||||
function renderMessageInput(menuItems: AttachmentMenuItem[]) {
|
||||
interface RenderMessageInputOptions {
|
||||
value?: string;
|
||||
submitIcon?: "arrow" | "return";
|
||||
}
|
||||
|
||||
function renderMessageInput(
|
||||
menuItems: AttachmentMenuItem[],
|
||||
{ value = "", submitIcon }: RenderMessageInputOptions = {},
|
||||
) {
|
||||
act(() => {
|
||||
root?.render(
|
||||
<MessageInput
|
||||
value=""
|
||||
value={value}
|
||||
onChangeText={vi.fn()}
|
||||
onSubmit={vi.fn()}
|
||||
attachments={[]}
|
||||
cwd="/repo"
|
||||
attachmentMenuItems={menuItems}
|
||||
client={{ isConnected: true } as never}
|
||||
isAgentRunning
|
||||
isAgentRunning={false}
|
||||
submitIcon={submitIcon}
|
||||
onQueue={vi.fn()}
|
||||
/>,
|
||||
);
|
||||
@@ -302,4 +312,16 @@ describe("MessageInput attachments", () => {
|
||||
|
||||
expect(queryAllByAriaLabel("Queue message")).toHaveLength(0);
|
||||
});
|
||||
|
||||
it("uses ArrowUp by default and CornerDownLeft when return submit icon is requested", () => {
|
||||
renderMessageInput([], { value: "Send this" });
|
||||
|
||||
expect(document.querySelectorAll('[data-icon="ArrowUp"]')).toHaveLength(1);
|
||||
expect(document.querySelectorAll('[data-icon="CornerDownLeft"]')).toHaveLength(0);
|
||||
|
||||
renderMessageInput([], { value: "Create this", submitIcon: "return" });
|
||||
|
||||
expect(document.querySelectorAll('[data-icon="ArrowUp"]')).toHaveLength(0);
|
||||
expect(document.querySelectorAll('[data-icon="CornerDownLeft"]')).toHaveLength(1);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -20,7 +20,7 @@ import {
|
||||
forwardRef,
|
||||
} from "react";
|
||||
import { StyleSheet, useUnistyles } from "react-native-unistyles";
|
||||
import { Mic, MicOff, CornerDownLeft, Plus, Square } from "lucide-react-native";
|
||||
import { ArrowUp, Mic, MicOff, CornerDownLeft, Plus, Square } from "lucide-react-native";
|
||||
import Animated, { useSharedValue, useAnimatedStyle, withTiming } from "react-native-reanimated";
|
||||
import { useDictation } from "@/hooks/use-dictation";
|
||||
import { DictationOverlay } from "./dictation-controls";
|
||||
@@ -85,6 +85,7 @@ export interface MessageInputProps {
|
||||
allowEmptySubmit?: boolean;
|
||||
/** Optional accessibility label for the primary submit button. */
|
||||
submitButtonAccessibilityLabel?: string;
|
||||
submitIcon?: "arrow" | "return";
|
||||
isSubmitDisabled?: boolean;
|
||||
isSubmitLoading?: boolean;
|
||||
attachments: ComposerAttachment[];
|
||||
@@ -217,6 +218,7 @@ export const MessageInput = forwardRef<MessageInputRef, MessageInputProps>(funct
|
||||
hasExternalContent = false,
|
||||
allowEmptySubmit = false,
|
||||
submitButtonAccessibilityLabel,
|
||||
submitIcon = "arrow",
|
||||
isSubmitDisabled = false,
|
||||
isSubmitLoading = false,
|
||||
attachments,
|
||||
@@ -1180,8 +1182,10 @@ export const MessageInput = forwardRef<MessageInputRef, MessageInputProps>(funct
|
||||
>
|
||||
{isSubmitLoading ? (
|
||||
<ActivityIndicator size="small" color="white" />
|
||||
) : (
|
||||
) : submitIcon === "return" ? (
|
||||
<CornerDownLeft size={buttonIconSize} color="white" />
|
||||
) : (
|
||||
<ArrowUp size={buttonIconSize} color="white" />
|
||||
)}
|
||||
</TooltipTrigger>
|
||||
<TooltipContent side="top" align="center" offset={8}>
|
||||
|
||||
Reference in New Issue
Block a user