51 lines
1.2 KiB
TypeScript
51 lines
1.2 KiB
TypeScript
import * as React from "react";
|
|
import { cn } from "tailwind-variants";
|
|
|
|
export interface SlotProps extends React.HTMLAttributes<HTMLElement> {
|
|
children: React.ReactNode;
|
|
}
|
|
|
|
export const Slot = React.forwardRef<HTMLElement, SlotProps>(
|
|
(
|
|
{
|
|
children,
|
|
onClick: externalOnClick,
|
|
style: styleProp,
|
|
className: classNameProp,
|
|
...props
|
|
},
|
|
ref,
|
|
) => {
|
|
if (!React.isValidElement(children)) return null;
|
|
|
|
const child = children as React.ReactElement<Record<string, unknown>>;
|
|
|
|
const mergedClassName = cn(child.props.className as string, classNameProp);
|
|
|
|
const mergedStyle = {
|
|
...(child.props.style ?? {}),
|
|
...(styleProp ?? {}),
|
|
} as React.CSSProperties;
|
|
|
|
const childOnClick = child.props.onClick as
|
|
| ((e: React.MouseEvent<HTMLElement>) => void)
|
|
| undefined;
|
|
|
|
const mergedOnClick = (e: React.MouseEvent<HTMLElement>) => {
|
|
childOnClick?.(e);
|
|
externalOnClick?.(e);
|
|
};
|
|
|
|
return React.cloneElement(child, {
|
|
...child.props,
|
|
...props,
|
|
ref,
|
|
style: mergedStyle,
|
|
className: mergedClassName,
|
|
onClick: mergedOnClick,
|
|
});
|
|
},
|
|
);
|
|
|
|
Slot.displayName = "Slot";
|