mirror of
https://github.com/bulwarkmail/webmail.git
synced 2026-11-02 08:15:55 +00:00
fix: drop duplicate selection checkbox in message list
This commit is contained in:
@@ -210,7 +210,7 @@ describe('ThreadListItem row content', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('ThreadListItem shift-range checkbox', () => {
|
||||
describe('ThreadListItem shift-range avatar selection', () => {
|
||||
beforeEach(() => {
|
||||
useSettingsStore.setState({
|
||||
emailKeywords: [...DEFAULT_KEYWORDS],
|
||||
@@ -219,11 +219,11 @@ describe('ThreadListItem shift-range checkbox', () => {
|
||||
});
|
||||
});
|
||||
|
||||
it('shift-clicking the checkbox extends the selection from the anchor', () => {
|
||||
it('shift-clicking the avatar extends the selection from the anchor', () => {
|
||||
const e1 = makeEmail({ id: 'e1', threadId: 't1' });
|
||||
const e2 = makeEmail({ id: 'e2', threadId: 't2' });
|
||||
const e3 = makeEmail({ id: 'e3', threadId: 't3' });
|
||||
// Selection mode active so the checkbox renders, with the anchor on e1.
|
||||
// Selection mode active, with the anchor on e1.
|
||||
useEmailStore.setState({
|
||||
emails: [e1, e2, e3],
|
||||
selectedEmailIds: new Set(['e1']),
|
||||
@@ -232,9 +232,9 @@ describe('ThreadListItem shift-range checkbox', () => {
|
||||
});
|
||||
|
||||
renderRow(e3);
|
||||
const checkbox = screen.getAllByRole('button')[0];
|
||||
const avatar = screen.getByRole('checkbox');
|
||||
act(() => {
|
||||
checkbox.dispatchEvent(new MouseEvent('click', { bubbles: true, shiftKey: true }));
|
||||
avatar.dispatchEvent(new MouseEvent('click', { bubbles: true, shiftKey: true }));
|
||||
});
|
||||
|
||||
const selected = useEmailStore.getState().selectedEmailIds;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
"use client";
|
||||
|
||||
import type { ComponentProps } from "react";
|
||||
import type { ComponentProps, MouseEvent } from "react";
|
||||
import { Check } from "lucide-react";
|
||||
import { Avatar } from "@/components/ui/avatar";
|
||||
import { cn } from "@/lib/utils";
|
||||
@@ -8,8 +8,11 @@ import { cn } from "@/lib/utils";
|
||||
type SelectableAvatarProps = ComponentProps<typeof Avatar> & {
|
||||
/** Whether the underlying message/thread is currently selected. */
|
||||
checked: boolean;
|
||||
/** Toggle selection. The wrapper stops propagation so the row is not opened. */
|
||||
onToggle: () => void;
|
||||
/**
|
||||
* Toggle selection. The wrapper stops propagation so the row is not opened.
|
||||
* Receives the click event so callers can honour shift-click range selection.
|
||||
*/
|
||||
onToggle: (e: MouseEvent<HTMLButtonElement>) => void;
|
||||
/** Accessible label for the selection control. */
|
||||
selectLabel?: string;
|
||||
};
|
||||
@@ -35,7 +38,7 @@ export function SelectableAvatar({
|
||||
aria-label={selectLabel}
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
onToggle();
|
||||
onToggle(e);
|
||||
}}
|
||||
className={cn(
|
||||
"group/select relative shrink-0 rounded-full outline-none",
|
||||
|
||||
@@ -294,8 +294,8 @@ const SingleEmailItem = React.forwardRef<HTMLDivElement, SingleEmailItemProps>(
|
||||
className={cn('px-3', isFocusedMailLayout ? 'flex items-center' : 'flex items-start', swipeEnabled && 'relative z-10 bg-inherit')}
|
||||
style={{ gap: 'var(--density-item-gap)', paddingBlock: 'var(--density-item-py)', transform: swipeEnabled && offsetX ? `translateX(${offsetX}px)` : undefined, transition: swipeEnabled && offsetX === 0 ? 'transform 200ms ease-out' : undefined }}
|
||||
>
|
||||
{/* Checkbox - only visible when in selection mode */}
|
||||
{selectedEmailIds.size > 0 && (
|
||||
{/* Checkbox - only for extra-compact density (no avatar) while in selection mode */}
|
||||
{density === 'extra-compact' && selectedEmailIds.size > 0 && (
|
||||
<button
|
||||
onClick={handleCheckboxClick}
|
||||
className={cn(
|
||||
@@ -329,7 +329,7 @@ const SingleEmailItem = React.forwardRef<HTMLDivElement, SingleEmailItemProps>(
|
||||
className="flex-shrink-0 shadow-sm"
|
||||
disableImages={hideJunkAvatarImages}
|
||||
checked={isChecked}
|
||||
onToggle={() => toggleEmailSelection(email.id)}
|
||||
onToggle={handleCheckboxClick}
|
||||
selectLabel={tBatch('select')}
|
||||
/>
|
||||
)}
|
||||
@@ -733,8 +733,8 @@ export const ThreadListItem = React.forwardRef<HTMLDivElement, ThreadListItemPro
|
||||
className={cn('px-3', isFocusedMailLayout ? 'flex items-center' : 'flex items-start')}
|
||||
style={{ gap: 'var(--density-item-gap)', paddingBlock: 'var(--density-item-py)' }}
|
||||
>
|
||||
{/* Checkbox for thread selection - only visible when in selection mode */}
|
||||
{selectedEmailIds.size > 0 && (
|
||||
{/* Checkbox for thread selection - only for extra-compact density (no avatar) while in selection mode */}
|
||||
{density === 'extra-compact' && selectedEmailIds.size > 0 && (
|
||||
<button
|
||||
onClick={handleThreadCheckboxClick}
|
||||
className={cn(
|
||||
@@ -769,7 +769,7 @@ export const ThreadListItem = React.forwardRef<HTMLDivElement, ThreadListItemPro
|
||||
className="shadow-sm"
|
||||
disableImages={hideJunkAvatarImages}
|
||||
checked={isChecked}
|
||||
onToggle={toggleThreadSelection}
|
||||
onToggle={handleThreadCheckboxClick}
|
||||
selectLabel={tBatch('select')}
|
||||
/>
|
||||
{!isMobile && (
|
||||
|
||||
Reference in New Issue
Block a user