refactor: mobile popover UX (#2140)
This commit is contained in:
@@ -89,7 +89,7 @@ const GeneralAccountMenu: FunctionComponent<Props> = ({
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="mt-1 mb-1 flex items-center justify-between px-3">
|
||||
<div className="mt-1 mb-1 hidden items-center justify-between px-3 md:flex">
|
||||
<div className="text-lg font-bold lg:text-base">Account</div>
|
||||
<div className="flex cursor-pointer" onClick={closeMenu}>
|
||||
<Icon type="close" className="text-neutral" />
|
||||
|
||||
@@ -32,6 +32,7 @@ const WorkspaceSwitcherOption: FunctionComponent<Props> = ({ mainApplicationGrou
|
||||
<Icon type="chevron-right" className={`text-neutral ${MenuItemIconSize}`} />
|
||||
</MenuItem>
|
||||
<Popover
|
||||
title="Switch workspace"
|
||||
align="end"
|
||||
anchorElement={buttonRef.current}
|
||||
className="py-2"
|
||||
|
||||
@@ -27,6 +27,7 @@ const LockscreenWorkspaceSwitcher: FunctionComponent<Props> = ({ mainApplication
|
||||
Switch workspace
|
||||
</Button>
|
||||
<Popover
|
||||
title="Switch workspace"
|
||||
align="center"
|
||||
anchorElement={buttonRef.current}
|
||||
className="py-2"
|
||||
|
||||
@@ -68,6 +68,7 @@ const ChangeEditorButton: FunctionComponent<Props> = ({
|
||||
iconClassName={`text-accessory-tint-${selectedEditorIconTint}`}
|
||||
/>
|
||||
<Popover
|
||||
title="Change note type"
|
||||
togglePopover={toggleMenu}
|
||||
disableClickOutside={isClickOutsideDisabled}
|
||||
anchorElement={buttonRef.current}
|
||||
|
||||
@@ -61,6 +61,7 @@ const AddItemMenuButton = ({
|
||||
<Icon type="add" size="custom" className="h-5 w-5" />
|
||||
</button>
|
||||
<Popover
|
||||
title="Add item"
|
||||
open={canShowMenu && isMenuOpen}
|
||||
anchorElement={addItemButtonRef.current}
|
||||
togglePopover={() => {
|
||||
|
||||
@@ -76,6 +76,7 @@ const ContentListHeader = ({
|
||||
togglePopover={toggleDisplayOptionsMenu}
|
||||
align="start"
|
||||
className="py-2"
|
||||
title="Display options"
|
||||
>
|
||||
<DisplayOptionsMenu
|
||||
application={application}
|
||||
|
||||
@@ -83,6 +83,7 @@ const ContextMenuCell = ({
|
||||
<Icon type="more" />
|
||||
</button>
|
||||
<Popover
|
||||
title="File options"
|
||||
open={contextMenuVisible}
|
||||
anchorElement={anchorElementRef.current}
|
||||
togglePopover={() => {
|
||||
@@ -153,6 +154,7 @@ const ItemLinksCell = ({
|
||||
<Icon type="link" />
|
||||
</button>
|
||||
<Popover
|
||||
title="Linked items"
|
||||
open={contextMenuVisible}
|
||||
anchorElement={anchorElementRef.current}
|
||||
togglePopover={() => {
|
||||
@@ -425,6 +427,7 @@ const ContentTableView = ({
|
||||
<Table table={table} />
|
||||
{contextMenuPosition && contextMenuItem && (
|
||||
<Popover
|
||||
title="Options"
|
||||
open={true}
|
||||
anchorPoint={contextMenuPosition}
|
||||
togglePopover={() => {
|
||||
|
||||
@@ -22,6 +22,7 @@ const FileContextMenu: FunctionComponent<Props> = observer(
|
||||
|
||||
return (
|
||||
<Popover
|
||||
title="File options"
|
||||
open={showFileContextMenu}
|
||||
anchorPoint={fileContextMenuLocation}
|
||||
togglePopover={() => setShowFileContextMenu(!showFileContextMenu)}
|
||||
|
||||
@@ -30,7 +30,13 @@ const FilesOptionsPanel = ({
|
||||
return (
|
||||
<>
|
||||
<RoundIconButton label="File options menu" onClick={toggleMenu} ref={buttonRef} icon="more" />
|
||||
<Popover togglePopover={toggleMenu} anchorElement={buttonRef.current} open={isOpen} className="py-2">
|
||||
<Popover
|
||||
title="File options"
|
||||
togglePopover={toggleMenu}
|
||||
anchorElement={buttonRef.current}
|
||||
open={isOpen}
|
||||
className="py-2"
|
||||
>
|
||||
<Menu a11yLabel="File options panel" isOpen={isOpen}>
|
||||
<FileMenuOptions
|
||||
filesController={filesController}
|
||||
|
||||
@@ -112,6 +112,7 @@ const FilePreviewModal: FunctionComponent<Props> = observer(({ application, view
|
||||
<Icon type="more" className="text-neutral" />
|
||||
</button>
|
||||
<Popover
|
||||
title="File options"
|
||||
open={showOptionsMenu}
|
||||
anchorElement={menuButtonRef.current}
|
||||
togglePopover={() => {
|
||||
@@ -153,7 +154,7 @@ const FilePreviewModal: FunctionComponent<Props> = observer(({ application, view
|
||||
</div>
|
||||
</div>
|
||||
{showLinkedBubblesContainer && (
|
||||
<div className="-mt-1 border-b border-border py-1.5 px-3.5">
|
||||
<div className="-mt-1 min-h-0 flex-shrink-0 border-b border-border py-1.5 px-3.5">
|
||||
<LinkedItemBubblesContainer
|
||||
linkingController={viewControllerManager.linkingController}
|
||||
item={currentFile}
|
||||
|
||||
@@ -101,6 +101,7 @@ const FileViewWithoutProtection = ({ application, viewControllerManager, file }:
|
||||
icon="info"
|
||||
/>
|
||||
<Popover
|
||||
title="Details"
|
||||
open={isFileInfoPanelOpen}
|
||||
togglePopover={toggleFileInfoPanel}
|
||||
anchorElement={fileInfoButtonRef.current}
|
||||
@@ -117,7 +118,9 @@ const FileViewWithoutProtection = ({ application, viewControllerManager, file }:
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<LinkedItemBubblesContainer item={file} linkingController={viewControllerManager.linkingController} />
|
||||
<div className="hidden md:flex">
|
||||
<LinkedItemBubblesContainer item={file} linkingController={viewControllerManager.linkingController} />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex min-h-0 flex-grow flex-col">
|
||||
|
||||
@@ -41,6 +41,7 @@ const AccountMenuButton = ({
|
||||
</button>
|
||||
</StyledTooltip>
|
||||
<Popover
|
||||
title="Account"
|
||||
anchorElement={buttonRef.current}
|
||||
open={isOpen}
|
||||
togglePopover={toggleMenu}
|
||||
|
||||
@@ -49,6 +49,7 @@ const QuickSettingsButton = ({ application, isOpen, toggleMenu, quickSettingsMen
|
||||
</button>
|
||||
</StyledTooltip>
|
||||
<Popover
|
||||
title="Quick settings"
|
||||
togglePopover={toggleMenu}
|
||||
anchorElement={buttonRef.current}
|
||||
open={isOpen}
|
||||
|
||||
@@ -5,6 +5,7 @@ import { useState } from 'react'
|
||||
import { FileItemActionType } from '../AttachedFilesPopover/PopoverFileItemAction'
|
||||
import { FileContextMenuBackupOption } from '../FileContextMenu/FileContextMenuBackupOption'
|
||||
import Icon from '../Icon/Icon'
|
||||
import MenuItem from '../Menu/MenuItem'
|
||||
import HorizontalSeparator from '../Shared/HorizontalSeparator'
|
||||
import Switch from '../Switch/Switch'
|
||||
|
||||
@@ -20,8 +21,7 @@ const LinkedFileMenuOptions = ({ file, closeMenu, handleFileAction, setIsRenamin
|
||||
|
||||
return (
|
||||
<>
|
||||
<button
|
||||
className="flex w-full cursor-pointer items-center border-0 bg-transparent px-3 py-1.5 text-left text-sm text-text hover:bg-contrast hover:text-foreground focus:bg-info-backdrop focus:shadow-none"
|
||||
<MenuItem
|
||||
onClick={() => {
|
||||
void handleFileAction({
|
||||
type: FileItemActionType.PreviewFile,
|
||||
@@ -35,10 +35,10 @@ const LinkedFileMenuOptions = ({ file, closeMenu, handleFileAction, setIsRenamin
|
||||
>
|
||||
<Icon type="file" className="mr-2 text-neutral" />
|
||||
Preview file
|
||||
</button>
|
||||
</MenuItem>
|
||||
<HorizontalSeparator classes="my-1" />
|
||||
<button
|
||||
className="flex w-full cursor-pointer items-center justify-between border-0 bg-transparent px-3 py-1.5 text-left text-sm text-text hover:bg-contrast hover:text-foreground focus:bg-info-backdrop focus:shadow-none"
|
||||
<MenuItem
|
||||
className="justify-between"
|
||||
onClick={() => {
|
||||
handleFileAction({
|
||||
type: FileItemActionType.ToggleFileProtection,
|
||||
@@ -54,10 +54,9 @@ const LinkedFileMenuOptions = ({ file, closeMenu, handleFileAction, setIsRenamin
|
||||
Password protect
|
||||
</span>
|
||||
<Switch className="pointer-events-none px-0" tabIndex={FOCUSABLE_BUT_NOT_TABBABLE} checked={isFileProtected} />
|
||||
</button>
|
||||
</MenuItem>
|
||||
<HorizontalSeparator classes="my-1" />
|
||||
<button
|
||||
className="flex w-full cursor-pointer items-center border-0 bg-transparent px-3 py-1.5 text-left text-sm text-text hover:bg-contrast hover:text-foreground focus:bg-info-backdrop focus:shadow-none"
|
||||
<MenuItem
|
||||
onClick={() => {
|
||||
handleFileAction({
|
||||
type: FileItemActionType.DownloadFile,
|
||||
@@ -68,9 +67,8 @@ const LinkedFileMenuOptions = ({ file, closeMenu, handleFileAction, setIsRenamin
|
||||
>
|
||||
<Icon type="download" className="mr-2 text-neutral" />
|
||||
Download
|
||||
</button>
|
||||
<button
|
||||
className="flex w-full cursor-pointer items-center border-0 bg-transparent px-3 py-1.5 text-left text-sm text-text hover:bg-contrast hover:text-foreground focus:bg-info-backdrop focus:shadow-none"
|
||||
</MenuItem>
|
||||
<MenuItem
|
||||
onClick={() => {
|
||||
setIsRenamingFile(true)
|
||||
closeMenu()
|
||||
@@ -78,9 +76,8 @@ const LinkedFileMenuOptions = ({ file, closeMenu, handleFileAction, setIsRenamin
|
||||
>
|
||||
<Icon type="pencil" className="mr-2 text-neutral" />
|
||||
Rename
|
||||
</button>
|
||||
<button
|
||||
className="flex w-full cursor-pointer items-center border-0 bg-transparent px-3 py-1.5 text-left text-sm text-text hover:bg-contrast hover:text-foreground focus:bg-info-backdrop focus:shadow-none"
|
||||
</MenuItem>
|
||||
<MenuItem
|
||||
onClick={() => {
|
||||
handleFileAction({
|
||||
type: FileItemActionType.DeleteFile,
|
||||
@@ -91,7 +88,7 @@ const LinkedFileMenuOptions = ({ file, closeMenu, handleFileAction, setIsRenamin
|
||||
>
|
||||
<Icon type="trash" className="mr-2 text-danger" />
|
||||
<span className="text-danger">Delete permanently</span>
|
||||
</button>
|
||||
</MenuItem>
|
||||
|
||||
<FileContextMenuBackupOption file={file} />
|
||||
</>
|
||||
|
||||
@@ -101,7 +101,7 @@ const LinkedItemBubblesContainer = ({ item, linkingController }: Props) => {
|
||||
return (
|
||||
<div
|
||||
className={classNames(
|
||||
'note-view-linking-container hidden min-w-80 max-w-full flex-wrap items-center gap-2 bg-transparent md:-mr-2 md:flex',
|
||||
'note-view-linking-container flex min-w-80 max-w-full flex-wrap items-center gap-2 bg-transparent md:-mr-2',
|
||||
allItemsLinkedToItem.length || notesLinkingToItem.length ? 'mt-1' : 'mt-0.5',
|
||||
)}
|
||||
>
|
||||
|
||||
@@ -36,7 +36,13 @@ const LinkedItemsButton = ({ linkingController, filesController, onClickPreproce
|
||||
<StyledTooltip label="Linked items panel">
|
||||
<RoundIconButton label="Linked items panel" onClick={toggleMenu} ref={buttonRef} icon="link" />
|
||||
</StyledTooltip>
|
||||
<Popover togglePopover={toggleMenu} anchorElement={buttonRef.current} open={isLinkingPanelOpen} className="pb-2">
|
||||
<Popover
|
||||
title="Linked items"
|
||||
togglePopover={toggleMenu}
|
||||
anchorElement={buttonRef.current}
|
||||
open={isLinkingPanelOpen}
|
||||
className="pb-2"
|
||||
>
|
||||
<LinkedItemsPanel
|
||||
item={activeItem}
|
||||
isOpen={isLinkingPanelOpen}
|
||||
|
||||
@@ -98,6 +98,7 @@ export const LinkedItemsSectionItem = ({
|
||||
<Icon type="more" className="text-neutral" />
|
||||
</button>
|
||||
<Popover
|
||||
title="Options"
|
||||
open={isMenuOpen}
|
||||
togglePopover={toggleMenu}
|
||||
anchorElement={menuButtonRef.current}
|
||||
|
||||
@@ -905,10 +905,12 @@ class NoteView extends AbstractComponent<NoteViewProps, State> {
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
<LinkedItemBubblesContainer
|
||||
item={this.note}
|
||||
linkingController={this.viewControllerManager.linkingController}
|
||||
/>
|
||||
<div className="hidden md:block">
|
||||
<LinkedItemBubblesContainer
|
||||
item={this.note}
|
||||
linkingController={this.viewControllerManager.linkingController}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
|
||||
@@ -109,6 +109,7 @@ export default function BlockPickerMenuPlugin(): JSX.Element {
|
||||
|
||||
return (
|
||||
<Popover
|
||||
title="Block picker"
|
||||
align="start"
|
||||
anchorElement={anchorElementRef.current}
|
||||
open={true}
|
||||
|
||||
@@ -96,6 +96,7 @@ export const ItemSelectionPlugin: FunctionComponent<Props> = ({ currentNote }) =
|
||||
|
||||
return (
|
||||
<Popover
|
||||
title="Select item"
|
||||
align="start"
|
||||
anchorElement={anchorElementRef.current}
|
||||
open={true}
|
||||
|
||||
@@ -35,6 +35,7 @@ const NotesContextMenu = ({
|
||||
|
||||
return (
|
||||
<Popover
|
||||
title="Note options"
|
||||
align="start"
|
||||
anchorPoint={{
|
||||
x: contextMenuClickLocation.x,
|
||||
|
||||
@@ -65,6 +65,7 @@ const AddTagOption: FunctionComponent<Props> = ({
|
||||
<Icon type="chevron-right" className="text-neutral" />
|
||||
</MenuItem>
|
||||
<Popover
|
||||
title="Add tag"
|
||||
togglePopover={toggleMenu}
|
||||
anchorElement={buttonRef.current}
|
||||
open={isOpen}
|
||||
|
||||
@@ -50,6 +50,7 @@ const ChangeEditorOption: FunctionComponent<ChangeEditorOptionProps> = ({ applic
|
||||
</div>
|
||||
</MenuItem>
|
||||
<Popover
|
||||
title="Change note type"
|
||||
align="start"
|
||||
anchorElement={buttonRef.current}
|
||||
className="pt-2 md:pt-0"
|
||||
|
||||
@@ -48,6 +48,7 @@ const ListedActionsOption: FunctionComponent<Props> = ({ application, note, icon
|
||||
<Icon type="chevron-right" className="text-neutral" />
|
||||
</MenuItem>
|
||||
<Popover
|
||||
title="Listed"
|
||||
togglePopover={toggleMenu}
|
||||
anchorElement={buttonRef.current}
|
||||
open={isOpen}
|
||||
|
||||
@@ -47,6 +47,7 @@ const NotesOptionsPanel = ({
|
||||
<>
|
||||
<RoundIconButton label="Note options menu" onClick={toggleMenu} ref={buttonRef} icon="more" />
|
||||
<Popover
|
||||
title="Note options"
|
||||
disableClickOutside={disableClickOutside}
|
||||
togglePopover={toggleMenu}
|
||||
anchorElement={buttonRef.current}
|
||||
|
||||
@@ -52,6 +52,7 @@ const SuperNoteOptions = ({ note, markdownShortcut, enableSuperMarkdownPreview }
|
||||
<Icon type="chevron-right" className="ml-auto text-neutral" />
|
||||
</MenuItem>
|
||||
<Popover
|
||||
title="Export note"
|
||||
side="left"
|
||||
align="start"
|
||||
open={isExportMenuOpen}
|
||||
|
||||
@@ -0,0 +1,92 @@
|
||||
import { useDisableBodyScrollOnMobile } from '@/Hooks/useDisableBodyScrollOnMobile'
|
||||
import { useLifecycleAnimation } from '@/Hooks/useLifecycleAnimation'
|
||||
import { classNames } from '@standardnotes/snjs'
|
||||
import { ReactNode } from 'react'
|
||||
import Portal from '../Portal/Portal'
|
||||
|
||||
const MobilePopoverContent = ({
|
||||
open,
|
||||
requestClose,
|
||||
children,
|
||||
title,
|
||||
className,
|
||||
}: {
|
||||
open: boolean
|
||||
requestClose: () => void
|
||||
children: ReactNode
|
||||
title: string
|
||||
className?: string
|
||||
}) => {
|
||||
const [isMounted, setPopoverElement] = useLifecycleAnimation({
|
||||
open,
|
||||
enter: {
|
||||
keyframes: [
|
||||
{
|
||||
opacity: 0.25,
|
||||
transform: 'translateY(1rem)',
|
||||
},
|
||||
{
|
||||
opacity: 1,
|
||||
transform: 'translateY(0)',
|
||||
},
|
||||
],
|
||||
options: {
|
||||
easing: 'cubic-bezier(.36,.66,.04,1)',
|
||||
duration: 150,
|
||||
fill: 'forwards',
|
||||
},
|
||||
initialStyle: {
|
||||
transformOrigin: 'bottom',
|
||||
},
|
||||
},
|
||||
enterCallback: (element) => {
|
||||
element.scrollTop = 0
|
||||
},
|
||||
exit: {
|
||||
keyframes: [
|
||||
{
|
||||
opacity: 1,
|
||||
transform: 'translateY(0)',
|
||||
},
|
||||
{
|
||||
opacity: 0,
|
||||
transform: 'translateY(1rem)',
|
||||
},
|
||||
],
|
||||
options: {
|
||||
easing: 'cubic-bezier(.36,.66,.04,1)',
|
||||
duration: 150,
|
||||
fill: 'forwards',
|
||||
},
|
||||
initialStyle: {
|
||||
transformOrigin: 'bottom',
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
useDisableBodyScrollOnMobile()
|
||||
|
||||
if (!isMounted) {
|
||||
return null
|
||||
}
|
||||
|
||||
return (
|
||||
<Portal>
|
||||
<div
|
||||
ref={setPopoverElement}
|
||||
className="absolute top-0 left-0 z-modal flex h-full w-full origin-bottom flex-col bg-default pt-safe-top pb-safe-bottom opacity-0"
|
||||
>
|
||||
<div className="flex items-center justify-between border-b border-border py-2.5 px-3 text-base">
|
||||
<div />
|
||||
<div className="font-semibold">{title}</div>
|
||||
<button className="font-semibold active:shadow-none active:outline-none" onClick={requestClose}>
|
||||
Done
|
||||
</button>
|
||||
</div>
|
||||
<div className={classNames('h-full overflow-y-auto', className)}>{children}</div>
|
||||
</div>
|
||||
</Portal>
|
||||
)
|
||||
}
|
||||
|
||||
export default MobilePopoverContent
|
||||
@@ -1,6 +1,8 @@
|
||||
import { MutuallyExclusiveMediaQueryBreakpoints, useMediaQuery } from '@/Hooks/useMediaQuery'
|
||||
import { useAndroidBackHandler } from '@/NativeMobileWeb/useAndroidBackHandler'
|
||||
import { UuidGenerator } from '@standardnotes/snjs'
|
||||
import { createContext, useCallback, useContext, useEffect, useMemo, useRef, useState } from 'react'
|
||||
import MobilePopoverContent from './MobilePopoverContent'
|
||||
import PositionedPopoverContent from './PositionedPopoverContent'
|
||||
import { PopoverProps } from './Types'
|
||||
|
||||
@@ -38,6 +40,7 @@ const Popover = ({
|
||||
open,
|
||||
overrideZIndex,
|
||||
side,
|
||||
title,
|
||||
togglePopover,
|
||||
disableClickOutside,
|
||||
disableMobileFullscreenTakeover,
|
||||
@@ -87,6 +90,23 @@ const Popover = ({
|
||||
}
|
||||
}, [addAndroidBackHandler, open, togglePopover])
|
||||
|
||||
const isMobileScreen = useMediaQuery(MutuallyExclusiveMediaQueryBreakpoints.sm)
|
||||
|
||||
if (isMobileScreen && !disableMobileFullscreenTakeover) {
|
||||
return (
|
||||
<MobilePopoverContent
|
||||
open={open}
|
||||
requestClose={() => {
|
||||
togglePopover?.()
|
||||
}}
|
||||
title={title}
|
||||
className={className}
|
||||
>
|
||||
{children}
|
||||
</MobilePopoverContent>
|
||||
)
|
||||
}
|
||||
|
||||
return open ? (
|
||||
<PopoverContext.Provider value={contextValue}>
|
||||
<PositionedPopoverContent
|
||||
@@ -95,13 +115,14 @@ const Popover = ({
|
||||
anchorPoint={anchorPoint}
|
||||
childPopovers={childPopovers}
|
||||
className={`popover-content-container ${className ?? ''}`}
|
||||
id={popoverId.current}
|
||||
overrideZIndex={overrideZIndex}
|
||||
side={side}
|
||||
togglePopover={togglePopover}
|
||||
disableClickOutside={disableClickOutside}
|
||||
disableMobileFullscreenTakeover={disableMobileFullscreenTakeover}
|
||||
id={popoverId.current}
|
||||
maxHeight={maxHeight}
|
||||
overrideZIndex={overrideZIndex}
|
||||
side={side}
|
||||
title={title}
|
||||
togglePopover={togglePopover}
|
||||
>
|
||||
{children}
|
||||
</PositionedPopoverContent>
|
||||
|
||||
@@ -30,25 +30,36 @@ type PopoverAnchorPointProps = {
|
||||
anchorElement?: never
|
||||
}
|
||||
|
||||
type PopoverMutuallyExclusiveProps =
|
||||
| {
|
||||
togglePopover: () => void
|
||||
disableMobileFullscreenTakeover?: never
|
||||
}
|
||||
| {
|
||||
togglePopover?: never
|
||||
disableMobileFullscreenTakeover: boolean
|
||||
}
|
||||
|
||||
type CommonPopoverProps = {
|
||||
align?: PopoverAlignment
|
||||
children: ReactNode
|
||||
side?: PopoverSide
|
||||
overrideZIndex?: string
|
||||
togglePopover?: () => void
|
||||
className?: string
|
||||
disableClickOutside?: boolean
|
||||
disableMobileFullscreenTakeover?: boolean
|
||||
maxHeight?: (calculatedMaxHeight: number) => number
|
||||
title: string
|
||||
}
|
||||
|
||||
export type PopoverContentProps = CommonPopoverProps & {
|
||||
anchorElement?: HTMLElement | null
|
||||
anchorPoint?: Point
|
||||
childPopovers: Set<string>
|
||||
togglePopover?: () => void
|
||||
disableMobileFullscreenTakeover?: boolean
|
||||
id: string
|
||||
}
|
||||
|
||||
export type PopoverProps =
|
||||
| (CommonPopoverProps & PopoverAnchorElementProps)
|
||||
| (CommonPopoverProps & PopoverAnchorPointProps)
|
||||
| (CommonPopoverProps & PopoverMutuallyExclusiveProps & PopoverAnchorElementProps)
|
||||
| (CommonPopoverProps & PopoverMutuallyExclusiveProps & PopoverAnchorPointProps)
|
||||
|
||||
@@ -94,6 +94,7 @@ const EditSmartViewModal = ({ controller, platform }: Props) => {
|
||||
<Icon type={icon || SmartViewDefaultIconName} />
|
||||
</button>
|
||||
<Popover
|
||||
title="Choose icon"
|
||||
open={shouldShowIconPicker}
|
||||
anchorElement={iconPickerButtonRef.current}
|
||||
togglePopover={toggleIconPicker}
|
||||
|
||||
@@ -144,6 +144,7 @@ const AddSmartViewModal = ({ controller, platform }: Props) => {
|
||||
<Icon type={icon || SmartViewDefaultIconName} />
|
||||
</button>
|
||||
<Popover
|
||||
title="Choose icon"
|
||||
open={shouldShowIconPicker}
|
||||
anchorElement={iconPickerButtonRef.current}
|
||||
togglePopover={toggleIconPicker}
|
||||
|
||||
@@ -64,6 +64,7 @@ const TagContextMenu = ({ navigationController, isEntitledToFolders, selectedTag
|
||||
|
||||
return (
|
||||
<Popover
|
||||
title="Tag options"
|
||||
open={contextMenuOpen}
|
||||
anchorPoint={contextMenuClickLocation}
|
||||
togglePopover={() => navigationController.setContextMenuOpen(!contextMenuOpen)}
|
||||
|
||||
@@ -4,90 +4,6 @@ export type AnimationConfig = {
|
||||
initialStyle?: Partial<CSSStyleDeclaration>
|
||||
}
|
||||
|
||||
export const EnterFromTopAnimation: AnimationConfig = {
|
||||
keyframes: [
|
||||
{
|
||||
opacity: 0,
|
||||
transform: 'scaleY(0)',
|
||||
},
|
||||
{
|
||||
opacity: 1,
|
||||
transform: 'scaleY(1)',
|
||||
},
|
||||
],
|
||||
options: {
|
||||
easing: 'ease-in-out',
|
||||
duration: 150,
|
||||
fill: 'forwards',
|
||||
},
|
||||
initialStyle: {
|
||||
transformOrigin: 'top',
|
||||
},
|
||||
}
|
||||
|
||||
export const EnterFromBelowAnimation: AnimationConfig = {
|
||||
keyframes: [
|
||||
{
|
||||
opacity: 0,
|
||||
transform: 'scaleY(0)',
|
||||
},
|
||||
{
|
||||
opacity: 1,
|
||||
transform: 'scaleY(1)',
|
||||
},
|
||||
],
|
||||
options: {
|
||||
easing: 'ease-in-out',
|
||||
duration: 150,
|
||||
fill: 'forwards',
|
||||
},
|
||||
initialStyle: {
|
||||
transformOrigin: 'bottom',
|
||||
},
|
||||
}
|
||||
|
||||
export const ExitToTopAnimation: AnimationConfig = {
|
||||
keyframes: [
|
||||
{
|
||||
opacity: 1,
|
||||
transform: 'scaleY(1)',
|
||||
},
|
||||
{
|
||||
opacity: 0,
|
||||
transform: 'scaleY(0)',
|
||||
},
|
||||
],
|
||||
options: {
|
||||
easing: 'ease-in-out',
|
||||
duration: 150,
|
||||
fill: 'forwards',
|
||||
},
|
||||
initialStyle: {
|
||||
transformOrigin: 'top',
|
||||
},
|
||||
}
|
||||
|
||||
export const ExitToBelowAnimation: AnimationConfig = {
|
||||
keyframes: [
|
||||
{
|
||||
opacity: 1,
|
||||
transform: 'scaleY(1)',
|
||||
},
|
||||
{
|
||||
opacity: 0,
|
||||
transform: 'scaleY(0)',
|
||||
},
|
||||
],
|
||||
options: {
|
||||
easing: 'ease-in-out',
|
||||
duration: 150,
|
||||
fill: 'forwards',
|
||||
},
|
||||
initialStyle: {
|
||||
transformOrigin: 'bottom',
|
||||
},
|
||||
}
|
||||
|
||||
export const TranslateFromTopAnimation: AnimationConfig = {
|
||||
keyframes: [
|
||||
{
|
||||
@@ -129,3 +45,45 @@ export const TranslateToTopAnimation: AnimationConfig = {
|
||||
transformOrigin: 'top',
|
||||
},
|
||||
}
|
||||
|
||||
export const TranslateFromBelowAnimation: AnimationConfig = {
|
||||
keyframes: [
|
||||
{
|
||||
opacity: 0,
|
||||
transform: 'translateY(100%)',
|
||||
},
|
||||
{
|
||||
opacity: 1,
|
||||
transform: 'translateY(0)',
|
||||
},
|
||||
],
|
||||
options: {
|
||||
easing: 'ease-in-out',
|
||||
duration: 150,
|
||||
fill: 'forwards',
|
||||
},
|
||||
initialStyle: {
|
||||
transformOrigin: 'bottom',
|
||||
},
|
||||
}
|
||||
|
||||
export const TranslateToBelowAnimation: AnimationConfig = {
|
||||
keyframes: [
|
||||
{
|
||||
opacity: 1,
|
||||
transform: 'translateY(0)',
|
||||
},
|
||||
{
|
||||
opacity: 0,
|
||||
transform: 'translateY(100%)',
|
||||
},
|
||||
],
|
||||
options: {
|
||||
easing: 'ease-in-out',
|
||||
duration: 150,
|
||||
fill: 'forwards',
|
||||
},
|
||||
initialStyle: {
|
||||
transformOrigin: 'bottom',
|
||||
},
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user