diff --git a/CHANGELOG.md b/CHANGELOG.md index 76d76770b5..0f3a5856fe 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -24,6 +24,7 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm ### Features - Accessibility for menu divider @jurokapsiar ([#822](https://github.com/stardust-ui/react/pull/822)) - Added slot class names in `ChatMessage`, `ChatItem`, `Dropdown`, `ItemLayout`, `Layout`, `MenuItem` @mnajdova ([#827](https://github.com/stardust-ui/react/pull/827)) +- Add `badge` and `badgePosition` properties on the `ChatMessage` @mnajdova ([#823](https://github.com/stardust-ui/react/pull/823)) ### Fixes - Fix `Dropdown` component styles regression @Bugaa92 ([#824](https://github.com/stardust-ui/react/pull/824)) diff --git a/docs/src/examples/components/Chat/Types/ChatMessageExampleBadge.shorthand.tsx b/docs/src/examples/components/Chat/Types/ChatMessageExampleBadge.shorthand.tsx new file mode 100644 index 0000000000..34b9d16a59 --- /dev/null +++ b/docs/src/examples/components/Chat/Types/ChatMessageExampleBadge.shorthand.tsx @@ -0,0 +1,51 @@ +import * as React from 'react' +import { Avatar, Chat } from '@stardust-ui/react' + +const janeAvatar = { + image: 'public/images/avatar/small/ade.jpg', + status: { color: 'green', icon: 'check' }, +} + +const items = [ + { + message: { + content: ( + + ), + }, + contentPosition: 'end', + key: 'message-id-1', + }, + { + gutter: { content: }, + message: { + content: ( + + ), + }, + attached: 'top', + key: 'message-id-4', + }, +] + +const ChatExample = () => + +export default ChatExample diff --git a/docs/src/examples/components/Chat/Types/ChatMessageExampleStyled.shorthand.tsx b/docs/src/examples/components/Chat/Types/ChatMessageExampleStyled.shorthand.tsx index 2d6d1c1489..36733fdda2 100644 --- a/docs/src/examples/components/Chat/Types/ChatMessageExampleStyled.shorthand.tsx +++ b/docs/src/examples/components/Chat/Types/ChatMessageExampleStyled.shorthand.tsx @@ -17,10 +17,11 @@ const content = ( ) -const slotLabelStyles: any = (label, beforeStyles) => ({ +const slotLabelStyles: any = (label, beforeStyles?, slotStyles?) => ({ position: 'relative', border: '1px solid #000', padding: '12px', + ...slotStyles, ':before': { content: `'${label}'`, position: 'absolute', @@ -56,6 +57,14 @@ const ChatMessageExampleStyled = () => ( }), content: { ...slotLabelStyles('content'), backgroundColor: '#F08080' }, timestamp: { ...slotLabelStyles('timestamp'), backgroundColor: '#FFFFE0' }, + badge: { + ...slotLabelStyles( + 'badge', + { textAlign: 'center', left: '0px' }, + { position: 'absolute', overflow: 'visible' }, + ), + backgroundColor: '#FFFF00', + }, }, }, componentVariables: { @@ -77,6 +86,8 @@ const ChatMessageExampleStyled = () => ( author="John Doe" timestamp="Yesterday, 10:15 PM" mine + badge={{ icon: 'at' }} + badgePosition="start" /> ), }, @@ -92,6 +103,7 @@ const ChatMessageExampleStyled = () => ( content={{ content }} author="Jane Doe" timestamp="Yesterday, 10:15 PM" + badge={{ icon: 'exclamation' }} /> ), }, diff --git a/docs/src/examples/components/Chat/Types/index.tsx b/docs/src/examples/components/Chat/Types/index.tsx index 935c668be7..83952f611a 100644 --- a/docs/src/examples/components/Chat/Types/index.tsx +++ b/docs/src/examples/components/Chat/Types/index.tsx @@ -19,6 +19,11 @@ const Types = () => ( description="A Chat item with custom styles for every slot." examplePath="components/Chat/Types/ChatMessageExampleStyled" /> + ) diff --git a/packages/react/src/components/Chat/ChatMessage.tsx b/packages/react/src/components/Chat/ChatMessage.tsx index ad6f27045e..4ff85ae46b 100644 --- a/packages/react/src/components/Chat/ChatMessage.tsx +++ b/packages/react/src/components/Chat/ChatMessage.tsx @@ -22,10 +22,12 @@ import { Accessibility, AccessibilityActionHandlers } from '../../lib/accessibil import Text from '../Text/Text' import Box from '../Box/Box' +import Label from '../Label/Label' export interface ChatMessageSlotClassNames { author: string timestamp: string + badge: string content: string } @@ -48,6 +50,12 @@ export interface ChatMessageProps /** Timestamp of the message. */ timestamp?: ShorthandValue + /** Badge attached to the message. */ + badge?: ShorthandValue + + /** A message can format the badge to appear at the start or the end of the message. */ + badgePosition?: 'start' | 'end' + /** * Called after user's focus. * @param {SyntheticEvent} event - React's original SyntheticEvent. @@ -76,6 +84,8 @@ class ChatMessage extends UIComponent, ChatMessageS ...commonPropTypes.createCommon({ content: 'shorthand' }), accessibility: PropTypes.oneOfType([PropTypes.object, PropTypes.func]), author: customPropTypes.itemShorthand, + badge: customPropTypes.itemShorthand, + badgePosition: PropTypes.oneOf(['start', 'end']), mine: PropTypes.bool, timestamp: customPropTypes.itemShorthand, onFocus: PropTypes.func, @@ -84,6 +94,7 @@ class ChatMessage extends UIComponent, ChatMessageS static defaultProps = { accessibility: chatMessageBehavior, as: 'div', + badgePosition: 'end', } public state = { @@ -110,9 +121,15 @@ class ChatMessage extends UIComponent, ChatMessageS unhandledProps, styles, }: RenderResultConfig) { - const { author, children, content, timestamp } = this.props + const { author, children, content, timestamp, badge, badgePosition } = this.props const childrenPropExists = childrenExist(children) const className = childrenPropExists ? cx(classes.root, classes.content) : classes.root + const badgeElement = Label.create(badge, { + defaultProps: { + className: ChatMessage.slotClassNames.badge, + styles: styles.badge, + }, + }) return ( , ChatMessageS children ) : ( <> + {badgePosition === 'start' && badgeElement} {Text.create(author, { defaultProps: { size: 'small', @@ -142,12 +160,14 @@ class ChatMessage extends UIComponent, ChatMessageS className: ChatMessage.slotClassNames.timestamp, }, })} + {Box.create(content, { defaultProps: { className: ChatMessage.slotClassNames.content, styles: styles.content, }, })} + {badgePosition === 'end' && badgeElement} )} @@ -159,6 +179,7 @@ ChatMessage.create = createShorthandFactory(ChatMessage, 'content') ChatMessage.slotClassNames = { author: `${ChatMessage.className}__author`, timestamp: `${ChatMessage.className}__timestamp`, + badge: `${ChatMessage.className}__badge`, content: `${ChatMessage.className}__content`, } diff --git a/packages/react/src/themes/teams/components/Chat/chatMessageStyles.ts b/packages/react/src/themes/teams/components/Chat/chatMessageStyles.ts index 3f8a84d0ec..a3a270044a 100644 --- a/packages/react/src/themes/teams/components/Chat/chatMessageStyles.ts +++ b/packages/react/src/themes/teams/components/Chat/chatMessageStyles.ts @@ -6,6 +6,7 @@ import { pxToRem } from '../../../../lib' const chatMessageStyles: ComponentSlotStylesInput = { root: ({ props: p, variables: v }): ICSSInJSStyle => ({ + position: 'relative', display: 'inline-block', paddingLeft: v.padding, paddingRight: v.padding, @@ -44,6 +45,21 @@ const chatMessageStyles: ComponentSlotStylesInput { + const sidePosition = p.badgePosition === 'start' ? 'left' : 'right' + return { + boxShadow: v.badgeShadow, + position: 'absolute', + padding: pxToRem(4), + height: 'auto', + width: 'auto', + borderRadius: '50%', + top: pxToRem(4), + zIndex: '1', + [sidePosition]: 0, + transform: p.badgePosition === 'start' ? 'translateX(-50%)' : 'translateX(50%)', + } + }, } export default chatMessageStyles diff --git a/packages/react/src/themes/teams/components/Chat/chatMessageVariables.ts b/packages/react/src/themes/teams/components/Chat/chatMessageVariables.ts index 9b473f6795..cf85908a51 100644 --- a/packages/react/src/themes/teams/components/Chat/chatMessageVariables.ts +++ b/packages/react/src/themes/teams/components/Chat/chatMessageVariables.ts @@ -11,6 +11,7 @@ export interface ChatMessageVariables { headerMarginBottom: string contentFocusOutlineColor: string border: string + badgeShadow: string } export default (siteVars): ChatMessageVariables => ({ @@ -24,4 +25,5 @@ export default (siteVars): ChatMessageVariables => ({ headerMarginBottom: pxToRem(2), contentFocusOutlineColor: siteVars.brand, border: 'none', + badgeShadow: siteVars.shadowLevel1Darker, }) diff --git a/packages/react/src/themes/teams/siteVariables.ts b/packages/react/src/themes/teams/siteVariables.ts index f7cf0aac2f..010188f9a1 100644 --- a/packages/react/src/themes/teams/siteVariables.ts +++ b/packages/react/src/themes/teams/siteVariables.ts @@ -45,6 +45,7 @@ export const green04 = '#237b4b' // SHADOW LEVELS // export const shadowLevel1 = '0 .2rem .4rem -.075rem rgba(0, 0, 0, 0.1)' +export const shadowLevel1Darker = '0 .2rem .4rem -.075rem rgba(0, 0, 0, 0.5)' // // FONT SIZES