Najjar\NajjarV02 b5876aead5
Some checks are pending
CI/CD / test-and-build (push) Waiting to run
CI/CD / deploy (push) Blocked by required conditions
refactor: update icon imports to individual paths and enhance industry page content
2026-05-21 14:38:45 +04:00

132 lines
3.2 KiB
TypeScript

'use client';
import Link from 'next/link';
import { forwardRef } from 'react';
import type { ReactNode, MouseEventHandler } from 'react';
import ArrowRight from 'lucide-react/dist/esm/icons/arrow-right';
import ArrowUpRight from 'lucide-react/dist/esm/icons/arrow-up-right';
export type CTAVariant = 'primary' | 'secondary' | 'ghost' | 'link';
export type CTASize = 'sm' | 'md' | 'lg';
export type CTAArrow = 'up-right' | 'right' | 'none';
type BaseProps = {
variant?: CTAVariant;
size?: CTASize;
arrow?: CTAArrow;
full?: boolean;
children: ReactNode;
className?: string;
ariaLabel?: string;
};
type AnchorProps = BaseProps & {
href: string;
external?: boolean;
download?: boolean | string;
type?: never;
onClick?: MouseEventHandler<HTMLAnchorElement>;
disabled?: never;
};
type ButtonProps = BaseProps & {
href?: undefined;
type?: 'button' | 'submit' | 'reset';
onClick?: MouseEventHandler<HTMLButtonElement>;
disabled?: boolean;
};
export type CTAButtonProps = AnchorProps | ButtonProps;
const arrowIcon = (arrow: CTAArrow, size: CTASize) => {
if (arrow === 'none') return null;
const px = size === 'sm' ? 12 : size === 'lg' ? 15 : 13;
return (
<span className="cta-arrow" aria-hidden="true">
{arrow === 'up-right' ? <ArrowUpRight size={px} /> : <ArrowRight size={px} />}
</span>
);
};
const classFor = (variant: CTAVariant, size: CTASize, full: boolean, extra?: string) =>
[
'cta-btn',
`cta-${variant}`,
`cta-${size}`,
full ? 'cta-full' : '',
extra ?? '',
]
.filter(Boolean)
.join(' ');
export const CTAButton = forwardRef<HTMLAnchorElement | HTMLButtonElement, CTAButtonProps>(
function CTAButton(props, ref) {
const {
variant = 'primary',
size = 'md',
arrow = 'up-right',
full = false,
children,
className,
ariaLabel,
} = props;
const cls = classFor(variant, size, full, className);
const inner = (
<>
<span className="cta-label">{children}</span>
{arrowIcon(arrow, size)}
</>
);
if ('href' in props && props.href) {
const isExternal = props.external || /^https?:\/\//.test(props.href);
if (isExternal) {
return (
<a
ref={ref as React.Ref<HTMLAnchorElement>}
href={props.href}
target="_blank"
rel="noopener noreferrer"
className={cls}
data-arrow={arrow}
aria-label={ariaLabel}
onClick={props.onClick}
>
{inner}
</a>
);
}
return (
<Link
ref={ref as React.Ref<HTMLAnchorElement>}
href={props.href}
className={cls}
data-arrow={arrow}
aria-label={ariaLabel}
onClick={props.onClick}
>
{inner}
</Link>
);
}
const btnProps = props as ButtonProps;
return (
<button
ref={ref as React.Ref<HTMLButtonElement>}
type={btnProps.type ?? 'button'}
onClick={btnProps.onClick}
disabled={btnProps.disabled}
className={cls}
data-arrow={arrow}
aria-label={ariaLabel}
>
{inner}
</button>
);
},
);
CTAButton.displayName = 'CTAButton';