Files
low-code-react-app-b/src/components/atoms/Rating.tsx
johndoe6345789 f05f896a67 feat: Complete JSON component migration for 9 components (atoms + BindingEditor)
Migration complete for:
- 5 atoms: Accordion, CopyButton, FileUpload, FilterInput, Image, Input, PasswordInput, Popover (8 total)
- 1 molecule: BindingEditor

Changes:
- Deleted 9 legacy TSX files that have complete JSON equivalents
- Exported BindingEditor from json-components.ts with useBindingEditor hook
- Registered useBindingEditor in hooks-registry.ts
- Updated all imports across codebase to use JSON-based components
- Fixed build errors: schema-loader dynamic import, DataSourceGroupSection
- Cleaned up component index exports

Build status:  PASSING
- 0 TypeScript errors
- All 9,408 modules transformed successfully
- No blocking build warnings

Next steps:
- 3 organisms still need conversion: DataSourceManager, NavigationMenu, TreeListPanel
- 120+ additional components have TSX versions (need individual migration)
- 22 JSON components now available for use throughout the app

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
2026-01-21 00:12:50 +00:00

72 lines
1.8 KiB
TypeScript

import { Star } from '@phosphor-icons/react'
import { cn } from '@/lib/utils'
interface RatingProps {
value: number
onChange?: (value: number) => void
max?: number
size?: 'sm' | 'md' | 'lg'
readonly?: boolean
showValue?: boolean
className?: string
}
export function Rating({
value,
onChange,
max = 5,
size = 'md',
readonly = false,
showValue = false,
className
}: RatingProps) {
const sizeStyles = {
sm: 16,
md: 20,
lg: 24,
}
const iconSize = sizeStyles[size]
return (
<div className={cn('flex items-center gap-2', className)}>
<div className="flex items-center gap-0.5">
{Array.from({ length: max }, (_, index) => {
const starValue = index + 1
const isFilled = starValue <= value
const isHalfFilled = starValue - 0.5 === value
return (
<button
key={index}
type="button"
onClick={() => !readonly && onChange?.(starValue)}
disabled={readonly}
className={cn(
'transition-colors',
!readonly && 'cursor-pointer hover:scale-110',
readonly && 'cursor-default'
)}
aria-label={`Rate ${starValue} out of ${max}`}
>
<Star
size={iconSize}
weight={isFilled ? 'fill' : 'regular'}
className={cn(
'transition-colors',
isFilled ? 'text-accent fill-accent' : 'text-muted'
)}
/>
</button>
)
})}
</div>
{showValue && (
<span className="text-sm font-medium text-muted-foreground">
{value.toFixed(1)} / {max}
</span>
)}
</div>
)
}