Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,9 @@ anchor: const SESSION_ACTIONS
created: 2026-10-15T06:53:53Z
norm: '1'
sig: c3fdfbf17fa1d7dd
body_hash: 3775672d82d8f674
raw_hash: 851c5d82951881de
body_hash: 1e4ad4c649f0964d
raw_hash: f11bb45a680ab29a
vouched: 2026-10-15T11:13:24Z
lines: 43-44
---

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
---
id: 01M4ZM8GB6RD86274YM563E355
anchor: const TRAILING
created: 2026-10-15T11:13:20Z
norm: '1'
sig: a8ae768d38878d21
body_hash: 1076ba67d59d383f
raw_hash: 1d733dc306227892
lines: 29-30
---

the gap between facepile and actions must cover the pin's hit-area spill so a face never pins
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ const ACTION_BUTTON = cn(
// Hit-testing must not wait for :hover. A press that arrives before hover styles apply lands on the
// row, its release lands on the button, and the click then reaches neither.
const SESSION_ACTIONS =
"absolute top-1/2 right-1 z-20 inline-flex -translate-y-1/2 items-center gap-0 -space-x-0.5 opacity-0 transition-opacity duration-150 ease-out motion-reduce:transition-none group-hover/row:opacity-100 group-focus-within/row:opacity-100 group-data-[menu-open=true]/menu:opacity-100";
"inline-flex items-center gap-0 -space-x-0.5 opacity-0 transition-opacity duration-150 ease-out motion-reduce:transition-none group-hover/row:opacity-100 group-focus-within/row:opacity-100 group-data-[menu-open=true]/menu:opacity-100";

type SessionActionsProps = ActionProps & {
data: SidebarRow;
Expand Down
31 changes: 17 additions & 14 deletions packages/ui/src/components/session-item/session-item.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,11 @@ const EXPANDED_CONTENT_PADDING_BOTTOM =
"data-[open=true]:pb-(--session-item-expanded-padding-bottom)";
const TITLE_TO_EXPANDED_CONTENT_GAP = "data-[open=true]:mt-(--session-item-title-to-content-gap)";
const EXPANDED_CONTENT_ROW_GAP = "gap-y-1";
// The facepile and the actions sit side by side so pointing at a face never reaches pin, and
// neither moves on hover. The 8px gap equals the spill of the pin's 40px hit area around its 24px
// button, so that hit area ends at the facepile's edge; the facepile also stacks above it.
const TRAILING =
"pointer-events-none absolute top-1/2 right-1 z-20 inline-flex -translate-y-1/2 items-center gap-2 *:pointer-events-auto";

export type SessionItemProps = ComponentPropsWithRef<"button"> & {
data: SidebarRow;
Expand Down Expand Up @@ -245,7 +250,7 @@ function buttonClass(
hasActions
&& online === 0
&& "group-hover/row:pr-13 group-focus-within/row:pr-13 group-data-[menu-open=true]/menu:pr-13",
online > 0 && "pr-17",
online > 0 && (hasActions ? "pr-24" : "pr-17"),
className,
);
}
Expand Down Expand Up @@ -400,21 +405,19 @@ export function SessionItem(
)
: line}
</button>
<span
className={cn(
"absolute top-1/2 right-1 z-10 inline-flex -translate-y-1/2 transition-opacity duration-150 ease-out motion-reduce:transition-none",
hasActions
&& "group-hover/row:opacity-0 group-focus-within/row:opacity-0 group-data-[menu-open=true]/menu:opacity-0",
<span className={TRAILING}>
{data.online.length > 0 && (
<span className="relative z-1 inline-flex">
<Presence members={data.online} />
</span>
)}
>
<Presence members={data.online} />
<SessionActions
data={data}
pinned={pinned}
onPin={actionPin}
onUnpin={actionUnpin}
/>
</span>
<SessionActions
data={data}
pinned={pinned}
onPin={actionPin}
onUnpin={actionUnpin}
/>
</div>
</RowMenu>
);
Expand Down