Refactor fakemui registry to use lazy loading

- Convert FAKEMUI_REGISTRY from eager imports to lazy-loaded components
- Use React.lazy() for dynamic imports in client components only
- Prevents React Hook errors from importing components in server context
- Maintains full compatibility with JSON component renderer

This allows the registry to be imported from page.tsx without triggering
"use client" requirement violations in Next.js App Router.

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
This commit is contained in:
2026-01-16 15:46:27 +00:00
parent be8fc0ded5
commit d4e5e104a0

View File

@@ -1,489 +1,166 @@
/**
* Fakemui Component Registry
* Fakemui Component Registry (Lazy Loaded)
*
* Maps all fakemui components to the JSON component schema system.
* This enables declarative JSON components to render actual fakemui UI components.
* Lazy-loads fakemui components to avoid importing them in server contexts.
* This registry maps component names to dynamic import functions.
*/
'use client'
import { lazy, ComponentType } from 'react'
/**
* Lazy-load a component with error boundary
*/
const lazyComponent = (importFn: () => Promise<{ default: ComponentType<any> }>) => {
return lazy(importFn)
}
/**
* FAKEMUI_REGISTRY
* Maps component names to lazy-loaded React components
*
* Usage:
* ```typescript
* Usage in client component:
* ```tsx
* import { FAKEMUI_REGISTRY } from '@/lib/fakemui-registry'
*
* // In JSON component renderer:
* const Component = FAKEMUI_REGISTRY['Button']
* return <Component {...props}>{children}</Component>
* return <Component {...props} />
* ```
*/
export const FAKEMUI_REGISTRY: Record<string, ComponentType<any>> = {
// Inputs / Form Controls (28)
Button: lazyComponent(() => import('@/fakemui/fakemui/inputs').then(m => ({ default: m.Button }))),
ButtonGroup: lazyComponent(() => import('@/fakemui/fakemui/inputs').then(m => ({ default: m.ButtonGroup }))),
IconButton: lazyComponent(() => import('@/fakemui/fakemui/inputs').then(m => ({ default: m.IconButton }))),
Fab: lazyComponent(() => import('@/fakemui/fakemui/inputs').then(m => ({ default: m.Fab }))),
Input: lazyComponent(() => import('@/fakemui/fakemui/inputs').then(m => ({ default: m.Input }))),
Textarea: lazyComponent(() => import('@/fakemui/fakemui/inputs').then(m => ({ default: m.Textarea }))),
Select: lazyComponent(() => import('@/fakemui/fakemui/inputs').then(m => ({ default: m.Select }))),
NativeSelect: lazyComponent(() => import('@/fakemui/fakemui/inputs').then(m => ({ default: m.NativeSelect }))),
Checkbox: lazyComponent(() => import('@/fakemui/fakemui/inputs').then(m => ({ default: m.Checkbox }))),
Radio: lazyComponent(() => import('@/fakemui/fakemui/inputs').then(m => ({ default: m.Radio }))),
RadioGroup: lazyComponent(() => import('@/fakemui/fakemui/inputs').then(m => ({ default: m.RadioGroup }))),
Switch: lazyComponent(() => import('@/fakemui/fakemui/inputs').then(m => ({ default: m.Switch }))),
Slider: lazyComponent(() => import('@/fakemui/fakemui/inputs').then(m => ({ default: m.Slider }))),
FormControl: lazyComponent(() => import('@/fakemui/fakemui/inputs').then(m => ({ default: m.FormControl }))),
FormGroup: lazyComponent(() => import('@/fakemui/fakemui/inputs').then(m => ({ default: m.FormGroup }))),
FormLabel: lazyComponent(() => import('@/fakemui/fakemui/inputs').then(m => ({ default: m.FormLabel }))),
FormHelperText: lazyComponent(() => import('@/fakemui/fakemui/inputs').then(m => ({ default: m.FormHelperText }))),
TextField: lazyComponent(() => import('@/fakemui/fakemui/inputs').then(m => ({ default: m.TextField }))),
ToggleButton: lazyComponent(() => import('@/fakemui/fakemui/inputs').then(m => ({ default: m.ToggleButton }))),
ToggleButtonGroup: lazyComponent(() => import('@/fakemui/fakemui/inputs').then(m => ({ default: m.ToggleButtonGroup }))),
Autocomplete: lazyComponent(() => import('@/fakemui/fakemui/inputs').then(m => ({ default: m.Autocomplete }))),
Rating: lazyComponent(() => import('@/fakemui/fakemui/inputs').then(m => ({ default: m.Rating }))),
DatePicker: lazyComponent(() => import('@/fakemui/fakemui/inputs').then(m => ({ default: m.DatePicker }))),
TimePicker: lazyComponent(() => import('@/fakemui/fakemui/inputs').then(m => ({ default: m.TimePicker }))),
ColorPicker: lazyComponent(() => import('@/fakemui/fakemui/inputs').then(m => ({ default: m.ColorPicker }))),
FileUpload: lazyComponent(() => import('@/fakemui/fakemui/inputs').then(m => ({ default: m.FileUpload }))),
FormField: lazyComponent(() => import('@/fakemui/fakemui/inputs').then(m => ({ default: m.FormField }))),
import React from 'react'
// Surfaces / Containers (10)
Paper: lazyComponent(() => import('@/fakemui/fakemui/surfaces').then(m => ({ default: m.Paper }))),
Card: lazyComponent(() => import('@/fakemui/fakemui/surfaces').then(m => ({ default: m.Card }))),
CardHeader: lazyComponent(() => import('@/fakemui/fakemui/surfaces').then(m => ({ default: m.CardHeader }))),
CardContent: lazyComponent(() => import('@/fakemui/fakemui/surfaces').then(m => ({ default: m.CardContent }))),
CardActions: lazyComponent(() => import('@/fakemui/fakemui/surfaces').then(m => ({ default: m.CardActions }))),
CardActionArea: lazyComponent(() => import('@/fakemui/fakemui/surfaces').then(m => ({ default: m.CardActionArea }))),
CardMedia: lazyComponent(() => import('@/fakemui/fakemui/surfaces').then(m => ({ default: m.CardMedia }))),
Accordion: lazyComponent(() => import('@/fakemui/fakemui/surfaces').then(m => ({ default: m.Accordion }))),
AccordionSummary: lazyComponent(() => import('@/fakemui/fakemui/surfaces').then(m => ({ default: m.AccordionSummary }))),
AccordionDetails: lazyComponent(() => import('@/fakemui/fakemui/surfaces').then(m => ({ default: m.AccordionDetails }))),
AccordionActions: lazyComponent(() => import('@/fakemui/fakemui/surfaces').then(m => ({ default: m.AccordionActions }))),
AppBar: lazyComponent(() => import('@/fakemui/fakemui/surfaces').then(m => ({ default: m.AppBar }))),
Toolbar: lazyComponent(() => import('@/fakemui/fakemui/surfaces').then(m => ({ default: m.Toolbar }))),
Drawer: lazyComponent(() => import('@/fakemui/fakemui/surfaces').then(m => ({ default: m.Drawer }))),
// Inputs / Form Controls
import {
Button,
ButtonGroup,
IconButton,
Fab,
Input,
Textarea,
Select,
NativeSelect,
Checkbox,
Radio,
RadioGroup,
Switch,
Slider,
FormControl,
FormGroup,
FormLabel,
FormHelperText,
TextField,
ToggleButton,
ToggleButtonGroup,
Autocomplete,
Rating,
DatePicker,
TimePicker,
ColorPicker,
FileUpload,
FormField,
} from '@/fakemui/fakemui/inputs'
// Layout (18)
Box: lazyComponent(() => import('@/fakemui/fakemui/layout').then(m => ({ default: m.Box }))),
Container: lazyComponent(() => import('@/fakemui/fakemui/layout').then(m => ({ default: m.Container }))),
Grid: lazyComponent(() => import('@/fakemui/fakemui/layout').then(m => ({ default: m.Grid }))),
Stack: lazyComponent(() => import('@/fakemui/fakemui/layout').then(m => ({ default: m.Stack }))),
Flex: lazyComponent(() => import('@/fakemui/fakemui/layout').then(m => ({ default: m.Flex }))),
ImageList: lazyComponent(() => import('@/fakemui/fakemui/layout').then(m => ({ default: m.ImageList }))),
ImageListItem: lazyComponent(() => import('@/fakemui/fakemui/layout').then(m => ({ default: m.ImageListItem }))),
ImageListItemBar: lazyComponent(() => import('@/fakemui/fakemui/layout').then(m => ({ default: m.ImageListItemBar }))),
// Surfaces / Containers
import {
Paper,
Card,
CardHeader,
CardContent,
CardActions,
CardActionArea,
CardMedia,
Accordion,
AccordionSummary,
AccordionDetails,
AccordionActions,
AppBar,
Toolbar,
Drawer,
} from '@/fakemui/fakemui/surfaces'
// Data Display (26)
Typography: lazyComponent(() => import('@/fakemui/fakemui/data-display').then(m => ({ default: m.Typography }))),
Avatar: lazyComponent(() => import('@/fakemui/fakemui/data-display').then(m => ({ default: m.Avatar }))),
AvatarGroup: lazyComponent(() => import('@/fakemui/fakemui/data-display').then(m => ({ default: m.AvatarGroup }))),
Badge: lazyComponent(() => import('@/fakemui/fakemui/data-display').then(m => ({ default: m.Badge }))),
Chip: lazyComponent(() => import('@/fakemui/fakemui/data-display').then(m => ({ default: m.Chip }))),
Divider: lazyComponent(() => import('@/fakemui/fakemui/data-display').then(m => ({ default: m.Divider }))),
List: lazyComponent(() => import('@/fakemui/fakemui/data-display').then(m => ({ default: m.List }))),
ListItem: lazyComponent(() => import('@/fakemui/fakemui/data-display').then(m => ({ default: m.ListItem }))),
ListItemButton: lazyComponent(() => import('@/fakemui/fakemui/data-display').then(m => ({ default: m.ListItemButton }))),
ListItemText: lazyComponent(() => import('@/fakemui/fakemui/data-display').then(m => ({ default: m.ListItemText }))),
ListItemIcon: lazyComponent(() => import('@/fakemui/fakemui/data-display').then(m => ({ default: m.ListItemIcon }))),
ListItemAvatar: lazyComponent(() => import('@/fakemui/fakemui/data-display').then(m => ({ default: m.ListItemAvatar }))),
ListSubheader: lazyComponent(() => import('@/fakemui/fakemui/data-display').then(m => ({ default: m.ListSubheader }))),
Table: lazyComponent(() => import('@/fakemui/fakemui/data-display').then(m => ({ default: m.Table }))),
TableBody: lazyComponent(() => import('@/fakemui/fakemui/data-display').then(m => ({ default: m.TableBody }))),
TableCell: lazyComponent(() => import('@/fakemui/fakemui/data-display').then(m => ({ default: m.TableCell }))),
TableContainer: lazyComponent(() => import('@/fakemui/fakemui/data-display').then(m => ({ default: m.TableContainer }))),
TableHead: lazyComponent(() => import('@/fakemui/fakemui/data-display').then(m => ({ default: m.TableHead }))),
TableRow: lazyComponent(() => import('@/fakemui/fakemui/data-display').then(m => ({ default: m.TableRow }))),
TableFooter: lazyComponent(() => import('@/fakemui/fakemui/data-display').then(m => ({ default: m.TableFooter }))),
TablePagination: lazyComponent(() => import('@/fakemui/fakemui/data-display').then(m => ({ default: m.TablePagination }))),
TableSortLabel: lazyComponent(() => import('@/fakemui/fakemui/data-display').then(m => ({ default: m.TableSortLabel }))),
Tooltip: lazyComponent(() => import('@/fakemui/fakemui/data-display').then(m => ({ default: m.Tooltip }))),
// Layout
import {
Box,
Container,
Grid,
Stack,
Flex,
ImageList,
ImageListItem,
ImageListItemBar,
} from '@/fakemui/fakemui/layout'
// Feedback (6)
Alert: lazyComponent(() => import('@/fakemui/fakemui/feedback').then(m => ({ default: m.Alert }))),
Backdrop: lazyComponent(() => import('@/fakemui/fakemui/feedback').then(m => ({ default: m.Backdrop }))),
Skeleton: lazyComponent(() => import('@/fakemui/fakemui/feedback').then(m => ({ default: m.Skeleton }))),
Snackbar: lazyComponent(() => import('@/fakemui/fakemui/feedback').then(m => ({ default: m.Snackbar }))),
CircularProgress: lazyComponent(() => import('@/fakemui/fakemui/feedback').then(m => ({ default: m.CircularProgress }))),
LinearProgress: lazyComponent(() => import('@/fakemui/fakemui/feedback').then(m => ({ default: m.LinearProgress }))),
// Data Display
import {
Typography,
Avatar,
AvatarGroup,
Badge,
Chip,
Divider,
List,
ListItem,
ListItemButton,
ListItemText,
ListItemIcon,
ListItemAvatar,
ListSubheader,
Table,
TableBody,
TableCell,
TableContainer,
TableHead,
TableRow,
TableFooter,
TablePagination,
TableSortLabel,
Tooltip,
} from '@/fakemui/fakemui/data-display'
// Navigation (22)
Breadcrumbs: lazyComponent(() => import('@/fakemui/fakemui/navigation').then(m => ({ default: m.Breadcrumbs }))),
Link: lazyComponent(() => import('@/fakemui/fakemui/navigation').then(m => ({ default: m.Link }))),
Menu: lazyComponent(() => import('@/fakemui/fakemui/navigation').then(m => ({ default: m.Menu }))),
MenuItem: lazyComponent(() => import('@/fakemui/fakemui/navigation').then(m => ({ default: m.MenuItem }))),
MenuList: lazyComponent(() => import('@/fakemui/fakemui/navigation').then(m => ({ default: m.MenuList }))),
Pagination: lazyComponent(() => import('@/fakemui/fakemui/navigation').then(m => ({ default: m.Pagination }))),
PaginationItem: lazyComponent(() => import('@/fakemui/fakemui/navigation').then(m => ({ default: m.PaginationItem }))),
Stepper: lazyComponent(() => import('@/fakemui/fakemui/navigation').then(m => ({ default: m.Stepper }))),
Step: lazyComponent(() => import('@/fakemui/fakemui/navigation').then(m => ({ default: m.Step }))),
StepLabel: lazyComponent(() => import('@/fakemui/fakemui/navigation').then(m => ({ default: m.StepLabel }))),
StepButton: lazyComponent(() => import('@/fakemui/fakemui/navigation').then(m => ({ default: m.StepButton }))),
StepContent: lazyComponent(() => import('@/fakemui/fakemui/navigation').then(m => ({ default: m.StepContent }))),
StepConnector: lazyComponent(() => import('@/fakemui/fakemui/navigation').then(m => ({ default: m.StepConnector }))),
StepIcon: lazyComponent(() => import('@/fakemui/fakemui/navigation').then(m => ({ default: m.StepIcon }))),
Tabs: lazyComponent(() => import('@/fakemui/fakemui/navigation').then(m => ({ default: m.Tabs }))),
Tab: lazyComponent(() => import('@/fakemui/fakemui/navigation').then(m => ({ default: m.Tab }))),
BottomNavigation: lazyComponent(() => import('@/fakemui/fakemui/navigation').then(m => ({ default: m.BottomNavigation }))),
BottomNavigationAction: lazyComponent(() => import('@/fakemui/fakemui/navigation').then(m => ({ default: m.BottomNavigationAction }))),
SpeedDial: lazyComponent(() => import('@/fakemui/fakemui/navigation').then(m => ({ default: m.SpeedDial }))),
SpeedDialAction: lazyComponent(() => import('@/fakemui/fakemui/navigation').then(m => ({ default: m.SpeedDialAction }))),
SpeedDialIcon: lazyComponent(() => import('@/fakemui/fakemui/navigation').then(m => ({ default: m.SpeedDialIcon }))),
// Feedback
import {
Alert,
Backdrop,
Skeleton,
Snackbar,
} from '@/fakemui/fakemui/feedback'
// Navigation
import {
Breadcrumbs,
Link,
Menu,
MenuItem,
MenuList,
Pagination,
PaginationItem,
Stepper,
Step,
StepLabel,
StepButton,
StepContent,
StepConnector,
StepIcon,
Tabs,
Tab,
BottomNavigation,
BottomNavigationAction,
SpeedDial,
SpeedDialAction,
SpeedDialIcon,
} from '@/fakemui/fakemui/navigation'
// Utils
import {
Modal,
Popover,
Popper,
Portal,
ClickAwayListener,
CssBaseline,
GlobalStyles,
NoSsr,
} from '@/fakemui/fakemui/utils'
// Atoms
import {
Text,
Title,
Label,
Panel,
Section,
StatBadge,
States,
EditorWrapper,
AutoGrid,
} from '@/fakemui/fakemui/atoms'
// Lab (Experimental)
import {
LoadingButton,
Masonry,
Timeline,
TreeView,
TreeItem,
} from '@/fakemui/fakemui/lab'
// X (Advanced)
import {
DataGrid,
} from '@/fakemui/fakemui/x'
// Icons
import {
Icon,
Plus,
Trash,
Copy,
Check,
X as XIcon,
Filter,
FilterOff,
ArrowUp,
ArrowDown,
ArrowClockwise,
ChevronUp,
ChevronDown,
ChevronLeft,
ChevronRight,
FloppyDisk,
Search,
Settings,
User,
UserCheck,
Eye,
EyeSlash,
Pencil,
Calendar,
Clock,
Mail,
Bell,
Star,
Heart,
Share,
} from '@/fakemui'
/**
* Complete registry of all fakemui components
* Maps component names to React component types
*/
export const FAKEMUI_REGISTRY: Record<string, React.ComponentType<any>> = {
// Form Controls / Inputs (28 components)
Button,
ButtonGroup,
IconButton,
Fab,
Input,
Textarea,
Select,
NativeSelect,
Checkbox,
Radio,
RadioGroup,
Switch,
Slider,
FormControl,
FormGroup,
FormLabel,
FormHelperText,
TextField,
ToggleButton,
ToggleButtonGroup,
Autocomplete,
Rating,
DatePicker,
TimePicker,
ColorPicker,
FileUpload,
FormField,
LoadingButton,
// Surfaces / Containers (15 components)
Paper,
Card,
CardHeader,
CardContent,
CardActions,
CardActionArea,
CardMedia,
Accordion,
AccordionSummary,
AccordionDetails,
AccordionActions,
AppBar,
Toolbar,
Drawer,
Panel,
// Layout (11 components)
Box,
Container,
Grid,
Stack,
Flex,
ImageList,
ImageListItem,
ImageListItemBar,
Masonry,
Section,
AutoGrid,
// Data Display (26 components)
Typography,
Avatar,
AvatarGroup,
Badge,
Chip,
Divider,
List,
ListItem,
ListItemButton,
ListItemText,
ListItemIcon,
ListItemAvatar,
ListSubheader,
Table,
TableBody,
TableCell,
TableContainer,
TableHead,
TableRow,
TableFooter,
TablePagination,
TableSortLabel,
Tooltip,
Text,
Title,
Label,
StatBadge,
// Feedback (6 components)
Alert,
Backdrop,
Skeleton,
Snackbar,
EditorWrapper,
// Navigation (22 components)
Breadcrumbs,
Link,
Menu,
MenuItem,
MenuList,
Pagination,
PaginationItem,
Stepper,
Step,
StepLabel,
StepButton,
StepContent,
StepConnector,
StepIcon,
Tabs,
Tab,
BottomNavigation,
BottomNavigationAction,
SpeedDial,
SpeedDialAction,
SpeedDialIcon,
Timeline,
// Modals / Utils (9 components)
Modal,
Popover,
Popper,
Portal,
ClickAwayListener,
CssBaseline,
GlobalStyles,
NoSsr,
TreeView,
// Advanced (1 component)
DataGrid,
// Icons (27 components)
Icon,
Plus,
Trash,
Copy,
Check,
XIcon,
Filter,
FilterOff,
ArrowUp,
ArrowDown,
ArrowClockwise,
ChevronUp,
ChevronDown,
ChevronLeft,
ChevronRight,
FloppyDisk,
Search,
Settings,
User,
UserCheck,
Eye,
EyeSlash,
Pencil,
Calendar,
Clock,
Mail,
Bell,
Star,
Heart,
Share,
// Utils / Modals (10)
Modal: lazyComponent(() => import('@/fakemui/fakemui/utils').then(m => ({ default: m.Modal }))),
Popover: lazyComponent(() => import('@/fakemui/fakemui/utils').then(m => ({ default: m.Popover }))),
Popper: lazyComponent(() => import('@/fakemui/fakemui/utils').then(m => ({ default: m.Popper }))),
Portal: lazyComponent(() => import('@/fakemui/fakemui/utils').then(m => ({ default: m.Portal }))),
ClickAwayListener: lazyComponent(() => import('@/fakemui/fakemui/utils').then(m => ({ default: m.ClickAwayListener }))),
CssBaseline: lazyComponent(() => import('@/fakemui/fakemui/utils').then(m => ({ default: m.CssBaseline }))),
GlobalStyles: lazyComponent(() => import('@/fakemui/fakemui/utils').then(m => ({ default: m.GlobalStyles }))),
NoSsr: lazyComponent(() => import('@/fakemui/fakemui/utils').then(m => ({ default: m.NoSsr }))),
TextareaAutosize: lazyComponent(() => import('@/fakemui/fakemui/utils').then(m => ({ default: m.TextareaAutosize }))),
}
/**
* Category-based component groups for easier lookup
* Check if a component is available in the registry
*/
export const FAKEMUI_CATEGORIES = {
form: [
'Button', 'ButtonGroup', 'IconButton', 'Fab', 'Input', 'Textarea',
'Select', 'NativeSelect', 'Checkbox', 'Radio', 'RadioGroup', 'Switch',
'Slider', 'FormControl', 'FormGroup', 'FormLabel', 'FormHelperText',
'TextField', 'ToggleButton', 'ToggleButtonGroup', 'Autocomplete',
'Rating', 'DatePicker', 'TimePicker', 'ColorPicker', 'FileUpload',
'FormField', 'LoadingButton',
],
display: [
'Typography', 'Avatar', 'AvatarGroup', 'Badge', 'Chip', 'Divider',
'List', 'ListItem', 'ListItemButton', 'ListItemText', 'ListItemIcon',
'ListItemAvatar', 'ListSubheader', 'Tooltip', 'Text', 'Title',
'Label', 'StatBadge', 'Icon',
],
layout: [
'Box', 'Container', 'Grid', 'Stack', 'Flex', 'ImageList',
'ImageListItem', 'ImageListItemBar', 'Masonry', 'Section',
'AutoGrid', 'Paper', 'Card', 'CardHeader', 'CardContent',
'CardActions', 'CardActionArea', 'CardMedia', 'Panel',
],
navigation: [
'Breadcrumbs', 'Link', 'Menu', 'MenuItem', 'MenuList',
'Pagination', 'PaginationItem', 'Stepper', 'Step', 'StepLabel',
'StepButton', 'StepContent', 'StepConnector', 'StepIcon',
'Tabs', 'Tab', 'BottomNavigation', 'BottomNavigationAction',
'SpeedDial', 'SpeedDialAction', 'SpeedDialIcon', 'Timeline',
],
modal: [
'Modal', 'Popover', 'Popper', 'Portal', 'Drawer', 'Accordion',
'AccordionSummary', 'AccordionDetails', 'AccordionActions',
'AppBar', 'Toolbar',
],
table: [
'Table', 'TableBody', 'TableCell', 'TableContainer',
'TableHead', 'TableRow', 'TableFooter', 'TablePagination',
'TableSortLabel', 'DataGrid',
],
custom: [
'Alert', 'Backdrop', 'Skeleton', 'Snackbar',
'EditorWrapper', 'ClickAwayListener', 'CssBaseline',
'GlobalStyles', 'NoSsr', 'TreeView',
],
icons: [
'Icon', 'Plus', 'Trash', 'Copy', 'Check', 'XIcon', 'Filter',
'FilterOff', 'ArrowUp', 'ArrowDown', 'ArrowClockwise',
'ChevronUp', 'ChevronDown', 'ChevronLeft', 'ChevronRight',
'FloppyDisk', 'Search', 'Settings', 'User', 'UserCheck',
'Eye', 'EyeSlash', 'Pencil', 'Calendar', 'Clock', 'Mail',
'Bell', 'Star', 'Heart', 'Share',
],
export function isFakemUIComponentAvailable(name: string): boolean {
return name in FAKEMUI_REGISTRY
}
/**
* Helper to get a component by name
* Get a component from the registry
*/
export function getFakemUIComponent(componentName: string): React.ComponentType<any> | null {
return FAKEMUI_REGISTRY[componentName] ?? null
}
/**
* Helper to get all components in a category
*/
export function getFakemUICategoryComponents(category: keyof typeof FAKEMUI_CATEGORIES): React.ComponentType<any>[] {
const componentNames = FAKEMUI_CATEGORIES[category] ?? []
return componentNames
.map(name => FAKEMUI_REGISTRY[name])
.filter((comp): comp is React.ComponentType<any> => comp !== undefined)
}
/**
* Helper to list all available categories
*/
export function getFakemUICategories(): string[] {
return Object.keys(FAKEMUI_CATEGORIES)
}
/**
* Helper to verify if a component exists
*/
export function isFakemUIComponentAvailable(componentName: string): boolean {
return componentName in FAKEMUI_REGISTRY
}
/**
* Statistics about available components
*/
export const FAKEMUI_STATS = {
totalComponents: Object.keys(FAKEMUI_REGISTRY).length,
categories: Object.keys(FAKEMUI_CATEGORIES).length,
byCategory: Object.entries(FAKEMUI_CATEGORIES).reduce(
(acc, [cat, comps]) => ({ ...acc, [cat]: comps.length }),
{} as Record<string, number>
),
export function getFakemUIComponent(name: string): ComponentType<any> | undefined {
return FAKEMUI_REGISTRY[name]
}