import React from 'react';
import {
type ResolvedFieldPresentation,
resolveFieldPresentation,
resolveFieldState,
} from '../../../../../internal/resolvers';
import type { FieldProps } from '../../../../../types/field';
import { View } from '../../../../layout/public';
import { Text } from '../../../../typography/public';
/*** Composes a control with its label and helper or error message. */
export function Field({
children,
label,
helperText,
errorText,
required = false,
disabled = false,
invalid = false,
readOnly = false,
testID,
}: FieldProps) {
const hasErrorText = Boolean(errorText);
const presentation = resolveFieldPresentation(
resolveFieldState({ disabled, invalid: invalid || hasErrorText, readOnly }),
);
const message = hasErrorText ? errorText : helperText;
return (
{renderFieldLabel(label, required, presentation)}
{children}
{renderFieldMessage(message, presentation)}
);
}
/*** Renders an optional field label and required indicator. */
function renderFieldLabel(
label: React.ReactNode,
required: boolean,
presentation: ResolvedFieldPresentation,
) {
if (label === undefined || label === null) return null;
const labelContent =
typeof label === 'string' || typeof label === 'number' ? (
{label}
) : (
label
);
return (
{labelContent}
{required ? (
*
) : null}
);
}
/*** Renders an optional helper or error message using field presentation semantics. */
function renderFieldMessage(message: React.ReactNode, presentation: ResolvedFieldPresentation) {
if (message === undefined || message === null || message === '') return null;
if (typeof message !== 'string' && typeof message !== 'number') return message;
return (
{message}
);
}