diff --git a/CHANGELOG.md b/CHANGELOG.md index 7e7e0c80bc..b5c8b50b22 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -21,6 +21,7 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm - `type` prop is replaced with `color` in `Divider` component @layershifter ([#558](https://github.com/stardust-ui/react/pull/558)) - Remove `createColorVariants` and `setColorLightness` utils @layershifter ([#583](https://github.com/stardust-ui/react/pull/583)) - Remove `accessibility` prop (and corresponding behavior) from `ButtonGroup` @kolaps33 ([#605](https://github.com/stardust-ui/react/pull/605)) +- Add `gutter` prop to `Chat.Item`, removed `avatar` from `Chat.Message`, renamed `content` slot to `message` for `Chat.Item`, deprecated Children API for `Chat` components @Bugaa92 ([#556](https://github.com/stardust-ui/react/pull/556)) ### Fixes - Fix `Provider` is not executing staticStyles with the merged siteVariables @mnajdova ([#559](https://github.com/stardust-ui/react/pull/559)) diff --git a/docs/src/examples/components/Chat/Types/ChatExample.shorthand.tsx b/docs/src/examples/components/Chat/Types/ChatExample.shorthand.tsx index 7204a22562..68a0a1f64d 100644 --- a/docs/src/examples/components/Chat/Types/ChatExample.shorthand.tsx +++ b/docs/src/examples/components/Chat/Types/ChatExample.shorthand.tsx @@ -1,5 +1,5 @@ import React from 'react' -import { Chat, Divider } from '@stardust-ui/react' +import { Avatar, Chat, Divider } from '@stardust-ui/react' const janeAvatar = { image: 'public/images/avatar/small/ade.jpg', @@ -8,59 +8,67 @@ const janeAvatar = { const items = [ { - content: ( - - ), + message: { + content: ( + + ), + }, key: 'message-id-1', }, { - content: ( - - ), + gutter: { content: }, + message: { + content: , + }, key: 'message-id-2', }, { - content: ( - - ), + message: { content: }, key: 'message-id-3', }, { - content: ( - - ), + message: { + content: ( + + ), + }, key: 'message-id-4', }, { - content: , + gutter: { content: }, + message: { + content: ( + + ), + }, key: 'message-id-5', }, { - content: ( - - ), + message: , key: 'message-id-6', }, + { + message: { + content: ( + + ), + }, + key: 'message-id-7', + }, ] const ChatExample = () => diff --git a/docs/src/examples/components/Chat/Types/ChatExample.tsx b/docs/src/examples/components/Chat/Types/ChatExample.tsx deleted file mode 100644 index 2e1d220815..0000000000 --- a/docs/src/examples/components/Chat/Types/ChatExample.tsx +++ /dev/null @@ -1,52 +0,0 @@ -import React from 'react' -import { Chat, Divider } from '@stardust-ui/react' - -const janeAvatar = { - image: 'public/images/avatar/small/ade.jpg', - status: { color: 'green', icon: 'check' }, -} - -const ChatExample = () => ( - - - - - - - - - - - - - - - - - - - - -) - -export default ChatExample diff --git a/docs/src/examples/components/Chat/Types/ChatExampleGutterPosition.shorthand.tsx b/docs/src/examples/components/Chat/Types/ChatExampleGutterPosition.shorthand.tsx new file mode 100644 index 0000000000..0adac90c0f --- /dev/null +++ b/docs/src/examples/components/Chat/Types/ChatExampleGutterPosition.shorthand.tsx @@ -0,0 +1,33 @@ +import React from 'react' +import { Avatar, Chat } from '@stardust-ui/react' + +const [janeAvatar, johnAvatar] = [ + 'public/images/avatar/small/ade.jpg', + 'public/images/avatar/small/joe.jpg', +].map(src => ({ + image: src, + status: { color: 'green', icon: 'check' }, +})) + +const items = [ + { + gutterPosition: 'start', + gutter: { content: }, + message: { + content: , + }, + key: 'message-id-1', + }, + { + gutterPosition: 'end', + gutter: { content: }, + message: { + content: , + }, + key: 'message-id-2', + }, +] + +const ChatExampleGutterPosition = () => + +export default ChatExampleGutterPosition diff --git a/docs/src/examples/components/Chat/Types/ChatMessageExampleStyled.shorthand.tsx b/docs/src/examples/components/Chat/Types/ChatMessageExampleStyled.shorthand.tsx index 84f895029f..f3ad53609c 100644 --- a/docs/src/examples/components/Chat/Types/ChatMessageExampleStyled.shorthand.tsx +++ b/docs/src/examples/components/Chat/Types/ChatMessageExampleStyled.shorthand.tsx @@ -1,5 +1,5 @@ import React from 'react' -import { Chat, Provider } from '@stardust-ui/react' +import { Avatar, Chat, Provider } from '@stardust-ui/react' const janeAvatar = { image: 'public/images/avatar/small/ade.jpg', @@ -40,14 +40,17 @@ const ChatMessageExampleStyled = () => ( ( }, componentVariables: { ChatMessage: siteVars => ({ - messageBody: { - focusOutlineColor: siteVars.white, + content: { + focusOutlineColor: siteVars.red, }, }), }, @@ -65,26 +68,30 @@ const ChatMessageExampleStyled = () => ( - ), + message: { + content: ( + + ), + }, key: 'message-id-1', }, { key: 'message-id-2', - content: ( - - ), + gutter: { content: }, + message: { + content: ( + + ), + }, }, ]} /> diff --git a/docs/src/examples/components/Chat/Types/ChatMessageExampleStyled.tsx b/docs/src/examples/components/Chat/Types/ChatMessageExampleStyled.tsx deleted file mode 100644 index 110553fd61..0000000000 --- a/docs/src/examples/components/Chat/Types/ChatMessageExampleStyled.tsx +++ /dev/null @@ -1,86 +0,0 @@ -import React from 'react' -import { Chat, Provider } from '@stardust-ui/react' - -const janeAvatar = { - image: 'public/images/avatar/small/ade.jpg', - status: { color: 'green', icon: 'check' }, -} - -const content = ( -
- Sure! Try one of these places: -
- www.goodFood1.com,
- www.goodFood2.com or -
- www.goodFood3.com -
-) - -const slotLabelStyles: any = (label, beforeStyles) => ({ - position: 'relative', - border: '1px solid #000', - padding: '12px', - ':before': { - content: `'${label}'`, - position: 'absolute', - background: '#000', - paddingBottom: '2px', - bottom: '-1px', - right: '-1px', - color: 'white', - fontSize: '11px', - letterSpacing: '0.1px', - lineHeight: '9px', - ...beforeStyles, - }, -}) - -const ChatMessageExampleStyled = () => ( - ({ - messageBody: { - focusOutlineColor: siteVars.white, - }, - }), - }, - }} - > - - - - - - - - - -) - -export default ChatMessageExampleStyled diff --git a/docs/src/examples/components/Chat/Types/index.tsx b/docs/src/examples/components/Chat/Types/index.tsx index 9578574d48..f855b2a3be 100644 --- a/docs/src/examples/components/Chat/Types/index.tsx +++ b/docs/src/examples/components/Chat/Types/index.tsx @@ -9,6 +9,11 @@ const Types = () => ( description="A default Chat." examplePath="components/Chat/Types/ChatExample" /> + this.setState({ open: !this.state.open }) - renderAvatar = (Avatar, props) => ( - ( - ( - ( - - )} - /> - )} - /> - )} - /> - ) - renderMenuItem = (MenuItem, props) => { if (props.icon !== 'thumbs up') { return @@ -63,7 +39,6 @@ class CustomChatMessage extends React.Component { key={props.key} position="below" open={this.state.open} - // content={{ content: ( Hover me to see the actions and async like count. @@ -130,12 +104,35 @@ class CustomChatMessage extends React.Component { ) } } + +const gutterContent = ( + ( + ( + + renderStatus({ + color: statusData === 'available' ? 'green' : undefined, + icon: statusData === 'available' ? 'check' : undefined, + }) + } + /> + )} + /> + )} + /> +) + const AsyncShorthand = () => ( }, - { key: 'b', content: }, - { key: 'c', content: }, + { key: 'a', gutter: { content: gutterContent }, message: { content: } }, + { key: 'b', gutter: { content: gutterContent }, message: { content: } }, + { key: 'c', gutter: { content: gutterContent }, message: { content: } }, ]} /> ) diff --git a/docs/src/prototypes/chatPane/chatPaneContent.tsx b/docs/src/prototypes/chatPane/chatPaneContent.tsx index 16805bffcc..a04b6a0f43 100644 --- a/docs/src/prototypes/chatPane/chatPaneContent.tsx +++ b/docs/src/prototypes/chatPane/chatPaneContent.tsx @@ -1,6 +1,6 @@ import * as React from 'react' import Scrollbars from 'react-custom-scrollbars' -import { Chat, Divider } from '@stardust-ui/react' +import { Chat, Divider, Avatar } from '@stardust-ui/react' import { ChatData, ChatItemTypes, generateChatProps } from './services' const screenReaderMessageContainerStyles: React.CSSProperties = { @@ -38,26 +38,37 @@ class ChatPaneContainer extends React.PureComponent { } private generateChatItems(chat: ChatData): JSX.Element[] { - return generateChatProps(chat).map(({ itemType, ...props }, index) => { - const ElementType = this.getElementType(itemType) - const maybeAttributesForDivider = - itemType === ChatItemTypes.divider - ? { - role: 'heading', - 'aria-level': 3, - } - : {} - return ( - - {itemType === ChatItemTypes.message && ( -
- {this.getMessagePreviewForScreenReader(props)} -
- )} - -
- ) - }) + return generateChatProps(chat).map( + ({ mine, gutter, message: { itemType, ...props } }, index) => { + const ElementType = this.getElementType(itemType) + const maybeAttributesForDivider = + itemType === ChatItemTypes.divider + ? { + role: 'heading', + 'aria-level': 3, + } + : {} + return ( + }} + message={{ + content: ( + <> + {itemType === ChatItemTypes.message && ( +
+ {this.getMessagePreviewForScreenReader(props)} +
+ )} + + + ), + }} + /> + ) + }, + ) } private getElementType = (itemType: ChatItemTypes) => { diff --git a/docs/src/prototypes/chatPane/services/messageFactoryMock.tsx b/docs/src/prototypes/chatPane/services/messageFactoryMock.tsx index 7d50c4ed2d..b0f22acbd6 100644 --- a/docs/src/prototypes/chatPane/services/messageFactoryMock.tsx +++ b/docs/src/prototypes/chatPane/services/messageFactoryMock.tsx @@ -1,4 +1,11 @@ -import { Attachment, Popup, Button, Menu, popupFocusTrapBehavior } from '@stardust-ui/react' +import { + Attachment, + Popup, + Button, + Menu, + popupFocusTrapBehavior, + AvatarProps, +} from '@stardust-ui/react' import * as React from 'react' import * as _ from 'lodash' import { ChatMessageProps } from 'src/components/Chat/ChatMessage' @@ -12,18 +19,22 @@ export enum ChatItemTypes { divider, } -interface ChatItem { +interface ChatItemType { itemType: ChatItemTypes } -interface ChatMessage extends ChatMessageProps, ChatItem { +interface ChatMessage extends ChatMessageProps, ChatItemType { tabIndex: number 'aria-labelledby': string text: string } -interface Divider extends DividerProps, ChatItem {} +interface Divider extends DividerProps, ChatItemType {} -type ChatItemContentProps = ChatMessage | Divider +type ChatItem = { + message?: ChatMessage | Divider + gutter?: AvatarProps + mine?: boolean +} type StatusPropsExtendable = Extendable const statusMap: Map = new Map([ @@ -33,7 +44,7 @@ const statusMap: Map = new Map([ ['Offline', { color: 'grey', title: 'Offline' }], ] as [UserStatus, StatusPropsExtendable][]) -function generateChatMsgProps(message: MessageData, fromUser: UserData): ChatMessage { +function generateChatMsgProps(message: MessageData, fromUser: UserData): ChatItem { const { content, mine } = message const messageProps: ChatMessage = { // aria-labelledby will need to by generated based on the needs. Currently just hardcoded. @@ -53,12 +64,15 @@ function generateChatMsgProps(message: MessageData, fromUser: UserData): ChatMes content: `${fromUser.firstName} ${fromUser.lastName} `, id: `sender-${message.id}`, }, - avatar: !message.mine && { image: fromUser.avatar, status: statusMap.get(fromUser.status) }, itemType: ChatItemTypes.message, text: content, } - return messageProps + return { + mine, + message: messageProps, + gutter: !message.mine && { image: fromUser.avatar, status: statusMap.get(fromUser.status) }, + } } function createMessageContent(message: MessageData): ShorthandValue { @@ -120,20 +134,20 @@ function createMessageContentWithAttachments(content: string, messageId: string) ) } -function generateDividerProps(props: DividerProps): Divider { +function generateDividerProps(props: DividerProps): ChatItem { const { content, important, color = 'secondary' } = props const dividerProps: Divider = { itemType: ChatItemTypes.divider, content, important, color } - return dividerProps + return { message: dividerProps } } -export function generateChatProps(chat: ChatData): ChatItemContentProps[] { +export function generateChatProps(chat: ChatData): ChatItem[] { if (!chat || !chat.members || !chat.messages) { return [] } const { messages, members } = chat - const chatProps: ChatItemContentProps[] = [] + const chatProps: ChatItem[] = [] // First date divider chatProps.push(generateDividerProps({ content: getFriendlyDateString(messages[0].date) })) @@ -152,7 +166,7 @@ export function generateChatProps(chat: ChatData): ChatItemContentProps[] { chatProps.push(generateChatMsgProps(lastMsg, members.get(lastMsg.from))) // Last read divider - const myLastMsgIndex = _.findLastIndex(chatProps, item => (item as ChatMessage).mine) + const myLastMsgIndex = _.findLastIndex(chatProps, item => item.mine) if (myLastMsgIndex < chatProps.length - 1) { chatProps.splice( myLastMsgIndex + 1, diff --git a/src/components/Chat/ChatItem.tsx b/src/components/Chat/ChatItem.tsx index 308e012394..fee9a407bf 100644 --- a/src/components/Chat/ChatItem.tsx +++ b/src/components/Chat/ChatItem.tsx @@ -1,4 +1,5 @@ import * as React from 'react' +import * as PropTypes from 'prop-types' import { Extendable, ShorthandValue } from '../../../types/utils' import { @@ -8,58 +9,67 @@ import { UIComponent, UIComponentProps, ChildrenComponentProps, - ContentComponentProps, commonPropTypes, + customPropTypes, } from '../../lib' import Slot from '../Slot/Slot' +import { ComponentSlotStylesPrepared } from '../../themes/types' -export interface ChatItemProps - extends UIComponentProps, - ChildrenComponentProps, - ContentComponentProps {} +export interface ChatItemProps extends UIComponentProps, ChildrenComponentProps { + /** Chat items can have a gutter. */ + gutter?: ShorthandValue + + /** Indicates whether the gutter is positioned at the start or the end. */ + gutterPosition?: 'start' | 'end' + + /** Chat items can have a message. */ + message?: ShorthandValue +} /** * A chat item represents a single event in a chat. */ class ChatItem extends UIComponent, any> { static className = 'ui-chat__item' - static create: Function - static displayName = 'ChatItem' static propTypes = { - ...commonPropTypes.createCommon({ - content: 'shorthand', - }), + ...commonPropTypes.createCommon({ content: false }), + gutter: customPropTypes.itemShorthand, + gutterPosition: PropTypes.oneOf(['start', 'end']), + message: customPropTypes.itemShorthand, } static defaultProps = { as: 'li', + gutterPosition: 'start', } - renderComponent({ - ElementType, - classes, - styles, - variables, - rest, - }: RenderResultConfig) { - const { children, content } = this.props + renderComponent({ ElementType, classes, rest, styles }: RenderResultConfig) { + const { children } = this.props return ( - {childrenExist(children) - ? children - : Slot.create(content, { - styles: styles.content, - variables: variables.content, - })} + {childrenExist(children) ? children : this.renderChatItem(styles)} ) } + + private renderChatItem(styles: ComponentSlotStylesPrepared) { + const { message, gutter, gutterPosition } = this.props + const gutterElement = gutter && Slot.create(gutter, { defaultProps: { styles: styles.gutter } }) + + return ( + <> + {gutterPosition === 'start' && gutterElement} + {Slot.create(message, { defaultProps: { styles: styles.message } })} + {gutterPosition === 'end' && gutterElement} + + ) + } } -ChatItem.create = createShorthandFactory(ChatItem, 'content') +ChatItem.create = createShorthandFactory(ChatItem, 'message') export default ChatItem diff --git a/src/components/Chat/ChatMessage.tsx b/src/components/Chat/ChatMessage.tsx index bd33694d03..97ae4d69a5 100644 --- a/src/components/Chat/ChatMessage.tsx +++ b/src/components/Chat/ChatMessage.tsx @@ -13,15 +13,10 @@ import { ContentComponentProps, commonPropTypes, } from '../../lib' -import { - ComponentVariablesInput, - ComponentSlotClasses, - ComponentSlotStylesInput, -} from '../../themes/types' import { Extendable, ShorthandValue } from '../../../types/utils' -import Avatar from '../Avatar/Avatar' import { chatMessageBehavior } from '../../lib/accessibility' import { Accessibility, AccessibilityActionHandlers } from '../../lib/accessibility/types' + import Text from '../Text/Text' import Slot from '../Slot/Slot' @@ -38,9 +33,6 @@ export interface ChatMessageProps /** Author of the message. */ author?: ShorthandValue - /** Chat messages can have an avatar. */ - avatar?: ShorthandValue - /** Indicates whether message belongs to the current user. */ mine?: boolean @@ -59,12 +51,9 @@ class ChatMessage extends UIComponent, any> { static displayName = 'ChatMessage' static propTypes = { - ...commonPropTypes.createCommon({ - content: 'shorthand', - }), + ...commonPropTypes.createCommon({ content: 'shorthand' }), accessibility: PropTypes.oneOfType([PropTypes.object, PropTypes.func]), author: customPropTypes.itemShorthand, - avatar: customPropTypes.itemShorthand, mine: PropTypes.bool, timestamp: customPropTypes.itemShorthand, } @@ -87,9 +76,8 @@ class ChatMessage extends UIComponent, any> { accessibility, rest, styles, - variables, }: RenderResultConfig) { - const { children } = this.props + const { author, children, content, mine, timestamp } = this.props const childrenPropExists = childrenExist(children) const className = childrenPropExists ? cx(classes.root, classes.content) : classes.root @@ -100,56 +88,21 @@ class ChatMessage extends UIComponent, any> { {...rest} className={className} > - {childrenPropExists ? children : this.renderContent(classes, styles, variables)} + {childrenPropExists ? ( + children + ) : ( + <> + {!mine && + Text.create(author, { defaultProps: { size: 'small', styles: styles.author } })} + {Text.create(timestamp, { + defaultProps: { size: 'small', styles: styles.timestamp, timestamp: true }, + })} + {Slot.create(content, { defaultProps: { styles: styles.content } })} + + )} ) } - - private renderContent = ( - classes: ComponentSlotClasses, - styles: ComponentSlotStylesInput, - variables: ComponentVariablesInput, - ) => { - const { author, avatar, content, mine, timestamp } = this.props - - const avatarElement = Avatar.create(avatar, { - defaultProps: { - styles: styles.avatar, - variables: variables.avatar, - }, - }) - - const authorElement = Text.create(author, { - defaultProps: { - size: 'small', - styles: styles.author, - }, - }) - - const timestampElement = Text.create(timestamp, { - defaultProps: { - size: 'small', - styles: styles.timestamp, - timestamp: true, - }, - }) - - const contentElement = Slot.create(content, { - defaultProps: { styles: styles.content }, - }) - - return ( - <> - {!mine && avatarElement} - - {!mine && authorElement} - {timestampElement} - {contentElement} - - {mine && avatarElement} - - ) - } } ChatMessage.create = createShorthandFactory(ChatMessage, 'content') diff --git a/src/themes/teams/componentVariables.ts b/src/themes/teams/componentVariables.ts index c21c3db458..a2b3261f0e 100644 --- a/src/themes/teams/componentVariables.ts +++ b/src/themes/teams/componentVariables.ts @@ -8,9 +8,7 @@ export { default as Button } from './components/Button/buttonVariables' export { default as ButtonGroup } from './components/Button/buttonVariables' export { default as Chat } from './components/Chat/chatVariables' - export { default as ChatItem } from './components/Chat/chatItemVariables' - export { default as ChatMessage } from './components/Chat/chatMessageVariables' export { default as Divider } from './components/Divider/dividerVariables' diff --git a/src/themes/teams/components/Chat/chatItemStyles.ts b/src/themes/teams/components/Chat/chatItemStyles.ts index eba9eb8e2f..6f9458713c 100644 --- a/src/themes/teams/components/Chat/chatItemStyles.ts +++ b/src/themes/teams/components/Chat/chatItemStyles.ts @@ -1,7 +1,25 @@ -import { ICSSInJSStyle } from '../../../types' +import { ICSSInJSStyle, ComponentSlotStylesInput } from '../../../types' +import { ChatItemVariables } from './chatItemVariables' +import { ChatItemProps } from '../../../../components/Chat/ChatItem' -const chatItemStyles = { - root: (): ICSSInJSStyle => ({}), +const chatItemStyles: ComponentSlotStylesInput = { + root: ({ props: p, variables: v }): ICSSInJSStyle => ({ + position: 'relative', + marginTop: v.margin, + marginBottom: v.margin, + }), + + gutter: ({ props: p, variables: v }): ICSSInJSStyle => ({ + position: 'absolute', + marginTop: v.gutterMargin, + [p.gutterPosition === 'end' ? 'right' : 'left']: 0, + }), + + message: ({ props: p, variables: v }): ICSSInJSStyle => ({ + position: 'relative', + marginLeft: v.messageMargin, + marginRight: v.messageMargin, + }), } export default chatItemStyles diff --git a/src/themes/teams/components/Chat/chatItemVariables.ts b/src/themes/teams/components/Chat/chatItemVariables.ts index c7770045c9..632d839aeb 100644 --- a/src/themes/teams/components/Chat/chatItemVariables.ts +++ b/src/themes/teams/components/Chat/chatItemVariables.ts @@ -1,15 +1,13 @@ +import { pxToRem } from '../../utils' + export interface ChatItemVariables { - messageWidth: string - messageColor: string - messageColorMine: string - avatar: { statusBorderColor: string } + margin: string + gutterMargin: string + messageMargin: string } -export default (siteVars): ChatItemVariables => ({ - messageWidth: '80%', - messageColor: siteVars.white, - messageColorMine: '#E0E0ED', - avatar: { - statusBorderColor: siteVars.gray10, - }, +export default (): ChatItemVariables => ({ + margin: pxToRem(8), + gutterMargin: pxToRem(10), + messageMargin: pxToRem(40), }) diff --git a/src/themes/teams/components/Chat/chatMessageStyles.ts b/src/themes/teams/components/Chat/chatMessageStyles.ts index ac3fc94955..bfd1cef48a 100644 --- a/src/themes/teams/components/Chat/chatMessageStyles.ts +++ b/src/themes/teams/components/Chat/chatMessageStyles.ts @@ -1,56 +1,33 @@ import { ComponentSlotStylesInput, ICSSInJSStyle } from '../../../types' import { ChatMessageProps } from '../../../../components/Chat/ChatMessage' import { ChatMessageVariables } from './chatMessageVariables' -import { pxToRem } from '../../utils' - -const px10asRem = pxToRem(10) const chatMessageStyles: ComponentSlotStylesInput = { root: ({ props: p, variables: v }): ICSSInJSStyle => ({ - display: 'inline-flex', - position: 'relative', - marginTop: '1rem', - marginBottom: '1rem', - ...(p.mine && { - float: 'right', - }), - maxWidth: v.messageWidth, + display: 'inline-block', + padding: v.padding, + borderRadius: v.borderRadius, + color: v.color, + backgroundColor: p.mine ? v.backgroundColorMine : v.backgroundColor, + maxWidth: v.width, wordBreak: 'break-word', wordWrap: 'break-word', + ...(p.mine && { float: 'right' }), ':focus': { - outline: 'none', - '& .ui-chat__message__messageBody': { - outline: `.2rem solid ${v.messageBody.focusOutlineColor}`, - }, + outline: `.2rem solid ${v.contentFocusOutlineColor}`, }, }), - avatar: ({ props: p }: { props: ChatMessageProps }): ICSSInJSStyle => ({ - flex: 'none', - display: p.mine ? 'none' : undefined, - marginTop: px10asRem, - marginBottom: px10asRem, - marginLeft: p.mine ? px10asRem : 0, - marginRight: p.mine ? 0 : px10asRem, - }), - - messageBody: ({ props: p, variables: v }): ICSSInJSStyle => ({ - padding: '1rem', - color: 'rgb(64, 64, 64)', - backgroundColor: p.mine ? v.messageColorMine : v.messageColor, - borderRadius: '0.3rem', - }), - - author: ({ props: p }): ICSSInJSStyle => ({ + author: ({ props: p, variables: v }): ICSSInJSStyle => ({ display: p.mine ? 'none' : undefined, - marginRight: px10asRem, + marginRight: v.authorMargin, }), content: ({ variables: v }): ICSSInJSStyle => ({ display: 'block', '& a:focus': { outline: 'none', - color: v.messageBody.focusOutlineColor, + color: v.contentFocusOutlineColor, textDecoration: 'underline', }, }), diff --git a/src/themes/teams/components/Chat/chatMessageVariables.ts b/src/themes/teams/components/Chat/chatMessageVariables.ts index 988709a7ac..baef4681e0 100644 --- a/src/themes/teams/components/Chat/chatMessageVariables.ts +++ b/src/themes/teams/components/Chat/chatMessageVariables.ts @@ -1,17 +1,23 @@ +import { pxToRem } from '../../utils' + export interface ChatMessageVariables { - messageWidth: string - messageColor: string - messageColorMine: string - avatar: { statusBorderColor: string } - messageBody: { focusOutlineColor: string } + width: string + backgroundColor: string + backgroundColorMine: string + borderRadius: string + color: string + padding: string + authorMargin: string + contentFocusOutlineColor: string } export default (siteVars): ChatMessageVariables => ({ - messageWidth: '80%', - messageColor: siteVars.white, - messageColorMine: '#E0E0ED', - avatar: { - statusBorderColor: siteVars.gray10, - }, - messageBody: { focusOutlineColor: siteVars.brand }, + width: '80%', + backgroundColor: siteVars.white, + backgroundColorMine: '#E0E0ED', + borderRadius: '0.3rem', + color: 'rgb(64, 64, 64)', + padding: pxToRem(14), + authorMargin: pxToRem(10), + contentFocusOutlineColor: siteVars.brand, }) diff --git a/src/themes/teams/components/Chat/chatStyles.ts b/src/themes/teams/components/Chat/chatStyles.ts index a046d1e8a9..aa5ad38ca4 100644 --- a/src/themes/teams/components/Chat/chatStyles.ts +++ b/src/themes/teams/components/Chat/chatStyles.ts @@ -1,9 +1,10 @@ -import { ICSSInJSStyle } from '../../../types' +import { ICSSInJSStyle, ComponentSlotStylesInput } from '../../../types' import { ChatVariables } from './chatVariables' import { pxToRem } from '../../utils' +import { ChatProps } from 'src/components/Chat/Chat' -const chatStyles = { - root: ({ variables: v }: { variables: ChatVariables }): ICSSInJSStyle => ({ +const chatStyles: ComponentSlotStylesInput = { + root: ({ variables: v }): ICSSInJSStyle => ({ backgroundColor: v.backgroundColor, border: `1px solid ${v.backgroundColor}`, display: 'flex', diff --git a/test/specs/components/Chat/Chat-test.ts b/test/specs/components/Chat/Chat-test.ts index bdff0c672d..0705f2e276 100644 --- a/test/specs/components/Chat/Chat-test.ts +++ b/test/specs/components/Chat/Chat-test.ts @@ -10,7 +10,7 @@ const chatImplementsCollectionShorthandProp = implementsCollectionShorthandProp( describe('Chat', () => { isConformant(Chat) - chatImplementsCollectionShorthandProp('items', ChatItem) + chatImplementsCollectionShorthandProp('items', ChatItem, { mapsValueToProp: 'message' }) describe('accessibility', () => { handlesAccessibility(Chat, { diff --git a/test/specs/components/Chat/ChatItem-test.tsx b/test/specs/components/Chat/ChatItem-test.tsx index dd6e78f310..c896daa242 100644 --- a/test/specs/components/Chat/ChatItem-test.tsx +++ b/test/specs/components/Chat/ChatItem-test.tsx @@ -1,7 +1,12 @@ -import { isConformant } from 'test/specs/commonTests' - +import { isConformant, implementsShorthandProp } from 'test/specs/commonTests' import ChatItem from 'src/components/Chat/ChatItem' +import Slot from 'src/components/Slot/Slot' + +const chatItemImplementsShorthandProp = implementsShorthandProp(ChatItem) describe('ChatItem', () => { isConformant(ChatItem) + + chatItemImplementsShorthandProp('gutter', Slot, { mapsValueToProp: 'children' }) + chatItemImplementsShorthandProp('message', Slot, { mapsValueToProp: 'children' }) }) diff --git a/test/specs/components/Chat/ChatMessage-test.tsx b/test/specs/components/Chat/ChatMessage-test.tsx index 419e7a81f9..6c12ed8dbb 100644 --- a/test/specs/components/Chat/ChatMessage-test.tsx +++ b/test/specs/components/Chat/ChatMessage-test.tsx @@ -1,31 +1,23 @@ -import * as React from 'react' import { handlesAccessibility, implementsShorthandProp, isConformant } from 'test/specs/commonTests' -import { mountWithProvider } from 'test/utils' import ChatMessage from 'src/components/Chat/ChatMessage' -import Avatar from 'src/components/Avatar/Avatar' import { chatMessageBehavior } from 'src/lib/accessibility' import { AccessibilityDefinition } from 'src/lib/accessibility/types' import Text from 'src/components/Text/Text' +import Slot from 'src/components/Slot/Slot' + +const chatMessageImplementsShorthandProp = implementsShorthandProp(ChatMessage) describe('ChatMessage', () => { isConformant(ChatMessage) - implementsShorthandProp(ChatMessage)('avatar', Avatar, { mapsValueToProp: 'name' }) - implementsShorthandProp(ChatMessage)('author', Text) - implementsShorthandProp(ChatMessage)('timestamp', Text) + + chatMessageImplementsShorthandProp('author', Text) + chatMessageImplementsShorthandProp('timestamp', Text) + chatMessageImplementsShorthandProp('content', Slot, { mapsValueToProp: 'children' }) describe('accessibility', () => { handlesAccessibility(ChatMessage, { focusZoneDefinition: (chatMessageBehavior as AccessibilityDefinition).focusZone, }) }) - - describe('avatar', () => { - it('creates an Avatar component when the avatar shorthand is provided', () => { - const name = 'John Doe' - const chatMessage = mountWithProvider() - - expect(chatMessage.find('Avatar').prop('name')).toEqual(name) - }) - }) })