mirror of
https://github.com/johndoe6345789/metabuilder.git
synced 2026-04-24 13:54:57 +00:00
config: fakemui,tsx,index (12 files)
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
export { Title, Subtitle } from './Title'
|
||||
export { Heading } from './Heading'
|
||||
export { Label } from './Label'
|
||||
export { Text } from './Text'
|
||||
export { StatBadge } from './StatBadge'
|
||||
|
||||
53
fakemui/fakemui/data-display/Markdown.tsx
Normal file
53
fakemui/fakemui/data-display/Markdown.tsx
Normal file
@@ -0,0 +1,53 @@
|
||||
import React from 'react'
|
||||
|
||||
export interface MarkdownProps extends React.HTMLAttributes<HTMLDivElement> {
|
||||
content?: string
|
||||
children?: string
|
||||
className?: string
|
||||
}
|
||||
|
||||
/**
|
||||
* Markdown renderer component
|
||||
* Renders markdown content as HTML
|
||||
* Uses the 'marked' library when available
|
||||
*/
|
||||
export const Markdown: React.FC<MarkdownProps> = ({
|
||||
content,
|
||||
children,
|
||||
className = '',
|
||||
...props
|
||||
}) => {
|
||||
const markdownContent = content || children || ''
|
||||
|
||||
// Simple markdown to HTML conversion for basic cases
|
||||
// In production, use 'marked' library
|
||||
const renderMarkdown = (md: string): string => {
|
||||
return md
|
||||
// Headers
|
||||
.replace(/^### (.*$)/gim, '<h3>$1</h3>')
|
||||
.replace(/^## (.*$)/gim, '<h2>$1</h2>')
|
||||
.replace(/^# (.*$)/gim, '<h1>$1</h1>')
|
||||
// Bold
|
||||
.replace(/\*\*(.*?)\*\*/gim, '<strong>$1</strong>')
|
||||
// Italic
|
||||
.replace(/\*(.*?)\*/gim, '<em>$1</em>')
|
||||
// Code blocks
|
||||
.replace(/```([\s\S]*?)```/gim, '<pre><code>$1</code></pre>')
|
||||
// Inline code
|
||||
.replace(/`(.*?)`/gim, '<code>$1</code>')
|
||||
// Links
|
||||
.replace(/\[(.*?)\]\((.*?)\)/gim, '<a href="$2">$1</a>')
|
||||
// Line breaks
|
||||
.replace(/\n/gim, '<br />')
|
||||
}
|
||||
|
||||
return (
|
||||
<div
|
||||
className={`markdown ${className}`}
|
||||
dangerouslySetInnerHTML={{ __html: renderMarkdown(markdownContent) }}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
export default Markdown
|
||||
26
fakemui/fakemui/data-display/Separator.tsx
Normal file
26
fakemui/fakemui/data-display/Separator.tsx
Normal file
@@ -0,0 +1,26 @@
|
||||
import React from 'react'
|
||||
|
||||
export interface SeparatorProps extends React.HTMLAttributes<HTMLHRElement> {
|
||||
orientation?: 'horizontal' | 'vertical'
|
||||
decorative?: boolean
|
||||
}
|
||||
|
||||
/**
|
||||
* Separator component (alias for Divider)
|
||||
* Used for visual separation between content sections
|
||||
*/
|
||||
export const Separator: React.FC<SeparatorProps> = ({
|
||||
orientation = 'horizontal',
|
||||
decorative = true,
|
||||
className = '',
|
||||
...props
|
||||
}) => (
|
||||
<hr
|
||||
className={`separator separator--${orientation} ${className}`}
|
||||
role={decorative ? 'presentation' : 'separator'}
|
||||
aria-orientation={orientation}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
|
||||
export default Separator
|
||||
@@ -7,3 +7,5 @@ export { List, ListItem, ListItemButton, ListItemIcon, ListItemText, ListItemAva
|
||||
export { Table, TableHead, TableBody, TableFooter, TableRow, TableCell, TableContainer, TablePagination, TableSortLabel } from './Table'
|
||||
export { Tooltip } from './Tooltip'
|
||||
export { Typography } from './Typography'
|
||||
export { Markdown } from './Markdown'
|
||||
export { Separator } from './Separator'
|
||||
|
||||
51
fakemui/fakemui/inputs/FormField.tsx
Normal file
51
fakemui/fakemui/inputs/FormField.tsx
Normal file
@@ -0,0 +1,51 @@
|
||||
import React from 'react'
|
||||
|
||||
export interface FormFieldProps extends React.HTMLAttributes<HTMLDivElement> {
|
||||
children?: React.ReactNode
|
||||
label?: string
|
||||
helperText?: string
|
||||
error?: boolean
|
||||
errorMessage?: string
|
||||
required?: boolean
|
||||
disabled?: boolean
|
||||
fullWidth?: boolean
|
||||
}
|
||||
|
||||
/**
|
||||
* FormField wraps form inputs with label, helper text, and error handling
|
||||
* Compatible with Lua package declarative rendering
|
||||
*/
|
||||
export const FormField: React.FC<FormFieldProps> = ({
|
||||
children,
|
||||
label,
|
||||
helperText,
|
||||
error,
|
||||
errorMessage,
|
||||
required,
|
||||
disabled,
|
||||
fullWidth,
|
||||
className = '',
|
||||
...props
|
||||
}) => (
|
||||
<div
|
||||
className={`form-field ${error ? 'form-field--error' : ''} ${disabled ? 'form-field--disabled' : ''} ${fullWidth ? 'form-field--full-width' : ''} ${className}`}
|
||||
{...props}
|
||||
>
|
||||
{label && (
|
||||
<label className="form-field__label">
|
||||
{label}
|
||||
{required && <span className="form-field__required">*</span>}
|
||||
</label>
|
||||
)}
|
||||
<div className="form-field__control">
|
||||
{children}
|
||||
</div>
|
||||
{(helperText || errorMessage) && (
|
||||
<div className={`form-field__helper ${error ? 'form-field__helper--error' : ''}`}>
|
||||
{error ? errorMessage : helperText}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
|
||||
export default FormField
|
||||
@@ -1,20 +1,139 @@
|
||||
import React, { forwardRef } from 'react'
|
||||
import React, { forwardRef, useId } from 'react'
|
||||
|
||||
/**
|
||||
* Valid input sizes
|
||||
*/
|
||||
export type InputSize = 'sm' | 'md' | 'lg'
|
||||
|
||||
export interface InputProps extends React.InputHTMLAttributes<HTMLInputElement> {
|
||||
/** Input size */
|
||||
size?: InputSize
|
||||
/** @deprecated Use size="sm" instead */
|
||||
sm?: boolean
|
||||
/** @deprecated Use size="md" instead */
|
||||
md?: boolean
|
||||
/** @deprecated Use size="lg" instead */
|
||||
lg?: boolean
|
||||
/** Error state styling */
|
||||
error?: boolean
|
||||
/** Error message to display */
|
||||
errorMessage?: string
|
||||
/** Label for the input */
|
||||
label?: string
|
||||
/** Helper text displayed below input */
|
||||
helperText?: string
|
||||
/** Full width input */
|
||||
fullWidth?: boolean
|
||||
/** Start adornment element */
|
||||
startAdornment?: React.ReactNode
|
||||
/** End adornment element */
|
||||
endAdornment?: React.ReactNode
|
||||
}
|
||||
|
||||
/**
|
||||
* Get size class from props
|
||||
*/
|
||||
const getSizeClass = (props: InputProps): string => {
|
||||
if (props.size) return `input--${props.size}`
|
||||
if (props.sm) return 'input--sm'
|
||||
if (props.lg) return 'input--lg'
|
||||
if (props.md) return 'input--md'
|
||||
return ''
|
||||
}
|
||||
|
||||
/**
|
||||
* Input component with label and error support
|
||||
*
|
||||
* @example
|
||||
* ```tsx
|
||||
* <Input label="Email" type="email" placeholder="Enter email" />
|
||||
* <Input error errorMessage="This field is required" />
|
||||
* ```
|
||||
*/
|
||||
export const Input = forwardRef<HTMLInputElement, InputProps>(
|
||||
({ sm, md, lg, error, className = '', ...props }, ref) => (
|
||||
<input
|
||||
ref={ref}
|
||||
className={`input ${sm ? 'input--sm' : ''} ${md ? 'input--md' : ''} ${lg ? 'input--lg' : ''} ${error ? 'input--error' : ''} ${className}`}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
(props, ref) => {
|
||||
const {
|
||||
size,
|
||||
sm,
|
||||
md,
|
||||
lg,
|
||||
error,
|
||||
errorMessage,
|
||||
label,
|
||||
helperText,
|
||||
fullWidth,
|
||||
startAdornment,
|
||||
endAdornment,
|
||||
className = '',
|
||||
id: idProp,
|
||||
'aria-describedby': ariaDescribedBy,
|
||||
...restProps
|
||||
} = props
|
||||
|
||||
const generatedId = useId()
|
||||
const id = idProp ?? generatedId
|
||||
const helperId = `${id}-helper`
|
||||
const errorId = `${id}-error`
|
||||
|
||||
const classes = [
|
||||
'input',
|
||||
getSizeClass(props),
|
||||
error ? 'input--error' : '',
|
||||
fullWidth ? 'input--full-width' : '',
|
||||
startAdornment ? 'input--has-start' : '',
|
||||
endAdornment ? 'input--has-end' : '',
|
||||
className,
|
||||
].filter(Boolean).join(' ')
|
||||
|
||||
// Build aria-describedby
|
||||
const describedByParts: string[] = []
|
||||
if (ariaDescribedBy) describedByParts.push(ariaDescribedBy)
|
||||
if (error && errorMessage) describedByParts.push(errorId)
|
||||
if (helperText && !error) describedByParts.push(helperId)
|
||||
const describedBy = describedByParts.length > 0 ? describedByParts.join(' ') : undefined
|
||||
|
||||
const inputElement = (
|
||||
<div className={`input-wrapper ${fullWidth ? 'input-wrapper--full-width' : ''}`}>
|
||||
{startAdornment && <span className="input__adornment input__adornment--start">{startAdornment}</span>}
|
||||
<input
|
||||
ref={ref}
|
||||
id={id}
|
||||
className={classes}
|
||||
aria-invalid={error}
|
||||
aria-describedby={describedBy}
|
||||
{...restProps}
|
||||
/>
|
||||
{endAdornment && <span className="input__adornment input__adornment--end">{endAdornment}</span>}
|
||||
</div>
|
||||
)
|
||||
|
||||
// If no label or helper text, return just the input
|
||||
if (!label && !helperText && !errorMessage) {
|
||||
return inputElement
|
||||
}
|
||||
|
||||
return (
|
||||
<div className={`input-field ${fullWidth ? 'input-field--full-width' : ''}`}>
|
||||
{label && (
|
||||
<label htmlFor={id} className="input__label">
|
||||
{label}
|
||||
{restProps.required && <span className="input__required" aria-hidden="true"> *</span>}
|
||||
</label>
|
||||
)}
|
||||
{inputElement}
|
||||
{error && errorMessage && (
|
||||
<span id={errorId} className="input__error-message" role="alert">
|
||||
{errorMessage}
|
||||
</span>
|
||||
)}
|
||||
{!error && helperText && (
|
||||
<span id={helperId} className="input__helper-text">
|
||||
{helperText}
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
)
|
||||
|
||||
Input.displayName = 'Input'
|
||||
|
||||
@@ -20,3 +20,4 @@ export { ToggleButton, ToggleButtonGroup } from './ToggleButton'
|
||||
export { Autocomplete } from './Autocomplete'
|
||||
export { Rating } from './Rating'
|
||||
export { ButtonBase, InputBase, FilledInput, OutlinedInput } from './InputBase'
|
||||
export { FormField } from './FormField'
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
export { Paper } from './Paper'
|
||||
export { Card, CardHeader, CardContent, CardActions, CardActionArea, CardMedia } from './Card'
|
||||
export { Card, CardHeader, CardContent, CardActions, CardActionArea, CardMedia, CardTitle, CardDescription, CardFooter } from './Card'
|
||||
export { Accordion, AccordionSummary, AccordionDetails, AccordionActions } from './Accordion'
|
||||
export { AppBar, Toolbar } from './AppBar'
|
||||
export { Drawer } from './Drawer'
|
||||
|
||||
38
fakemui/fakemui/utils/Iframe.tsx
Normal file
38
fakemui/fakemui/utils/Iframe.tsx
Normal file
@@ -0,0 +1,38 @@
|
||||
import React from 'react'
|
||||
|
||||
export interface IframeProps extends React.IframeHTMLAttributes<HTMLIFrameElement> {
|
||||
src: string
|
||||
title: string
|
||||
width?: string | number
|
||||
height?: string | number
|
||||
allowFullScreen?: boolean
|
||||
sandbox?: string
|
||||
}
|
||||
|
||||
/**
|
||||
* Iframe component for embedded content
|
||||
* Used by Lua packages for embedding external content
|
||||
*/
|
||||
export const Iframe: React.FC<IframeProps> = ({
|
||||
src,
|
||||
title,
|
||||
width = '100%',
|
||||
height = 400,
|
||||
allowFullScreen = true,
|
||||
sandbox,
|
||||
className = '',
|
||||
...props
|
||||
}) => (
|
||||
<iframe
|
||||
src={src}
|
||||
title={title}
|
||||
width={width}
|
||||
height={height}
|
||||
allowFullScreen={allowFullScreen}
|
||||
sandbox={sandbox}
|
||||
className={`iframe ${className}`}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
|
||||
export default Iframe
|
||||
@@ -12,3 +12,4 @@ export { useMediaQuery, useMediaQueryUp, useMediaQueryDown, useMediaQueryBetween
|
||||
export { GlobalStyles } from './GlobalStyles'
|
||||
export { classNames } from './classNames'
|
||||
export { ToastProvider, useToast } from './ToastContext'
|
||||
export { Iframe } from './Iframe'
|
||||
|
||||
35
packages/ui_level6/seed/scripts/tests/transfer.cases.json
Normal file
35
packages/ui_level6/seed/scripts/tests/transfer.cases.json
Normal file
@@ -0,0 +1,35 @@
|
||||
{
|
||||
"transferForm": {
|
||||
"valid": [
|
||||
{
|
||||
"fromId": "supergod_001",
|
||||
"fromName": "Current SuperGod",
|
||||
"toId": "god_002",
|
||||
"toName": "Promoted God",
|
||||
"description": "transfer from supergod to god"
|
||||
},
|
||||
{
|
||||
"fromId": "supergod_001",
|
||||
"fromName": "Admin User",
|
||||
"toId": "admin_003",
|
||||
"toName": "New Admin",
|
||||
"description": "transfer between admins"
|
||||
},
|
||||
{
|
||||
"fromId": "original_owner",
|
||||
"fromName": "Original Owner",
|
||||
"toId": "new_owner",
|
||||
"toName": "New Owner",
|
||||
"description": "full ownership transfer"
|
||||
}
|
||||
]
|
||||
},
|
||||
"transferHistory": {
|
||||
"columns": [
|
||||
{ "id": "date", "label": "Date", "type": "date" },
|
||||
{ "id": "from", "label": "From User" },
|
||||
{ "id": "to", "label": "To User" },
|
||||
{ "id": "reason", "label": "Reason" }
|
||||
]
|
||||
}
|
||||
}
|
||||
77
packages/ui_level6/seed/scripts/tests/transfer.test.lua
Normal file
77
packages/ui_level6/seed/scripts/tests/transfer.test.lua
Normal file
@@ -0,0 +1,77 @@
|
||||
-- Transfer Tests for ui_level6
|
||||
-- Parameterized tests for supergod-level transfer functions
|
||||
|
||||
local describe = require("lua_test.describe")
|
||||
local it = require("lua_test.it")
|
||||
local it_each = require("lua_test.it_each")
|
||||
local expect = require("lua_test.expect")
|
||||
|
||||
local cases = require("tests.transfer.cases")
|
||||
local transferForm = require("transfer.transfer_form")
|
||||
local transferHistory = require("transfer.transfer_history")
|
||||
|
||||
describe("transfer (level6)", function()
|
||||
|
||||
describe("transferForm", function()
|
||||
it_each(cases.transferForm.valid, "$description", function(case)
|
||||
local fromUser = { id = case.fromId, name = case.fromName }
|
||||
local toUser = { id = case.toId, name = case.toName }
|
||||
local form = transferForm(fromUser, toUser)
|
||||
|
||||
expect(form.type).toBe("power_transfer_form")
|
||||
expect(form.fromUser.id).toBe(case.fromId)
|
||||
expect(form.toUser.id).toBe(case.toId)
|
||||
expect(form.confirmationRequired).toBe(true)
|
||||
expect(form.warningMessage).toBeTruthy()
|
||||
end)
|
||||
|
||||
it("should require confirmation", function()
|
||||
local fromUser = { id = "supergod_1", name = "SuperGod" }
|
||||
local toUser = { id = "new_god", name = "NewGod" }
|
||||
local form = transferForm(fromUser, toUser)
|
||||
expect(form.confirmationRequired).toBe(true)
|
||||
end)
|
||||
|
||||
it("should include warning message", function()
|
||||
local fromUser = { id = "supergod_1", name = "SuperGod" }
|
||||
local toUser = { id = "new_god", name = "NewGod" }
|
||||
local form = transferForm(fromUser, toUser)
|
||||
expect(form.warningMessage).toContain("cannot be undone")
|
||||
end)
|
||||
end)
|
||||
|
||||
describe("transferHistory", function()
|
||||
it("should return history component configuration", function()
|
||||
local history = transferHistory()
|
||||
expect(history.type).toBe("transfer_history")
|
||||
expect(history.columns).toBeTruthy()
|
||||
end)
|
||||
|
||||
it_each(cases.transferHistory.columns, "should have $label column", function(case)
|
||||
local history = transferHistory()
|
||||
local found = false
|
||||
for _, col in ipairs(history.columns) do
|
||||
if col.id == case.id then
|
||||
expect(col.label).toBe(case.label)
|
||||
if case.type then
|
||||
expect(col.type).toBe(case.type)
|
||||
end
|
||||
found = true
|
||||
break
|
||||
end
|
||||
end
|
||||
expect(found).toBe(true)
|
||||
end)
|
||||
|
||||
it("should have all required columns", function()
|
||||
local history = transferHistory()
|
||||
expect(#history.columns).toBeGreaterThanOrEqual(4)
|
||||
end)
|
||||
end)
|
||||
|
||||
end)
|
||||
|
||||
return {
|
||||
name = "transfer.test",
|
||||
description = "Tests for supergod transfer functions"
|
||||
}
|
||||
Reference in New Issue
Block a user