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: Entity list item isSelected prop #2312

Closed
38 changes: 37 additions & 1 deletion packages/components/entity-list/src/EntityList.styles.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,51 @@
import { css } from 'emotion';
import tokens from '@contentful/f36-tokens';
import { getEntityListItemStyles } from './EntityListItem/EntityListItem.styles';

const entityListItemStyles = getEntityListItemStyles();

export const getEntityListStyles = () => ({
root: css({
display: 'block',
listStyle: 'none',
margin: 0,
padding: 0,
border: `1px solid ${tokens.gray200}`,
borderBottom: 'none',
borderRadius: tokens.borderRadiusMedium,
overflow: 'hidden',
[`& .${entityListItemStyles.root({})}`]: {
borderLeft: `1px solid ${tokens.gray200}`,
borderRight: `1px solid ${tokens.gray200}`,
},
[`& .${entityListItemStyles.root({})}:first-child`]: {
borderTop: `1px solid ${tokens.gray200}`,
},
[`& .${entityListItemStyles.root({ isSelected: true })}`]: {
borderLeft: `1px solid ${tokens.colorPrimary}`,
borderRight: `1px solid ${tokens.colorPrimary}`,
},
[`& .${entityListItemStyles.root({ isSelected: true })}:first-child`]: {
borderTop: `1px solid ${tokens.colorPrimary}`,
},
[`& .${entityListItemStyles.root({
isSelected: true,
})}:not(:first-child)::before`]: {
content: '""',
display: 'block',
width: 'calc(100% + 2px)',
position: 'absolute',
height: '1px',
top: -1,
left: -1,
backgroundColor: tokens.colorPrimary,
},
'&>li:first-child': {
borderTopLeftRadius: tokens.borderRadiusMedium,
borderTopRightRadius: tokens.borderRadiusMedium,
},
'&>li:last-child': {
borderBottomLeftRadius: tokens.borderRadiusMedium,
borderBottomRightRadius: tokens.borderRadiusMedium,
},
}),
});
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import tokens from '@contentful/f36-tokens';
import { EntityListItemProps } from './EntityListItem';

export const getEntityListItemStyles = () => ({
root: (props: Pick<EntityListItemProps, 'isDragActive'>) =>
root: (props: Pick<EntityListItemProps, 'isDragActive' | 'isSelected'>) =>
css({
display: 'flex',
boxShadow: `inset 0 -1px 0 ${tokens.gray200}`,
Expand All @@ -18,20 +18,31 @@ export const getEntityListItemStyles = () => ({
: {}),

'&:hover': {
backgroundColor: tokens.gray100,
backgroundColor: props.isSelected ? tokens.blue100 : tokens.gray100,
},
...(props.isSelected
? {
boxShadow: `inset 0 -1px 0 ${tokens.colorPrimary}`,
background: tokens.blue100,
}
: {}),
}),
card: (props: Pick<EntityListItemProps, 'onClick'>) =>
css({
display: 'flex',
textDecoration: 'none',
width: '100%',
minHeight: tokens.spacing3Xl,
padding: tokens.spacingXs,
border: 'none',
background: 'none',
textAlign: 'left',
...(props.onClick
? {
cursor: 'pointer',
}
: {}),
}),
card: css({
display: 'flex',
textDecoration: 'none',
width: '100%',
minHeight: tokens.spacing3Xl,
padding: tokens.spacingXs,
margin: 0, // remove the default button margin in Safari.
border: 'none',
background: 'none',
textAlign: 'left',
}),
content: css({
flexGrow: 1,
minWidth: 0,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,10 @@ export interface EntityListItemProps extends CommonProps {
* A boolean used to disable the CardActions
*/
isActionsDisabled?: boolean;
/**
* Applies selected styles to the element
*/
isSelected?: boolean;
}

export const EntityListItem = ({
Expand All @@ -127,6 +131,7 @@ export const EntityListItem = ({
cardDragHandleProps,
cardDragHandleComponent,
isActionsDisabled = false,
isSelected = false,
...otherProps
}: EntityListItemProps): React.ReactElement => {
const styles = getEntityListItemStyles();
Expand Down Expand Up @@ -158,12 +163,12 @@ export const EntityListItem = ({
return (
<li
{...otherProps}
className={cx(styles.root({ isDragActive }), className)}
className={cx(styles.root({ isDragActive, isSelected }), className)}
data-test-id={testId}
>
{renderCardDragHandle()}
{isLoading ? (
<article className={styles.card}>
<article className={styles.card({ onClick })}>
<Skeleton.Container clipId="f36-entity-list-item-skeleton">
<Skeleton.Image height={46} width={46} />
<Skeleton.BodyText
Expand All @@ -175,7 +180,7 @@ export const EntityListItem = ({
</article>
) : (
<Element
className={styles.card}
className={styles.card({ onClick })}
onClick={onClick}
href={href}
type={Element === 'button' ? 'button' : undefined}
Expand Down
46 changes: 45 additions & 1 deletion packages/components/entity-list/stories/EntityList.stories.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React from 'react';
import React, { useState } from 'react';
import type { Meta, Story } from '@storybook/react/types-6-0';

import { EntityList, type EntityListProps } from '../src';
Expand Down Expand Up @@ -35,6 +35,50 @@ export const Basic: Story<EntityListProps> = () => (
</EntityList>
);

export const SelectableEntryListItems: Story<EntityListProps> = () => {
const [firstEntry, setFirstEntry] = useState(false);
const [secondEntry, setSecondEntry] = useState(false);
const [thirdEntry, setThirdEntry] = useState(false);
const [fourthEntry, setFourthEntry] = useState(false);

return (
<EntityList>
<EntityList.Item
title="Entry 1"
description="Description"
contentType="My content type"
status="published"
isSelected={firstEntry}
onClick={() => setFirstEntry(!firstEntry)}
/>
<EntityList.Item
title="Entry 2"
description="Description"
contentType="My content type"
status="draft"
isSelected={secondEntry}
onClick={() => setSecondEntry(!secondEntry)}
/>
<EntityList.Item
title="Entry 3"
description="Description"
contentType="My content type"
status="archived"
isSelected={thirdEntry}
onClick={() => setThirdEntry(!thirdEntry)}
/>
<EntityList.Item
title="Entry 4"
description="Description"
contentType="My content type"
status="archived"
isSelected={fourthEntry}
onClick={() => setFourthEntry(!fourthEntry)}
/>
</EntityList>
);
};

export const withDragHandle = () => (
<EntityList>
<EntityList.Item
Expand Down