From 8954e3814492d7a6892d57c84c3e189f6d9d51fa Mon Sep 17 00:00:00 2001 From: ComputelessComputer <63365510+ComputelessComputer@users.noreply.github.com> Date: Fri, 26 Jun 2026 17:59:27 +0900 Subject: [PATCH] Show detach icon on chat chips Remove chat context chip tooltips and reveal a circled detach icon for removable chips on hover. --- .../src/chat/components/context-bar.test.tsx | 33 +++++--- .../src/chat/components/context-bar.tsx | 80 ++++++++----------- apps/desktop/src/chat/context/registry.ts | 9 --- 3 files changed, 57 insertions(+), 65 deletions(-) diff --git a/apps/desktop/src/chat/components/context-bar.test.tsx b/apps/desktop/src/chat/components/context-bar.test.tsx index acb9e92a39..f2afcd01c1 100644 --- a/apps/desktop/src/chat/components/context-bar.test.tsx +++ b/apps/desktop/src/chat/components/context-bar.test.tsx @@ -1,19 +1,10 @@ import { cleanup, fireEvent, render, screen } from "@testing-library/react"; -import type { ReactNode } from "react"; import { beforeEach, describe, expect, it, vi } from "vitest"; const { openNewMock } = vi.hoisted(() => ({ openNewMock: vi.fn(), })); -vi.mock("@hypr/ui/components/ui/tooltip", () => ({ - Tooltip: ({ children }: { children: ReactNode }) =>
{children}
, - TooltipContent: ({ children }: { children: ReactNode }) => ( -
{children}
- ), - TooltipTrigger: ({ children }: { children: ReactNode }) => <>{children}, -})); - vi.mock("~/store/zustand/tabs", () => ({ useTabs: (selector: (state: { openNew: typeof openNewMock }) => T) => selector({ openNew: openNewMock }), @@ -54,6 +45,28 @@ describe("ContextBar", () => { expect(screen.queryByText("Search sessions...")).toBeNull(); }); + it("does not render chip tooltips", () => { + render( + , + ); + + expect(screen.getByText("Artem")).toBeTruthy(); + expect(screen.queryByText(/artem@example.com/)).toBeNull(); + }); + it("centers the squircle chip strip above the input surface", () => { const { container } = render( { const removeButton = screen.getByRole("button", { name: "Remove Current Note", }); + const removeIcon = removeButton.querySelector("svg"); expect(iconSlot?.className).toContain("size-4"); expect(iconSlot?.contains(removeButton)).toBe(true); expect(contextIcon?.className.baseVal).toContain("group-hover:opacity-0"); + expect(removeIcon?.className.baseVal).toContain("size-3.5"); expect(removeButton.className).toContain("group-hover:opacity-100"); expect(removeButton.className).toContain("group-hover:pointer-events-auto"); diff --git a/apps/desktop/src/chat/components/context-bar.tsx b/apps/desktop/src/chat/components/context-bar.tsx index d7f0485f08..783d5268a2 100644 --- a/apps/desktop/src/chat/components/context-bar.tsx +++ b/apps/desktop/src/chat/components/context-bar.tsx @@ -1,11 +1,6 @@ -import { ChevronUpIcon, XIcon } from "lucide-react"; +import { ChevronUpIcon, XCircleIcon } from "lucide-react"; import { useMemo, useState } from "react"; -import { - Tooltip, - TooltipContent, - TooltipTrigger, -} from "@hypr/ui/components/ui/tooltip"; import { cn } from "@hypr/utils"; import { type ContextChipProps, renderChip } from "~/chat/context/registry"; @@ -48,49 +43,40 @@ function ContextChip({ }; return ( - - - + + - - - {chip.removable && onRemove && ( - - )} - - {chip.label} - - - - {chip.tooltip} - - + /> + {chip.removable && onRemove && ( + + )} + + {chip.label} + ); } diff --git a/apps/desktop/src/chat/context/registry.ts b/apps/desktop/src/chat/context/registry.ts index 2ffea078cf..8909c1f953 100644 --- a/apps/desktop/src/chat/context/registry.ts +++ b/apps/desktop/src/chat/context/registry.ts @@ -12,7 +12,6 @@ export type ContextChipProps = { key: string; icon: React.ComponentType<{ className?: string }>; label: string; - tooltip: string; removable?: boolean; entityKind?: ContextEntityKind; entityId?: string; @@ -40,7 +39,6 @@ const renderers: RendererMap = { key: entity.key, icon: isFromTool ? SearchIcon : CalendarIcon, label, - tooltip: entity.title || "Session", removable: entity.removable, entityKind: "session", entityId: entity.sessionId, @@ -51,14 +49,10 @@ const renderers: RendererMap = { human: { toChip: (entity) => { const label = entity.name || entity.email || "Person"; - const tooltip = [entity.name, entity.email, entity.organizationName] - .filter(Boolean) - .join(" • "); return { key: entity.key, icon: UserIcon, label, - tooltip: tooltip || label, removable: entity.removable, entityKind: "human", entityId: entity.humanId, @@ -73,7 +67,6 @@ const renderers: RendererMap = { key: entity.key, icon: Building2Icon, label, - tooltip: label, removable: entity.removable, entityKind: "organization", entityId: entity.organizationId, @@ -88,7 +81,6 @@ const renderers: RendererMap = { key: entity.key, icon: UserIcon, label: "Account", - tooltip: entity.email || "Account", }; }, }, @@ -99,7 +91,6 @@ const renderers: RendererMap = { key: entity.key, icon: MonitorIcon, label: "Device", - tooltip: "Device", }; }, },