Skip to content

Commit

Permalink
feat: update card list item component (#1113)
Browse files Browse the repository at this point in the history
* feat: update card list item component

* feat: update card list item component

* chore: update card list items documentation

* test: update tests

* style: add mixincode

* style: update card list item style

* chore: remove unused background color
  • Loading branch information
danimuller20 authored Jun 26, 2024
1 parent 89bb744 commit 1c8cf3d
Show file tree
Hide file tree
Showing 4 changed files with 210 additions and 64 deletions.
103 changes: 82 additions & 21 deletions packages/ocean-core/src/components/_card-list-item.scss
Original file line number Diff line number Diff line change
@@ -1,29 +1,28 @@
@mixin default-line {
animation: pulse 1.5s infinite ease-in-out;
background-color: $color-interface-light-up;
border-radius: $border-radius-tiny;
}

.ods-card-list-item {
align-items: center;
border: $border-width-hairline solid $color-interface-light-down;
border-radius: $border-radius-md;
border-radius: $border-radius-sm;
box-sizing: border-box;
cursor: pointer;
display: flex;
flex-direction: row;
gap: $spacing-inline-xs;
padding: $spacing-stack-xs;
gap: $spacing-inline-xxs-extra;
padding: $spacing-stack-xs $spacing-inline-xxs-extra $spacing-stack-xs
$spacing-stack-xs;
transition: 200ms;
width: 320px;

&__leading-icon {
background-color: $color-interface-light-up;
border-radius: 50%;
box-sizing: content-box;
color: $color-brand-primary-down;
height: $font-size-md;
padding: $spacing-stack-xxs;
transition: 200ms;
width: $font-size-md;

svg {
height: $font-size-md;
width: $font-size-md;
color: $color-brand-primary-down;
height: $spacing-stack-sm;
width: $spacing-stack-sm;
}
}

Expand Down Expand Up @@ -52,9 +51,9 @@
color: $color-interface-dark-down;
font-family: $font-family-base;
font-size: $font-size-xxxs;
font-weight: $font-weight-regular;
font-weight: $font-weight-medium;
line-height: $line-height-comfy;
margin-top: $spacing-inset-xxs;
margin-top: $spacing-inline-xxs;
}
}

Expand All @@ -74,12 +73,8 @@
}
}

&:hover:not(.ods-card-list-item--disabled) {
&:hover:not(.ods-card-list-item--disabled, .ods-card-list-item--loading) {
background-color: $color-interface-light-up;

&:not(.ods-card-list-item--size-small) .ods-card-list-item__leading-icon {
background-color: rgba(184, 195, 255, 0.16);
}
}

&--disabled {
Expand Down Expand Up @@ -110,9 +105,75 @@
background-color: transparent;
padding: 0;
}

.ods-card-list-item__lines {
margin-left: 0;
}

.ods-card-list-item__circle {
height: 20px;
min-height: 20px;
min-width: 20px;
width: 20px;
}

.ods-card-list-item__lines__line2 {
width: 87px;
}

.ods-card-list-item__lines__line2 {
width: 260px;
}
}

&--full-width {
width: 100%;
}

&__circle {
animation: pulse 1.5s infinite ease-in-out;
background-color: $color-interface-light-up;
border-radius: 50%;
height: $spacing-stack-lg;
width: $spacing-stack-lg;
}

&__lines {
display: flex;
flex-direction: column;
gap: $spacing-inline-xxs;
margin-left: $spacing-inline-xxxs;

&__line1 {
@include default-line;
height: 16px;
width: 80px;
}

&__line2 {
@include default-line;
height: 16px;
width: 236px;
}

&__line3 {
@include default-line;
height: 16px;
width: 118px;
}
}
}

@keyframes pulse {
0% {
opacity: 1;
}

50% {
opacity: 0.5;
}

100% {
opacity: 1;
}
}
154 changes: 111 additions & 43 deletions packages/ocean-react/src/CardListItem/CardListItem.tsx
Original file line number Diff line number Diff line change
@@ -1,59 +1,127 @@
import React from 'react';
import React, { ComponentPropsWithoutRef, forwardRef } from 'react';
import classNames from 'classnames';

interface CardListItemProps {
type CardListItemProps = {
/*
* The title of the card list item.
*/
title: string;
/*
* The description of the card list item.
*/
description?: string;
/*
* The caption of the card list item.
*/
caption?: string;
/*
* The action icon of the card list item.
*/
actionIcon?: React.ReactNode;
/*
* The leading icon of the card list item.
*/
leadingIcon?: React.ReactNode;
/*
* The size of the card list item.
*/
size?: 'small' | 'medium';
/*
* Whether the card list item is disabled.
*/
disabled?: boolean;
/*
* Whether the card list item is full width.
*/
fullWidth?: boolean;
/*
* The function to call when the card list item is clicked.
*/
onClick?: () => void;
}
/*
* Whether the card list item is loading.
*/
loading?: boolean;
} & ComponentPropsWithoutRef<'div'>;

