veza/apps/web/src/components/ui/FAB.tsx
senke 0a29c544af fix(web): resolve all 568 TypeScript errors — tsc --noEmit now passes with zero errors
Major categories fixed:
- TS6133 (188): Remove unused imports (React, icons, types) and variables
- TS2322 (222): Fix type mismatches in stories (satisfies Meta -> const meta: Meta),
  add nullish coalescing for optional values, fix component prop types
- TS2345 (43): Fix argument type mismatches with proper null checks and type narrowing
- TS2741 (21): Add missing required properties to mock/story data
- TS2339 (19): Fix property access on incorrect types, add type guards
- TS2353 (13): Remove extra properties from object literals or extend interfaces
- TS2352 (11): Fix type conversion chains
- TS2307 (9): Fix import paths and module references
- Other (42): Fix implicit any, possibly undefined, export declarations

Vite build and tsc --noEmit both pass cleanly.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-13 00:32:08 +01:00

113 lines
2.5 KiB
TypeScript

import { cn } from '@/lib/utils';
import { Button, ButtonProps } from './button';
export interface FABProps extends Omit<ButtonProps, 'size' | 'variant'> {
/**
* Position of the FAB on the screen
* @default 'bottom-right'
*/
position?: 'bottom-right' | 'bottom-left' | 'top-right' | 'top-left';
/**
* Size of the FAB
* @default 'lg'
*/
size?: 'sm' | 'md' | 'lg';
/**
* Whether to show a label next to the FAB
* @default false
*/
showLabel?: boolean;
/**
* Label text (only shown if showLabel is true)
*/
label?: string;
/**
* Additional CSS classes for the container
*/
containerClassName?: string;
}
const positionClasses = {
'bottom-right': 'bottom-6 right-6',
'bottom-left': 'bottom-6 left-6',
'top-right': 'top-6 right-6',
'top-left': 'top-6 left-6',
};
const sizeClasses = {
sm: 'h-12 w-12 text-base',
md: 'h-14 w-14 text-lg',
lg: 'h-16 w-16 text-xl',
};
/**
* FAB (Floating Action Button) - Floating action button component
*
* A prominent floating button that appears fixed on the screen, typically
* used for primary actions like upload, create, or add.
*
* @example
* ```tsx
* <FAB onClick={() => handleUpload()}>
* <Plus className="w-6 h-6" />
* </FAB>
* ```
*
* @example
* ```tsx
* <FAB
* position="bottom-right"
* size="lg"
* showLabel
* label="Upload Track"
* onClick={() => navigate('/upload')}
* >
* <Upload className="w-6 h-6" />
* </FAB>
* ```
*/
export function FAB({
position = 'bottom-right',
size = 'lg',
showLabel = false,
label,
className,
containerClassName,
children,
...buttonProps
}: FABProps) {
return (
<div
className={cn(
'fixed z-50 flex items-center gap-4',
positionClasses[position],
containerClassName,
)}
>
{showLabel && label && (
<span className="text-sm font-semibold text-foreground bg-card/90 backdrop-blur-md px-4 py-2 rounded-lg border border-white/10 shadow-lg whitespace-nowrap">
{label}
</span>
)}
<Button
variant="default"
aria-label={label || 'Action'}
className={cn(
'rounded-full aspect-square p-0',
'shadow-fab-glow shadow-fab-glow-hover',
'transition-all duration-[var(--sumi-duration-normal)]',
'active:opacity-80',
sizeClasses[size],
className,
)}
{...buttonProps}
>
{children}
</Button>
</div>
);
}