Files
metabuilder/fakemui/react/components/inputs/TextField.tsx
johndoe6345789 d23f4a8be4 feat: FakeMUI MUI-compatibility + shared components library + hooks consolidation
FakeMUI Components (MUI API compatibility):
- Add sx prop support to all components via sxToStyle utility
- Add MUI-style variants to Button (contained, outlined)
- Add component prop to Typography for polymorphic rendering
- Add label prop to Chip (MUI uses label vs children)
- Add edge/color/size props to IconButton
- Add component prop to List for nav rendering
- Add href support to ListItemButton
- Add variant prop to Avatar
- Add PaperProps to Drawer

New @metabuilder/components package:
- vanilla/loading - LoadingIndicator, InlineLoader, AsyncLoading
- vanilla/error - ErrorBoundary, ErrorDisplay, withErrorBoundary
- vanilla/empty-state - EmptyState + 7 specialized variants
- vanilla/skeleton - Skeleton + 6 specialized variants
- Organized by framework: vanilla/, radix/, fakemui/

Hooks consolidation (FakeMUI → root hooks/):
- useAccessible (5 accessibility hooks)
- useToast with ToastProvider
- FakeMUI re-exports from hooks for backward compatibility

WorkflowUI fixes:
- Fix showNotification → useUI error/success methods
- Fix Redux reducer setTimeout (Immer proxy issue)
- Fix useRef type error
- Update to Next.js 16.1.6 with webpack mode
- Add @metabuilder/fakemui dependency

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-01 22:05:47 +00:00

80 lines
2.8 KiB
TypeScript

import React, { forwardRef, useId } from 'react'
import { FormLabel } from './FormLabel'
import { FormHelperText } from './FormHelperText'
import { Input, InputProps } from './Input'
import { Select } from './Select'
import { useAccessible } from '../../../src/utils/useAccessible'
import { sxToStyle } from '../utils/sx'
export interface TextFieldProps extends Omit<InputProps, 'size' | 'label' | 'helperText'> {
label?: React.ReactNode
helperText?: React.ReactNode
error?: boolean
/** Render as a select dropdown instead of input */
select?: boolean
/** Children (for select mode - MenuItem components) */
children?: React.ReactNode
/** Input size */
size?: 'small' | 'medium'
/** Unique identifier for testing and accessibility */
testId?: string
/** MUI sx prop for styling */
sx?: Record<string, unknown>
}
export const TextField = forwardRef<HTMLInputElement | HTMLSelectElement, TextFieldProps>(
({ label, helperText, error, className = '', id: providedId, select, children, size, testId: customTestId, sx, style, ...props }, ref) => {
const generatedId = useId()
const id = providedId ?? generatedId
const helperTextId = `${id}-helper-text`
// Convert size prop to Input's expected format
const inputSize = size === 'small' ? 'sm' : size === 'medium' ? 'md' : undefined
const accessible = useAccessible({
feature: 'form',
component: select ? 'select' : 'input',
identifier: customTestId || String(label)?.substring(0, 20),
ariaDescribedBy: helperText ? helperTextId : undefined,
})
return (
<div className={`text-field ${error ? 'text-field--error' : ''} ${className}`} style={{ ...sxToStyle(sx), ...style }}>
{label && <FormLabel htmlFor={id}>{label}</FormLabel>}
{select ? (
<Select
ref={ref as React.Ref<HTMLSelectElement>}
id={id}
error={error}
className="select--full-width"
data-testid={accessible['data-testid']}
aria-invalid={error}
aria-describedby={helperText ? helperTextId : undefined}
{...(props as unknown as React.SelectHTMLAttributes<HTMLSelectElement>)}
>
{children}
</Select>
) : (
<Input
ref={ref as React.Ref<HTMLInputElement>}
id={id}
error={error}
size={inputSize}
data-testid={accessible['data-testid']}
aria-invalid={error}
aria-describedby={helperText ? helperTextId : undefined}
{...props}
/>
)}
{helperText && (
<FormHelperText error={error} id={helperTextId} role="status">
{helperText}
</FormHelperText>
)}
</div>
)
}
)
TextField.displayName = 'TextField'