Skip to content

Commit 3834ee1

Browse files
committed
Add AvatarPrimitiveContext for Avatar fragments
1 parent bc71437 commit 3834ee1

File tree

7 files changed

+114
-54
lines changed

7 files changed

+114
-54
lines changed
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
import { createContext } from 'react';
2+
3+
interface AvatarPrimitiveContextType {
4+
isImageLoaded: boolean;
5+
hasError: boolean;
6+
handleLoadImage: () => void;
7+
handleErrorImage: () => void;
8+
}
9+
10+
export const AvatarPrimitiveContext = createContext<AvatarPrimitiveContextType>({} as AvatarPrimitiveContextType);

src/core/primitives/Avatar/fragments/AvatarPrimitiveFallback.tsx

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,18 @@
1-
import React from 'react';
1+
import React, { useContext } from 'react';
2+
import { AvatarPrimitiveContext } from '../contexts/AvatarPrimitiveContext';
23

34
export interface AvatarPrimitiveFallbackProps {
45
children: React.ReactNode;
56
className?: string;
67
}
78

89
const AvatarPrimitiveFallback = ({ children, className = '' }: AvatarPrimitiveFallbackProps) => {
10+
const { isImageLoaded, hasError } = useContext(AvatarPrimitiveContext);
11+
12+
if (isImageLoaded || hasError) {
13+
return null;
14+
}
15+
916
return <div className={className}>{children}</div>;
1017
};
1118

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
import React, { useContext } from 'react';
2+
3+
import { AvatarPrimitiveContext } from '../contexts/AvatarPrimitiveContext';
4+
5+
export interface AvatarRootImageProps extends React.ImgHTMLAttributes<HTMLImageElement> {
6+
src?: string;
7+
alt?: string;
8+
className?: string;
9+
status?: 'loading' | 'loaded' | 'error';
10+
}
11+
12+
const AvatarPrimitiveImage = ({
13+
src,
14+
alt = 'Avatar',
15+
className = '',
16+
status = 'loading',
17+
...props
18+
}: AvatarRootImageProps) => {
19+
const { handleErrorImage, handleLoadImage } = useContext(AvatarPrimitiveContext);
20+
21+
// If there's no src or there's an error, render nothing
22+
if (!src || status === 'error') {
23+
return null;
24+
}
25+
26+
return (
27+
<img
28+
src={src}
29+
alt={alt}
30+
onError={handleErrorImage}
31+
onLoad={handleLoadImage}
32+
className={className}
33+
{...props}
34+
/>
35+
);
36+
};
37+
38+
export default AvatarPrimitiveImage;
Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,36 @@
1-
import React from 'react';
1+
import React, { useContext, useState } from 'react';
2+
3+
import { AvatarPrimitiveContext } from '../contexts/AvatarPrimitiveContext';
24

35
export interface AvatarPrimitiveRootProps {
46
children: React.ReactNode;
57
className?: string;
68
}
79

810
const AvatarPrimitiveRoot = ({ children, className = '' }: AvatarPrimitiveRootProps) => {
9-
return <div className={className}>{children}</div>;
11+
const [isImageLoaded, setIsImageLoaded] = useState(false);
12+
const [hasError, setHasError] = useState(false);
13+
14+
const handleLoadImage = () => {
15+
setIsImageLoaded(true);
16+
setHasError(false);
17+
};
18+
19+
const handleErrorImage = () => {
20+
setIsImageLoaded(false);
21+
setHasError(true);
22+
};
23+
24+
const values = {
25+
isImageLoaded,
26+
hasError,
27+
handleLoadImage,
28+
handleErrorImage
29+
};
30+
31+
return <AvatarPrimitiveContext.Provider value={values}>
32+
<div className={className}>{children}</div>
33+
</AvatarPrimitiveContext.Provider>;
1034
};
1135

1236
export default AvatarPrimitiveRoot;

src/core/primitives/Avatar/fragments/AvatarRootImage.tsx

Lines changed: 0 additions & 49 deletions
This file was deleted.
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
import AvatarPrimitiveRoot from './fragments/AvatarPrimitiveRoot';
22
import AvatarPrimitiveFallback from './fragments/AvatarPrimitiveFallback';
3-
import AvatarRootImage from './fragments/AvatarRootImage';
3+
import AvatarPrimitiveImage from './fragments/AvatarPrimitiveImage';
44

55
const AvatarPrimitive = {
66
Root: AvatarPrimitiveRoot,
77
Fallback: AvatarPrimitiveFallback,
8-
Image: AvatarRootImage
8+
Image: AvatarPrimitiveImage
99
} as const;
1010

1111
export default AvatarPrimitive;
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
import React from 'react';
2+
import AvatarPrimitive from '../index';
3+
import SandboxEditor from '~/components/tools/SandboxEditor/SandboxEditor';
4+
5+
// More on how to set up stories at: https://storybook.js.org/docs/react/writing-stories/introduction#default-export
6+
export default {
7+
title: 'Primitives/AvatarPrimitive',
8+
component: AvatarPrimitive,
9+
render: (args) => <SandboxEditor>
10+
<div >
11+
<div className='flex space-x-2 w-full flex-1'>
12+
<AvatarPrimitive.Root>
13+
<AvatarPrimitive.Image src='https://via.placeholder.com/150' alt='Avatar' />
14+
<AvatarPrimitive.Fallback>
15+
<span>AB</span>
16+
</AvatarPrimitive.Fallback>
17+
</AvatarPrimitive.Root>
18+
19+
</div>
20+
21+
</div>
22+
</SandboxEditor>
23+
};
24+
25+
// More on writing stories with args: https://storybook.js.org/docs/react/writing-stories/args
26+
export const All = {
27+
args: {
28+
29+
}
30+
};

0 commit comments

Comments
 (0)