diff --git a/.changeset/lucky-tables-train.md b/.changeset/lucky-tables-train.md new file mode 100644 index 0000000..eddfbdd --- /dev/null +++ b/.changeset/lucky-tables-train.md @@ -0,0 +1,5 @@ +--- +"ai-elements": patch +--- + +React improvements diff --git a/.oxfmtrc.jsonc b/.oxfmtrc.jsonc index 452aec7..2f77791 100644 --- a/.oxfmtrc.jsonc +++ b/.oxfmtrc.jsonc @@ -20,5 +20,15 @@ "newlinesBetween": true, "order": "asc", }, - "ignorePatterns": ["packages/shadcn-ui"], + "ignorePatterns": [ + "packages/shadcn-ui", + "apps/docs/components/geistdocs", + "apps/docs/lib/geistdocs", + "apps/docs/hooks/geistdocs", + "apps/docs/app", + "apps/docs/geistdocs.tsx", + "apps/docs/proxy.ts", + "apps/docs/source.config.ts", + "skills", + ], } diff --git a/packages/elements/__tests__/speech-input.test.tsx b/packages/elements/__tests__/speech-input.test.tsx index c63daf5..9bd55b5 100644 --- a/packages/elements/__tests__/speech-input.test.tsx +++ b/packages/elements/__tests__/speech-input.test.tsx @@ -321,11 +321,8 @@ describe("speechInput - Speech Recognition", () => { expect(handleTranscription).not.toHaveBeenCalled(); }); - it("handles speech recognition errors and logs them", async () => { + it("handles speech recognition errors and stops listening", async () => { setupSpeechInputTests(); - const consoleErrorSpy = vi - .spyOn(console, "error") - .mockImplementation(vi.fn()); const instanceRef: InstanceRef = { current: null }; // oxlint-disable-next-line typescript-eslint(no-explicit-any) @@ -350,14 +347,10 @@ describe("speechInput - Speech Recognition", () => { }); instanceRef.current?.dispatchEvent(errorEvent); + // Button should return to mic icon (not listening state) await waitFor(() => { - expect(consoleErrorSpy).toHaveBeenCalledWith( - "Speech recognition error:", - "no-speech" - ); + expect(screen.getByRole("button")).not.toBeDisabled(); }); - - consoleErrorSpy.mockRestore(); }); it("handles empty transcript gracefully", async () => { @@ -677,9 +670,6 @@ describe("speechInput - MediaRecorder Fallback", () => { it("handles transcription errors gracefully", async () => { const ctx = setupMediaRecorderTests(); const user = userEvent.setup(); - const consoleErrorSpy = vi - .spyOn(console, "error") - .mockImplementation(vi.fn()); const handleAudioRecorded = vi .fn() .mockRejectedValue(new Error("Transcription failed")); @@ -716,16 +706,12 @@ describe("speechInput - MediaRecorder Fallback", () => { // Stop recording await user.click(button); + // Wait for the error to be handled and processing to complete await waitFor(() => { - expect(consoleErrorSpy).toHaveBeenCalledWith( - "Transcription error:", - expect.any(Error) - ); + expect(handleAudioRecorded).toHaveBeenCalled(); }); // Transcription change should not be called on error expect(handleTranscriptionChange).not.toHaveBeenCalled(); - - consoleErrorSpy.mockRestore(); }); }); diff --git a/packages/elements/src/attachments.tsx b/packages/elements/src/attachments.tsx index 245c046..59e37c8 100644 --- a/packages/elements/src/attachments.tsx +++ b/packages/elements/src/attachments.tsx @@ -39,6 +39,15 @@ export type AttachmentMediaCategory = export type AttachmentVariant = "grid" | "inline" | "list"; +const mediaCategoryIcons: Record = { + audio: Music2Icon, + document: FileTextIcon, + image: ImageIcon, + source: GlobeIcon, + unknown: PaperclipIcon, + video: VideoIcon, +}; + // ============================================================================ // Utility Functions // ============================================================================ @@ -247,16 +256,7 @@ export const AttachmentPreview = ({ return