Skip to content
This repository has been archived by the owner on Mar 4, 2020. It is now read-only.

feat(Chat): add actionMenu prop for ChatMessage #811

Merged
merged 21 commits into from
Feb 5, 2019
Merged
Show file tree
Hide file tree
Changes from 17 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm
- 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))
- Add `hasMention`, `isImportant`, `hasMentionColor` and `isImportantColor` in ChatMessage variables in Teams theme @mnajdova ([#841](https://github.com/stardust-ui/react/pull/841))
- Add `actionMenu` prop to `ChatMessage` component @layershifter ([#811](https://github.com/stardust-ui/react/pull/811))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

just putting my vote on that: would rather prefer actions than actionsMenu for the following reasons

  • it will be easier to avoid breaking changes in future - for example, if at some point it will become an actionsPanel
  • it is consistent with the naming taken for Attachment component, where there is an action slot

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

but given the example from description, agree that it is definitely better to use singular menu noun in the name of the prop, to properly reflect underlying semantics

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

actually, a bit surprised that we are not handling array as 'primitive' shorthand values - is there any particular reason for that? Might expect that this feature is necessary for all the places where collection-container component stays as a default one for shorthand value

Copy link
Member Author

@layershifter layershifter Feb 5, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can be wrong, but this decision came from the consistency point: you can pass only ShorthandValue or ShorthandValue[]. However, I understand your point, had the same feeling about it.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

got it, thank you @layershifter! actually, this original problem (actions and necessity to compromise on actionsMenu) is a good example that might serve as an inspiration for us to further refine this moment in future


### Fixes
- Fix `Dropdown` component styles regression @Bugaa92 ([#824](https://github.com/stardust-ui/react/pull/824))
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import { Avatar, Chat } from '@stardust-ui/react'
import * as React from 'react'

const actionMenu = {
iconOnly: true,
items: [
{ key: 'like', icon: 'like', title: 'Like' },
{ key: 'more', icon: 'more', title: 'More actions' },
],
}

const items = [
{
attached: 'top',
contentPosition: 'end',
message: {
content: (
<Chat.Message
actionMenu={actionMenu}
content="Hello"
author="John Doe"
timestamp="Yesterday, 10:15 PM"
mine
/>
),
},
key: 'message-1',
},
{
attached: 'bottom',
contentPosition: 'end',
key: 'message-2',
message: {
content: (
<Chat.Message
actionMenu={actionMenu}
content="I'm back!"
author="John Doe"
timestamp="Yesterday, 10:15 PM"
mine
/>
),
},
},
{
gutter: { content: <Avatar image="public/images/avatar/small/ade.jpg" /> },
message: {
content: (
<Chat.Message
actionMenu={actionMenu}
content="Hi"
author="Jane Doe"
timestamp="Yesterday, 10:15 PM"
/>
),
},
key: 'message-3',
},
]

const ChatExample = () => <Chat items={items} />

export default ChatExample
16 changes: 16 additions & 0 deletions docs/src/examples/components/Chat/Content/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import * as React from 'react'

import ComponentExample from 'docs/src/components/ComponentDoc/ComponentExample'
import ExampleSection from 'docs/src/components/ComponentDoc/ExampleSection'

const Content = () => (
<ExampleSection title="Types">
<ComponentExample
title="Actions"
description="A chat message can contain actions."
examplePath="components/Chat/Content/ChatExampleActions"
/>
</ExampleSection>
)

export default Content
7 changes: 5 additions & 2 deletions docs/src/examples/components/Chat/index.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
import * as React from 'react'

import Content from './Content'
import Types from './Types'

const ChatExamples = () => (
<div>
<>
<Types />
</div>
<Content />
</>
)

export default ChatExamples

This file was deleted.

86 changes: 71 additions & 15 deletions docs/src/prototypes/chatMessageWithPopover/ChatWithPopover.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { Chat, Provider, Avatar } from '@stardust-ui/react'
import * as React from 'react'
import ChatMessageWithPopover from './ChatMessageWithPopover'
import Popover from './Popover'

const janeAvatar = {
image: 'public/images/avatar/small/ade.jpg',
Expand All @@ -12,15 +12,7 @@ const ChatWithPopover = () => (
theme={{
componentStyles: {
ChatMessage: {
root: ({ theme: { siteVariables } }) => ({
position: 'relative',

'&.focused .actions': {
opacity: 1,
},
':hover .actions': {
opacity: 1,
},
root: ({ props: p, theme: { siteVariables } }) => ({
'& a': {
color: siteVariables.brand,
},
Expand All @@ -29,15 +21,34 @@ const ChatWithPopover = () => (
Menu: {
root: {
background: '#fff',
boxShadow: '0px 2px 4px #ddd',
borderRadius: '.3rem',
transition: 'opacity 0.2s',
position: 'absolute',

'& a:focus': {
textDecoration: 'none',
color: 'inherit',
},
'& a': {
color: 'inherit',
},

'& .smile-emoji': {
position: 'absolute',
opacity: 0,
zIndex: -1,
},

'&.focused .smile-emoji': {
position: 'initial',
zIndex: 'initial',
opacity: 1,
},

'&:hover .smile-emoji': {
position: 'initial',
zIndex: 'initial',
opacity: 1,
},
},
},
},
Expand All @@ -47,17 +58,62 @@ const ChatWithPopover = () => (
items={[
{
key: 'a',
message: { content: <ChatMessageWithPopover /> },
message: {
content: (
<Chat.Message
actionMenu={<Popover />}
author="Jane Doe"
content={{
content: (
<div>
<a href="/">Link</a> Hover me to see the actions <a href="/">Some Link</a>
</div>
),
}}
timestamp="Yesterday, 10:15 PM"
/>
),
},
gutter: { content: <Avatar {...janeAvatar} /> },
},
{
key: 'b',
message: { content: <ChatMessageWithPopover /> },
message: {
content: (
<Chat.Message
actionMenu={<Popover />}
author="Jane Doe"
content={{
content: (
<div>
<a href="/">Link</a> Hover me to see the actions <a href="/">Some Link</a>
</div>
),
}}
timestamp="Yesterday, 10:15 PM"
/>
),
},
gutter: { content: <Avatar {...janeAvatar} /> },
},
{
key: 'c',
message: { content: <ChatMessageWithPopover /> },
message: {
content: (
<Chat.Message
actionMenu={<Popover />}
author="Jane Doe"
content={{
content: (
<div>
<a href="/">Link</a> Hover me to see the actions <a href="/">Some Link</a>
</div>
),
}}
timestamp="Yesterday, 10:15 PM"
/>
),
},
gutter: { content: <Avatar {...janeAvatar} /> },
},
]}
Expand Down
36 changes: 13 additions & 23 deletions docs/src/prototypes/chatMessageWithPopover/Popover.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Menu, toolbarBehavior, toolbarButtonBehavior } from '@stardust-ui/react'
import { Accessibility, Menu, toolbarBehavior, toolbarButtonBehavior } from '@stardust-ui/react'
import * as React from 'react'
import cx from 'classnames'

Expand All @@ -10,6 +10,16 @@ interface PopoverState {
focused: boolean
}

const popoverBehavior: Accessibility = (props: any) => {
const behavior = toolbarBehavior(props)

behavior.focusZone.props.defaultTabbableElement = (root: HTMLElement): HTMLElement => {
return root.querySelector('[aria-label="thumbs up"]')
}

return behavior
}

class Popover extends React.Component<PopoverProps, PopoverState> {
state = {
focused: false,
Expand All @@ -28,30 +38,11 @@ class Popover extends React.Component<PopoverProps, PopoverState> {
this.changeFocusState(shouldPreserveFocusState)
}

popoverStyles = ({ theme: { siteVariables } }) => ({
transition: 'opacity 0.2s',
position: 'absolute',
top: '-20px',
right: '5px',
opacity: 0,

'& .smile-emoji': {
display: 'none',
},

'&.focused .smile-emoji': {
display: 'flex',
},

'&:hover .smile-emoji': {
display: 'flex',
},
})

render() {
return (
<Menu
styles={this.popoverStyles}
{...this.props}
accessibility={popoverBehavior}
iconOnly
className={cx(this.props.className, this.state.focused ? 'focused' : '')}
items={[
Expand Down Expand Up @@ -100,7 +91,6 @@ class Popover extends React.Component<PopoverProps, PopoverState> {
]}
onFocus={this.handleFocus}
onBlur={this.handleBlur}
accessibility={toolbarBehavior}
data-is-focusable={true}
/>
)
Expand Down
Loading