77 lines
2.1 KiB
TypeScript
77 lines
2.1 KiB
TypeScript
import { LucideIcon } from 'lucide-react';
|
|
import React from 'react';
|
|
import { Box, BoxProps } from './Box';
|
|
|
|
export interface IconProps extends Omit<BoxProps<'div'>, 'children'> {
|
|
icon: LucideIcon | React.ReactNode;
|
|
size?: 3 | 3.5 | 4 | 5 | 6 | 7 | 8 | 10 | 12 | 16 | 'full' | number;
|
|
intent?: 'primary' | 'telemetry' | 'warning' | 'success' | 'critical' | 'high' | 'med' | 'low';
|
|
animate?: 'spin' | 'pulse' | 'none';
|
|
}
|
|
|
|
export function Icon({
|
|
icon: IconProp,
|
|
size = 4,
|
|
intent,
|
|
animate = 'none',
|
|
...props
|
|
}: IconProps) {
|
|
const sizeMap: Record<string | number, string> = {
|
|
3: '0.75rem',
|
|
3.5: '0.875rem',
|
|
4: '1rem',
|
|
5: '1.25rem',
|
|
6: '1.5rem',
|
|
7: '1.75rem',
|
|
8: '2rem',
|
|
10: '2.5rem',
|
|
12: '3rem',
|
|
16: '4rem',
|
|
'full': '100%'
|
|
};
|
|
|
|
const dimension = typeof size === 'string' ? sizeMap[size] : (sizeMap[size] || `${size * 0.25}rem`);
|
|
|
|
const intentColorMap: Record<string, string> = {
|
|
primary: 'var(--ui-color-intent-primary)',
|
|
telemetry: 'var(--ui-color-intent-telemetry)',
|
|
warning: 'var(--ui-color-intent-warning)',
|
|
success: 'var(--ui-color-intent-success)',
|
|
critical: 'var(--ui-color-intent-critical)',
|
|
high: 'var(--ui-color-text-high)',
|
|
med: 'var(--ui-color-text-med)',
|
|
low: 'var(--ui-color-text-low)',
|
|
};
|
|
|
|
const style: React.CSSProperties = {
|
|
width: dimension,
|
|
height: dimension,
|
|
color: intent ? intentColorMap[intent] : undefined,
|
|
};
|
|
|
|
const renderIcon = () => {
|
|
if (!IconProp) return null;
|
|
if (typeof IconProp === 'function' || (typeof IconProp === 'object' && 'render' in IconProp)) {
|
|
const LucideIconComponent = IconProp as LucideIcon;
|
|
return <LucideIconComponent size="100%" />;
|
|
}
|
|
return IconProp;
|
|
};
|
|
|
|
const animationClass = animate === 'spin' ? 'animate-spin' : (animate === 'pulse' ? 'animate-pulse' : '');
|
|
|
|
return (
|
|
<Box
|
|
display="inline-flex"
|
|
alignItems="center"
|
|
justifyContent="center"
|
|
style={style}
|
|
{...props}
|
|
>
|
|
<div className={`${animationClass} w-full h-full flex items-center justify-center`}>
|
|
{renderIcon()}
|
|
</div>
|
|
</Box>
|
|
);
|
|
}
|