1010 * governing permissions and limitations under the License.
1111 */
1212
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' ;
1414import 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' ;
1715import type { Meta } from '@storybook/react' ;
1816import { style } from '../style/spectrum-theme' with { type : 'macro' } ;
19- import { useAsyncList } from 'react-stately' ;
2017
2118const meta : Meta < typeof CardView > = {
2219 component : CardView ,
@@ -44,120 +41,6 @@ const cardViewStyles = style({
4441 }
4542} ) ;
4643
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-
16144export const Empty = ( args : CardViewProps < any > , { viewMode} ) => {
16245 return (
16346 < CardView
@@ -175,84 +58,3 @@ export const Empty = (args: CardViewProps<any>, {viewMode}) => {
17558 </ CardView >
17659 ) ;
17760} ;
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