10
10
* governing permissions and limitations under the License.
11
11
*/
12
12
13
- import { ActionMenu , Avatar , Card , CardPreview , CardView , CardViewProps , Collection , CollectionCardPreview , Content , Heading , IllustratedMessage , Image , MenuItem , SkeletonCollection , Text } from '../src' ;
13
+ import { CardView , CardViewProps , Content , Heading , IllustratedMessage } from '../src' ;
14
14
import EmptyIcon from 'illustration:../spectrum-illustrations/gradient/S2_fill_image_generic1_160.svg' ;
15
- import ErrorIcon from '../spectrum-illustrations/linear/AlertNotice' ;
16
- import Folder from '../s2wf-icons/S2_Icon_Folder_20_N.svg' ;
17
15
import type { Meta } from '@storybook/react' ;
18
16
import { style } from '../style/spectrum-theme' with { type : 'macro' } ;
19
- import { useAsyncList } from 'react-stately' ;
20
17
21
18
const meta : Meta < typeof CardView > = {
22
19
component : CardView ,
@@ -44,120 +41,6 @@ const cardViewStyles = style({
44
41
}
45
42
} ) ;
46
43
47
- type Item = {
48
- id : number ,
49
- user : {
50
- name : string ,
51
- profile_image : { small : string }
52
- } ,
53
- urls : { regular : string } ,
54
- description : string ,
55
- alt_description : string ,
56
- width : number ,
57
- height : number
58
- } ;
59
-
60
- const avatarSize = {
61
- XS : 16 ,
62
- S : 20 ,
63
- M : 24 ,
64
- L : 28 ,
65
- XL : 32
66
- } as const ;
67
-
68
- function PhotoCard ( { item, layout} : { item : Item , layout : string } ) {
69
- return (
70
- < Card id = { item . id } textValue = { item . description || item . alt_description } >
71
- { ( { size} ) => ( < >
72
- < CardPreview >
73
- < Image
74
- src = { item . urls . regular }
75
- styles = { style ( {
76
- width : 'full' ,
77
- pointerEvents : 'none'
78
- } ) }
79
- // TODO - should we have a safe `dynamicStyles` or something for this?
80
- UNSAFE_style = { {
81
- aspectRatio : layout === 'waterfall' ? `${ item . width } / ${ item . height } ` : '4/3' ,
82
- objectFit : layout === 'waterfall' ? 'contain' : 'cover'
83
- } }
84
- renderError = { ( ) => (
85
- < div className = { style ( { display : 'flex' , alignItems : 'center' , justifyContent : 'center' , size : 'full' } ) } >
86
- < ErrorIcon size = "S" />
87
- </ div >
88
- ) } />
89
- </ CardPreview >
90
- < Content >
91
- < Text slot = "title" > { item . description || item . alt_description } </ Text >
92
- { size !== 'XS' && < ActionMenu >
93
- < MenuItem > Test</ MenuItem >
94
- </ ActionMenu > }
95
- < div className = { style ( { display : 'flex' , alignItems : 'center' , gap : 8 , gridArea : 'description' } ) } >
96
- < Avatar src = { item . user . profile_image . small } size = { avatarSize [ size ] } />
97
- < Text slot = "description" > { item . user . name } </ Text >
98
- </ div >
99
- </ Content >
100
- </ > ) }
101
- </ Card >
102
- ) ;
103
- }
104
-
105
- export const Example = ( args : CardViewProps < any > , { viewMode} ) => {
106
- let list = useAsyncList < Item , number | null > ( {
107
- async load ( { signal, cursor, items} ) {
108
- let page = cursor || 1 ;
109
- let res = await fetch (
110
- `https://api.unsplash.com/topics/nature/photos?page=${ page } &per_page=30&client_id=AJuU-FPh11hn7RuumUllp4ppT8kgiLS7LtOHp_sp4nc` ,
111
- { signal}
112
- ) ;
113
- let nextItems = await res . json ( ) ;
114
- // Filter duplicates which might be returned by the API.
115
- let existingKeys = new Set ( items . map ( i => i . id ) ) ;
116
- nextItems = nextItems . filter ( i => ! existingKeys . has ( i . id ) && ( i . description || i . alt_description ) ) ;
117
- return { items : nextItems , cursor : nextItems . length ? page + 1 : null } ;
118
- }
119
- } ) ;
120
-
121
- let loadingState = args . loadingState === 'idle' ? list . loadingState : args . loadingState ;
122
- let items = loadingState === 'loading' ? [ ] : list . items ;
123
-
124
- return (
125
- < CardView
126
- aria-label = "Nature photos"
127
- { ...args }
128
- loadingState = { loadingState }
129
- onLoadMore = { args . loadingState === 'idle' ? list . loadMore : undefined }
130
- styles = { cardViewStyles ( { viewMode} ) } >
131
- < Collection items = { items } dependencies = { [ args . layout ] } >
132
- { item => < PhotoCard item = { item } layout = { args . layout || 'grid' } /> }
133
- </ Collection >
134
- { ( loadingState === 'loading' || loadingState === 'loadingMore' ) && (
135
- < SkeletonCollection >
136
- { ( ) => (
137
- < PhotoCard
138
- item = { {
139
- id : Math . random ( ) ,
140
- user : { name : 'Devon Govett' , profile_image : { small : '' } } ,
141
- urls : { regular : '' } ,
142
- description : 'This is a fake description. Kinda long so it wraps to a new line.' ,
143
- alt_description : '' ,
144
- width : 400 ,
145
- height : 200 + Math . max ( 0 , Math . round ( Math . random ( ) * 400 ) )
146
- } }
147
- layout = { args . layout || 'grid' } />
148
- ) }
149
- </ SkeletonCollection >
150
- ) }
151
- </ CardView >
152
- ) ;
153
- } ;
154
-
155
- Example . args = {
156
- loadingState : 'idle' ,
157
- onAction : null ,
158
- selectionMode : 'multiple'
159
- } ;
160
-
161
44
export const Empty = ( args : CardViewProps < any > , { viewMode} ) => {
162
45
return (
163
46
< CardView
@@ -175,84 +58,3 @@ export const Empty = (args: CardViewProps<any>, {viewMode}) => {
175
58
</ CardView >
176
59
) ;
177
60
} ;
178
-
179
- interface Topic {
180
- id : string ,
181
- title : string ,
182
- total_photos : number ,
183
- links : { html : string } ,
184
- preview_photos : { id : string , urls : { small : string } } [ ]
185
- }
186
-
187
- function TopicCard ( { topic} : { topic : Topic } ) {
188
- return (
189
- < Card href = { topic . links . html } target = "_blank" textValue = { topic . title } >
190
- < CollectionCardPreview >
191
- { topic . preview_photos . slice ( 0 , 4 ) . map ( photo => (
192
- < Image key = { photo . id } alt = "" src = { photo . urls . small } />
193
- ) ) }
194
- </ CollectionCardPreview >
195
- < Content >
196
- < Text slot = "title" > { topic . title } </ Text >
197
- < div className = { style ( { display : 'flex' , alignItems : 'center' , gap : 8 } ) } >
198
- < Folder />
199
- < Text slot = "description" > { topic . total_photos . toLocaleString ( ) } photos</ Text >
200
- </ div >
201
- </ Content >
202
- </ Card >
203
- ) ;
204
- }
205
-
206
- export const CollectionCards = ( args : CardViewProps < any > , { viewMode} ) => {
207
- let list = useAsyncList < Topic , number | null > ( {
208
- async load ( { signal, cursor} ) {
209
- let page = cursor || 1 ;
210
- let res = await fetch (
211
- `https://api.unsplash.com/topics?page=${ page } &per_page=30&client_id=AJuU-FPh11hn7RuumUllp4ppT8kgiLS7LtOHp_sp4nc` ,
212
- { signal}
213
- ) ;
214
- let items = ( await res . json ( ) ) . filter ( ( topic : Topic ) => ! ! topic . preview_photos ) ;
215
- return { items, cursor : items . length ? page + 1 : null } ;
216
- }
217
- } ) ;
218
-
219
- let loadingState = args . loadingState === 'idle' ? list . loadingState : args . loadingState ;
220
- let items = loadingState === 'loading' ? [ ] : list . items ;
221
-
222
- return (
223
- < CardView
224
- aria-label = "Topics"
225
- { ...args }
226
- loadingState = { loadingState }
227
- onLoadMore = { args . loadingState === 'idle' ? list . loadMore : undefined }
228
- styles = { cardViewStyles ( { viewMode} ) } >
229
- < Collection items = { items } >
230
- { topic => < TopicCard topic = { topic } /> }
231
- </ Collection >
232
- { ( loadingState === 'loading' || loadingState === 'loadingMore' ) && (
233
- < SkeletonCollection >
234
- { ( ) => (
235
- < TopicCard
236
- topic = { {
237
- id : Math . random ( ) . toString ( 36 ) ,
238
- title : 'Topic title' ,
239
- total_photos : 80 ,
240
- links : { html : '' } ,
241
- preview_photos : [
242
- { id : 'a' , urls : { small : '' } } ,
243
- { id : 'b' , urls : { small : '' } } ,
244
- { id : 'c' , urls : { small : '' } } ,
245
- { id : 'd' , urls : { small : '' } }
246
- ]
247
- } } />
248
- ) }
249
- </ SkeletonCollection >
250
- ) }
251
- </ CardView >
252
- ) ;
253
- } ;
254
-
255
- CollectionCards . args = {
256
- loadingState : 'idle' ,
257
- onAction : null
258
- } ;
0 commit comments