Skip to content

Commit

Permalink
feat: styled components for attachments (#773)
Browse files Browse the repository at this point in the history
  • Loading branch information
Yonom authored Sep 8, 2024
1 parent dece2ec commit 19c6365
Show file tree
Hide file tree
Showing 4 changed files with 143 additions and 3 deletions.
2 changes: 2 additions & 0 deletions apps/docs/content/docs/ui/styled/Decomposition.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,8 @@ import { Composer } from "@assistant-ui/react";
const MyComposer: FC = () => {
return (
<Composer.Root>
<Composer.Attachments />
<Composer.AddAttachment />
<Composer.Input autoFocus />
<Composer.Action />
</Composer.Root>
Expand Down
15 changes: 14 additions & 1 deletion packages/react/src/styles/tailwindcss/thread.css
Original file line number Diff line number Diff line change
Expand Up @@ -53,10 +53,23 @@
}

.aui-composer-send,
.aui-composer-cancel {
.aui-composer-cancel,
.aui-composer-attach {
@apply my-2.5 size-8 p-2 transition-opacity ease-in;
}

.aui-composer-attachments-container {
@apply flex w-full flex-row gap-3 px-10;
}

.aui-composer-attachment-container {
@apply bg-aui-muted relative mt-4 flex size-20 items-center justify-center rounded-lg p-2;
}

.aui-composer-attachment-remove {
@apply absolute -right-3 -top-3 size-7;
}

/* user message */

.aui-user-message-root {
Expand Down
115 changes: 113 additions & 2 deletions packages/react/src/ui/composer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

import { ComponentPropsWithoutRef, forwardRef, type FC } from "react";

import { SendHorizontalIcon } from "lucide-react";
import { CircleXIcon, PaperclipIcon, SendHorizontalIcon } from "lucide-react";
import { withDefaults } from "./utils/withDefaults";
import { useThreadConfig } from "./thread-config";
import {
Expand All @@ -11,11 +11,22 @@ import {
} from "./base/tooltip-icon-button";
import { CircleStopIcon } from "./base/CircleStopIcon";
import { ComposerPrimitive, ThreadPrimitive } from "../primitives";
import { useThreadContext } from "../context";
import { useThreadContext } from "../context/react/ThreadContext";
import { useAttachmentContext } from "../context/react/AttachmentContext";

const useAllowAttachments = (ensureCapability = false) => {
const { composer: { allowAttachments = true } = {} } = useThreadConfig();
const { useThread } = useThreadContext();
const attachmentsSupported = useThread((t) => t.capabilities.attachments);
return allowAttachments && (!ensureCapability || attachmentsSupported);
};

const Composer: FC = () => {
const allowAttachments = useAllowAttachments(true);
return (
<ComposerRoot>
{allowAttachments && <ComposerAttachments />}
{allowAttachments && <ComposerAddAttachment />}
<ComposerInput autoFocus />
<ComposerAction />
</ComposerRoot>
Expand Down Expand Up @@ -52,8 +63,104 @@ const ComposerInput = forwardRef<HTMLTextAreaElement, ComposerInputProps>(
},
);

const ComposerAttachmentsContainer = withDefaults("div", {
className: "aui-composer-attachments-container",
});

const ComposerAttachments: FC = () => {
return (
<ComposerAttachmentsContainer>
<ComposerPrimitive.Attachments
components={{ Fallback: ComposerAttachment }}
/>
</ComposerAttachmentsContainer>
);
};

const ComposerAttachmentContainer = withDefaults("div", {
className: "aui-composer-attachment-container",
});

const ComposerAttachment: FC = () => {
const { useAttachment } = useAttachmentContext();
const attachment = useAttachment((a) => a.attachment);

return (
<ComposerAttachmentContainer>
.{attachment.name.split(".").pop()}
<ComposerRemoveAttachment />
</ComposerAttachmentContainer>
);
};

ComposerAttachment.displayName = "ComposerAttachment";

const ComposerRemoveAttachment = forwardRef<
HTMLButtonElement,
Partial<TooltipIconButtonProps>
>((props, ref) => {
const {
strings: {
composer: { removeAttachment: { tooltip = "Remove file" } = {} } = {},
} = {},
} = useThreadConfig();

const { useComposer } = useThreadContext();
const handleRemoveAttachment = () => {
// TODO delete the correct attachment
useComposer
.getState()
.removeAttachment(useComposer.getState().attachments[0]?.id!);
};
return (
<TooltipIconButton
tooltip={tooltip}
className="aui-composer-attachment-remove"
side="top"
{...props}
onClick={handleRemoveAttachment}
ref={ref}
>
{props.children ?? <CircleXIcon />}
</TooltipIconButton>
);
});

ComposerRemoveAttachment.displayName = "ComposerRemoveAttachment";

ComposerInput.displayName = "ComposerInput";

const ComposerAttachButton = withDefaults(TooltipIconButton, {
variant: "default",
className: "aui-composer-attach",
});

const ComposerAddAttachment = forwardRef<
HTMLButtonElement,
Partial<TooltipIconButtonProps>
>((props, ref) => {
const {
strings: {
composer: { addAttachment: { tooltip = "Attach file" } = {} } = {},
} = {},
} = useThreadConfig();
const allowAttachments = useAllowAttachments();
return (
<ComposerPrimitive.AddAttachment disabled={!allowAttachments} asChild>
<ComposerAttachButton
tooltip={tooltip}
variant={"ghost"}
{...props}
ref={ref}
>
{props.children ?? <PaperclipIcon />}
</ComposerAttachButton>
</ComposerPrimitive.AddAttachment>
);
});

ComposerAddAttachment.displayName = "ComposerAddAttachment";

const useAllowCancel = () => {
const { useThread } = useThreadContext();
const cancelSupported = useThread((t) => t.capabilities.cancel);
Expand Down Expand Up @@ -129,6 +236,10 @@ const exports = {
Action: ComposerAction,
Send: ComposerSend,
Cancel: ComposerCancel,
AddAttachment: ComposerAddAttachment,
Attachments: ComposerAttachments,
Attachment: ComposerAttachment,
RemoveAttachment: ComposerRemoveAttachment,
};

export default Object.assign(Composer, exports) as typeof Composer &
Expand Down
14 changes: 14 additions & 0 deletions packages/react/src/ui/thread-config.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,10 @@ export type BranchPickerConfig = {
allowBranchPicker?: boolean | undefined;
};

export type ComposerConfig = {
allowAttachments?: boolean | undefined;
};

export type StringsConfig = {
assistantModal?: {
open: {
Expand Down Expand Up @@ -101,6 +105,14 @@ export type StringsConfig = {
tooltip?: string | undefined;
}
| undefined;
addAttachment?:
| {
tooltip?: string | undefined;
}
| undefined;
removeAttachment?: {
tooltip?: string | undefined;
};
input?: {
placeholder?: string | undefined;
};
Expand Down Expand Up @@ -135,6 +147,8 @@ export type ThreadConfig = {

branchPicker?: BranchPickerConfig;

composer?: ComposerConfig;

strings?: StringsConfig;

tools?: AssistantToolUI[]; // TODO add AssistantTool support
Expand Down

0 comments on commit 19c6365

Please sign in to comment.