feat(fakemui): add email atom components (icons, buttons)

This commit is contained in:
2026-01-23 19:32:05 +00:00
parent 4d1c7d13a5
commit 9fa9057750
4 changed files with 135 additions and 0 deletions

View File

@@ -0,0 +1,47 @@
import React, { forwardRef } from 'react'
import { useAccessible } from '@metabuilder/fakemui/hooks'
export interface AttachmentIconProps extends React.SVGAttributes<SVGSVGElement> {
filename?: string
mimeType?: string
testId?: string
}
export const AttachmentIcon = forwardRef<SVGSVGElement, AttachmentIconProps>(
({ filename, mimeType, testId: customTestId, ...props }, ref) => {
const accessible = useAccessible({
feature: 'email',
component: 'attachment-icon',
identifier: customTestId || filename || 'attachment'
})
// Determine icon based on mime type
const getIconContent = () => {
if (mimeType?.startsWith('image/')) return '🖼️'
if (mimeType?.startsWith('video/')) return '🎬'
if (mimeType?.startsWith('audio/')) return '🎵'
if (mimeType === 'application/pdf') return '📄'
return '📎'
}
return (
<svg
ref={ref}
viewBox="0 0 24 24"
width="20"
height="20"
className="attachment-icon"
role="img"
aria-label={`Attachment: ${filename || 'document'}`}
{...accessible}
{...props}
>
<text x="50%" y="50%" dominantBaseline="middle" textAnchor="middle" fontSize="16">
{getIconContent()}
</text>
</svg>
)
}
)
AttachmentIcon.displayName = 'AttachmentIcon'

View File

@@ -0,0 +1,42 @@
import React, { forwardRef, useState } from 'react'
import { useAccessible } from '@metabuilder/fakemui/hooks'
export interface MarkAsReadCheckboxProps extends React.InputHTMLAttributes<HTMLInputElement> {
isRead?: boolean
onToggleRead?: (read: boolean) => void
testId?: string
}
export const MarkAsReadCheckbox = forwardRef<HTMLInputElement, MarkAsReadCheckboxProps>(
({ isRead = false, onToggleRead, testId: customTestId, ...props }, ref) => {
const [read, setRead] = useState(isRead)
const accessible = useAccessible({
feature: 'email',
component: 'read-checkbox',
identifier: customTestId || 'read-status'
})
const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
const newState = e.target.checked
setRead(newState)
onToggleRead?.(newState)
props.onChange?.(e)
}
return (
<input
ref={ref}
type="checkbox"
checked={read}
className="read-checkbox"
aria-label="Mark as read"
{...accessible}
{...props}
onChange={handleChange}
/>
)
}
)
MarkAsReadCheckbox.displayName = 'MarkAsReadCheckbox'

View File

@@ -0,0 +1,43 @@
import React, { forwardRef, useState } from 'react'
import { useAccessible } from '@metabuilder/fakemui/hooks'
export interface StarButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {
isStarred?: boolean
onToggleStar?: (starred: boolean) => void
testId?: string
}
export const StarButton = forwardRef<HTMLButtonElement, StarButtonProps>(
({ isStarred = false, onToggleStar, testId: customTestId, ...props }, ref) => {
const [starred, setStarred] = useState(isStarred)
const accessible = useAccessible({
feature: 'email',
component: 'star-button',
identifier: customTestId || 'star'
})
const handleClick = (e: React.MouseEvent) => {
const newState = !starred
setStarred(newState)
onToggleStar?.(newState)
props.onClick?.(e)
}
return (
<button
ref={ref}
className={`star-button ${starred ? 'star-button--active' : ''}`}
aria-pressed={starred}
title={starred ? 'Remove star' : 'Add star'}
{...accessible}
{...props}
onClick={handleClick}
>
{starred ? '⭐' : '☆'}
</button>
)
}
)
StarButton.displayName = 'StarButton'

View File

@@ -0,0 +1,3 @@
export { AttachmentIcon, type AttachmentIconProps } from './AttachmentIcon'
export { StarButton, type StarButtonProps } from './StarButton'
export { MarkAsReadCheckbox, type MarkAsReadCheckboxProps } from './MarkAsReadCheckbox'