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":
+ +