chore: initial deploy for code base
This commit is contained in:
@@ -0,0 +1,69 @@
|
||||
import React from 'react';
|
||||
import { render, screen, fireEvent } from '@testing-library/react';
|
||||
import Card from './Card';
|
||||
import Button from '../../lib/button/Button';
|
||||
import EditIcon from '../icon/EditIcon'
|
||||
|
||||
test('verify basic card data displays with button click', async () => {
|
||||
const title = 'This is a title for a card';
|
||||
const description = 'that title sucks';
|
||||
const body = 'this is the body';
|
||||
const buttonText = 'Click this';
|
||||
const handleExtraButtonClickMock = jest.fn();
|
||||
|
||||
render(<>
|
||||
<Card
|
||||
title={title}
|
||||
icon={<EditIcon />}
|
||||
description={description}
|
||||
extra={<Button onClick={handleExtraButtonClickMock}>{buttonText}</Button>}
|
||||
>{body}</Card>
|
||||
</>)
|
||||
|
||||
//Validate card is being displayed with data.
|
||||
await screen.findByText(title);
|
||||
await screen.findByLabelText('edit');
|
||||
await screen.findByText(description);
|
||||
await screen.findByText(body);
|
||||
|
||||
//find and kick off close button
|
||||
const button = await screen.findByRole('button', { name: buttonText });
|
||||
fireEvent.click(button);
|
||||
|
||||
//Verify close function called
|
||||
expect(handleExtraButtonClickMock).toBeCalled();
|
||||
});
|
||||
|
||||
test('verify card displays and is clicked', async () => {
|
||||
const body = 'This is a clickable body for a card';
|
||||
const handleCardClicked = jest.fn();
|
||||
|
||||
render(<>
|
||||
<Card onClick={handleCardClicked}
|
||||
>{body}</Card>
|
||||
</>);
|
||||
|
||||
//Find and click card
|
||||
const card = await screen.findByText(body);
|
||||
fireEvent.click(card);
|
||||
|
||||
//verify click function is called.
|
||||
expect(handleCardClicked).toBeCalled();
|
||||
});
|
||||
|
||||
test('verify multiple cards displays with types', async () => {
|
||||
const titleError = 'black jack';
|
||||
const titleSuccess = 'success';
|
||||
const body = 'poker';
|
||||
|
||||
render(<>
|
||||
<Card title={titleError} type='error' />
|
||||
<Card title={titleSuccess} type='success'>{body}</Card>
|
||||
</>);
|
||||
|
||||
await screen.findByText(titleError);
|
||||
await screen.findByText(titleSuccess);
|
||||
await screen.findByText(body);
|
||||
await screen.findByLabelText('warning');
|
||||
await screen.findByLabelText('check-circle');
|
||||
});
|
||||
@@ -0,0 +1,156 @@
|
||||
import * as React from "react";
|
||||
import { Card as AntCard } from "antd";
|
||||
import Loader from "../loader/Loader";
|
||||
import Spacing from "../spacing/Spacing";
|
||||
import Text from '../text/Text';
|
||||
import Image from '../image/Image';
|
||||
import Link from '../link/Link';
|
||||
import CheckCircleIcon from "../icon/CheckCircleIcon";
|
||||
import WarningIcon from "../icon/WarningIcon";
|
||||
import IIconProps from "../icon/IIconProps";
|
||||
import WarningCircleIcon from "../icon/WarningCircleIcon";
|
||||
|
||||
export interface ICardProps {
|
||||
/** Card title */
|
||||
title?: React.ReactNode;
|
||||
|
||||
/** Title icon */
|
||||
icon?: React.ReactElement<IIconProps>;
|
||||
|
||||
/** Card type. Default is "normal." "success", "attention", and "error" override the icon prop */
|
||||
type?: "normal" | "success" | "error" | "attention";
|
||||
|
||||
/** Card description below the title */
|
||||
description?: string;
|
||||
|
||||
/** Content to the right of the card title */
|
||||
extra?: React.ReactNode;
|
||||
|
||||
/** Cover image src. Cannot be used with title */
|
||||
image?: string;
|
||||
|
||||
/** Card footer. Requires children to be set */
|
||||
footer?: React.ReactNode;
|
||||
|
||||
/** Remove body padding */
|
||||
removeBodyPadding?: boolean;
|
||||
|
||||
/** Min height of the card, excluding the height of the title or image */
|
||||
height?: number | string;
|
||||
|
||||
/** Trigger an action on card click. Cannot be used with href */
|
||||
onClick?: () => void;
|
||||
|
||||
/** Trigger a link on card click. Cannot be used with onClick */
|
||||
href?: string;
|
||||
|
||||
/** Show loading mask */
|
||||
loading?: boolean;
|
||||
|
||||
/** Add selected style */
|
||||
selected?: boolean;
|
||||
}
|
||||
|
||||
/** Cards structure content like text, forms, and tables. */
|
||||
const Card: React.FC<ICardProps> = (props) => {
|
||||
const { removeBodyPadding, loading, selected, type, image, description, height, onClick, href, ...validProps } = props;
|
||||
|
||||
let className = "tempo-card";
|
||||
if (removeBodyPadding || !validProps.children) {
|
||||
className += " tempo-card--body-no-padding";
|
||||
}
|
||||
if (selected) {
|
||||
className += " tempo-card--selected"
|
||||
}
|
||||
|
||||
let title = validProps.title;
|
||||
if (title) {
|
||||
title = <Text.Heading level={3}>{title}</Text.Heading>;
|
||||
|
||||
if (description) {
|
||||
title = (
|
||||
<Spacing column padding={"12px 0"}>
|
||||
{title}
|
||||
<Text color="secondary">{description}</Text>
|
||||
</Spacing>
|
||||
);
|
||||
}
|
||||
|
||||
let icon: React.ReactElement<IIconProps> | null = null;
|
||||
|
||||
if (props.icon) {
|
||||
icon = React.cloneElement(props.icon, {
|
||||
size: props.icon.props.size || 20,
|
||||
});
|
||||
}
|
||||
|
||||
if (type === "success") {
|
||||
icon = <CheckCircleIcon color='success' size={20} />
|
||||
} else if (type === "error") {
|
||||
icon = <WarningIcon color='error' size={20} />;
|
||||
}
|
||||
else if (type === "attention") {
|
||||
icon = <WarningCircleIcon color='attention' size={20} />;
|
||||
}
|
||||
|
||||
if (icon != null) {
|
||||
title = (
|
||||
<Spacing vAlign="center" itemSpacing={8}>
|
||||
{icon}
|
||||
{title}
|
||||
</Spacing>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
let extra = validProps.extra;
|
||||
|
||||
let cover;
|
||||
if (!title && image) {
|
||||
cover = <Image src={image} height={180} border="bottom" backgroundColor="#F5F5F5" />;
|
||||
}
|
||||
|
||||
let contents = validProps.children;
|
||||
if (contents) {
|
||||
contents = <div style={{ minHeight: height }}>{contents}</div>;
|
||||
|
||||
if (validProps.footer) {
|
||||
contents = (
|
||||
<div className="tempo-card-contents-and-footer" style={{ minHeight: height }}>
|
||||
<div>{validProps.children}</div>
|
||||
<div className="tempo-card-footer">{validProps.footer}</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
let tabIndex, onKeyPress;
|
||||
if (onClick && !loading) {
|
||||
tabIndex = 0;
|
||||
|
||||
onKeyPress = (e: React.KeyboardEvent<HTMLDivElement>) => {
|
||||
e.key === 'Enter' && onClick();
|
||||
}
|
||||
}
|
||||
|
||||
Object.assign(validProps, {
|
||||
hoverable: props.onClick || href
|
||||
});
|
||||
|
||||
const card = <AntCard {...validProps}
|
||||
onClick={onClick}
|
||||
onKeyPress={onKeyPress}
|
||||
tabIndex={tabIndex}
|
||||
title={title}
|
||||
extra={extra}
|
||||
cover={cover}
|
||||
className={className}>{contents}</AntCard>;
|
||||
|
||||
return (
|
||||
<Loader loading={loading}>
|
||||
{href ? <Link href={href}>{card}</Link> : card}
|
||||
</Loader>
|
||||
);
|
||||
}
|
||||
|
||||
export default Card;
|
||||
@@ -0,0 +1,4 @@
|
||||
import Card, { ICardProps } from "./Card"
|
||||
|
||||
export default Card;
|
||||
export { ICardProps }
|
||||
Reference in New Issue
Block a user