fix(mobile): super editor autocomplete dropdowns (#2019)

This commit is contained in:
Aman Harwara
2022-11-17 02:44:16 +05:30
committed by GitHub
parent bb64320f80
commit d21f3ba6f3
8 changed files with 44 additions and 13 deletions

View File

@@ -21,6 +21,7 @@ import { GetDynamicTableBlocks, GetTableBlock } from './Blocks/Table'
import Popover from '@/Components/Popover/Popover' import Popover from '@/Components/Popover/Popover'
import { PopoverClassNames } from '../ClassNames' import { PopoverClassNames } from '../ClassNames'
import { GetDatetimeBlocks } from './Blocks/DateTime' import { GetDatetimeBlocks } from './Blocks/DateTime'
import { isMobileScreen } from '@/Utils'
export default function BlockPickerMenuPlugin(): JSX.Element { export default function BlockPickerMenuPlugin(): JSX.Element {
const [editor] = useLexicalComposerContext() const [editor] = useLexicalComposerContext()
@@ -109,12 +110,14 @@ export default function BlockPickerMenuPlugin(): JSX.Element {
align="start" align="start"
anchorPoint={{ anchorPoint={{
x: anchorElementRef.current.offsetLeft, x: anchorElementRef.current.offsetLeft,
y: anchorElementRef.current.offsetTop + anchorElementRef.current.offsetHeight, y: anchorElementRef.current.offsetTop + (!isMobileScreen() ? anchorElementRef.current.offsetHeight : 0),
}} }}
open={popoverOpen} open={popoverOpen}
togglePopover={() => { togglePopover={() => {
setPopoverOpen((prevValue) => !prevValue) setPopoverOpen((prevValue) => !prevValue)
}} }}
disableMobileFullscreenTakeover={true}
side={isMobileScreen() ? 'top' : 'bottom'}
> >
<div className={PopoverClassNames}> <div className={PopoverClassNames}>
<ul> <ul>

View File

@@ -11,6 +11,7 @@ import Popover from '@/Components/Popover/Popover'
import { INSERT_BUBBLE_COMMAND, INSERT_FILE_COMMAND } from '../Commands' import { INSERT_BUBBLE_COMMAND, INSERT_FILE_COMMAND } from '../Commands'
import { useLinkingController } from '../../../../../Controllers/LinkingControllerProvider' import { useLinkingController } from '../../../../../Controllers/LinkingControllerProvider'
import { PopoverClassNames } from '../ClassNames' import { PopoverClassNames } from '../ClassNames'
import { isMobileScreen } from '@/Utils'
type Props = { type Props = {
currentNote: SNNote currentNote: SNNote
@@ -106,12 +107,14 @@ export const ItemSelectionPlugin: FunctionComponent<Props> = ({ currentNote }) =
align="start" align="start"
anchorPoint={{ anchorPoint={{
x: anchorElementRef.current.offsetLeft, x: anchorElementRef.current.offsetLeft,
y: anchorElementRef.current.offsetTop + anchorElementRef.current.offsetHeight, y: anchorElementRef.current.offsetTop + (!isMobileScreen() ? anchorElementRef.current.offsetHeight : 0),
}} }}
open={popoverOpen} open={popoverOpen}
togglePopover={() => { togglePopover={() => {
setPopoverOpen((prevValue) => !prevValue) setPopoverOpen((prevValue) => !prevValue)
}} }}
disableMobileFullscreenTakeover={true}
side={isMobileScreen() ? 'top' : 'bottom'}
> >
<div className={PopoverClassNames}> <div className={PopoverClassNames}>
<ul> <ul>

View File

@@ -102,7 +102,7 @@ export const SuperEditor: FunctionComponent<Props> = ({
<BlocksEditor <BlocksEditor
onChange={handleChange} onChange={handleChange}
ignoreFirstChange={true} ignoreFirstChange={true}
className="relative relative h-full resize-none text-base focus:shadow-none focus:outline-none" className="relative h-full resize-none text-base focus:shadow-none focus:outline-none"
previewLength={NotePreviewCharLimit} previewLength={NotePreviewCharLimit}
spellcheck={spellcheck} spellcheck={spellcheck}
> >

View File

@@ -4,10 +4,15 @@ import { PopoverAlignment, PopoverSide } from './Types'
import { OppositeSide, checkCollisions, getNonCollidingSide, getNonCollidingAlignment } from './Utils/Collisions' import { OppositeSide, checkCollisions, getNonCollidingSide, getNonCollidingAlignment } from './Utils/Collisions'
import { getPositionedPopoverRect } from './Utils/Rect' import { getPositionedPopoverRect } from './Utils/Rect'
const getStylesFromRect = (rect: DOMRect): CSSProperties => { const getStylesFromRect = (rect: DOMRect, disableMobileFullscreenTakeover?: boolean): CSSProperties => {
return { return {
willChange: 'transform', willChange: 'transform',
transform: `translate(${rect.x}px, ${rect.y}px)`, transform: `translate(${rect.x}px, ${rect.y}px)`,
...(disableMobileFullscreenTakeover
? {
maxWidth: `${window.innerWidth - rect.x * 2}px`,
}
: {}),
} }
} }
@@ -17,6 +22,7 @@ type Options = {
documentRect: DOMRect documentRect: DOMRect
popoverRect?: DOMRect popoverRect?: DOMRect
side: PopoverSide side: PopoverSide
disableMobileFullscreenTakeover?: boolean
} }
export const getPositionedPopoverStyles = ({ export const getPositionedPopoverStyles = ({
@@ -25,6 +31,7 @@ export const getPositionedPopoverStyles = ({
documentRect, documentRect,
popoverRect, popoverRect,
side, side,
disableMobileFullscreenTakeover,
}: Options): [CSSProperties | null, PopoverSide, PopoverAlignment] => { }: Options): [CSSProperties | null, PopoverSide, PopoverAlignment] => {
if (!popoverRect || !anchorRect) { if (!popoverRect || !anchorRect) {
return [null, side, align] return [null, side, align]
@@ -32,7 +39,7 @@ export const getPositionedPopoverStyles = ({
const matchesMediumBreakpoint = matchMedia(MediaQueryBreakpoints.md).matches const matchesMediumBreakpoint = matchMedia(MediaQueryBreakpoints.md).matches
if (!matchesMediumBreakpoint) { if (!matchesMediumBreakpoint && !disableMobileFullscreenTakeover) {
return [null, side, align] return [null, side, align]
} }
@@ -51,5 +58,5 @@ export const getPositionedPopoverStyles = ({
}) })
const finalPositionedRect = getPositionedPopoverRect(popoverRect, anchorRect, finalSide, finalAlignment) const finalPositionedRect = getPositionedPopoverRect(popoverRect, anchorRect, finalSide, finalAlignment)
return [getStylesFromRect(finalPositionedRect), finalSide, finalAlignment] return [getStylesFromRect(finalPositionedRect, disableMobileFullscreenTakeover), finalSide, finalAlignment]
} }

View File

@@ -27,7 +27,6 @@ const useRegisterPopoverToParent = (popoverId: string) => {
type Props = PopoverProps & { type Props = PopoverProps & {
open: boolean open: boolean
disableClickOutside?: boolean
} }
const Popover = ({ const Popover = ({
@@ -41,6 +40,7 @@ const Popover = ({
side, side,
togglePopover, togglePopover,
disableClickOutside, disableClickOutside,
disableMobileFullscreenTakeover,
}: Props) => { }: Props) => {
const popoverId = useRef(UuidGenerator.GenerateUuid()) const popoverId = useRef(UuidGenerator.GenerateUuid())
@@ -99,6 +99,7 @@ const Popover = ({
side={side} side={side}
togglePopover={togglePopover} togglePopover={togglePopover}
disableClickOutside={disableClickOutside} disableClickOutside={disableClickOutside}
disableMobileFullscreenTakeover={disableMobileFullscreenTakeover}
> >
{children} {children}
</PositionedPopoverContent> </PositionedPopoverContent>

View File

@@ -24,6 +24,7 @@ const PositionedPopoverContent = ({
side = 'bottom', side = 'bottom',
togglePopover, togglePopover,
disableClickOutside, disableClickOutside,
disableMobileFullscreenTakeover,
}: PopoverContentProps) => { }: PopoverContentProps) => {
const [popoverElement, setPopoverElement] = useState<HTMLDivElement | null>(null) const [popoverElement, setPopoverElement] = useState<HTMLDivElement | null>(null)
const popoverRect = useAutoElementRect(popoverElement) const popoverRect = useAutoElementRect(popoverElement)
@@ -44,6 +45,7 @@ const PositionedPopoverContent = ({
documentRect, documentRect,
popoverRect: popoverRect ?? popoverElement?.getBoundingClientRect(), popoverRect: popoverRect ?? popoverElement?.getBoundingClientRect(),
side, side,
disableMobileFullscreenTakeover: disableMobileFullscreenTakeover,
}) })
usePopoverCloseOnClickOutside({ usePopoverCloseOnClickOutside({
@@ -72,23 +74,30 @@ const PositionedPopoverContent = ({
<Portal> <Portal>
<div <div
className={classNames( className={classNames(
'absolute top-0 left-0 flex h-full w-full min-w-80 cursor-auto flex-col', 'absolute top-0 left-0 flex w-full min-w-80 cursor-auto flex-col',
'overflow-y-auto rounded bg-default shadow-main md:h-auto md:max-w-xs', 'overflow-y-auto rounded bg-default shadow-main md:h-auto md:max-w-xs',
!disableMobileFullscreenTakeover && 'h-full',
overrideZIndex ? overrideZIndex : 'z-dropdown-menu', overrideZIndex ? overrideZIndex : 'z-dropdown-menu',
!isDesktopScreen ? 'pt-safe-top pb-safe-bottom' : '', !isDesktopScreen && !disableMobileFullscreenTakeover ? 'pt-safe-top pb-safe-bottom' : '',
!styles && 'md:invisible', !styles && 'md:invisible',
)} )}
style={{ style={{
...styles, ...styles,
maxHeight: styles maxHeight: styles
? getPopoverMaxHeight(getAppRect(documentRect), anchorRect, positionedSide, positionedAlignment) ? getPopoverMaxHeight(
getAppRect(documentRect),
anchorRect,
positionedSide,
positionedAlignment,
disableMobileFullscreenTakeover,
)
: '', : '',
top: !isDesktopScreen ? `${document.documentElement.scrollTop}px` : '', top: !isDesktopScreen ? `${document.documentElement.scrollTop}px` : '',
}} }}
ref={setPopoverElement} ref={setPopoverElement}
data-popover={id} data-popover={id}
> >
<div className="md:hidden"> <div className={classNames(disableMobileFullscreenTakeover && 'hidden', 'md:hidden')}>
<div className="flex items-center justify-end px-3 pt-2"> <div className="flex items-center justify-end px-3 pt-2">
<button className="rounded-full border border-border p-1" onClick={togglePopover}> <button className="rounded-full border border-border p-1" onClick={togglePopover}>
<Icon type="close" className="h-6 w-6" /> <Icon type="close" className="h-6 w-6" />

View File

@@ -37,6 +37,8 @@ type CommonPopoverProps = {
overrideZIndex?: string overrideZIndex?: string
togglePopover: () => void togglePopover: () => void
className?: string className?: string
disableClickOutside?: boolean
disableMobileFullscreenTakeover?: boolean
} }
export type PopoverContentProps = CommonPopoverProps & { export type PopoverContentProps = CommonPopoverProps & {
@@ -44,7 +46,6 @@ export type PopoverContentProps = CommonPopoverProps & {
anchorPoint?: Point anchorPoint?: Point
childPopovers: Set<string> childPopovers: Set<string>
id: string id: string
disableClickOutside?: boolean
} }
export type PopoverProps = export type PopoverProps =

View File

@@ -6,14 +6,18 @@ export const getPopoverMaxHeight = (
buttonRect: DOMRect | undefined, buttonRect: DOMRect | undefined,
side: PopoverSide, side: PopoverSide,
alignment: PopoverAlignment, alignment: PopoverAlignment,
disableMobileFullscreenTakeover?: boolean,
): number | 'none' => { ): number | 'none' => {
const matchesMediumBreakpoint = matchMedia(MediaQueryBreakpoints.md).matches const matchesMediumBreakpoint = matchMedia(MediaQueryBreakpoints.md).matches
if (!matchesMediumBreakpoint) { if (!matchesMediumBreakpoint && !disableMobileFullscreenTakeover) {
return 'none' return 'none'
} }
const MarginFromAppBorderInPX = 10 const MarginFromAppBorderInPX = 10
const topSafeAreaInset = parseInt(
getComputedStyle(document.documentElement).getPropertyValue('--safe-area-inset-top'),
)
let constraint = 0 let constraint = 0
@@ -21,6 +25,9 @@ export const getPopoverMaxHeight = (
switch (side) { switch (side) {
case 'top': case 'top':
constraint = appRect.height - buttonRect.top constraint = appRect.height - buttonRect.top
if (topSafeAreaInset > 0) {
constraint += topSafeAreaInset
}
break break
case 'bottom': case 'bottom':
constraint = buttonRect.bottom constraint = buttonRect.bottom