gab-social/app/javascript/gabsocial/components/popover/popover_root.js

177 lines
4.8 KiB
JavaScript
Raw Normal View History

2020-02-28 15:20:47 +00:00
import detectPassiveEvents from 'detect-passive-events'
import { closePopover } from '../../actions/popover'
import Bundle from '../../features/ui/util/bundle'
import BundleModalError from '../bundle_modal_error'
import PopoverBase from './popover_base'
import ContentWarningPopover from './content_warning_popover'
import DatePickerPopover from './date_picker_popover'
2020-03-27 15:29:52 +00:00
import EmojiPickerPopover from './emoji_picker_popover'
2020-02-28 15:20:47 +00:00
import GroupInfoPopover from './group_info_popover'
import ProfileOptionsPopover from './profile_options_popover'
import SearchPopover from './search_popover'
import SidebarMorePopover from './sidebar_more_popover'
import StatusOptionsPopover from './status_options_popover'
2020-03-25 03:08:43 +00:00
import StatusSharePopover from './status_share_popover'
2020-02-28 15:20:47 +00:00
import StatusVisibilityPopover from './status_visibility_popover'
2020-03-25 03:08:43 +00:00
import UserInfoPopover from './user_info_popover'
2020-02-28 15:20:47 +00:00
const listenerOptions = detectPassiveEvents.hasSupport ? { passive: true } : false
const POPOVER_COMPONENTS = {
CONTENT_WARNING: () => Promise.resolve({ default: ContentWarningPopover }),
DATE_PICKER: () => Promise.resolve({ default: DatePickerPopover }),
2020-03-27 15:29:52 +00:00
EMOJI_PICKER: () => Promise.resolve({ default: EmojiPickerPopover }),
2020-02-28 15:20:47 +00:00
GROUP_INFO: () => GroupInfoPopover,
2020-03-14 17:31:29 +00:00
PROFILE_OPTIONS: () => Promise.resolve({ default: ProfileOptionsPopover }),
2020-02-28 15:20:47 +00:00
SEARCH: () => Promise.resolve({ default: SearchPopover }),
SIDEBAR_MORE: () => Promise.resolve({ default: SidebarMorePopover }),
STATUS_OPTIONS: () => Promise.resolve({ default: StatusOptionsPopover }),
2020-03-25 03:08:43 +00:00
STATUS_SHARE: () => Promise.resolve({ default: StatusSharePopover }),
2020-02-28 15:20:47 +00:00
STATUS_VISIBILITY: () => Promise.resolve({ default: StatusVisibilityPopover }),
2020-03-11 23:56:18 +00:00
USER_INFO: () => Promise.resolve({ default: UserInfoPopover }),
2020-02-28 15:20:47 +00:00
}
2020-04-11 23:29:19 +01:00
const mapStateToProps = (state) => ({
2020-04-08 02:06:59 +01:00
type: state.getIn(['popover', 'popoverType']),
props: state.getIn(['popover', 'popoverProps'], {}),
2020-02-28 15:20:47 +00:00
})
const mapDispatchToProps = (dispatch) => ({
onClose(optionalType) {
2020-04-02 04:17:21 +01:00
dispatch(closePopover(optionalType))
2020-02-28 15:20:47 +00:00
},
})
export default
@connect(mapStateToProps, mapDispatchToProps)
class PopoverRoot extends PureComponent {
2020-04-08 02:06:59 +01:00
2020-02-28 15:20:47 +00:00
static propTypes = {
type: PropTypes.string,
props: PropTypes.object,
onClose: PropTypes.func.isRequired,
}
2020-02-29 15:42:47 +00:00
// getSnapshotBeforeUpdate() {
// return { visible: !!this.props.type }
// }
2020-02-28 15:20:47 +00:00
static contextTypes = {
router: PropTypes.object,
}
static propTypes = {
onClose: PropTypes.func.isRequired,
}
handleDocumentClick = e => {
2020-03-14 17:31:29 +00:00
if (this.node && !this.node.contains(e.target)) {
this.props.onClose()
}
2020-02-28 15:20:47 +00:00
}
componentDidMount() {
2020-03-14 17:31:29 +00:00
document.addEventListener('click', this.handleDocumentClick, false)
document.addEventListener('keydown', this.handleKeyDown, false)
document.addEventListener('touchend', this.handleDocumentClick, listenerOptions)
2020-02-28 15:20:47 +00:00
}
componentWillUnmount() {
2020-03-14 17:31:29 +00:00
document.removeEventListener('click', this.handleDocumentClick, false)
document.removeEventListener('keydown', this.handleKeyDown, false)
document.removeEventListener('touchend', this.handleDocumentClick, listenerOptions)
2020-02-28 15:20:47 +00:00
}
setRef = c => {
this.node = c
}
setFocusRef = c => {
this.focusedItem = c
}
handleKeyDown = e => {
const items = Array.from(this.node.getElementsByTagName('a'))
const index = items.indexOf(document.activeElement)
let element
switch (e.key) {
2020-04-08 02:06:59 +01:00
case 'ArrowDown':
element = items[index + 1]
if (element) element.focus()
break
case 'ArrowUp':
element = items[index - 1]
if (element) element.focus()
break
case 'Home':
element = items[0]
if (element) element.focus()
break
case 'End':
element = items[items.length - 1]
if (element) element.focus()
break
2020-02-28 15:20:47 +00:00
}
}
handleItemKeyDown = e => {
if (e.key === 'Enter') {
this.handleClick(e)
}
}
handleClick = e => {
const i = Number(e.currentTarget.getAttribute('data-index'))
const { action, to } = this.props.items[i]
this.props.onClose()
if (typeof action === 'function') {
e.preventDefault()
action(e)
} else if (to) {
e.preventDefault()
this.context.router.history.push(to)
}
}
2020-03-11 23:56:18 +00:00
renderError = () => {
return null
}
renderLoading = () => {
return null
2020-02-28 15:20:47 +00:00
}
render() {
2020-03-11 23:56:18 +00:00
const {
type,
props,
} = this.props
2020-02-28 15:20:47 +00:00
const visible = !!type
return (
2020-03-11 23:56:18 +00:00
<PopoverBase
visible={visible}
2020-03-14 17:31:29 +00:00
innerRef={this.setRef}
2020-03-11 23:56:18 +00:00
{...props}
>
{
visible &&
<Bundle
fetchComponent={POPOVER_COMPONENTS[type]}
loading={this.renderLoading(type)}
error={this.renderError}
renderDelay={200}
>
{
(SpecificComponent) => <SpecificComponent {...props} />
}
</Bundle>
}
</PopoverBase>
2020-02-28 15:20:47 +00:00
)
}
2020-04-08 02:06:59 +01:00
2020-02-28 15:20:47 +00:00
}