import { useEffect, useMemo, type ComponentType, type ReactNode } from 'react' import type { LucideIcon } from 'lucide-react' import type { Identifier, ResourceDefinition } from '../types' import { ResourceProvider } from '../context/resource-context' import { useResources } from '../context/resource-context' export interface ResourceProps { /** Resource identifier used in URLs and data provider calls */ name: string /** Human-readable singular label */ label?: string /** Human-readable plural label */ labelPlural?: string /** Icon component for navigation */ icon?: LucideIcon /** Component to render the list view */ list?: ComponentType /** Component to render the show/detail view */ show?: ComponentType<{ id: Identifier }> /** Component to render the create view */ create?: ComponentType /** Component to render the edit view */ edit?: ComponentType<{ id: Identifier }> /** Custom options for this resource */ options?: Record /** Children to render (optional - for custom resource rendering) */ children?: ReactNode } /** * Resource component for registering and configuring CRUD resources. * * Resources are automatically registered with the ResourcesProvider when mounted, * and unregistered when unmounted. This allows for dynamic resource registration * in your application. * * **Usage Patterns:** * * 1. **Declarative Registration** - Use Resource components inside App * 2. **Programmatic Registration** - Pass resources array to App * 3. **Router Integration** - Use with your router * * @example * ```tsx * // Declarative registration * * * * * ``` */ export function Resource({ name, label, labelPlural, icon, list, show, create, edit, options, children, }: ResourceProps) { const { registerResource, unregisterResource } = useResources() // Build memoized resource definition to avoid unnecessary re-registrations // Only recreate when any of the resource properties change const definition = useMemo(() => ({ name, label, labelPlural, icon, list, show, create, edit, options, }), [name, label, labelPlural, icon, list, show, create, edit, options]) // Register when definition changes, unregister on unmount useEffect(() => { registerResource(definition) return () => unregisterResource(name) }, [definition, name, registerResource, unregisterResource]) // If children are provided, wrap them in ResourceProvider if (children) { return ( {children} ) } // If no children, just return null (resource is registered via useEffect) return null } /** * Higher-order component to wrap a view component with resource context. * * @example * ```tsx * const UsersListWithContext = withResource(UsersList, { * name: 'users', * label: 'Users', * }) * ``` */ export function withResource

( WrappedComponent: ComponentType

, resourceDef: ResourceDefinition ) { function WithResource(props: P) { return ( ) } WithResource.displayName = `withResource(${WrappedComponent.displayName ?? WrappedComponent.name ?? 'Component'})` return WithResource }