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",
};
},
},