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

docs(Prototype): Chat messages with reactions popover prototype #524

Merged
merged 36 commits into from
Dec 6, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
39ca2e2
work in progress
Nov 23, 2018
6bf584b
Merge branch 'master' into docs/chat-messages-popover-prototype
Nov 23, 2018
8631f95
WIP
Nov 23, 2018
10b0b29
Improvements to menu behaviors
Nov 23, 2018
beff3ee
Merge branch 'master' into feat/menu-behaviors-improvements
sophieH29 Nov 23, 2018
19b9967
Merge branch 'master' into feat/menu-behaviors-improvements
sophieH29 Nov 26, 2018
499081c
Update changelog
Nov 26, 2018
d8c6b36
Merge branch 'feat/menu-behaviors-improvements' into docs/chat-messag…
Nov 26, 2018
01c020c
Small improvement
Nov 26, 2018
1c6e2eb
Merge branch 'master' into docs/chat-messages-popover-prototype
Nov 26, 2018
3b084ec
Small improvement
Nov 26, 2018
d1c14f2
Small improvement
Nov 26, 2018
73b2715
Merge branch 'master' into docs/chat-messages-popover-prototype
sophieH29 Nov 26, 2018
1259d8b
Adressed CR comments
Nov 27, 2018
5c401bb
Adressed CR comments
Nov 27, 2018
0c76d8e
Merge branch 'master' into docs/chat-messages-popover-prototype
sophieH29 Nov 27, 2018
ca3c550
Merge branch 'master' into docs/chat-messages-popover-prototype
sophieH29 Nov 27, 2018
726a7b0
Merge branch 'master' into docs/chat-messages-popover-prototype
sophieH29 Nov 27, 2018
7f8bb6d
Small improvements
Nov 27, 2018
02a325f
Merge branch 'docs/chat-messages-popover-prototype' of https://github…
Nov 27, 2018
5550bfd
Merge branch 'master' into docs/chat-messages-popover-prototype
sophieH29 Nov 28, 2018
d40b59e
Improvements with styles
Nov 28, 2018
4fd8c54
Updates
Nov 29, 2018
4bcf1f3
Merge branch 'master' into docs/chat-messages-popover-prototype
sophieH29 Nov 29, 2018
d869638
Merge branch 'master' into docs/chat-messages-popover-prototype
sophieH29 Nov 29, 2018
2ff7cbb
Merge branch 'master' into docs/chat-messages-popover-prototype
sophieH29 Nov 30, 2018
84073c5
Merge branch 'master' into docs/chat-messages-popover-prototype
sophieH29 Dec 3, 2018
e0ac380
Add toolbarButtonBehavior
Dec 3, 2018
d2df165
adding aria-label and adding toolbarButton behavior
mituron Dec 4, 2018
b633ddb
Merge branch 'master' into docs/chat-messages-popover-prototype
sophieH29 Dec 4, 2018
5fa45ba
Small improvements
Dec 4, 2018
ec461c7
Merge branch 'docs/chat-messages-popover-prototype' of https://github…
Dec 4, 2018
a77319d
Merge branch 'master' into docs/chat-messages-popover-prototype
sophieH29 Dec 5, 2018
8a7de82
Improvements / fixes after CR
Dec 5, 2018
734a641
Merge branch 'master' into docs/chat-messages-popover-prototype
sophieH29 Dec 5, 2018
09fc24f
Merge branch 'master' into docs/chat-messages-popover-prototype
sophieH29 Dec 6, 2018
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
8 changes: 8 additions & 0 deletions docs/src/components/Sidebar/Sidebar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -265,6 +265,14 @@ class Sidebar extends React.Component<any, any> {
<Menu.Item as={NavLink} exact to="/prototype-chat-pane" activeClassName="active">
Chat Pane
</Menu.Item>
<Menu.Item
as={NavLink}
exact
to="/prototype-chat-message-with-popover"
activeClassName="active"
>
Chat message with popover
</Menu.Item>
<Menu.Item
as={NavLink}
exact
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import { ChatMessage } from '@stardust-ui/react'

import * as React from 'react'
import * as cx from 'classnames'
import Popover from './Popover'

const janeAvatar = {
image: 'public/images/avatar/small/ade.jpg',
status: { color: 'green', icon: 'check' },
}

interface ChatMessageWithPopoverProps {
className?: string
}

interface ChatMessageWithPopoverState {
focused: boolean
}

class ChatMessageWithPopover extends React.Component<
ChatMessageWithPopoverProps,
ChatMessageWithPopoverState
> {
state = {
focused: false,
}

changeFocusState = (isFocused: boolean) => {
this.state.focused !== isFocused && this.setState({ focused: isFocused })
}

handleFocus = () => {
this.changeFocusState(true)
}

handleBlur = e => {
const shouldPreserveFocusState = e.currentTarget.contains(e.relatedTarget)
this.changeFocusState(shouldPreserveFocusState)
}

render() {
return (
<ChatMessage
author="Jane Doe"
timestamp="Yesterday, 10:15 PM"
content={{
content: (
<div>
<Popover className="actions" />
<a href="/">Link</a> Hover me to see the actions <a href="/">Some Link</a>
</div>
),
}}
avatar={janeAvatar}
onFocus={this.handleFocus}
onBlur={this.handleBlur}
className={cx(this.props.className, this.state.focused ? 'focused' : '')}
/>
)
}
}

export default ChatMessageWithPopover
56 changes: 56 additions & 0 deletions docs/src/prototypes/chatMessageWithPopover/ChatWithPopover.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import { Chat, Provider } from '@stardust-ui/react'
import * as React from 'react'
import ChatMessageWithPopover from './ChatMessageWithPopover'

const ChatWithPopover = () => (
<Provider
theme={{
componentStyles: {
ChatMessage: {
root: ({ theme: { siteVariables } }) => ({
position: 'relative',

'&.focused .actions': {
opacity: 1,
},
':hover .actions': {
opacity: 1,
},
'& a': {
color: siteVariables.brand,
},
}),
},
ContextMenu: {
root: ({ theme: { siteVariables } }) => ({
background: siteVariables.white,
boxShadow: '0 0.2rem 1.6rem 0 rgba(37,36,35,.3)',
borderRadius: '.3rem',
marginTop: '5px',
}),
},
Menu: {
root: {
'& a:focus': {
textDecoration: 'none',
color: 'inherit',
},
'& a': {
color: 'inherit',
},
},
},
},
}}
>
<Chat
items={[
{ key: 'a', content: <ChatMessageWithPopover /> },
{ key: 'b', content: <ChatMessageWithPopover /> },
{ key: 'c', content: <ChatMessageWithPopover /> },
]}
/>
</Provider>
)

export default ChatWithPopover
184 changes: 184 additions & 0 deletions docs/src/prototypes/chatMessageWithPopover/Popover.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,184 @@
import {
Menu,
Popup,
toolbarBehavior,
popupFocusTrapBehavior,
createComponent,
ComponentSlotStyle,
ComponentVariablesInput,
toolbarButtonBehavior,
} from '@stardust-ui/react'
import { ReactChildren } from 'types/utils'
import * as React from 'react'
import * as cx from 'classnames'

export interface PopoverProps {
className?: string
}

interface PopoverState {
focused: boolean
popupOpened: boolean
}

class Popover extends React.Component<PopoverProps, PopoverState> {
state = {
focused: false,
popupOpened: false,
}

changeFocusState = (isFocused: boolean) => {
this.state.focused !== isFocused && this.setState({ focused: isFocused })
}

handleFocus = () => {
this.changeFocusState(true)
}

handleBlur = e => {
// if e.relatedTarget === null it means the click was outside this container
if (!this.state.popupOpened || e.relatedTarget === null) {
const shouldPreserveFocusState = e.currentTarget.contains(e.relatedTarget)
this.changeFocusState(shouldPreserveFocusState)
} else {
e.stopPropagation()
}
}

handleMenuClick = () => {
// close popup when other MenuItem clicked, but the event propagation was stopped
this.state.popupOpened && this.setState({ popupOpened: false })
}

popoverStyles = ({ theme: { siteVariables } }) => ({
transition: 'opacity 0.2s',
position: 'absolute',
top: '-20px',
right: '5px',
background: siteVariables.white,
boxShadow: '0px 2px 4px #ddd',
borderRadius: '.3rem',
opacity: 0,

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

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

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

render() {
return (
<Menu
styles={this.popoverStyles}
iconOnly
className={cx(this.props.className, this.state.focused ? 'focused' : '')}
items={[
{
key: 'smile',
icon: 'smile',
className: 'smile-emoji',
accessibility: toolbarButtonBehavior,
'aria-label': 'smile one',
},
{
key: 'smile2',
icon: 'smile',
className: 'smile-emoji',
accessibility: toolbarButtonBehavior,
'aria-label': 'smile two',
},
{
key: 'smile3',
icon: 'smile',
className: 'smile-emoji',
accessibility: toolbarButtonBehavior,
'aria-label': 'smile three',
},
{
key: 'a',
icon: 'thumbs up',
accessibility: toolbarButtonBehavior,
'aria-label': 'thumbs up',
},
{
key: 'c',
icon: 'ellipsis horizontal',
accessibility: toolbarButtonBehavior,
'aria-label': 'more options',
},
].map(itemShorthandValue => render =>
render(itemShorthandValue, this.renderItemOrContextMenu),
)}
onFocus={this.handleFocus}
onBlur={this.handleBlur}
onClick={this.handleMenuClick}
accessibility={toolbarBehavior}
data-is-focusable={true}
/>
)
}

renderItemOrContextMenu = (MenuItem, props) => {
if (props.icon !== 'ellipsis horizontal') {
return <MenuItem {...props} />
}

return (
<Popup
key={props.key}
position="below"
accessibility={popupFocusTrapBehavior}
trigger={
<MenuItem
{...props}
onClick={e => {
this.setState(prev => ({ popupOpened: !prev.popupOpened }))
}}
/>
}
open={this.state.popupOpened}
onOpenChange={(e, newProps) => {
this.setState({ popupOpened: newProps.open })
}}
content={
<ContextMenu>
<Menu
vertical
pills
className="actions"
items={[
{ key: 'bookmark', icon: 'folder', content: 'Save this message' },
{ key: 'linkify', icon: 'linkify', content: 'Copy link' },
{ key: 'translate', icon: 'translate', content: 'Translate' },
]}
/>
</ContextMenu>
}
/>
)
}
}

export default Popover

const ContextMenu = createComponent<ContextMenuProps>({
displayName: 'ContextMenu',
render: ({ stardust, className, children }) => {
const { classes } = stardust
return <div className={cx(className, classes.root)}>{children}</div>
},
})

interface ContextMenuProps {
className?: string
styles?: ComponentSlotStyle
variables?: ComponentVariablesInput
children?: ReactChildren
}
1 change: 1 addition & 0 deletions docs/src/prototypes/chatMessageWithPopover/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { default } from './ChatWithPopover'
6 changes: 6 additions & 0 deletions docs/src/routes.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,12 @@ const Router = () => (
path="/prototype-chat-pane"
component={require('./prototypes/chatPane/index').default}
/>,
<DocsLayout
exact
key="/prototype-chat-message-with-popover"
path="/prototype-chat-message-with-popover"
component={require('./prototypes/chatMessageWithPopover/index').default}
/>,
<DocsLayout
exact
key="/prototype-async-shorthand"
Expand Down