Skip to content

Commit

Permalink
feat: support intrinsic props from link components
Browse files Browse the repository at this point in the history
  • Loading branch information
angeloashmore committed Oct 8, 2021
1 parent 7d8b69c commit ab82e96
Showing 1 changed file with 48 additions and 26 deletions.
74 changes: 48 additions & 26 deletions src/PrismicLink.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -33,10 +33,23 @@ export interface LinkProps {
children?: React.ReactNode;
}

type ComponentProps<T> = T extends React.ComponentType<infer U>
? U
: T extends keyof JSX.IntrinsicElements
? React.ComponentProps<T>
: unknown;

/**
* Props for `<PrismicLink>`.
*/
export type PrismicLinkProps = {
export type PrismicLinkProps<
InternalComponent extends string | React.ComponentType<LinkProps> =
| string
| React.ComponentType<LinkProps>,
ExternalComponent extends string | React.ComponentType<LinkProps> =
| string
| React.ComponentType<LinkProps>,
> = ComponentProps<InternalComponent> & {
/**
* The Link Resolver used to resolve links.
*
Expand All @@ -53,12 +66,12 @@ export type PrismicLinkProps = {
* If your app uses a client-side router that requires a special Link
* component, provide the Link component to this prop.
*/
internalComponent?: string | React.ComponentType<LinkProps>;
internalComponent?: InternalComponent;

/**
* The component rendered for external URLs. Defaults to `<a>`.
*/
externalComponent?: string | React.ComponentType<LinkProps>;
externalComponent?: ExternalComponent;

/**
* The `target` attribute for anchor elements. If the Prismic field is
Expand All @@ -77,27 +90,27 @@ export type PrismicLinkProps = {
*/
children?: React.ReactNode;
} & (
| {
/**
* The Prismic Link field containing the URL or document to link.
*
* @see Learn about Prismic Link fields {@link https://prismic.io/docs/core-concepts/link-content-relationship}
*/
field?: prismicT.LinkField;
}
| {
/**
* The Prismic document to link.
*/
document?: prismicT.PrismicDocument;
}
| {
/**
* The URL to link.
*/
href?: string;
}
);
| {
/**
* The Prismic Link field containing the URL or document to link.
*
* @see Learn about Prismic Link fields {@link https://prismic.io/docs/core-concepts/link-content-relationship}
*/
field?: prismicT.LinkField;
}
| {
/**
* The Prismic document to link.
*/
document?: prismicT.PrismicDocument;
}
| {
/**
* The URL to link.
*/
href?: string;
}
);

/**
* The default component rendered for internal URLs.
Expand All @@ -124,7 +137,16 @@ const defaultExternalComponent = "a";
* @returns The internal or external link component depending on whether the
* link is internal or external.
*/
export const PrismicLink = (props: PrismicLinkProps): JSX.Element | null => {
export const PrismicLink = <
InternalComponent extends
| string
| React.ComponentType<LinkProps> = typeof defaultInternalComponent,
ExternalComponent extends
| string
| React.ComponentType<LinkProps> = typeof defaultExternalComponent,
>(
props: PrismicLinkProps<InternalComponent, ExternalComponent>,
): JSX.Element | null => {
const context = usePrismicContext();

const linkResolver = props.linkResolver || context.linkResolver;
Expand Down Expand Up @@ -164,7 +186,7 @@ export const PrismicLink = (props: PrismicLinkProps): JSX.Element | null => {
const Component = isInternal ? InternalComponent : ExternalComponent;

return href ? (
<Component href={href} target={target} rel={rel}>
<Component {...props} href={href} target={target} rel={rel}>
{props.children}
</Component>
) : null;
Expand Down

0 comments on commit ab82e96

Please sign in to comment.