Skip to content

Commit

Permalink
Merge pull request #410 from lifeomic/expansion-panel-secondary-header
Browse files Browse the repository at this point in the history
feat: Add secondary header to `<ExpansionPanel`
  • Loading branch information
dexterca authored Oct 20, 2023
2 parents a7f3a44 + 441aa79 commit ac6f8c8
Show file tree
Hide file tree
Showing 2 changed files with 95 additions and 48 deletions.
19 changes: 19 additions & 0 deletions src/components/ExpansionPanel/ExpansionPanel.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { StoryObj, StoryFn, Meta } from '@storybook/react';

import { ExpansionPanel } from './ExpansionPanel';
import { Check, ArrowRight } from '@lifeomic/chromicons';
import { Button } from '../Button';

const meta: Meta<typeof ExpansionPanel> = {
title: 'Components/ExpansionPanel',
Expand Down Expand Up @@ -48,3 +49,21 @@ export const TruncatedTitle: Story = {
},
},
};

export const SecondaryHeader: Story = {
render: Template,
args: {
title:
'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.',
leadingIcon: ArrowRight,
secondaryHeader: <Button variant="text">Secondary Button</Button>,
truncateTitle: true,
},
parameters: {
docs: {
description: {
story: `Secondary content or actions can be placed in the expansion panel header.`,
},
},
},
};
124 changes: 76 additions & 48 deletions src/components/ExpansionPanel/ExpansionPanel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ import { makeStyles } from '../../styles';
import { GetClasses } from '../../typeUtils';
import { generateUniqueId } from '../_private/UniqueId';
import { Text } from '../Text';
import { Box } from '../Box';
import { IconButton } from '../IconButton';

export const ExpansionPanelStylesKey = 'ChromaExpansionPanel';

Expand All @@ -17,21 +19,30 @@ export const useStyles = makeStyles(
rootOpen: {
maxHeight: 'inherit',
},
header: {
background: theme.palette.common.white,
position: 'relative',
zIndex: 2,
},
headerShadow: {
boxShadow: theme.boxShadows.table,
},
button: {
width: '100%',
alignItems: 'center',
background: theme.palette.common.white,
border: 'none',
cursor: 'pointer',
display: 'flex',
flex: 1,
justifyContent: 'space-between',
alignItems: 'center',
position: 'relative',
textAlign: 'left',
border: 'none',
outline: 'none',
overflow: 'hidden',
paddingLeft: theme.spacing(2),
paddingRight: theme.spacing(2),
paddingRight: 0,
paddingTop: theme.spacing(1.25),
paddingBottom: theme.spacing(1.25),
cursor: 'pointer',
position: 'relative',
textAlign: 'left',
'&:focus': {
outline: 'none',
},
Expand All @@ -40,18 +51,11 @@ export const useStyles = makeStyles(
transform: 'translate3d(2px, 0, 0)',
},
},
buttonShadow: {
boxShadow: theme.boxShadows.table,
},
leadingIcon: {
marginRight: theme.spacing(1),
minWidth: theme.pxToRem(18),
},
titleContainer: {
alignItems: 'center',
display: 'flex',
maxWidth: `calc(100% - ${theme.pxToRem(34)})`, // 34 = icon width of 18px + 16px padding
flexGrow: 1,
flex: 1,
minWidth: 0,
},
title: {
color: theme.palette.text.secondary,
Expand All @@ -63,10 +67,20 @@ export const useStyles = makeStyles(
overflow: 'hidden',
textOverflow: 'ellipsis',
},
icon: {
leadingIcon: {
marginRight: theme.spacing(1),
minWidth: theme.pxToRem(18),
},
iconButton: {
transition: 'transform 0.25s ease',
color: theme.palette.primary.main,
minWidth: theme.pxToRem(18),
paddingRight: theme.spacing(2),
paddingLeft: theme.spacing(2),
'& > svg': {
maxHeight: theme.pxToRem(18),
maxWidth: theme.pxToRem(18),
},
},
rotate: {
transform: 'rotate(45deg)',
Expand Down Expand Up @@ -110,6 +124,8 @@ export interface ExpansionPanelProps
leadingIconClassName?: string;
title: string;
leadingIcon?: React.ComponentType<React.SVGProps<SVGSVGElement>>;
secondaryHeaderClassName?: string;
secondaryHeader?: React.ReactNode;
truncateTitle?: boolean;
onToggle?: (isExpanded: boolean) => void;
isOpen?: boolean;
Expand Down Expand Up @@ -150,6 +166,8 @@ export const ExpansionPanel = React.forwardRef<
contentDirection = 'column',
title,
leadingIcon: LeadingIcon,
secondaryHeaderClassName,
secondaryHeader,
truncateTitle = false,
...rootProps
},
Expand Down Expand Up @@ -206,39 +224,49 @@ export const ExpansionPanel = React.forwardRef<
ref={ref}
{...rootProps}
>
<button
aria-expanded={isExpanded}
aria-owns={ariaId}
className={clsx(classes.button, isExpanded && classes.buttonShadow)}
onClick={handleClick}
tabIndex={0}
<Box
align="center"
className={clsx(classes.header, isExpanded && classes.headerShadow)}
>
<div className={classes.titleContainer}>
{LeadingIcon && (
<LeadingIcon
role="img"
aria-hidden
className={clsx(classes.leadingIcon, leadingIconClassName)}
width={18}
height={18}
/>
)}
<Text
className={clsx(classes.title, truncateTitle && classes.truncate)}
size="subbody"
weight="bold"
>
{title}
</Text>
</div>

<Plus
className={clsx(classes.icon, isExpanded && classes.rotate)}
aria-hidden="true"
width={18}
height={18}
<button
aria-expanded={isExpanded}
aria-owns={ariaId}
className={clsx(classes.button)}
onClick={handleClick}
tabIndex={0}
>
<div className={classes.titleContainer}>
{LeadingIcon && (
<LeadingIcon
role="img"
aria-hidden
className={clsx(classes.leadingIcon, leadingIconClassName)}
width={18}
height={18}
/>
)}
<Text
className={clsx(
classes.title,
truncateTitle && classes.truncate
)}
size="subbody"
weight="bold"
>
{title}
</Text>
</div>
</button>
<Box className={secondaryHeaderClassName} align="center" gap={1}>
{secondaryHeader}
</Box>
<IconButton
aria-label="Expand/collapse"
icon={Plus}
className={clsx(classes.iconButton, isExpanded && classes.rotate)}
onClick={handleClick}
/>
</button>
</Box>
<div
aria-hidden={!isExpanded}
id={ariaId}
Expand Down

0 comments on commit ac6f8c8

Please sign in to comment.