bytelyst-devops-tools/dashboard/web/src/components/ui/Primitives.tsx
Hermes VM cdc23696b2 fix: resolve all TypeScript errors — green tsc
Primitives.tsx (TS2339):
- asChild branch read children.props.className before the cast applied,
  making props typed as unknown. Extract typedChild first, then read props.

hermes/page.tsx + agents/page.tsx + tasks/page.tsx + tasks/[id]/page.tsx (TS2322):
- Badge.variant accepts 'neutral'|'success'|'warning'|'error'|'info' but
  callers were passing 'danger' (should be 'error') and 'default' (should
  be 'neutral'). MetricCard.tone is a separate type and is correct as-is.

Changes:
- statusTone map in hermes/page.tsx: 'danger' → 'error', 'default' → 'neutral'
- getTaskTone fallback: 'default' → 'neutral'; explicit return type added
- levelTone in tasks/[id]/page.tsx: 'danger' → 'error'; explicit return type added
- Inline Badge variants: all remaining 'danger' → 'error' across 3 files

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-27 18:53:20 +00:00

108 lines
3.8 KiB
TypeScript

import * as React from 'react';
import { cn } from '@/lib/utils';
// Basic button component using design tokens
export interface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {
variant?: 'primary' | 'secondary' | 'ghost' | 'link';
size?: 'sm' | 'md' | 'lg';
asChild?: boolean;
}
export const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(
({ variant = 'primary', size = 'md', asChild = false, className, children, ...props }, ref) => {
const baseStyles = 'inline-flex items-center justify-center rounded-md font-medium transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50';
const variantStyles = {
primary: 'bg-[var(--bl-accent)] text-[var(--bl-accent-foreground)] hover:opacity-90 focus-visible:ring-[var(--bl-focus-ring)]',
secondary: 'bg-[var(--bl-surface-muted)] text-[var(--bl-text-primary)] hover:bg-[var(--bl-surface-highlight)] focus-visible:ring-[var(--bl-focus-ring)]',
ghost: 'text-[var(--bl-text-primary)] hover:bg-[var(--bl-surface-muted)] focus-visible:ring-[var(--bl-focus-ring)]',
link: 'text-[var(--bl-accent)] hover:underline focus-visible:ring-[var(--bl-focus-ring)]',
};
const sizeStyles = {
sm: 'h-9 px-3 text-sm',
md: 'h-10 px-4 text-sm',
lg: 'h-11 px-8 text-base',
};
const classes = cn(baseStyles, variantStyles[variant], sizeStyles[size], className);
if (asChild && React.isValidElement(children)) {
const typedChild = children as React.ReactElement<{ className?: string }>;
return React.cloneElement(typedChild, {
className: cn(typedChild.props.className, classes),
});
}
return (
<button
ref={ref}
className={classes}
{...props}
>
{children}
</button>
);
},
);
Button.displayName = 'Button';
// Basic badge component using design tokens
export interface BadgeProps extends React.HTMLAttributes<HTMLDivElement> {
variant?: 'neutral' | 'success' | 'warning' | 'error' | 'info';
dot?: boolean;
}
export function Badge({ variant = 'neutral', dot = false, className, children, ...props }: BadgeProps) {
const variantStyles = {
neutral: 'bg-[var(--bl-surface-muted)] text-[var(--bl-fg-muted)]',
success: 'bg-[var(--bl-success-bg)] text-[var(--bl-success-fg)]',
warning: 'bg-[var(--bl-warning-bg)] text-[var(--bl-warning-fg)]',
error: 'bg-[var(--bl-danger-bg)] text-[var(--bl-danger-fg)]',
info: 'bg-[var(--bl-info-bg)] text-[var(--bl-info-fg)]',
};
return (
<div
className={cn(
'inline-flex items-center gap-1.5 rounded-full px-2.5 py-0.5 text-xs font-medium',
variantStyles[variant],
className,
)}
{...props}
>
{dot && <span className="h-1.5 w-1.5 rounded-full current-color" />}
{children}
</div>
);
}
// Input component using design tokens
export interface InputProps extends React.InputHTMLAttributes<HTMLInputElement> {
variant?: 'surface' | 'muted';
}
export const Input = React.forwardRef<HTMLInputElement, InputProps>(
({ variant = 'surface', className, ...props }, ref) => {
const variantStyles = {
surface: 'bg-[var(--bl-input)] border-[var(--bl-border)]',
muted: 'bg-[var(--bl-surface-muted)] border-[var(--bl-border)]',
};
return (
<input
ref={ref}
className={cn(
'flex h-10 w-full rounded-md border px-3.5 py-2.5 text-sm placeholder:text-[var(--bl-fg-muted)] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--bl-primary)] focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50',
variantStyles[variant],
className,
)}
{...props}
/>
);
},
);
Input.displayName = 'Input';