mirror of
https://github.com/johndoe6345789/metabuilder.git
synced 2026-04-24 13:54:57 +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>
65 lines
1.5 KiB
TypeScript
65 lines
1.5 KiB
TypeScript
// fakemui/react/components/email/inputs/BodyEditor.tsx
|
|
import React, { forwardRef } from 'react'
|
|
import { Box } from '../../layout/Box'
|
|
import { useAccessible } from '../../../../hooks/useAccessible'
|
|
|
|
export interface BodyEditorProps
|
|
extends React.TextareaHTMLAttributes<
|
|
HTMLTextAreaElement
|
|
> {
|
|
mode?: 'plain' | 'html'
|
|
onModeChange?: (mode: 'plain' | 'html') => void
|
|
testId?: string
|
|
}
|
|
|
|
export const BodyEditor = forwardRef<
|
|
HTMLTextAreaElement,
|
|
BodyEditorProps
|
|
>(({
|
|
mode = 'plain',
|
|
onModeChange,
|
|
testId: customTestId,
|
|
...props
|
|
}, ref) => {
|
|
const accessible = useAccessible({
|
|
feature: 'email',
|
|
component: 'body-editor',
|
|
identifier: customTestId || 'body',
|
|
ariaLabel: 'Email body'
|
|
})
|
|
|
|
const modeBtn = (m: 'plain' | 'html', label: string) => (
|
|
<button
|
|
type="button"
|
|
className={`mode-btn${mode === m ? ' mode-btn--active' : ''}`}
|
|
onClick={() => onModeChange?.(m)}
|
|
aria-pressed={mode === m}
|
|
data-testid={`mode-${m}`}
|
|
>
|
|
{label}
|
|
</button>
|
|
)
|
|
|
|
return (
|
|
<Box className="body-editor">
|
|
<div
|
|
className="body-editor-toolbar"
|
|
role="toolbar"
|
|
aria-label="Editor mode"
|
|
>
|
|
{modeBtn('plain', 'Plain Text')}
|
|
{modeBtn('html', 'HTML')}
|
|
</div>
|
|
<textarea
|
|
ref={ref}
|
|
className="body-editor-textarea"
|
|
placeholder="Write your message here..."
|
|
{...accessible}
|
|
{...props}
|
|
/>
|
|
</Box>
|
|
)
|
|
})
|
|
|
|
BodyEditor.displayName = 'BodyEditor'
|