Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: update card list item component #1113

Merged
merged 18 commits into from
Jun 26, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading