From ce945f265641bf7d0f1b090ab9e2648e0fb6ca34 Mon Sep 17 00:00:00 2001
From: anuradha9712
Date: Wed, 27 Nov 2024 14:46:24 +0400
Subject: [PATCH] feat(avatar): add presence indicator support in avatar
component
---
core/components/atoms/avatar/Avatar.tsx | 45 +-
.../avatar/__stories__/Presence.story.jsx | 36 +
.../atoms/avatar/__tests__/Avatar.test.tsx | 41 +-
.../__snapshots__/Avatar.test.tsx.snap | 1204 +++++++-----
.../__snapshots__/AvatarIcon.test.tsx.snap | 936 +++++----
.../__snapshots__/AvatarImage.test.tsx.snap | 132 +-
.../__snapshots__/AvatarGroup.test.tsx.snap | 332 ++--
.../AvatarSelection.test.tsx.snap | 1750 ++++++++++-------
.../__tests__/__snapshots__/TS.test.tsx.snap | 30 +-
css/src/components/avatar.css | 17 +
10 files changed, 2611 insertions(+), 1912 deletions(-)
create mode 100644 core/components/atoms/avatar/__stories__/Presence.story.jsx
diff --git a/core/components/atoms/avatar/Avatar.tsx b/core/components/atoms/avatar/Avatar.tsx
index 5e4e54fd61..489cb2d988 100644
--- a/core/components/atoms/avatar/Avatar.tsx
+++ b/core/components/atoms/avatar/Avatar.tsx
@@ -8,6 +8,8 @@ import AvatarIcon from './avatarIcon';
import AvatarImage from './avatarImage';
import AvatarProvider from './AvatarProvider';
+type TPresence = 'active' | 'away';
+
export interface AvatarProps extends BaseProps {
/**
* Color of the `Avatar`
@@ -57,6 +59,14 @@ export interface AvatarProps extends BaseProps {
* Defines tabIndex of the `Avatar`
*/
tabIndex?: number;
+ /**
+ * Show presence indicator for the `Avatar`
+ */
+ presence?: TPresence;
+ /**
+ * Stroke color of `Presence indicator` & `Status indicator` in `Avatar`
+ */
+ strokeColor?: string;
}
const initialsLength = 2;
@@ -77,6 +87,8 @@ export const Avatar = (props: AvatarProps) => {
disabled,
tooltipSuffix,
tabIndex,
+ presence,
+ strokeColor,
role = 'presentation',
} = props;
@@ -99,6 +111,7 @@ export const Avatar = (props: AvatarProps) => {
appearance || colors[(initials.charCodeAt(0) + (initials.charCodeAt(1) || 0)) % 8] || DefaultAppearance;
const darkAppearance = ['secondary', 'success', 'warning', 'accent1', 'accent4'];
+ const showPresence = presence && !disabled && shape === 'round';
const AvatarClassNames = classNames(
{
@@ -127,6 +140,16 @@ export const Avatar = (props: AvatarProps) => {
['Avatar-content']: darkAppearance.includes(AvatarAppearance),
});
+ const presenceClassNames = classNames({
+ ['Avatar-presence']: presence,
+ ['Avatar-presence--active']: presence === 'active',
+ ['Avatar-presence--away']: presence === 'away',
+ });
+
+ const borderStyle = {
+ boxShadow: `0 0 0 var(--spacing-s) ${strokeColor}`,
+ };
+
const sharedProp = {
size,
firstName,
@@ -180,17 +203,20 @@ export const Avatar = (props: AvatarProps) => {
);
};
- const renderTooltip = () => {
- if (withTooltip && initials) {
- return (
-
+ const renderTooltip = () => (
+
+ {withTooltip && initials ? (
+
{renderAvatar()}
- );
- }
-
- return renderAvatar();
- };
+ ) : (
+ renderAvatar()
+ )}
+ {showPresence && (
+
+ )}
+
+ );
return renderTooltip();
};
@@ -205,6 +231,7 @@ Avatar.defaultProps = {
withTooltip: true,
size: 'regular',
shape: 'round',
+ strokeColor: 'var(--white)',
};
export default Avatar;
diff --git a/core/components/atoms/avatar/__stories__/Presence.story.jsx b/core/components/atoms/avatar/__stories__/Presence.story.jsx
new file mode 100644
index 0000000000..bafe97f20f
--- /dev/null
+++ b/core/components/atoms/avatar/__stories__/Presence.story.jsx
@@ -0,0 +1,36 @@
+import * as React from 'react';
+import { Avatar, Row, Column, Text } from '@/index';
+
+// CSF format story
+export const presence = () => {
+ const weight = 'strong';
+
+ return (
+
+
+ Active
+
+
+
+
+
+ Away
+
+
+
+
+
+ );
+};
+
+export default {
+ title: 'Components/Avatar/Avatar/Presence',
+ component: Avatar,
+ parameters: {
+ docs: {
+ docPage: {
+ title: 'Avatar',
+ },
+ },
+ },
+};
diff --git a/core/components/atoms/avatar/__tests__/Avatar.test.tsx b/core/components/atoms/avatar/__tests__/Avatar.test.tsx
index cf7279134d..51d743e69b 100644
--- a/core/components/atoms/avatar/__tests__/Avatar.test.tsx
+++ b/core/components/atoms/avatar/__tests__/Avatar.test.tsx
@@ -1,5 +1,5 @@
import * as React from 'react';
-import { fireEvent, render } from '@testing-library/react';
+import { fireEvent, render, screen } from '@testing-library/react';
import Avatar, { AvatarProps as Props } from '../Avatar';
import { AccentAppearance, AvatarShape, AvatarSize } from '@/common.type';
import { testHelper, filterUndefined, valueHelper, testMessageHelper } from '@/utils/testHelper';
@@ -231,3 +231,42 @@ describe('Avatar component with tooltip', () => {
expect(tooltip).toHaveTextContent('John Doe (Deactivated)');
});
});
+
+describe('Avatar component with prop:presence', () => {
+ it('presence should be available for only round avatar', () => {
+ const { getByTestId } = render();
+ const presenceEle = getByTestId('DesignSystem-Avatar--Presence');
+ expect(presenceEle).toBeInTheDocument();
+ expect(presenceEle).toHaveClass('Avatar-presence');
+ });
+
+ it('presence should not be available for square avatar', () => {
+ render();
+ const presenceEle = screen.queryByText('DesignSystem-Avatar--Presence');
+ expect(presenceEle).not.toBeInTheDocument();
+ });
+
+ it('presence should not be available for disabled avatar', () => {
+ render();
+ const presenceEle = screen.queryByText('DesignSystem-Avatar--Presence');
+ expect(presenceEle).not.toBeInTheDocument();
+ });
+
+ it('presence should have active class for prop presence:active', () => {
+ const { getByTestId } = render();
+ const presenceEle = getByTestId('DesignSystem-Avatar--Presence');
+ expect(presenceEle).toHaveClass('Avatar-presence--active');
+ });
+
+ it('presence should have active class for prop presence:away', () => {
+ const { getByTestId } = render();
+ const presenceEle = getByTestId('DesignSystem-Avatar--Presence');
+ expect(presenceEle).toHaveClass('Avatar-presence--away');
+ });
+
+ it('presence should have custom stroke color', () => {
+ const { getByTestId } = render();
+ const presenceEle = getByTestId('DesignSystem-Avatar--Presence');
+ expect(presenceEle).toHaveStyle('box-shadow: 0 0 0 var(--spacing-s) red');
+ });
+});
diff --git a/core/components/atoms/avatar/__tests__/__snapshots__/Avatar.test.tsx.snap b/core/components/atoms/avatar/__tests__/__snapshots__/Avatar.test.tsx.snap
index c61690820e..eae3cd0c62 100644
--- a/core/components/atoms/avatar/__tests__/__snapshots__/Avatar.test.tsx.snap
+++ b/core/components/atoms/avatar/__tests__/__snapshots__/Avatar.test.tsx.snap
@@ -7,6 +7,39 @@ Object {
"asFragment": [Function],
"baseElement":
+
+
+
+
+
+
+ JD
+
+
+
+
+
+
+ ,
+ "container":
-
+
+
+
+
+
+
+ JD
+
+
+
+
+
+
+
+
+
+
+
+
+
+ JD
+
+
+
+
+
+
+
+
+
+
+
+
+
+ JD
+
+
+
+
+
+
+
+
+
+
+
+
+
+ JD
+
+
+
+
+
+
+
+
+
+
+
+
+
+ JD
+
+
+
+
+
+
+
+
+
+
+
+
+
+ JD
+
+
+
+
+
+
+
+
+
+
+
+
+
+ JD
+
+
+
+
+
+
+
+
+
+
+
+
+
+ JD
+
+
+
+
+
+
+
+
+
+
+
+
+
+ JD
+
+
+
+
+
+
+
+
+
+
+
+
+
+ JD
+
+
+
+
+
+
+
+
+
+
+
+
+
+ JD
+
+
+
+
+
+
+
+
+
+
+
+
+
+ JD
+
+
+
+
+
+
+
+
+
+
+
+
+
+ JD
+
+
+
+
+
+
+
+
+
+
+
+
+
+ JD
+
+
+
+
+
+
+
+
+
+
+
+
+
+ JD
+
+
+
+
+
+
+
+
+
+
+
+
+
+ JD
+
+
+
+
+
+
+
+
+
+
+
+
+
+ JD
+
+
+
+
+
+
+
+
+
+
+
+
+
+ JD
+
+
+
+
+
+
+
+
+
+
+
+
+
+ JD
+
+
+
+
+
+
+
+
+
+
+
+ events
+
+
+
+
+
+
+
+
+
+
+ events
+
+
+
+
+
+
+
+
+
+
+ events
+
+
+
+
+
+
+
+
+
+
+ events
+
+
+
+
+
+
+
+
+
+
+ events
+
+
+
+
+
+
+
+
+
+
+ events
+
+
+
+
+
+
+
+
+
+
+ events
+
+
+
+
+
+
+
+
+
+
+ events
+
+
+
+
+
+
+
+
+
+
+ events
+
+
+
+
+
+
+
+
+
+
+ events
+
+
+
+
+
+
+
+
+
+
+ events
+
+
+
+
+
+
+
+
+
+
+ events
+
+
+
+
+
+
+
+
+
+
+ events
+
+
+
+
+
+
+
+
+
+
+ events
+
+
+
+
+
+
+
+
+
+
+ events
+
+
+
+
+
+
+
+
+
+
+ events
+
+
+
+
+
+
+
+
+
+
+ events
+
+
+
+
+
+
+
+
+
+
+ events
+
+
+
+
+
+
-
-
+
+
+
+
+
+
+
+
+
+
+
+
-
+
-
+
+