import { validateAvatarDefinition, type AnimationKey, type AvatarDefinition, type ExpressionKey, } from '@bible-strong/avatar-core' import type { ReactElement } from 'react' import { Avatar, markAvatarDefinitionValidated, type AvatarController, type AvatarProps, } from './Avatar' type AvatarDefinitionInput = { expressions: object animations: object } type StringKey = Extract /** Props for a component created from one concrete avatar definition. */ export type CreatedAvatarProps = Omit< AvatarProps, 'definition' | 'animation' | 'expression' | 'defaultAnimation' | 'defaultExpression' > & { animation?: StringKey defaultAnimation?: StringKey expression?: StringKey defaultExpression?: StringKey } /** A concrete avatar component with animation and expression keys from its definition. */ export type CreatedAvatarComponent = ( props: CreatedAvatarProps ) => ReactElement const invalidDefinitionError = (errors: readonly { path: string; message: string }[]) => { const first = errors[0] return new Error( first ? `Invalid avatar definition${first.path ? ` at ${first.path}` : ''}: ${first.message}` : 'Invalid avatar definition.' ) } const buildAvatarComponent = (definition: Readonly) => { const ConcreteAvatar = (props: CreatedAvatarProps): ReactElement => ( ) ConcreteAvatar.displayName = 'CreatedAvatar' return ConcreteAvatar } /** * Validate a JSON-compatible definition once and create a concrete React component from it. * * When the input is a statically typed definition, the returned component narrows its animation * and expression props to that definition's semantic keys. Values loaded at runtime are still * validated, but necessarily expose the broad string-key API at compile time. */ export function createAvatar( definition: Definition ): CreatedAvatarComponent export function createAvatar(definition: unknown): CreatedAvatarComponent export function createAvatar(definition: unknown): CreatedAvatarComponent { const result = validateAvatarDefinition(definition) if (!result.ok) throw invalidDefinitionError(result.errors) markAvatarDefinitionValidated(result.value) return buildAvatarComponent(result.value) } export type { AnimationKey, AvatarController, ExpressionKey }