Skip to content

Commit

Permalink
fix: cannot focus compositon dialog in twitter
Browse files Browse the repository at this point in the history
  • Loading branch information
guanbinrui committed Apr 27, 2020
1 parent e9324c4 commit 1c0d0fe
Show file tree
Hide file tree
Showing 6 changed files with 47 additions and 23 deletions.
7 changes: 6 additions & 1 deletion src/components/InjectedComponents/PostDialog.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import {
Chip,
ThemeProvider,
Theme,
DialogProps,
} from '@material-ui/core'
import { MessageCenter, CompositionEvent } from '../../utils/messages'
import { useCapturedInput } from '../../utils/hooks/useCapturedEvents'
Expand Down Expand Up @@ -96,6 +97,8 @@ export interface PostDialogUIProps
onFinishButtonClicked: () => void
onCloseButtonClicked: () => void
onSetSelected: SelectRecipientsUIProps['onSetSelected']
DialogProps?: Partial<DialogProps>
RedPacketDialogProps?: Partial<DialogProps>
SelectRecipientsUIProps?: Partial<SelectRecipientsUIProps>
}
export function PostDialogUI(props: PostDialogUIProps) {
Expand Down Expand Up @@ -131,7 +134,8 @@ export function PostDialogUI(props: PostDialogUIProps) {
onEscapeKeyDown={props.onCloseButtonClicked}
BackdropProps={{
className: classes.backdrop,
}}>
}}
{...props.DialogProps}>
<DialogTitle className={classes.header}>
<IconButton
classes={{ root: classes.close }}
Expand Down Expand Up @@ -240,6 +244,7 @@ export function PostDialogUI(props: PostDialogUIProps) {
open={props.open && redPacketDialogOpen}
onConfirm={() => setRedPacketDialogOpen(false)}
onDecline={() => setRedPacketDialogOpen(false)}
DialogProps={props.DialogProps}
/>
</div>
)
Expand Down
8 changes: 5 additions & 3 deletions src/plugins/Wallet/UI/RedPacket/RedPacketDialog.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import {
InputLabel,
Select,
MenuItem,
DialogProps,
} from '@material-ui/core'
import { useStylesExtends, or } from '../../../../components/custom-ui-helper'
import { DialogDismissIconUI } from '../../../../components/InjectedComponents/DialogDismissIcon'
Expand All @@ -28,7 +29,7 @@ import {
WalletRecord,
ERC20TokenRecord,
} from '../../database/types'
import { useLastRecognizedIdentity, useCurrentIdentity } from '../../../../components/DataSource/useActivatedUI'
import { useCurrentIdentity } from '../../../../components/DataSource/useActivatedUI'
import { useCapturedInput } from '../../../../utils/hooks/useCapturedEvents'
import { PluginMessageCenter } from '../../../PluginMessages'
import { getActivatedUI } from '../../../../social-network/ui'
Expand Down Expand Up @@ -58,6 +59,7 @@ interface RedPacketDialogProps
open: boolean
onConfirm: (opt?: RedPacketJSONPayload | null) => void
onDecline: () => void
DialogProps?: Partial<DialogProps>
}

