mirror of
https://github.com/johndoe6345789/metabuilder.git
synced 2026-04-24 13:54:57 +00:00
docs: tsx,nextjs,frontends (9 files)
This commit is contained in:
421
docs/fakemui-icons-integration.md
Normal file
421
docs/fakemui-icons-integration.md
Normal file
@@ -0,0 +1,421 @@
|
||||
# FakeMUI Icons Integration Guide
|
||||
|
||||
This document describes how to use fakemui icons in Lua packages declaratively.
|
||||
|
||||
## Overview
|
||||
|
||||
The fakemui icon system allows Lua packages to reference icons by name without directly importing React components. Icons are resolved at render time through the component registry and icon registry.
|
||||
|
||||
## Architecture
|
||||
|
||||
### Components
|
||||
|
||||
1. **Icon Registry** (`frontends/nextjs/src/lib/rendering/icon-registry.ts`)
|
||||
- Maps icon names to fakemui icon components
|
||||
- Provides alias resolution for common icon names
|
||||
- Supports case-insensitive lookups
|
||||
|
||||
2. **Component Registry** (`frontends/nextjs/src/lib/rendering/component-registry.ts`)
|
||||
- Registers the `Icon` component for use in Lua
|
||||
- Maps component type names to React components
|
||||
|
||||
3. **Package Icon Modules** (e.g., `packages/dashboard/seed/scripts/icons.lua`)
|
||||
- Provide package-specific icon name constants
|
||||
- Document available icons for each package
|
||||
|
||||
## Usage in Lua Packages
|
||||
|
||||
### Basic Icon Usage
|
||||
|
||||
Icons can be used in Lua by specifying the icon name in the component tree:
|
||||
|
||||
```lua
|
||||
-- Using Icon component directly
|
||||
local icon_component = {
|
||||
type = "Icon",
|
||||
props = {
|
||||
name = "CheckCircle", -- Icon name from fakemui
|
||||
size = "medium", -- small, medium, large, inherit
|
||||
className = "text-green-500"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Icon Sizes
|
||||
|
||||
Available sizes:
|
||||
- `small` - 20px
|
||||
- `medium` - 24px (default)
|
||||
- `large` - 32px
|
||||
- `inherit` - Inherits from parent
|
||||
|
||||
### Icon Name Resolution
|
||||
|
||||
The icon registry supports multiple name formats:
|
||||
|
||||
1. **PascalCase** (exact match): `CheckCircle`, `ChevronRight`
|
||||
2. **kebab-case** (alias): `check-circle`, `chevron-right`
|
||||
3. **lowercase** (alias): `checkcircle`, `chevronright`
|
||||
|
||||
Example:
|
||||
```lua
|
||||
-- All of these resolve to the same icon
|
||||
{ type = "Icon", props = { name = "CheckCircle" } }
|
||||
{ type = "Icon", props = { name = "check-circle" } }
|
||||
{ type = "Icon", props = { name = "checkcircle" } }
|
||||
```
|
||||
|
||||
## Package-Specific Icon Modules
|
||||
|
||||
Each package has an `icons.lua` module that provides constants for commonly used icons:
|
||||
|
||||
### Dashboard Package
|
||||
|
||||
```lua
|
||||
local icons = require("icons")
|
||||
|
||||
-- Using icon constants
|
||||
local stat_card = {
|
||||
icon = icons.get("CHART_LINE"), -- Returns "ChartLine"
|
||||
label = "Total Revenue",
|
||||
value = 12500
|
||||
}
|
||||
```
|
||||
|
||||
Available icons in `dashboard/icons.lua`:
|
||||
- `CHART_LINE`, `TREND_UP`, `BAR_CHART`, `PIE_CHART`
|
||||
- `CHECK_CIRCLE`, `SHIELD_CHECK`, `WARNING`, `ERROR`
|
||||
- `CLOCK`, `CALENDAR`, `SCHEDULE`
|
||||
- And more...
|
||||
|
||||
### Navigation Menu Package
|
||||
|
||||
```lua
|
||||
local icons = require("icons")
|
||||
|
||||
local sidebar_item = {
|
||||
label = "Dashboard",
|
||||
path = "/dashboard",
|
||||
icon = icons.get("DASHBOARD") -- Returns "Dashboard"
|
||||
}
|
||||
```
|
||||
|
||||
Available icons in `nav_menu/icons.lua`:
|
||||
- `HOME`, `DASHBOARD`, `SETTINGS`, `PROFILE`
|
||||
- `SEARCH`, `NOTIFICATIONS`, `MAIL`
|
||||
- `ADMIN_PANEL`, `SECURITY`, `VERIFIED_USER`
|
||||
- And more...
|
||||
|
||||
### Data Table Package
|
||||
|
||||
```lua
|
||||
local icons = require("icons")
|
||||
|
||||
local actions = {
|
||||
{ id = "edit", icon = icons.get("EDIT"), label = "Edit" },
|
||||
{ id = "delete", icon = icons.get("DELETE"), label = "Delete" },
|
||||
{ id = "export", icon = icons.get("CSV"), label = "Export CSV" }
|
||||
}
|
||||
```
|
||||
|
||||
Available icons in `data_table/icons.lua`:
|
||||
- `SORT`, `SORT_ASCENDING`, `SORT_DESCENDING`
|
||||
- `FILTER`, `FILTER_CLEAR`, `FILTER_OFF`
|
||||
- `EDIT`, `DELETE`, `ADD`, `REMOVE`
|
||||
- `CSV`, `JSON`, `EXPORT`
|
||||
- And more...
|
||||
|
||||
### Workflow Editor Package
|
||||
|
||||
```lua
|
||||
local icons = require("icons")
|
||||
|
||||
local workflow_node = {
|
||||
type = "action",
|
||||
label = "Process Data",
|
||||
icon = icons.get("WORKFLOW") -- Returns "Workflow"
|
||||
}
|
||||
```
|
||||
|
||||
Available icons in `workflow_editor/icons.lua`:
|
||||
- `WORKFLOW`, `GIT_BRANCH`, `CALL_SPLIT`
|
||||
- `PLAY`, `STOP`, `PAUSE`
|
||||
- `CHECK_CIRCLE`, `ERROR`, `WARNING`
|
||||
- And more...
|
||||
|
||||
### Form Builder Package
|
||||
|
||||
```lua
|
||||
local icons = require("icons")
|
||||
|
||||
local validation_rule = {
|
||||
type = "required",
|
||||
message = "This field is required",
|
||||
icon = icons.get("ERROR") -- Returns "CircleX"
|
||||
}
|
||||
```
|
||||
|
||||
Available icons in `form_builder/icons.lua`:
|
||||
- `CHECK_CIRCLE`, `ERROR`, `WARNING`, `INFO`
|
||||
- `TEXT_FIELDS`, `EMAIL`, `LOCK`, `CALENDAR`
|
||||
- `VISIBILITY`, `VISIBILITY_OFF`
|
||||
- `FORMAT_BOLD`, `FORMAT_ITALIC`, `INSERT_LINK`
|
||||
- And more...
|
||||
|
||||
## Complete Examples
|
||||
|
||||
### Dashboard Stat Card with Icon
|
||||
|
||||
```lua
|
||||
local icons = require("icons")
|
||||
local stat_card = require("stats.card")
|
||||
|
||||
local revenue_card = stat_card.create({
|
||||
label = "Total Revenue",
|
||||
value = 12500,
|
||||
icon = icons.get("CHART_LINE"),
|
||||
change = "+12.5%",
|
||||
positive = true,
|
||||
className = "col-span-1"
|
||||
})
|
||||
```
|
||||
|
||||
### Sidebar Navigation with Icons
|
||||
|
||||
```lua
|
||||
local icons = require("icons")
|
||||
|
||||
local sidebar_items = {
|
||||
{
|
||||
label = "Dashboard",
|
||||
path = "/dashboard",
|
||||
icon = icons.get("DASHBOARD")
|
||||
},
|
||||
{
|
||||
label = "Users",
|
||||
path = "/users",
|
||||
icon = icons.get("USERS")
|
||||
},
|
||||
{
|
||||
label = "Settings",
|
||||
path = "/settings",
|
||||
icon = icons.get("SETTINGS")
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Data Table with Action Icons
|
||||
|
||||
```lua
|
||||
local icons = require("icons")
|
||||
local action_column = require("columns.action")
|
||||
|
||||
local actions = action_column("actions", {
|
||||
{ id = "edit", icon = icons.get("EDIT"), label = "Edit", handler = "edit_user" },
|
||||
{ id = "delete", icon = icons.get("TRASH"), label = "Delete", handler = "delete_user", confirm = true },
|
||||
{ id = "view", icon = icons.get("EYE"), label = "View", handler = "view_user" }
|
||||
})
|
||||
```
|
||||
|
||||
### Workflow Node with Icon
|
||||
|
||||
```lua
|
||||
local icons = require("icons")
|
||||
local action_node = require("nodes.action")
|
||||
|
||||
local process_node = action_node(
|
||||
"process_data",
|
||||
"Process Data",
|
||||
"transform",
|
||||
icons.get("WORKFLOW")
|
||||
)
|
||||
```
|
||||
|
||||
### Form Field with Validation Icons
|
||||
|
||||
```lua
|
||||
local icons = require("icons")
|
||||
|
||||
local email_field = {
|
||||
type = "TextField",
|
||||
props = {
|
||||
label = "Email",
|
||||
type = "email",
|
||||
required = true,
|
||||
helperText = "Enter your email address",
|
||||
-- Icons can be added to show validation state
|
||||
startIcon = icons.get("EMAIL"),
|
||||
endIcon = nil -- Will be set based on validation
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Available Icons
|
||||
|
||||
The fakemui icon library includes 390+ icons. Common categories:
|
||||
|
||||
### Actions
|
||||
`Plus`, `Add`, `Remove`, `Trash`, `Delete`, `Copy`, `Check`, `Done`, `X`, `Edit`, `Save`
|
||||
|
||||
### Navigation
|
||||
`ArrowUp`, `ArrowDown`, `ArrowLeft`, `ArrowRight`, `ChevronUp`, `ChevronDown`, `Home`, `Menu`
|
||||
|
||||
### UI Controls
|
||||
`Settings`, `Search`, `Filter`, `More`, `Expand`, `Collapse`, `ZoomIn`, `ZoomOut`
|
||||
|
||||
### Data & Status
|
||||
`CheckCircle`, `Error`, `Warning`, `Info`, `Star`, `Heart`, `Flag`
|
||||
|
||||
### Users & Security
|
||||
`User`, `Users`, `UserCircle`, `Lock`, `Key`, `Shield`, `Verified`
|
||||
|
||||
### Data Table
|
||||
`Sort`, `SortAscending`, `FilterList`, `Csv`, `Json`, `Pagination`
|
||||
|
||||
### Workflow
|
||||
`Workflow`, `GitBranch`, `CallSplit`, `Play`, `Stop`, `Pause`
|
||||
|
||||
### Forms
|
||||
`TextFields`, `Email`, `Calendar`, `Checkbox`, `Radio`, `Visibility`
|
||||
|
||||
For a complete list, see:
|
||||
- `frontends/nextjs/src/lib/rendering/icon-registry.ts` - Icon registry with aliases
|
||||
- `fakemui/icons/index.ts` - All available icons
|
||||
|
||||
## Best Practices
|
||||
|
||||
1. **Use Icon Constants**: Always use the package-specific icon modules rather than hardcoding icon names:
|
||||
```lua
|
||||
-- Good
|
||||
local icons = require("icons")
|
||||
icon = icons.get("DASHBOARD")
|
||||
|
||||
-- Avoid
|
||||
icon = "Dashboard" -- Works but not type-safe
|
||||
```
|
||||
|
||||
2. **Check Icon Availability**: Ensure the icon exists in fakemui before using it. All icons in the package icon modules are guaranteed to exist.
|
||||
|
||||
3. **Use Semantic Names**: Choose icons that match the action or concept:
|
||||
- Delete actions: `Trash` or `Delete`
|
||||
- Edit actions: `Edit` or `Pencil`
|
||||
- Success states: `CheckCircle`
|
||||
- Errors: `CircleX` or `XCircle`
|
||||
|
||||
4. **Consistent Sizing**: Use consistent icon sizes within the same context:
|
||||
- Buttons: `medium` (24px)
|
||||
- Large cards/headers: `large` (32px)
|
||||
- Inline text: `small` (20px)
|
||||
|
||||
5. **Accessibility**: Icons should be paired with text labels for accessibility:
|
||||
```lua
|
||||
{
|
||||
type = "Button",
|
||||
children = {
|
||||
{ type = "Icon", props = { name = "Delete", className = "mr-2" } },
|
||||
{ type = "Typography", props = { text = "Delete" } }
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Type Definitions
|
||||
|
||||
### Lua Type Annotations
|
||||
|
||||
```lua
|
||||
---@class IconProps
|
||||
---@field name string Icon name from fakemui
|
||||
---@field size? "small"|"medium"|"large"|"inherit"
|
||||
---@field className? string Additional CSS classes
|
||||
|
||||
---@class UIComponent
|
||||
---@field type "Icon"
|
||||
---@field props IconProps
|
||||
```
|
||||
|
||||
## Migration from MUI Icons
|
||||
|
||||
If migrating from @mui/icons-material, use the icon registry aliases:
|
||||
|
||||
| MUI Icon | FakeMUI Equivalent |
|
||||
|----------|-------------------|
|
||||
| `AccountCircle` | `AccountCircle` |
|
||||
| `Dashboard` | `Dashboard` |
|
||||
| `Delete` | `Delete` or `Trash` |
|
||||
| `Edit` | `Edit` or `Pencil` |
|
||||
| `Settings` | `Settings` or `Gear` |
|
||||
| `MoreVert` | `MoreVert` or `MoreVertical` |
|
||||
| `ExpandMore` | `ExpandMore` or `ChevronDown` |
|
||||
| `Error` | `CircleX` or `XCircle` |
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Icon Not Rendering
|
||||
|
||||
1. Check icon name spelling
|
||||
2. Verify icon exists in fakemui (see `fakemui/icons/index.ts`)
|
||||
3. Check browser console for warnings
|
||||
|
||||
### Icon Name Not Found
|
||||
|
||||
```
|
||||
Warning: Icon "IconName" not found in @/fakemui/icons
|
||||
```
|
||||
|
||||
Solution: Use correct icon name or add to icon registry aliases
|
||||
|
||||
### Icon Size Not Applied
|
||||
|
||||
Ensure size prop is one of: `small`, `medium`, `large`, `inherit`
|
||||
|
||||
```lua
|
||||
-- Correct
|
||||
{ type = "Icon", props = { name = "Check", size = "medium" } }
|
||||
|
||||
-- Incorrect
|
||||
{ type = "Icon", props = { name = "Check", size = 24 } } -- Use "medium" instead
|
||||
```
|
||||
|
||||
## Reference
|
||||
|
||||
### Icon Registry Functions
|
||||
|
||||
```typescript
|
||||
// Get icon component by name
|
||||
getIconComponent(iconName: string): ComponentType | undefined
|
||||
|
||||
// Resolve icon name (handles aliases)
|
||||
resolveIconName(luaIconName: string): IconName | undefined
|
||||
|
||||
// Check if icon name is valid
|
||||
isValidIconName(iconName: string): boolean
|
||||
|
||||
// Get all available icon names
|
||||
getAllIconNames(): IconName[]
|
||||
```
|
||||
|
||||
### Component Registry
|
||||
|
||||
The Icon component is registered in the component registry:
|
||||
|
||||
```typescript
|
||||
import { Icon } from '@/components/atoms/display/Icon'
|
||||
|
||||
componentRegistry = {
|
||||
// ... other components
|
||||
Icon,
|
||||
}
|
||||
```
|
||||
|
||||
## Summary
|
||||
|
||||
The fakemui icon integration provides:
|
||||
|
||||
1. ✅ Declarative icon usage in Lua packages
|
||||
2. ✅ Type-safe icon name constants per package
|
||||
3. ✅ Flexible name resolution (PascalCase, kebab-case, lowercase)
|
||||
4. ✅ 390+ icons covering common use cases
|
||||
5. ✅ Consistent icon sizing and styling
|
||||
6. ✅ No direct React imports needed in Lua
|
||||
|
||||
All icons are rendered as SVG components from the fakemui library, ensuring consistent styling and performance across the application.
|
||||
@@ -1,41 +1,44 @@
|
||||
'use client'
|
||||
|
||||
import {
|
||||
Box,
|
||||
CircularProgress,
|
||||
CircularProgressProps,
|
||||
LinearProgress,
|
||||
LinearProgressProps,
|
||||
Typography,
|
||||
} from '@mui/material'
|
||||
import { LinearProgress, CircularProgress } from '@/fakemui'
|
||||
import { forwardRef } from 'react'
|
||||
|
||||
/**
|
||||
* Props for the Progress component
|
||||
* @extends {LinearProgressProps} Inherits Material-UI LinearProgress props
|
||||
* Wrapper around fakemui LinearProgress to maintain API compatibility
|
||||
*/
|
||||
export interface ProgressProps extends LinearProgressProps {
|
||||
export interface ProgressProps extends React.HTMLAttributes<HTMLDivElement> {
|
||||
/** Progress value (0-100) */
|
||||
value?: number
|
||||
/** Whether to display a percentage label next to the progress bar */
|
||||
showLabel?: boolean
|
||||
/** Variant of the progress bar */
|
||||
variant?: 'determinate' | 'indeterminate'
|
||||
/** Color of the progress bar */
|
||||
color?: string
|
||||
/** MUI sx prop - converted to className for compatibility */
|
||||
sx?: any
|
||||
}
|
||||
|
||||
const Progress = forwardRef<HTMLDivElement, ProgressProps>(
|
||||
({ value, showLabel, sx, ...props }, ref) => {
|
||||
({ value, showLabel, variant, color, sx, className, ...props }, ref) => {
|
||||
// Combine className with any sx-based classes
|
||||
const combinedClassName = [className, sx?.className].filter(Boolean).join(' ')
|
||||
|
||||
if (showLabel && value !== undefined) {
|
||||
return (
|
||||
<Box ref={ref} sx={{ display: 'flex', alignItems: 'center', gap: 2 }}>
|
||||
<Box sx={{ flex: 1 }}>
|
||||
<div ref={ref} className={`progress-with-label ${combinedClassName}`} style={{ display: 'flex', alignItems: 'center', gap: '1rem' }}>
|
||||
<div style={{ flex: 1 }}>
|
||||
<LinearProgress
|
||||
variant="determinate"
|
||||
value={value}
|
||||
sx={{ height: 8, borderRadius: 1, ...sx }}
|
||||
className={combinedClassName}
|
||||
{...props}
|
||||
/>
|
||||
</Box>
|
||||
<Typography variant="body2" color="text.secondary" sx={{ minWidth: 40 }}>
|
||||
</div>
|
||||
<span className="progress-label text-secondary" style={{ minWidth: '40px' }}>
|
||||
{Math.round(value)}%
|
||||
</Typography>
|
||||
</Box>
|
||||
</span>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -43,8 +46,7 @@ const Progress = forwardRef<HTMLDivElement, ProgressProps>(
|
||||
<LinearProgress
|
||||
ref={ref}
|
||||
value={value}
|
||||
variant={value !== undefined ? 'determinate' : 'indeterminate'}
|
||||
sx={{ height: 8, borderRadius: 1, ...sx }}
|
||||
className={combinedClassName}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
|
||||
@@ -1,24 +1,32 @@
|
||||
'use client'
|
||||
|
||||
import { Divider, DividerProps } from '@mui/material'
|
||||
import { Divider } from '@/fakemui'
|
||||
import { forwardRef } from 'react'
|
||||
|
||||
/**
|
||||
* Props for the Separator component
|
||||
* @extends {DividerProps} Inherits Material-UI Divider props
|
||||
* Wrapper around fakemui Divider to maintain API compatibility
|
||||
*/
|
||||
export interface SeparatorProps extends DividerProps {
|
||||
export interface SeparatorProps extends React.HTMLAttributes<HTMLHRElement> {
|
||||
/** Orientation of the separator */
|
||||
orientation?: 'horizontal' | 'vertical'
|
||||
/** Whether the separator is decorative (for accessibility) */
|
||||
decorative?: boolean
|
||||
/** MUI sx prop - converted to className for compatibility */
|
||||
sx?: any
|
||||
}
|
||||
|
||||
const Separator = forwardRef<HTMLHRElement, SeparatorProps>(
|
||||
({ orientation = 'horizontal', decorative, ...props }, ref) => {
|
||||
({ orientation = 'horizontal', decorative, sx, className, ...props }, ref) => {
|
||||
// Combine className with any sx-based classes
|
||||
const combinedClassName = [className, sx?.className].filter(Boolean).join(' ')
|
||||
|
||||
return (
|
||||
<Divider
|
||||
ref={ref}
|
||||
orientation={orientation}
|
||||
role={decorative ? 'presentation' : 'separator'}
|
||||
className={combinedClassName}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
|
||||
@@ -1,22 +1,48 @@
|
||||
'use client'
|
||||
|
||||
import { Skeleton as MuiSkeleton } from '@mui/material'
|
||||
import { type ComponentProps, forwardRef } from 'react'
|
||||
|
||||
type MuiSkeletonProps = ComponentProps<typeof MuiSkeleton>
|
||||
import { Skeleton as FakemuiSkeleton } from '@/fakemui'
|
||||
import { forwardRef } from 'react'
|
||||
import type { SkeletonProps as FakemuiSkeletonProps } from '@/fakemui/fakemui/feedback/Skeleton'
|
||||
|
||||
/**
|
||||
* Props for the Skeleton component
|
||||
* @extends {MuiSkeletonProps} Inherits Material-UI Skeleton props
|
||||
* Wrapper around fakemui Skeleton to maintain API compatibility
|
||||
*/
|
||||
export interface SkeletonProps extends MuiSkeletonProps {
|
||||
/** CSS class name for custom styling */
|
||||
className?: string
|
||||
export interface SkeletonProps extends React.HTMLAttributes<HTMLSpanElement> {
|
||||
/** Shape variant */
|
||||
variant?: 'text' | 'rectangular' | 'circular' | 'rounded'
|
||||
/** Animation type */
|
||||
animation?: 'pulse' | 'wave' | false
|
||||
/** Width of the skeleton */
|
||||
width?: string | number
|
||||
/** Height of the skeleton */
|
||||
height?: string | number
|
||||
/** MUI sx prop - converted to className for compatibility */
|
||||
sx?: any
|
||||
}
|
||||
|
||||
const Skeleton = forwardRef<HTMLSpanElement, SkeletonProps>(
|
||||
({ variant = 'rounded', animation = 'wave', ...props }, ref) => {
|
||||
return <MuiSkeleton ref={ref} variant={variant} animation={animation} {...props} />
|
||||
({ variant = 'rounded', animation = 'wave', width, height, sx, className, ...props }, ref) => {
|
||||
// Map MUI variant to fakemui variant
|
||||
const fakemuiVariant = variant === 'rounded' ? 'rectangular' : variant
|
||||
|
||||
// Map MUI animation to fakemui animation
|
||||
const fakemuiAnimation = animation === 'wave' ? 'pulse' : animation
|
||||
|
||||
// Combine className with any sx-based classes
|
||||
const combinedClassName = [className, sx?.className].filter(Boolean).join(' ')
|
||||
|
||||
return (
|
||||
<FakemuiSkeleton
|
||||
ref={ref}
|
||||
variant={fakemuiVariant}
|
||||
animation={fakemuiAnimation}
|
||||
width={width}
|
||||
height={height}
|
||||
className={combinedClassName}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
'use client'
|
||||
|
||||
import { Box, CircularProgress, CircularProgressProps } from '@mui/material'
|
||||
import { CircularProgress } from '@/fakemui'
|
||||
import { forwardRef } from 'react'
|
||||
|
||||
/** Spinner size options */
|
||||
@@ -8,13 +8,17 @@ export type SpinnerSize = 'xs' | 'sm' | 'md' | 'lg'
|
||||
|
||||
/**
|
||||
* Props for the Spinner component
|
||||
* @extends {CircularProgressProps} Inherits Material-UI CircularProgress props
|
||||
* Wrapper around fakemui CircularProgress to maintain API compatibility
|
||||
*/
|
||||
export interface SpinnerProps extends Omit<CircularProgressProps, 'size'> {
|
||||
export interface SpinnerProps extends React.HTMLAttributes<HTMLDivElement> {
|
||||
/** Size of the spinner (xs: 16px, sm: 20px, md: 24px, lg: 40px) or a custom number */
|
||||
size?: SpinnerSize | number
|
||||
/** Whether to center the spinner in its container */
|
||||
centered?: boolean
|
||||
/** Color of the spinner */
|
||||
color?: string
|
||||
/** MUI sx prop - converted to className for compatibility */
|
||||
sx?: any
|
||||
}
|
||||
|
||||
const sizeMap: Record<SpinnerSize, number> = {
|
||||
@@ -25,16 +29,26 @@ const sizeMap: Record<SpinnerSize, number> = {
|
||||
}
|
||||
|
||||
const Spinner = forwardRef<HTMLDivElement, SpinnerProps>(
|
||||
({ size = 'md', centered, ...props }, ref) => {
|
||||
({ size = 'md', centered, color, sx, className, ...props }, ref) => {
|
||||
const dimension = typeof size === 'number' ? size : sizeMap[size]
|
||||
|
||||
const spinner = <CircularProgress ref={ref} size={dimension} {...props} />
|
||||
// Combine className with any sx-based classes
|
||||
const combinedClassName = [className, sx?.className].filter(Boolean).join(' ')
|
||||
|
||||
const spinner = (
|
||||
<CircularProgress
|
||||
ref={ref}
|
||||
size={dimension}
|
||||
className={combinedClassName}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
|
||||
if (centered) {
|
||||
return (
|
||||
<Box sx={{ display: 'flex', justifyContent: 'center', alignItems: 'center', p: 2 }}>
|
||||
<div style={{ display: 'flex', justifyContent: 'center', alignItems: 'center', padding: '1rem' }}>
|
||||
{spinner}
|
||||
</Box>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -1,12 +1,11 @@
|
||||
'use client'
|
||||
|
||||
import { Tooltip as MuiTooltip } from '@mui/material'
|
||||
import { type ComponentProps, forwardRef, ReactElement, ReactNode } from 'react'
|
||||
|
||||
type MuiTooltipProps = ComponentProps<typeof MuiTooltip>
|
||||
import { Tooltip as FakemuiTooltip } from '@/fakemui'
|
||||
import { forwardRef, ReactElement, ReactNode } from 'react'
|
||||
|
||||
/**
|
||||
* Props for the Tooltip component
|
||||
* Wrapper around fakemui Tooltip to maintain API compatibility
|
||||
*/
|
||||
export interface TooltipProps {
|
||||
/** The element that triggers the tooltip */
|
||||
@@ -27,13 +26,10 @@ export interface TooltipProps {
|
||||
onOpen?: () => void
|
||||
/** Callback when tooltip is closed */
|
||||
onClose?: () => void
|
||||
}
|
||||
|
||||
const sideMap: Record<string, MuiTooltipProps['placement']> = {
|
||||
top: 'top',
|
||||
right: 'right',
|
||||
bottom: 'bottom',
|
||||
left: 'left',
|
||||
/** MUI placement prop (mapped to side) */
|
||||
placement?: 'top' | 'right' | 'bottom' | 'left'
|
||||
/** MUI enterDelay prop (mapped to delayDuration) */
|
||||
enterDelay?: number
|
||||
}
|
||||
|
||||
const Tooltip = forwardRef<HTMLDivElement, TooltipProps>(
|
||||
@@ -42,8 +38,10 @@ const Tooltip = forwardRef<HTMLDivElement, TooltipProps>(
|
||||
children,
|
||||
content,
|
||||
title,
|
||||
side = 'top',
|
||||
delayDuration = 300,
|
||||
side,
|
||||
placement,
|
||||
delayDuration,
|
||||
enterDelay,
|
||||
arrow = true,
|
||||
open,
|
||||
onOpen,
|
||||
@@ -53,17 +51,15 @@ const Tooltip = forwardRef<HTMLDivElement, TooltipProps>(
|
||||
ref
|
||||
) => {
|
||||
return (
|
||||
<MuiTooltip
|
||||
<FakemuiTooltip
|
||||
title={content || title || ''}
|
||||
placement={sideMap[side]}
|
||||
enterDelay={delayDuration}
|
||||
placement={side || placement || 'top'}
|
||||
arrow={arrow}
|
||||
open={open}
|
||||
onOpen={onOpen}
|
||||
onClose={onClose}
|
||||
{...props}
|
||||
>
|
||||
{children}
|
||||
</MuiTooltip>
|
||||
</FakemuiTooltip>
|
||||
)
|
||||
}
|
||||
)
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
---@field pattern? string
|
||||
---@field value? number | string
|
||||
---@field message string
|
||||
---@field icon? string Icon name from fakemui icons for validation feedback
|
||||
|
||||
---@param message? string
|
||||
---@return ValidationRule
|
||||
|
||||
1
packages/stats_grid/seed/components.json
Normal file
1
packages/stats_grid/seed/components.json
Normal file
@@ -0,0 +1 @@
|
||||
[]
|
||||
32
packages/stats_grid/seed/metadata.json
Normal file
32
packages/stats_grid/seed/metadata.json
Normal file
@@ -0,0 +1,32 @@
|
||||
{
|
||||
"packageId": "stats_grid",
|
||||
"name": "Stats Grid",
|
||||
"version": "1.0.0",
|
||||
"description": "Configurable statistics grid display for dashboards and monitoring",
|
||||
"icon": "static_content/icon.svg",
|
||||
"author": "MetaBuilder",
|
||||
"category": "ui",
|
||||
"dependencies": [],
|
||||
"devDependencies": ["lua_test"],
|
||||
"exports": {
|
||||
"components": [
|
||||
"StatsGrid",
|
||||
"StatCard"
|
||||
],
|
||||
"scripts": [
|
||||
"stats",
|
||||
"formatters"
|
||||
]
|
||||
},
|
||||
"tests": {
|
||||
"scripts": [
|
||||
"tests/stats.test.lua",
|
||||
"tests/formatters.test.lua"
|
||||
],
|
||||
"cases": [
|
||||
"tests/stats.cases.json",
|
||||
"tests/formatters.cases.json"
|
||||
]
|
||||
},
|
||||
"minLevel": 2
|
||||
}
|
||||
Reference in New Issue
Block a user