UNPKG

@docyrus/react-icon

Version:

docy-icon component for react

157 lines (156 loc) 4.66 kB
import { jsx as _jsx } from "react/jsx-runtime"; import * as React from "react"; import { cva } from "class-variance-authority"; import { cn } from "../lib/utils"; import { isEmoji, isDotCharacter, getIconComponent, getDefaultIcon, validateIconProps, validateNumericSize } from "./utils"; const DEFAULT_ICON_SIZE = "md"; const DEFAULT_ICON_LIB = "lucide"; const DEFAULT_STROKE_WIDTH = 1.5; export const SIZE_VALIDATION_RANGE = { min: 4, max: 200 }; const iconVariants = cva("inline-flex items-center justify-center shrink-0", { variants: { size: { xs: "w-3 h-3", sm: "w-3.5 h-3.5", md: "w-4 h-4", lg: "w-5 h-5", xl: "w-6 h-6", "2xl": "w-8 h-8" }, animation: { none: "", spin: "animate-spin", pulse: "animate-pulse", bounce: "animate-bounce" }, lib: { lucide: "lucide", heroicons: "heroicons", tabler: "tabler", phosphor: "phosphor", custom: "custom-icon" } }, defaultVariants: { size: "md", animation: "none", lib: 'lucide' } }); const sizeMap = { xs: 12, sm: 14, md: 20, lg: 24, xl: 28, "2xl": 32 }; // Helper functions for style optimization function createDotStyle(size, color) { return { width: size, height: size, color, fontSize: size * 0.4, lineHeight: 1 }; } function createEmojiStyle(size, color) { return { fontSize: size * 0.8, lineHeight: 1, color, width: size, height: size }; } function renderIcon(name, lib, size, color, className, decorative = false) { if (!validateIconProps(name, lib)) { const DefaultIcon = getDefaultIcon(); return /*#__PURE__*/ _jsx(DefaultIcon, { size: size, className: className, style: { color }, strokeWidth: DEFAULT_STROKE_WIDTH, "aria-hidden": decorative }); } if (isDotCharacter(name)) { return /*#__PURE__*/ _jsx("span", { className: cn("flex items-center justify-center", className), style: createDotStyle(size, color), role: "img", "aria-label": decorative ? undefined : "dot", "aria-hidden": decorative, children: "•" }); } if (isEmoji(name)) { return /*#__PURE__*/ _jsx("span", { className: cn("flex items-center justify-center", className), style: createEmojiStyle(size, color), role: "img", "aria-label": decorative ? undefined : `${name} emoji`, "aria-hidden": decorative, children: name }); } const IconComponent = getIconComponent(name, lib); if (IconComponent) { return /*#__PURE__*/ _jsx(IconComponent, { size: size, className: className, style: { color }, strokeWidth: DEFAULT_STROKE_WIDTH, "aria-hidden": decorative }); } const DefaultIcon = getDefaultIcon(); return /*#__PURE__*/ _jsx(DefaultIcon, { size: size, className: className, style: { color }, strokeWidth: DEFAULT_STROKE_WIDTH, "aria-hidden": decorative }); } const DocyIcon = /*#__PURE__*/ React.forwardRef(({ name, lib = DEFAULT_ICON_LIB, size = DEFAULT_ICON_SIZE, color = "currentColor", animation, className, decorative = false, ...props }, ref)=>{ const validatedSize = typeof size === "number" ? validateNumericSize(size) : sizeMap[size]; const iconClasses = cn(iconVariants({ size: typeof size === "number" ? DEFAULT_ICON_SIZE : size, animation }), className); const iconElement = renderIcon(name, lib, validatedSize, color, iconClasses, decorative); // Add error boundary around React.cloneElement try { if (/*#__PURE__*/ React.isValidElement(iconElement)) { return /*#__PURE__*/ React.cloneElement(iconElement, { ...props }); } } catch { // Fallback if cloneElement fails return /*#__PURE__*/ _jsx("span", { ref: ref, ...props, children: iconElement }); } return /*#__PURE__*/ _jsx("span", { ref: ref, ...props, children: iconElement }); }); DocyIcon.displayName = "DocyIcon"; export { DocyIcon, iconVariants }; export default DocyIcon;