Lorem ipsum
@@ -31,8 +40,56 @@ describe('
component', () => {
);
- const heading = getByRole('heading');
- expect(heading).toBeVisible();
- expect(heading).toHaveTextContent('Lorem ipsum');
+ const [, nestedHeading] = getAllByRole('heading');
+ expect(nestedHeading).toBeVisible();
+ expect(nestedHeading).toHaveTextContent('Lorem ipsum');
+ });
+
+ it('should allow expanding hidden content', () => {
+ const expandableText = 'dolor sit amet';
+ const { getByText } = render(
+
+ Lorem ipsum
+
+ );
+
+ const expander = getByText('Show more');
+ expect(() => getByText(expandableText)).toThrow();
+ fireEvent.click(expander);
+ expect(getByText(expandableText)).toBeVisible();
+ fireEvent.click(expander);
+ expect(() => getByText(expandableText)).toThrow();
+ });
+
+ it('should display action buttons', () => {
+ const secondaryAction = vi.fn();
+ const destructiveAction = vi.fn();
+ const { getByText } = render(
+
+ Lorem ipsum
+
+ );
+
+ const secondaryButton = getByText('Details');
+ fireEvent.click(secondaryButton);
+ expect(secondaryAction).toHaveBeenCalled();
+
+ const destructiveButton = getByText('Delete');
+ fireEvent.click(destructiveButton);
+ expect(destructiveAction).toHaveBeenCalled();
});
});
diff --git a/packages/react-components/src/components/Card/Card.stories.tsx b/packages/react-components/src/components/Card/Card.stories.tsx
index 084497177..3ac25893e 100644
--- a/packages/react-components/src/components/Card/Card.stories.tsx
+++ b/packages/react-components/src/components/Card/Card.stories.tsx
@@ -1,30 +1,82 @@
import * as React from 'react';
-import { ComponentMeta } from '@storybook/react';
+import { ComponentMeta, Story } from '@storybook/react';
-import { Card as CardComponent, CardProps } from '../Card';
+import { Card, CardProps } from '../Card';
+import { action } from '@storybook/addon-actions';
export default {
title: 'Components/Card',
- component: CardComponent,
-} as ComponentMeta
;
+ component: Card,
+} as ComponentMeta;
-type ICardArgs = CardProps;
+export const Default: Story = (args: CardProps) => (
+
+);
-export const Card = (args: ICardArgs): React.ReactElement => {
- return (
-
-
-
- );
-};
+Default.args = {
+ title: 'Card title',
+ src: 'https://via.placeholder.com/100',
+ alt: 'Image description',
+ children:
+ 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore',
+} as CardProps;
+Default.storyName = 'Card';
-Card.args = {
- title: 'Title goes here',
- img: 'https://via.placeholder.com/100',
- children: (
-
- Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod
- tempor incididunt ut labore
-
- ),
-} as ICardArgs;
+export const Expandable: Story = (): JSX.Element => (
+
+ Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod
+ tempor incididunt ut labore
+
+);
+
+export const WithButtons: Story = (): JSX.Element => (
+
+ Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod
+ tempor incididunt ut labore
+
+);
+
+export const ExpandableWithButtons: Story = (): JSX.Element => (
+
+ Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod
+ tempor incididunt ut labore
+
+);
diff --git a/packages/react-components/src/components/Card/Card.tsx b/packages/react-components/src/components/Card/Card.tsx
index 0d008637c..79cd9d139 100644
--- a/packages/react-components/src/components/Card/Card.tsx
+++ b/packages/react-components/src/components/Card/Card.tsx
@@ -1,34 +1,110 @@
import * as React from 'react';
import cx from 'clsx';
+import {
+ ChevronUp,
+ ChevronDown,
+} from '@livechat/design-system-icons/react/material';
+
import { Text, Heading } from '../Typography';
+import { Button, ButtonProps } from '../Button';
+import { Icon } from '../Icon';
+
import styles from './Card.module.scss';
+export type CardButtonOptions = Pick<
+ ButtonProps,
+ 'children' | 'kind' | 'onClick'
+>;
+
export interface CardProps extends React.HTMLAttributes {
+ alt?: string;
+ buttonsOptions?: CardButtonOptions[];
+ description?: string;
+ expandableContent?: React.ReactNode;
+ src?: string;
title: string;
- img?: string;
}
+const baseClass = 'card';
+const headerClass = `${baseClass}__header`;
+const headingClass = `${headerClass}__heading`;
+const actionsClass = `${baseClass}__actions`;
+
export const Card: React.FC = ({
- img,
- title,
+ alt,
+ buttonsOptions = [],
children,
className,
- ...restProps
+ description,
+ expandableContent,
+ src,
+ title,
+ ...divProps
}) => {
+ const [isExpanded, setIsExpanded] = React.useState(false);
+ const expandIcon = isExpanded ? ChevronUp : ChevronDown;
+ const expandButtonText = isExpanded ? 'Hide' : 'Show more';
+ const shouldShowActionButtons = buttonsOptions?.length > 0;
+ const shouldShowExpandAction = !!expandableContent;
+ const shouldShowActions = shouldShowActionButtons || shouldShowExpandAction;
+
return (
-
- {(img || title) && (
-
- {img && }
- {title && {title}
}
-
+
+
+ {src && (
+
+ )}
+
+
+ {title}
+
+
+ {description}
+
+
+
+
+ {children}
+
+ {isExpanded && (
+
+ {expandableContent}
+
+ )}
+ {shouldShowActions && (
+
+
+
+ {shouldShowActionButtons &&
+ buttonsOptions.map(
+ ({ kind, onClick, children: buttonChildren }) => (
+
+ )
+ )}
+ {shouldShowExpandAction && (
+ }
+ onClick={() => setIsExpanded(!isExpanded)}
+ >
+ {expandButtonText}
+
+ )}
+
+
)}
- {children}
-
+
);
};