const useNewPacketStyles = makeStyles(theme =>
Expand Down Expand Up @@ -471,7 +473,6 @@ export function RedPacketDialogUI(
props: RedPacketDialogProps & NewPacketProps & ExistingPacketProps & { tab?: [0 | 1, (next: 0 | 1) => void] },
) {
const classes = useStylesExtends(useStyles(), props)
const rootRef = useRef<HTMLDivElement>(null)
const [currentTab, setCurrentTab] = or(props.tab, useState<0 | 1>(0)) as [
number,
React.Dispatch<React.SetStateAction<number>>,
Expand Down Expand Up @@ -504,7 +505,8 @@ export function RedPacketDialogUI(
disableEnforceFocus
BackdropProps={{
className: classes.backdrop,
}}>
}}
{...props.DialogProps}>
<DialogTitle className={classes.header}>
<IconButton classes={{ root: classes.close }} onClick={props.onDecline}>
<DialogDismissIconUI />
Expand Down
21 changes: 16 additions & 5 deletions src/social-network-provider/twitter.com/ui/injectPostDialog.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,8 @@ import { renderInShadowRoot } from '../../../utils/jss/renderInShadowRoot'
import { PostDialog } from '../../../components/InjectedComponents/PostDialog'
import { useTwitterButton, useTwitterCloseButton, useTwitterLabel, useTwitterDialog } from '../utils/theme'
import { makeStyles } from '@material-ui/styles'
import { postEditorInPopupSelector, rootSelector } from '../utils/selector'
import { postEditorContentInPopupSelector, rootSelector } from '../utils/selector'
import { Theme } from '@material-ui/core'
import { useValueRef } from '../../../utils/hooks/useValueRef'
import { instanceOfTwitterUI } from '.'

const useStyles = makeStyles((theme: Theme) => ({
MUIInputInput: {
Expand All @@ -34,7 +32,7 @@ const useStyles = makeStyles((theme: Theme) => ({

export function injectPostDialogAtTwitter() {
if (location.hostname.indexOf(twitterUrl.hostIdentifier) === -1) return
renderPostDialogTo('popup', postEditorInPopupSelector())
renderPostDialogTo('popup', postEditorContentInPopupSelector())
renderPostDialogTo('timeline', rootSelector())
}

Expand All @@ -52,7 +50,15 @@ function renderPostDialogTo<T>(reason: 'timeline' | 'popup', ls: LiveSelector<T,
}

function PostDialogAtTwitter(props: { reason: 'timeline' | 'popup' }) {
return (
const rootRef = React.useRef<HTMLDivElement>(null)
const dialogProps =
props.reason === 'popup'
? {
disablePortal: true,
container: () => rootRef.current,
}
: {}
const dialog = (
<PostDialog
classes={{
...useStyles(),
Expand All @@ -61,6 +67,7 @@ function PostDialogAtTwitter(props: { reason: 'timeline' | 'popup' }) {
...useTwitterButton(),
...useTwitterCloseButton(),
}}
DialogProps={dialogProps}
SelectRecipientsUIProps={{
SelectRecipientsDialogUIProps: {
classes: {
Expand All @@ -73,4 +80,8 @@ function PostDialogAtTwitter(props: { reason: 'timeline' | 'popup' }) {
reason={props.reason}
/>
)

// ! Render dialog into native composition view instead of portal shadow
// ! More https://github.com/DimensionDev/Maskbook/issues/837
return props.reason === 'popup' ? <div ref={rootRef}>{dialog}</div> : dialog
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,17 @@ import { hasEditor, isCompose } from '../utils/postBox'
export function injectPostDialogHintAtTwitter() {
if (location.hostname.indexOf(twitterUrl.hostIdentifier) === -1) return
const emptyNode = document.createElement('div')
renderPostDialogHintTo(postEditorInTimelineSelector().map(x => (hasEditor() ? x : emptyNode)))
renderPostDialogHintTo(postEditorInPopupSelector().map(x => (isCompose() && hasEditor() ? x : emptyNode)))
renderPostDialogHintTo(
'timeline',
postEditorInTimelineSelector().map(x => (hasEditor() ? x : emptyNode)),
)
renderPostDialogHintTo(
'popup',
postEditorInPopupSelector().map(x => (isCompose() && hasEditor() ? x : emptyNode)),
)
}

function renderPostDialogHintTo<T>(ls: LiveSelector<T, true>) {
function renderPostDialogHintTo<T>(reason: 'timeline' | 'popup', ls: LiveSelector<T, true>) {
const watcher = new MutationObserverWatcher(ls)
.setDOMProxyOption({
afterShadowRootInit: { mode: 'closed' },
Expand All @@ -27,7 +33,7 @@ function renderPostDialogHintTo<T>(ls: LiveSelector<T, true>) {
subtree: true,
})

renderInShadowRoot(<PostDialogHintAtTwitter />, watcher.firstDOMProxy.afterShadow)
renderInShadowRoot(<PostDialogHintAtTwitter reason={reason} />, watcher.firstDOMProxy.afterShadow)
}

export const useTwitterThemedPostDialogHint = makeStyles((theme: Theme) => ({
Expand All @@ -53,15 +59,14 @@ export const useTwitterThemedPostDialogHint = makeStyles((theme: Theme) => ({
},
}))

function PostDialogHintAtTwitter() {
function PostDialogHintAtTwitter({ reason }: { reason: 'timeline' | 'popup' }) {
const classes = {
...useTwitterThemedPostDialogHint(),
...useTwitterButton(),
}
const onHintButtonClicked = useCallback(
() => MessageCenter.emit('compositionUpdated', { reason: 'timeline', open: true }),
[],
)
const onHintButtonClicked = useCallback(() => MessageCenter.emit('compositionUpdated', { reason, open: true }), [
reason,
])
return (
<PostDialogHint
classes={classes}
Expand Down
3 changes: 2 additions & 1 deletion src/social-network-provider/twitter.com/utils/selector.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@ export const rootSelector: () => LiveSelector<E, true> = () => querySelector<E>(

export const composeAnchorSelector: () => LiveSelector<HTMLAnchorElement, true> = () =>
querySelector<HTMLAnchorElement>('a[href="/compose/tweet"]')

export const postEditorContentInPopupSelector: () => LiveSelector<E, true> = () =>
querySelector<E>('[aria-labelledby="modal-header"] > div:first-child > div:nth-child(3)')
export const postEditorInPopupSelector: () => LiveSelector<E, true> = () =>
querySelector<E>(
'[aria-labelledby="modal-header"] > div:first-child > div:nth-child(3) > div:first-child > div:first-child',
Expand Down
8 changes: 4 additions & 4 deletions src/utils/jss/ShadowRootDialog.tsx
Original file line number Diff line number Diff line change
@@ -1,21 +1,21 @@
import React from 'react'
import { Dialog, withMobileDialog } from '@material-ui/core'
import { Dialog, withMobileDialog, DialogProps } from '@material-ui/core'
import '../../utils/jss/ShadowRootPortal'
import { PortalShadowRoot } from '../../utils/jss/ShadowRootPortal'
import { useSheetsRegistryStyles } from './renderInShadowRoot'

const ResponsiveDialog = withMobileDialog({ breakpoint: 'xs' })(Dialog)

export default function ShadowRootDialog(_props: any) {
export default function ShadowRootDialog(_props: DialogProps) {
const ref = React.useRef<HTMLDivElement>(null)
const styles = useSheetsRegistryStyles(ref.current)

// ? I need the render tree to get the shadowroot. Is the extra div must be rendered?
// ? can style be transported to shadowroot directly instead of with dialog children?
const { children, ...props } = _props
const { children, container, ...props } = _props
return (
<div ref={ref}>
<ResponsiveDialog {...props} container={PortalShadowRoot}>
<ResponsiveDialog {...props} container={container ?? PortalShadowRoot}>
<style>{styles}</style>
{children}
</ResponsiveDialog>
Expand Down

0 comments on commit 1c0d0fe

Please sign in to comment.