44 lines
1.4 KiB
TypeScript
44 lines
1.4 KiB
TypeScript
import React, { CSSProperties, forwardRef } from 'react';
|
|
import classNames from 'classnames';
|
|
import type { LucideIcon } from 'lucide-react';
|
|
import { ICON_PIXEL_SIZES } from './iconSizes';
|
|
import type { IconSize } from './types';
|
|
import * as iconStyles from './style.css';
|
|
|
|
export type IconProps = {
|
|
src: LucideIcon;
|
|
size?: IconSize;
|
|
filled?: boolean;
|
|
className?: string;
|
|
style?: CSSProperties;
|
|
fill?: string;
|
|
} & Omit<React.SVGAttributes<SVGSVGElement>, 'fill'>;
|
|
|
|
export const Icon = forwardRef<SVGSVGElement, IconProps>(
|
|
({ className, size = '400', filled = false, src: LucideIconComponent, style, fill, ...props }, ref) => {
|
|
const pixelSize = ICON_PIXEL_SIZES[size];
|
|
|
|
return (
|
|
<LucideIconComponent
|
|
ref={ref}
|
|
className={classNames(iconStyles.Icon({ size }), className)}
|
|
style={
|
|
size === 'Inherit'
|
|
? { width: '1em', height: '1em', ...style }
|
|
: pixelSize
|
|
? { width: pixelSize, height: pixelSize, ...style }
|
|
: style
|
|
}
|
|
// Lucide icons are stroke-based; solid fill turns faces (e.g. Smile) into blobs.
|
|
// Emphasize selection with a heavier stroke instead.
|
|
strokeWidth={filled ? 2.75 : 2}
|
|
fill={fill ?? 'none'}
|
|
aria-hidden={props['aria-hidden'] ?? props['aria-label'] ? undefined : true}
|
|
{...props}
|
|
/>
|
|
);
|
|
}
|
|
);
|
|
|
|
Icon.displayName = 'Icon';
|