import React, { HTMLAttributes, forwardRef } from "react";
import type { AkselColor } from "../types";
import { BodyLong, Heading } from "../typography";
import {
LinkAnchor,
LinkAnchorArrow,
LinkAnchorOverlay,
LinkAnchorProps,
} from "../utils/components/link-anchor";
import { cl, createStrictContext } from "../utils/helpers";
/* ------------------------------ LinkCard Root ----------------------------- */
interface LinkCardProps extends HTMLAttributes {
/**
* @default true
*/
arrow?: boolean;
/**
* Adjusts arrow position.
* @default "baseline"
*/
arrowPosition?: "baseline" | "center";
/**
* Changes padding and typo sizes.
* @default "medium"
*/
size?: "small" | "medium";
/**
* Overrides inherited color.
*
* We reccomend avoiding status-colors (`info`, `success`, `warning`, `danger`) in LinkCards.
* @see 🏷️ {@link AkselColor}
* @see [📝 Documentation](https://aksel.nav.no/grunnleggende/styling/farger-tokens)
*/
"data-color"?: AkselColor;
/**
* Changes the HTML element used for the root element.
*
* **When using `section`, provide either `aria-label` or `aria-labelledby` for better accessibility.**
* `axe-core` might warn about unique landmarks if you have multiple Accordions on page with the same label.
* In those cases consider updating to unique `aria-label` or `aria-labelledby` props.
* @see [📝 Landmarks unique](https://dequeuniversity.com/rules/axe/4.6/landmark-unique)
*
*
* **When using `article`, make sure `` is a heading and not a `span`.**
* @default "div"
*/
as?: "div" | "section" | "article";
}
type LinkCardContextProps = {
size: LinkCardProps["size"];
};
const { Provider: LinkCardContextProvider, useContext: useLinkCardContext } =
createStrictContext({
name: "LinkCardContextProvider",
});
interface LinkCardComponent extends React.ForwardRefExoticComponent<
LinkCardProps & React.RefAttributes
> {
/**
* @see 🏷️ {@link LinkCardTitleProps}
*/
Title: typeof LinkCardTitle;
/**
* @see 🏷️ {@link LinkCardAnchorProps}
*/
Anchor: typeof LinkCardAnchor;
/**
* @see 🏷️ {@link LinkCardDescriptionProps}
*/
Description: typeof LinkCardDescription;
/**
* @see 🏷️ {@link LinkCardFooterProps}
*/
Footer: typeof LinkCardFooter;
/**
* @see 🏷️ {@link LinkCardIconProps}
*/
Icon: typeof LinkCardIcon;
/**
* @see 🏷️ {@link LinkCardImageProps}
*/
Image: typeof LinkCardImage;
}
/**
* Accessible clickable card as a link.
*
* @see [📝 Documentation](https://aksel.nav.no/komponenter/core/linkcard)
* @see 🏷️ {@link LinkCardProps}
*
*
* @example
* ```tsx
*
*
*
*
*
*
* LinkCard title
*
*
*
* This is a description of the link card.
*
* Footer content
*
* ```
*/
export const LinkCard = forwardRef(
(
{
children,
className,
arrow = true,
arrowPosition = "baseline",
size = "medium",
as: Component = "div",
...restProps
}: LinkCardProps,
forwardedRef,
) => {
return (
{children}
{arrow && (
)}
);
},
) as LinkCardComponent;
/* ---------------------------- LinkCard Title ---------------------------- */
type LinkCardTitleProps = HTMLAttributes & {
children: React.ReactNode;
/**
* Heading tag. Use "span" if you want a non header defining card
* (eg. you have a lot of them all at once, such as in a grid)
* @default "span"
*/
as?: "span" | "h2" | "h3" | "h4" | "h5" | "h6";
};
/**
* @see 🏷️ {@link LinkCardTitleProps}
*/
export const LinkCardTitle = forwardRef(
(
{ children, as = "span", className, ...restProps }: LinkCardTitleProps,
forwardedRef,
) => {
const context = useLinkCardContext();
return (
{children}
);
},
);
/* ---------------------------- LinkCard Anchor ---------------------------- */
type LinkCardAnchorProps = LinkAnchorProps;
/**
* @see 🏷️ {@link LinkCardAnchorProps}
*/
export const LinkCardAnchor = LinkAnchor;
/* ---------------------------- LinkCard Description ---------------------------- */
interface LinkCardDescriptionProps extends HTMLAttributes {
children: React.ReactNode;
}
/**
* @see 🏷️ {@link LinkCardDescriptionProps}
*/
export const LinkCardDescription = forwardRef<
HTMLDivElement,
LinkCardDescriptionProps
>(
(
{ children, className, ...restProps }: LinkCardDescriptionProps,
forwardedRef,
) => {
return (
{children}
);
},
);
/* ---------------------------- LinkCard Footer ---------------------------- */
interface LinkCardFooterProps extends HTMLAttributes {
children: React.ReactNode;
}
/**
* @see 🏷️ {@link LinkCardFooterProps}
*/
export const LinkCardFooter = forwardRef(
(
{ children, className, ...restProps }: LinkCardFooterProps,
forwardedRef,
) => {
return (
{children}
);
},
);
/* ---------------------------- LinkCard Icon ---------------------------- */
interface LinkCardIconProps extends HTMLAttributes {
children: React.ReactNode;
}
/**
* @see 🏷️ {@link LinkCardIconProps}
*/
export const LinkCardIcon = forwardRef(
({ children, className, ...restProps }: LinkCardIconProps, forwardedRef) => {
return (
{children}
);
},
);
/* ---------------------------- LinkCard Image ---------------------------- */
type ImageAspectRatio = "1/1" | "16/9" | "16/10" | "4/3" | (string & {});
interface LinkCardImageProps extends HTMLAttributes {
children: React.ReactNode;
/**
* The aspect-ratio CSS property allows you to define the desired width-to-height ratio of an element's box.
* This means that even if the parent container or viewport size changes, the browser will adjust the element's dimensions to maintain the specified width-to-height ratio.
*/
aspectRatio?: ImageAspectRatio;
}
/**
* @see 🏷️ {@link LinkCardImageProps}
*/
export const LinkCardImage = forwardRef(
(
{
children,
className,
aspectRatio,
style,
...restProps
}: LinkCardImageProps,
forwardedRef,
) => {
return (
{children}
);
},
);
LinkCard.Title = LinkCardTitle;
LinkCard.Anchor = LinkCardAnchor;
LinkCard.Description = LinkCardDescription;
LinkCard.Footer = LinkCardFooter;
LinkCard.Icon = LinkCardIcon;
LinkCard.Image = LinkCardImage;
export type {
LinkCardAnchorProps,
LinkCardDescriptionProps,
LinkCardFooterProps,
LinkCardIconProps,
LinkCardImageProps,
LinkCardProps,
LinkCardTitleProps,
};