code: tsx,nextjs,frontends (8 files)

This commit is contained in:
Richard Ward
2025-12-30 12:52:40 +00:00
parent a818ed1021
commit 136b2cf592
8 changed files with 101 additions and 13 deletions

View File

@@ -0,0 +1,80 @@
import React, { forwardRef, Children, cloneElement, isValidElement } from 'react'
/**
* Props for ButtonGroup component
*/
export interface ButtonGroupProps extends React.HTMLAttributes<HTMLDivElement> {
children: React.ReactNode
/** Button size to apply to all children */
size?: 'sm' | 'md' | 'lg'
/** Button variant to apply to all children */
variant?: 'contained' | 'outlined' | 'text'
/** Color theme for buttons */
color?: 'primary' | 'secondary' | 'error' | 'success' | 'warning'
/** Stack buttons vertically */
vertical?: boolean
/** Disable all buttons */
disabled?: boolean
/** Full width button group */
fullWidth?: boolean
}
/**
* ButtonGroup - Groups related buttons together with consistent styling
*
* @example
* ```tsx
* <ButtonGroup variant="contained" color="primary">
* <Button>One</Button>
* <Button>Two</Button>
* <Button>Three</Button>
* </ButtonGroup>
* ```
*/
export const ButtonGroup = forwardRef<HTMLDivElement, ButtonGroupProps>(
(
{
children,
size = 'md',
variant = 'outlined',
color = 'primary',
vertical = false,
disabled = false,
fullWidth = false,
className = '',
...props
},
ref
) => {
const childArray = Children.toArray(children)
const enhancedChildren = childArray.map((child, index) => {
if (isValidElement(child)) {
const isFirst = index === 0
const isLast = index === childArray.length - 1
return cloneElement(child as React.ReactElement<Record<string, unknown>>, {
size,
variant,
color,
disabled: disabled || (child.props as Record<string, unknown>).disabled,
className: `btn-group__btn ${isFirst ? 'btn-group__btn--first' : ''} ${isLast ? 'btn-group__btn--last' : ''} ${!isFirst && !isLast ? 'btn-group__btn--middle' : ''}`,
})
}
return child
})
return (
<div
ref={ref}
className={`btn-group ${vertical ? 'btn-group--vertical' : ''} ${fullWidth ? 'btn-group--full-width' : ''} ${className}`}
role="group"
{...props}
>
{enhancedChildren}
</div>
)
}
)
ButtonGroup.displayName = 'ButtonGroup'

View File

@@ -1,13 +1,17 @@
export { Button } from './Button'
export { ButtonGroup } from './ButtonGroup'
export { IconButton } from './IconButton'
export { Fab } from './Fab'
export { Input } from './Input'
export { Textarea } from './Textarea'
export { Select } from './Select'
export { NativeSelect } from './NativeSelect'
export { Checkbox } from './Checkbox'
export { Radio } from './Radio'
export { RadioGroup, useRadioGroup } from './RadioGroup'
export { Switch } from './Switch'
export { Slider } from './Slider'
export { FormControl, useFormControl } from './FormControl'
export { FormGroup } from './FormGroup'
export { FormLabel } from './FormLabel'
export { FormHelperText } from './FormHelperText'

View File

@@ -1,7 +1,8 @@
import SearchIcon from '@mui/icons-material/Search'
import { Box, Card, InputAdornment, Stack, TextField, Typography } from '@mui/material'
import { useState } from 'react'
import { Search } from '@/fakemui/icons'
import { getComponentIcon } from '@/components/get-component-icon'
import type { ComponentDefinition } from '@/lib/builder-types'
import { componentCatalog } from '@/lib/component-catalog'
@@ -47,7 +48,7 @@ export function ComponentCatalog({ onDragStart }: ComponentCatalogProps) {
InputProps={{
startAdornment: (
<InputAdornment position="start">
<SearchIcon sx={{ color: 'text.secondary', fontSize: 18 }} />
<Search style={{ color: 'rgba(0,0,0,0.54)', fontSize: 18 }} />
</InputAdornment>
),
}}

View File

@@ -1,6 +1,5 @@
'use client'
import ExpandMoreIcon from '@mui/icons-material/ExpandMore'
import {
Accordion as MuiAccordion,
AccordionDetails,
@@ -9,6 +8,8 @@ import {
} from '@mui/material'
import { forwardRef, ReactNode, useState } from 'react'
import { ExpandMore } from '@/fakemui/icons'
interface AccordionProps {
children: ReactNode
type?: 'single' | 'multiple'

View File

@@ -1,10 +1,10 @@
'use client'
import MoreHorizIcon from '@mui/icons-material/MoreHoriz'
import NavigateNextIcon from '@mui/icons-material/NavigateNext'
import { Box, Breadcrumbs as MuiBreadcrumbs, Link, Typography } from '@mui/material'
import { forwardRef, ReactNode } from 'react'
import { MoreHoriz, NavigateNext } from '@/fakemui/icons'
interface BreadcrumbProps {
children: ReactNode
className?: string
@@ -14,7 +14,7 @@ const Breadcrumb = forwardRef<HTMLElement, BreadcrumbProps>(({ children, ...prop
return (
<MuiBreadcrumbs
ref={ref}
separator={<NavigateNextIcon fontSize="small" />}
separator={<NavigateNext size={16} />}
aria-label="breadcrumb"
{...props}
>

View File

@@ -1,7 +1,5 @@
'use client'
import ExpandLessIcon from '@mui/icons-material/ExpandLess'
import ExpandMoreIcon from '@mui/icons-material/ExpandMore'
import {
Box,
Collapse,
@@ -14,6 +12,8 @@ import {
} from '@mui/material'
import { forwardRef, ReactNode, useState } from 'react'
import { ExpandLess, ExpandMore } from '@/fakemui/icons'
export interface NavGroupProps {
label: string
icon?: ReactNode
@@ -72,9 +72,9 @@ const NavGroup = forwardRef<HTMLDivElement, NavGroupProps>(
}}
/>
{open ? (
<ExpandLessIcon fontSize="small" sx={{ color: 'text.secondary' }} />
<ExpandLess size={16} style={{ color: 'rgba(0,0,0,0.54)' }} />
) : (
<ExpandMoreIcon fontSize="small" sx={{ color: 'text.secondary' }} />
<ExpandMore size={16} style={{ color: 'rgba(0,0,0,0.54)' }} />
)}
</ListItemButton>
</ListItem>

View File

@@ -1,6 +1,5 @@
'use client'
import CloseIcon from '@mui/icons-material/Close'
import {
Box,
Dialog as MuiDialog,
@@ -11,6 +10,8 @@ import {
} from '@mui/material'
import { forwardRef, ReactNode } from 'react'
import { Close } from '@/fakemui/icons'
import { DialogContent, type DialogContentProps } from './dialog/Body'
import { DialogFooter, type DialogFooterProps } from './dialog/Footer'
import { DialogHeader, type DialogHeaderProps } from './dialog/Header'

View File

@@ -1,9 +1,10 @@
'use client'
import CloseIcon from '@mui/icons-material/Close'
import { DialogContent as MuiDialogContent, IconButton } from '@mui/material'
import { forwardRef, ReactNode } from 'react'
import { Close } from '@/fakemui/icons'
export interface DialogBodyProps {
children: ReactNode
className?: string
@@ -25,7 +26,7 @@ const DialogBody = forwardRef<HTMLDivElement, DialogBodyProps>(
onClick={onClose}
sx={{ position: 'absolute', right: 8, top: 8, color: 'text.secondary' }}
>
<CloseIcon />
<Close />
</IconButton>
)}
{children}