diff --git a/src/components/dataDisplay/Typography/Typography.tsx b/src/components/dataDisplay/Typography/Typography.tsx index d210ca41..1cb999ca 100644 --- a/src/components/dataDisplay/Typography/Typography.tsx +++ b/src/components/dataDisplay/Typography/Typography.tsx @@ -69,7 +69,10 @@ Typography.propTypes = { /** * The color of the text. */ - color: PropTypes.oneOf(['initial', 'inherit', 'primary', 'secondary', 'textPrimary', 'textSecondary', 'error']), + color: PropTypes.oneOfType([ + PropTypes.oneOf(['initial', 'inherit', 'primary', 'secondary', 'textPrimary', 'textSecondary', 'error']), + PropTypes.string + ]), /** * Controls the text emphasis. Different font styles can be used individually or in combination. */ diff --git a/src/components/dataDisplay/Typography/types.ts b/src/components/dataDisplay/Typography/types.ts index 9da82080..356f61ad 100644 --- a/src/components/dataDisplay/Typography/types.ts +++ b/src/components/dataDisplay/Typography/types.ts @@ -5,7 +5,15 @@ import { TypographyProps as MuiTypographyProps } from '@mui/material' /** * The color of the text. */ -export type TypographyColor = 'initial' | 'inherit' | 'primary' | 'secondary' | 'textPrimary' | 'textSecondary' | 'error' +export type TypographyColor = + | 'initial' + | 'inherit' + | 'primary' + | 'secondary' + | 'textPrimary' + | 'textSecondary' + | 'error' + | string /** * Controls the text emphasis. Different font styles can be used individually or in combination. diff --git a/src/components/surfaces/Card/Card.tsx b/src/components/surfaces/Card/Card.tsx index a1478be9..462ccdce 100644 --- a/src/components/surfaces/Card/Card.tsx +++ b/src/components/surfaces/Card/Card.tsx @@ -45,6 +45,8 @@ const Card: React.FC = ({ icon: Icon, iconColor = 'secondary', mediaProps, + avatarProps, + headerContentProps, ...props }) => { const hasIcon = !!Icon @@ -64,7 +66,13 @@ const Card: React.FC = ({ return ( {hasHeader && ( - + )} {mediaProps && } {disablePadding ? children : } @@ -148,7 +156,17 @@ Card.propTypes = { /* * Props applied to the CardMedia component. */ - mediaProps: PropTypes.object + mediaProps: PropTypes.object, + /** + * @default {} + * Props applied to the avatar. + */ + avatarProps: PropTypes.object, + /** + * @default {} + * Props applied to the CardHeader component. + */ + headerContentProps: PropTypes.object } export default Card diff --git a/src/components/surfaces/Card/CardActions/CardActions.test.tsx b/src/components/surfaces/Card/CardActions/CardActions.test.tsx index bf147eb9..b2e41972 100644 --- a/src/components/surfaces/Card/CardActions/CardActions.test.tsx +++ b/src/components/surfaces/Card/CardActions/CardActions.test.tsx @@ -31,7 +31,7 @@ describe('CardActions', () => { ) - expect(screen.getByRole('button').parentElement).toHaveStyle('justify-content: flex-start') + expect(screen.getByRole('button').parentElement).toHaveStyle('justify-content: unset') }) it('displays actions on the right when `align` is set to `right`', () => { diff --git a/src/components/surfaces/Card/CardActions/CardActionsStyles.ts b/src/components/surfaces/Card/CardActions/CardActionsStyles.ts index 7ca3cddc..58be2e46 100644 --- a/src/components/surfaces/Card/CardActions/CardActionsStyles.ts +++ b/src/components/surfaces/Card/CardActions/CardActionsStyles.ts @@ -10,7 +10,7 @@ const contentAlignment = cond([ [equals('left'), always('flex-start')], [equals('right'), always('flex-end')], [equals('center'), always('center')], - [T, always('flex-start')] + [T, always('unset')] ]) const CardActions = styled(MuiCardActions, { diff --git a/src/components/surfaces/Card/CardHeader/CardHeaderStyles.ts b/src/components/surfaces/Card/CardHeader/CardHeaderStyles.ts index fe5a974f..4f1b44e0 100644 --- a/src/components/surfaces/Card/CardHeader/CardHeaderStyles.ts +++ b/src/components/surfaces/Card/CardHeader/CardHeaderStyles.ts @@ -4,33 +4,52 @@ import { styled } from '@mui/material/styles' import { includes } from 'ramda' import { CardColor } from '../types' -type StyledProps = { theme: Theme; filled: boolean; hasIcon: boolean; iconColor: CardColor } +type StyledProps = { + theme: Theme + filled: boolean + hasIcon: boolean + iconColor: CardColor + avatarProps: any + headerContentProps: any +} const CardHeader = styled(MuiCardHeader, { - shouldForwardProp: prop => !includes(prop, ['variant', 'hasIcon', 'iconColor', 'filled']) -})(({ theme, filled, hasIcon, iconColor = 'secondary' as CardColor & keyof Palette }: Partial) => ({ - ['&.MuiCardHeader-root']: { - ...(filled && { backgroundColor: theme?.palette.grey[200], minHeight: '48px' }) - }, - ['& .MuiCardHeader-avatar']: { - ...(hasIcon && { - width: '3rem', - height: '3rem', - borderRadius: '0.75rem', - background: `linear-gradient(195deg, ${theme?.palette[iconColor].light}, ${theme?.palette[iconColor].main})`, - position: 'absolute', - top: '-20px' - }) - }, - ['& .MuiCardHeader-content']: { - ...(hasIcon && { - paddingLeft: '80px' - }) - }, - ['& .MuiCardHeader-action']: { - display: 'flex', - alignItems: 'center' - } -})) + shouldForwardProp: prop => + !includes(prop, ['variant', 'hasIcon', 'iconColor', 'filled', 'avatarProps', 'headerContentProps']) +})( + ({ + theme, + filled, + hasIcon, + iconColor = 'secondary' as CardColor & keyof Palette, + avatarProps, + headerContentProps + }: Partial) => ({ + ['&.MuiCardHeader-root']: { + ...(filled && { backgroundColor: theme?.palette.grey[200], minHeight: '48px' }) + }, + ['& .MuiCardHeader-avatar']: { + ...(hasIcon && { + width: '3rem', + height: '3rem', + borderRadius: '0.75rem', + background: `linear-gradient(195deg, ${theme?.palette[iconColor].light}, ${theme?.palette[iconColor].main})`, + position: 'absolute', + top: '-20px', + ...avatarProps + }) + }, + ['& .MuiCardHeader-content']: { + ...(hasIcon && { + paddingLeft: '80px' + }), + ...headerContentProps + }, + ['& .MuiCardHeader-action']: { + display: 'flex', + alignItems: 'center' + } + }) +) export default CardHeader diff --git a/src/components/surfaces/Card/types.ts b/src/components/surfaces/Card/types.ts index 8d8776df..da03082f 100644 --- a/src/components/surfaces/Card/types.ts +++ b/src/components/surfaces/Card/types.ts @@ -5,7 +5,7 @@ import { CardProps as MuiCardProps, CardContentProps as MuiCardContentProps } from '@mui/material' -import { ElementType } from 'react' +import { ElementType, HTMLAttributes } from 'react' import { SvgIconComponent } from '@mui/icons-material' import { Color } from '../../types' @@ -62,6 +62,14 @@ export interface CardHeaderProps extends Omit { * Icon color. */ iconColor?: CardColor + /** + * Props applied to the avatar. + */ + avatarProps?: HTMLAttributes + /** + * Style applied to the header content. + */ + headerContentProps?: HTMLAttributes } export interface CardProps extends Omit { @@ -134,4 +142,12 @@ export interface CardProps extends Omit { * Props applied to the CardContent component */ contentProps?: MuiCardContentProps + /** + * Props applied to the avatar. + */ + avatarProps?: HTMLAttributes + /** + * Style applied to the header content. + */ + headerContentProps?: HTMLAttributes } diff --git a/src/stories/surfaces/Card/Card.stories.tsx b/src/stories/surfaces/Card/Card.stories.tsx index 1c76fc29..5ee0a698 100644 --- a/src/stories/surfaces/Card/Card.stories.tsx +++ b/src/stories/surfaces/Card/Card.stories.tsx @@ -34,7 +34,6 @@ const subheader = 'Subheader' const children = 'Cards are surfaces that display content and actions on a single topic. They should be easy to scan for relevant and actionable information. Elements, like text and images, should be placed on them in a way that clearly indicates hierarchy. Although cards can support multiple actions, UI controls, and an overflow menu, use restraint and remember that cards are entry points to more complex and detailed information.' const footer = - const actions = ( @@ -58,7 +57,7 @@ export const Card: Story = { children={--Text content here--} icon={People} footer={} - action={ + actions={ @@ -113,8 +112,8 @@ export const Filled: Story = { /** * Examples of cards using images, video or audio files to reinforce the content. - * - * By default, we use the combination of a `
` element and a background image to display the media. + * + * By default, we use the combination of a `
` element and a background image to display the media. * It can be problematic in some situations, for example, you might want to display a video or a responsive image. Use the component prop for these use cases: */ export const Media: Story = {