const CardListItem = ({
title,
description,
caption,
leadingIcon,
actionIcon,
size = 'medium',
disabled = false,
fullWidth = false,
onClick,
}: CardListItemProps): JSX.Element => (
<div
data-testid="card-list-item"
className={classNames(
'ods-card-list-item',
`ods-card-list-item--size-${size}`,
{ 'ods-card-list-item--disabled': disabled },
{ 'ods-card-list-item--full-width': fullWidth }
)}
onClick={() => {
if (!disabled && onClick) onClick();
}}
>
{leadingIcon && (
<div className="ods-card-list-item__leading-icon">{leadingIcon}</div>
)}
<div className="ods-card-list-item__content">
<div className="ods-card-list-item__content__title">{title}</div>
{description && (
<div className="ods-card-list-item__content__description">
{description}
const CardListItem = forwardRef<HTMLDivElement, CardListItemProps>(
(
{
title,
description,
caption,
leadingIcon,
actionIcon,
size = 'medium',
disabled = false,
fullWidth = false,
onClick,
loading,
...rest
},
ref
): JSX.Element =>
loading ? (
<div
ref={ref}
{...rest}
data-testid="card-list-item"
className={classNames(
'ods-card-list-item',
`ods-card-list-item--size-${size}`,
{ 'ods-card-list-item--full-width': fullWidth },
{
'ods-card-list-item--loading': loading,
}
)}
>
<div className="ods-card-list-item__circle" />
<div className="ods-card-list-item__lines">
<div className="ods-card-list-item__lines__line1" />
<div className="ods-card-list-item__lines__line2" />
{size === 'medium' && (
<div className="ods-card-list-item__lines__line3" />
)}
</div>
)}
{caption && size === 'medium' && (
<div className="ods-card-list-item__content__caption">{caption}</div>
)}
</div>
{actionIcon && (
<div className="ods-card-list-item__action">{actionIcon}</div>
)}
</div>
</div>
) : (
<div
ref={ref}
{...rest}
data-testid="card-list-item"
className={classNames(
'ods-card-list-item',
`ods-card-list-item--size-${size}`,
{ 'ods-card-list-item--disabled': disabled },
{ 'ods-card-list-item--full-width': fullWidth }
)}
onClick={() => {
if (!disabled && onClick) onClick();
}}
>
{leadingIcon && (
<div className="ods-card-list-item__leading-icon">{leadingIcon}</div>
)}
<div className="ods-card-list-item__content">
<div className="ods-card-list-item__content__title">{title}</div>
{description && (
<div className="ods-card-list-item__content__description">
{description}
</div>
)}
{caption && size === 'medium' && (
<div className="ods-card-list-item__content__caption">
{caption}
</div>
)}
</div>
{actionIcon && (
<div className="ods-card-list-item__action">{actionIcon}</div>
)}
</div>
)
);

CardListItem.displayName = 'CardListItem';

export default CardListItem;
Original file line number Diff line number Diff line change
Expand Up @@ -74,4 +74,11 @@ describe('CardListItem', () => {
'ods-card-list-item--full-width'
);
});

test('renders the loading state', () => {
render(<CardListItem title="Test Title" loading />);
expect(screen.getByTestId('card-list-item')).toHaveClass(
'ods-card-list-item--loading'
);
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,10 @@ import { CardListItem } from '@useblu/ocean-react';
</Story>
</Canvas>

## Props

<ArgsTable of="." />

## CSS

| Global class | Description |
Expand All @@ -43,6 +47,12 @@ import { CardListItem } from '@useblu/ocean-react';
| .ods-card-list-item\_\_content\_\_description | Styles applied to the content description. |
| .ods-card-list-item\_\_content\_\_caption | Styles applied to the content caption. |
| .ods-card-list-item\_\_action-icon | Styles applied to the action icon. |
| .ods-card-list-item--loading | Styles applied to the root element when loading |
| .ods-card-list-item\_\_circle | Styles applied to the content of loading representing icon |
| .ods-card-list-item\_\_lines | Styles applied to the content of loading representing a box |
| .ods-card-list-item**lines**line1 | Styles applied to the content of loading representing a line |
| .ods-card-list-item**lines**line2 | Styles applied to the content of loading representing a line |
| .ods-card-list-item**lines**line3 | Styles applied to the content of loading representing a line |

If that's not sufficient, you can check the [implementation of the component](https://github.com/ocean-ds/ocean-web/blob/master/packages/ocean-react/src/CardListItem/CardListItem.tsx) for more detail.

Expand Down

0 comments on commit 1c8cf3d

Please sign in to comment.