From a257675bf75903499eb31924805b64252086dce1 Mon Sep 17 00:00:00 2001 From: Xevion Date: Thu, 23 Oct 2025 14:58:26 -0500 Subject: [PATCH] refactor: improve icon handling with component-based approach Replace ReactNode icon props with IconComponent type for better type safety and consistency. Add configurable iconSize prop to control icon dimensions. Update ShareButton to pass icon components instead of JSX elements. --- src/components/CopyButton.tsx | 22 +++++++++++++++++----- src/components/ShareButton.tsx | 13 +++++++++++-- 2 files changed, 28 insertions(+), 7 deletions(-) diff --git a/src/components/CopyButton.tsx b/src/components/CopyButton.tsx index 1c9781d..308afdf 100644 --- a/src/components/CopyButton.tsx +++ b/src/components/CopyButton.tsx @@ -1,4 +1,4 @@ -import type { FunctionComponent, ReactNode } from "react"; +import type { FunctionComponent, ComponentType } from "react"; import { useState, useCallback, useEffect, useRef } from "react"; import { CheckIcon, ClipboardIcon } from "@radix-ui/react-icons"; import type { IconButtonProps } from "@radix-ui/themes"; @@ -15,6 +15,9 @@ export type ButtonSize = IconButtonProps["size"]; export type ButtonVariant = IconButtonProps["variant"]; export type ButtonColor = IconButtonProps["color"]; +// Type for icon components that accept width/height props (e.g., Radix UI icons) +export type IconComponent = ComponentType<{ width?: string | number; height?: string | number }>; + export type CopyButtonProps = { /** * The value to copy to clipboard when the button is clicked @@ -35,9 +38,14 @@ export type CopyButtonProps = { */ color?: ButtonColor | null; /** - * Optional custom icon to show when not copied (defaults to ClipboardIcon) + * Optional custom icon component to show when not copied (defaults to ClipboardIcon) */ - icon?: ReactNode; + icon?: IconComponent; + /** + * Size for both the custom icon and checkmark icon + * @default 16 + */ + iconSize?: number; /** * Tooltip text to show when not copied (defaults to "Copy to Clipboard") */ @@ -49,7 +57,8 @@ const CopyButton: FunctionComponent = ({ size = "1", variant = "ghost", color = "gray", - icon, + icon: IconComp, + iconSize = 16, tooltipText = "Copy to Clipboard", }) => { const [copied, setCopied] = useState(false); @@ -91,6 +100,9 @@ const CopyButton: FunctionComponent = ({ setTooltipOpen(open); }, []); + // Determine which icon component to render + const ActiveIcon = copied ? CheckIcon : (IconComp ?? ClipboardIcon); + return ( = ({ aria-label={copied ? "Copied!" : tooltipText} onClick={handleCopy} > - {copied ? : (icon ?? )} + ); diff --git a/src/components/ShareButton.tsx b/src/components/ShareButton.tsx index e6ccb16..32bc9d5 100644 --- a/src/components/ShareButton.tsx +++ b/src/components/ShareButton.tsx @@ -11,7 +11,8 @@ export type ShareButtonProps = Omit & { const ShareButton: FunctionComponent = ({ url, - icon = , + icon = Link2Icon, + iconSize = 18, tooltipText = "Copy shareable link", ...copyButtonProps }) => { @@ -24,7 +25,15 @@ const ShareButton: FunctionComponent = ({ } } - return ; + return ( + + ); }; export default ShareButton;