mirror of
https://github.com/johndoe6345789/metabuilder.git
synced 2026-04-26 14:54:55 +00:00
Accessibility: - All components: data-testid, aria-label, aria-pressed, aria-current - ComposeWindow: role=dialog, aria-modal, focus trap, Escape handler - EmailCard: role=article, keyboard nav (Enter/Space), aria-current - ThreadList: role=list with listitem wrappers, role=status empty state - FolderNavigation: role=navigation, role=list, aria-current - RecipientInput: role=group, aria-label per type, onKeyPress→onKeyDown - BodyEditor: role=toolbar, aria-pressed on mode buttons - StarButton: MaterialIcon (star/star_border), dynamic aria-label - MarkAsReadCheckbox: dynamic label based on read state - EmailHeader: role=banner, <time> element, data-testids Component decomposition: - Extract useEmailClient hook (state + callbacks) - Extract demo-emails.ts (data constants) - EmailClientContent.tsx: 267→127 LOC (composition only) New: useKeyboardShortcuts hook (Gmail-style, 47 LOC) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
77 lines
1.9 KiB
TypeScript
77 lines
1.9 KiB
TypeScript
// fakemui/react/components/email/data-display/ThreadList.tsx
|
|
import React from 'react'
|
|
import { Box, BoxProps } from '../..'
|
|
import { useAccessible } from '../../../../hooks/useAccessible'
|
|
import { EmailCard, type EmailCardProps } from '../surfaces'
|
|
|
|
export interface ThreadListProps extends BoxProps {
|
|
emails: Array<Omit<
|
|
EmailCardProps,
|
|
'onSelect' | 'onToggleRead' | 'onToggleStar'
|
|
>>
|
|
selectedEmailId?: string
|
|
onSelectEmail?: (emailId: string) => void
|
|
onToggleRead?: (id: string, read: boolean) => void
|
|
onToggleStar?: (id: string, star: boolean) => void
|
|
testId?: string
|
|
}
|
|
|
|
export const ThreadList = ({
|
|
emails,
|
|
selectedEmailId,
|
|
onSelectEmail,
|
|
onToggleRead,
|
|
onToggleStar,
|
|
testId: customTestId,
|
|
...props
|
|
}: ThreadListProps) => {
|
|
const accessible = useAccessible({
|
|
feature: 'email',
|
|
component: 'thread-list',
|
|
identifier: customTestId || 'threads'
|
|
})
|
|
|
|
const emailId = (e: typeof emails[0], i: number) =>
|
|
e.testId || `email-${i}`
|
|
|
|
return (
|
|
<Box
|
|
role="list"
|
|
aria-label="Email messages"
|
|
className="thread-list"
|
|
{...accessible}
|
|
{...props}
|
|
>
|
|
{emails.length === 0 ? (
|
|
<div className="no-emails" role="status">
|
|
No emails
|
|
</div>
|
|
) : (
|
|
emails.map((email, idx) => (
|
|
<div role="listitem" key={idx}>
|
|
<EmailCard
|
|
{...email}
|
|
selected={
|
|
selectedEmailId === email.testId
|
|
}
|
|
onSelect={() =>
|
|
onSelectEmail?.(emailId(email, idx))
|
|
}
|
|
onToggleRead={(read) =>
|
|
onToggleRead?.(
|
|
emailId(email, idx), read
|
|
)
|
|
}
|
|
onToggleStar={(starred) =>
|
|
onToggleStar?.(
|
|
emailId(email, idx), starred
|
|
)
|
|
}
|
|
/>
|
|
</div>
|
|
))
|
|
)}
|
|
</Box>
|
|
)
|
|
}
|