46 lines
1.3 KiB
TypeScript
46 lines
1.3 KiB
TypeScript
'use client';
|
|
|
|
import { ComponentProps, ReactNode, useState } from 'react';
|
|
import Link from 'next/link';
|
|
import LinkWithStatusChild from './primitives/LinkWithStatusChild';
|
|
import clsx from 'clsx/lite';
|
|
|
|
export default function LinkWithStatus({
|
|
children,
|
|
className,
|
|
loadingClassName,
|
|
isLoading: isLoadingProp = false,
|
|
setIsLoading: setIsLoadingProp,
|
|
...props
|
|
}: Omit<ComponentProps<typeof Link>, 'children'> & {
|
|
children: ReactNode | ((props: { isLoading: boolean }) => ReactNode)
|
|
loadingClassName?: string
|
|
// For hoisting state to a parent component, e.g., <EntityLink />
|
|
isLoading?: boolean
|
|
setIsLoading?: (isLoading: boolean) => void
|
|
}) {
|
|
const [_isLoading, _setIsLoading] = useState(false);
|
|
const isLoading = isLoadingProp || _isLoading;
|
|
const setIsLoading = setIsLoadingProp || _setIsLoading;
|
|
|
|
const isControlled = typeof children === 'function';
|
|
|
|
return <Link
|
|
{...props}
|
|
className={clsx(
|
|
'transition-[colors,opacity]',
|
|
(loadingClassName || isControlled)
|
|
? 'opacity-100'
|
|
: isLoading ? 'opacity-50' : 'opacity-100',
|
|
className,
|
|
isLoading && loadingClassName,
|
|
)}
|
|
>
|
|
<LinkWithStatusChild {...{ setIsLoading }}>
|
|
{typeof children === 'function'
|
|
? children({ isLoading })
|
|
: children}
|
|
</LinkWithStatusChild>
|
|
</Link>;
|
|
}
|