Skip to content
This repository was archived by the owner on Mar 25, 2025. It is now read-only.

Commit e882d22

Browse files
author
Anton
authored
feat(card)!: refactors CardHeader to use only ReactNode (#26)
BEAKING CHANGE: - Refactors the `CardHeader` to use only `ReactNode` in order to allow easier placement of the content without the need for many confusing props. - Adds `CardHeaderTypography` component for the header text. - Adds `CardSubHeaderTypography` component for the subheader text. - Adds examples in `.mdx` files for how to implelement previous examples.
1 parent 7ffe563 commit e882d22

File tree

3 files changed

+132
-168
lines changed

3 files changed

+132
-168
lines changed

packages/core/src/Card/CardHeader.tsx

Lines changed: 22 additions & 124 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,19 @@
11
import React, { useCallback } from 'react'
22
import styled, { css } from 'styled-components'
3-
import { MoreVertIcon } from 'practical-react-components-icons'
43

54
import { CARD_PADDING } from './padding'
6-
import { Typography } from '../Typography'
75
import { Arrow } from '../Expandable'
8-
import { Menu, IMenuItem } from '../Menu'
6+
import { Typography } from '../Typography'
97
import { spacing } from '../designparams'
108

119
export type CardHeaderHeightType = 'small' | 'normal' | 'large'
1210
type BaseElement = HTMLDivElement
1311
type BaseProps = React.HTMLAttributes<BaseElement>
1412

15-
const HEADER_HEIGHT = {
16-
small: '40px',
17-
normal: '48px',
18-
large: '60px',
19-
}
20-
21-
const ICON_CONTAINER_WIDTH = '72px'
22-
2313
/**
2414
* Empty header with just a bottom border
2515
*/
26-
export const EmptyHeader = styled.div`
16+
export const BaseHeader = styled.div`
2717
flex: none;
2818
box-sizing: border-box;
2919
width: 100%;
@@ -32,37 +22,14 @@ export const EmptyHeader = styled.div`
3222
border-bottom: 1px solid ${({ theme }) => theme.color.element12()};
3323
`
3424

35-
interface ITitleHeaderProps {
36-
readonly height: CardHeaderHeightType
37-
readonly hasIcon: boolean
38-
}
39-
40-
const TitleHeader = styled(EmptyHeader)<ITitleHeaderProps>`
41-
position: relative; /* This is for special icon like corner triangle */
25+
const TitleHeader = styled(BaseHeader)`
4226
display: flex;
4327
flex-direction: row;
4428
flex-wrap: nowrap;
4529
align-items: center;
46-
height: ${({ height }) => HEADER_HEIGHT[height]};
4730
cursor: default;
48-
49-
${({ hasIcon }) =>
50-
hasIcon
51-
? css`
52-
padding-right: ${CARD_PADDING};
53-
`
54-
: css`
55-
padding: 0 ${CARD_PADDING};
56-
`}
57-
`
58-
59-
const HeaderIcon = styled.div`
60-
width: ${ICON_CONTAINER_WIDTH};
61-
height: 100%;
62-
display: flex;
63-
align-items: center;
64-
justify-content: center;
65-
color: ${({ theme }) => theme.color.element11()};
31+
height: auto;
32+
padding: ${spacing.medium} ${CARD_PADDING};
6633
`
6734

6835
const TitleContainer = styled.div`
@@ -74,95 +41,36 @@ const TitleContainer = styled.div`
7441
text-overflow: ellipsis;
7542
`
7643

77-
interface ITabsHeaderContainerProps extends Pick<ITitleHeaderProps, 'height'> {}
44+
export const CardHeaderTypography = styled(Typography).attrs({
45+
variant: 'card-title',
46+
})``
7847

79-
/* Header container for inside tabs */
80-
export const TabsHeaderContainer = styled(
81-
EmptyHeader
82-
)<ITabsHeaderContainerProps>`
83-
display: flex;
84-
flex-direction: row;
85-
flex-wrap: nowrap;
86-
align-items: center;
87-
height: ${({ height }) => HEADER_HEIGHT[height]};
88-
padding: 0 ${spacing.large};
89-
`
48+
export const CardSubHeaderTypography = styled(Typography).attrs({
49+
variant: 'caption',
50+
})``
9051

91-
export interface ICardHeaderProps extends BaseProps {
92-
/**
93-
* Label that shows inside Card Header
94-
*/
95-
readonly header: string
96-
/**
97-
* Small label that shows inside Card Header under header label
98-
*/
99-
readonly subhead?: string
100-
/**
101-
* Header height
102-
*
103-
* Default: `normal`
104-
*/
105-
readonly height?: CardHeaderHeightType
106-
/**
107-
* Optional icon
108-
*/
109-
readonly icon?: React.ReactNode
52+
export interface CardHeaderProps extends BaseProps {
11053
/**
111-
* Menu items that shows inside menu
54+
* `class` to be passed to the component.
11255
*/
113-
readonly menu?: ReadonlyArray<IMenuItem>
114-
/**
115-
* if `true` return a header for inside tabs.
116-
*
117-
* Default: `false`
118-
*/
119-
readonly tab?: boolean
56+
readonly className?: string
12057
}
12158

122-
export const CardHeader: React.FC<ICardHeaderProps> = ({
123-
header,
124-
subhead,
125-
height = 'normal',
126-
icon,
127-
menu,
128-
tab = false,
59+
export const CardHeader: React.FC<CardHeaderProps> = ({
12960
children,
13061
...props
131-
}) => {
132-
const hasIcon = icon !== undefined
133-
134-
if (tab) {
135-
return (
136-
<TabsHeaderContainer height={height} {...props}>
137-
{children}
138-
</TabsHeaderContainer>
139-
)
140-
}
141-
142-
return (
143-
<TitleHeader height={height} hasIcon={hasIcon} {...props}>
144-
{icon !== undefined ? <HeaderIcon>{icon}</HeaderIcon> : undefined}
145-
<TitleContainer>
146-
<Typography variant="card-title">{header}</Typography>
147-
<Typography variant="caption">{subhead}</Typography>
148-
</TitleContainer>
149-
{menu !== undefined ? (
150-
<Menu icon={MoreVertIcon} items={menu} />
151-
) : undefined}
152-
</TitleHeader>
153-
)
154-
}
62+
}) => <TitleHeader {...props}>{children}</TitleHeader>
15563

15664
/**
15765
* Expandable header
15866
*/
15967

160-
interface IExpandableTitleHeaderProps {
68+
interface ExpandableTitleHeaderProps {
16169
readonly expanded: boolean
16270
readonly disabled: boolean
16371
}
16472

165-
const ExpandableTitleHeader = styled(TitleHeader)<IExpandableTitleHeaderProps>`
73+
const ExpandableTitleHeader = styled(TitleHeader)<ExpandableTitleHeaderProps>`
16674
cursor: ${({ disabled }) => (disabled ? undefined : 'pointer')};
16775
16876
${({ expanded }) =>
@@ -174,23 +82,19 @@ const ExpandableTitleHeader = styled(TitleHeader)<IExpandableTitleHeaderProps>`
17482
: undefined};
17583
`
17684

177-
export interface ICardExpandableHeaderProps extends ICardHeaderProps {
85+
export interface CardExpandableHeaderProps extends CardHeaderProps {
17886
readonly disabled?: boolean
17987
readonly expanded?: boolean
18088
readonly onToggle: (expanded: boolean) => void
18189
}
18290

183-
export const CardExpandableHeader: React.FC<ICardExpandableHeaderProps> = ({
184-
header,
185-
subhead,
186-
height = 'normal',
187-
icon,
91+
export const CardExpandableHeader: React.FC<CardExpandableHeaderProps> = ({
18892
disabled = false,
18993
expanded = false,
19094
onToggle,
95+
children,
19196
...props
19297
}) => {
193-
const hasIcon = icon !== undefined
19498
const onClick = useCallback<React.MouseEventHandler<HTMLDivElement>>(() => {
19599
if (!disabled) {
196100
onToggle(!expanded)
@@ -199,18 +103,12 @@ export const CardExpandableHeader: React.FC<ICardExpandableHeaderProps> = ({
199103

200104
return (
201105
<ExpandableTitleHeader
202-
height={height}
203106
disabled={disabled}
204107
expanded={expanded}
205108
onClick={onClick}
206-
hasIcon={hasIcon}
207109
{...props}
208110
>
209-
{icon !== undefined ? <HeaderIcon>{icon}</HeaderIcon> : undefined}
210-
<TitleContainer>
211-
<Typography variant="card-title">{header}</Typography>
212-
<Typography variant="caption">{subhead}</Typography>
213-
</TitleContainer>
111+
<TitleContainer>{children}</TitleContainer>
214112
<Arrow disabled={disabled} expanded={expanded} />
215113
</ExpandableTitleHeader>
216114
)

0 commit comments

Comments
 (0)