@@ -4,6 +4,7 @@ import React, {
4
4
Children ,
5
5
ImgHTMLAttributes ,
6
6
isValidElement ,
7
+ CSSProperties ,
7
8
} from "react"
8
9
import styled from "@emotion/styled"
9
10
import { theme } from "../ThemeProvider/ThemeProvider"
@@ -81,22 +82,31 @@ const Info = styled.div<{ size?: Size }>`
81
82
margin-bottom: ${ ( { size } ) => ( size === "small" ? 4 : 8 ) } px;
82
83
`
83
84
84
- const Title = styled . h3 < { size ?: Size } > `
85
+ const Title = styled . h3 < { lines ?: number ; size ?: Size } > `
85
86
text-overflow: ellipsis;
86
- height: ${ ( { size } ) => theme . typography . pxToRem ( size === "small" ? 36 : 60 ) } ;
87
+ height: ${ ( { lines, size } ) => {
88
+ const lineHeightPx = size === "small" ? 18 : 20
89
+ lines = lines ?? ( size === "small" ? 2 : 3 )
90
+ return theme . typography . pxToRem ( lines * lineHeightPx )
91
+ } } ;
87
92
overflow: hidden;
88
93
margin: 0;
89
94
90
95
${ ( { size } ) =>
91
96
size === "small"
92
97
? { ...theme . typography . subtitle2 }
93
98
: { ...theme . typography . subtitle1 } }
94
- @supports (-webkit-line-clamp: ${ ( { size } ) => ( size === "small" ? 2 : 3 ) } ) {
95
- white-space: initial;
96
- display: -webkit-box;
97
- -webkit-line-clamp: ${ ( { size } ) => ( size === "small" ? 2 : 3 ) } ;
98
- -webkit-box-orient: vertical;
99
- }
99
+
100
+ ${ ( { lines, size } ) => {
101
+ lines = lines ?? ( size === "small" ? 2 : 3 )
102
+ return `
103
+ @supports (-webkit-line-clamp: ${ lines } ) {
104
+ white-space: initial;
105
+ display: -webkit-box;
106
+ -webkit-line-clamp: ${ lines } ;
107
+ -webkit-box-orient: vertical;
108
+ }`
109
+ } }
100
110
`
101
111
102
112
const Footer = styled . span `
@@ -134,17 +144,34 @@ type CardProps = {
134
144
size ?: Size
135
145
href ?: string
136
146
}
147
+
148
+ type ImageProps = ImgHTMLAttributes < HTMLImageElement > & {
149
+ size ?: Size
150
+ style ?: CSSProperties
151
+ }
152
+ type TitleProps = {
153
+ children ?: ReactNode
154
+ lines ?: number
155
+ style ?: CSSProperties
156
+ }
157
+ type SlotProps = { children ?: ReactNode ; style ?: CSSProperties }
158
+
137
159
type Card = FC < CardProps > & {
138
160
Content : FC < { children : ReactNode } >
139
- Image : FC < ImgHTMLAttributes < HTMLImageElement > | { size ?: Size } >
140
- Info : FC < { children : ReactNode } >
141
- Title : FC < { children : ReactNode ; size ?: Size } >
142
- Footer : FC < { children : ReactNode } >
143
- Actions : FC < { children : ReactNode } >
161
+ Image : FC < ImageProps >
162
+ Info : FC < SlotProps >
163
+ Title : FC < TitleProps >
164
+ Footer : FC < SlotProps >
165
+ Actions : FC < SlotProps >
144
166
}
145
167
146
168
const Card : Card = ( { children, className, size, href } ) => {
147
- let content , imageProps , info , title , footer , actions
169
+ let content ,
170
+ image : ImageProps = { } ,
171
+ info : SlotProps = { } ,
172
+ title : TitleProps = { } ,
173
+ footer : SlotProps = { } ,
174
+ actions : SlotProps = { }
148
175
149
176
const _Container = href ? LinkContainer : Container
150
177
@@ -164,11 +191,11 @@ const Card: Card = ({ children, className, size, href }) => {
164
191
Children . forEach ( children , ( child ) => {
165
192
if ( ! isValidElement ( child ) ) return
166
193
if ( child . type === Content ) content = child . props . children
167
- else if ( child . type === Image ) imageProps = child . props
168
- else if ( child . type === Info ) info = child . props . children
169
- else if ( child . type === Title ) title = child . props . children
170
- else if ( child . type === Footer ) footer = child . props . children
171
- else if ( child . type === Actions ) actions = child . props . children
194
+ else if ( child . type === Image ) image = child . props
195
+ else if ( child . type === Info ) info = child . props
196
+ else if ( child . type === Title ) title = child . props
197
+ else if ( child . type === Footer ) footer = child . props
198
+ else if ( child . type === Actions ) actions = child . props
172
199
} )
173
200
174
201
if ( content ) {
@@ -184,21 +211,27 @@ const Card: Card = ({ children, className, size, href }) => {
184
211
return (
185
212
< Wrapper className = { className } size = { size } >
186
213
< _Container to = { href ! } >
187
- { imageProps && (
214
+ { image && (
188
215
< Image
189
216
size = { size }
190
- { ...( imageProps as ImgHTMLAttributes < HTMLImageElement > ) }
217
+ { ...( image as ImgHTMLAttributes < HTMLImageElement > ) }
191
218
/>
192
219
) }
193
220
< Body >
194
- { info && < Info size = { size } > { info } </ Info > }
195
- < Title size = { size } > { title } </ Title >
221
+ { info . children && (
222
+ < Info size = { size } { ...info } >
223
+ { info . children }
224
+ </ Info >
225
+ ) }
226
+ < Title size = { size } { ...title } >
227
+ { title . children }
228
+ </ Title >
196
229
</ Body >
197
230
< Bottom >
198
- < Footer > { footer } </ Footer >
231
+ < Footer { ... footer } > { footer . children } </ Footer >
199
232
</ Bottom >
200
233
</ _Container >
201
- { actions && < Actions > { actions } </ Actions > }
234
+ { actions . children && < Actions { ... actions } > { actions . children } </ Actions > }
202
235
</ Wrapper >
203
236
)
204
237
}
0 commit comments