chore: modal animations

This commit is contained in:
Aman Harwara
2023-08-11 17:09:01 +05:30
parent d1142976a5
commit 7fb960470a
19 changed files with 267 additions and 206 deletions

View File

@@ -239,18 +239,16 @@ const ChallengeModal: FunctionComponent<Props> = ({ application, mainApplication
ref={setModalElement} ref={setModalElement}
close={cancelChallenge} close={cancelChallenge}
hideOnInteractOutside={false} hideOnInteractOutside={false}
backdropClassName={isFullScreenBlocker ? 'bg-passive-5' : ''}
className={classNames(
'sn-component challenge-modal relative m-0 flex h-full w-full flex-col items-center rounded border-solid border-border bg-default p-0 md:h-auto md:!w-max',
!isMobileScreen && 'shadow-overlay-light',
isMobileOverlay && 'shadow-overlay-light border border-solid border-border',
)}
> >
<Modal <Modal
title="Authenticate" title="Authenticate"
close={cancelChallenge} close={cancelChallenge}
className={{
content: classNames(
'sn-component challenge-modal relative m-0 flex h-full w-full flex-col items-center rounded border-solid border-border bg-default p-0 md:h-auto md:!w-max md:border md:translucent-ui:bg-[--popover-background-color] translucent-ui:[backdrop-filter:var(--popover-backdrop-filter)]',
!isMobileScreen && 'shadow-overlay-light',
isMobileOverlay && 'shadow-overlay-light border border-solid border-border',
),
backdrop: isFullScreenBlocker ? 'bg-passive-5' : '',
}}
customHeader={<></>} customHeader={<></>}
customFooter={<></>} customFooter={<></>}
disableCustomHeader={isMobileScreen} disableCustomHeader={isMobileScreen}

View File

@@ -253,7 +253,11 @@ const ChangeEditorMenu: FunctionComponent<ChangeEditorMenuProps> = ({
/> />
)} )}
</ModalOverlay> </ModalOverlay>
<ModalOverlay isOpen={showSuperNoteConverter} close={closeSuperNoteConverter}> <ModalOverlay
isOpen={showSuperNoteConverter}
close={closeSuperNoteConverter}
className="md:h-full md:max-h-[90%]"
>
{note && pendingConversionItem && ( {note && pendingConversionItem && (
<SuperNoteConverter <SuperNoteConverter
note={note} note={note}

View File

@@ -103,10 +103,7 @@ const EditorWidthSelectionModal = ({
customFooter={<></>} customFooter={<></>}
disableCustomHeader={isMobileScreen} disableCustomHeader={isMobileScreen}
actions={actions} actions={actions}
className={{ className="flex min-h-[50vh] flex-col"
content: 'select-none md:min-w-[40vw]',
description: 'flex min-h-[50vh] flex-col',
}}
> >
<div className="flex min-h-0 flex-grow flex-col overflow-hidden rounded bg-passive-5 p-4 pb-0"> <div className="flex min-h-0 flex-grow flex-col overflow-hidden rounded bg-passive-5 p-4 pb-0">
<div <div
@@ -195,7 +192,7 @@ const EditorWidthSelectionModalWrapper = () => {
}, [application, toggle]) }, [application, toggle])
return ( return (
<ModalOverlay isOpen={isOpen} close={toggle}> <ModalOverlay isOpen={isOpen} close={toggle} className="select-none md:min-w-[40vw]">
<EditorWidthSelectionModal initialValue={lineWidth} handleChange={setLineWidth} close={toggle} note={note} /> <EditorWidthSelectionModal initialValue={lineWidth} handleChange={setLineWidth} close={toggle} note={note} />
</ModalOverlay> </ModalOverlay>
) )

View File

@@ -117,11 +117,6 @@ const FilePreviewModal = observer(({ application }: Props) => {
<Modal <Modal
title={currentFile.name} title={currentFile.name}
close={dismiss} close={dismiss}
className={{
content: classNames(
'm-0 flex h-full w-full flex-col rounded bg-[--popover-background-color] p-0 shadow-main md:!h-full md:max-h-[90%] md:!w-full md:max-w-[90%]',
),
}}
actions={[ actions={[
{ {
label: 'Done', label: 'Done',
@@ -281,6 +276,7 @@ const FilePreviewModalWrapper: FunctionComponent<Props> = ({ application }) => {
aria-label="File preview modal" aria-label="File preview modal"
isOpen={application.filePreviewModalController.isOpen} isOpen={application.filePreviewModalController.isOpen}
close={application.filePreviewModalController.dismiss} close={application.filePreviewModalController.dismiss}
className="md:!h-full md:max-h-[90%] md:!w-full md:max-w-[90%]"
> >
<FilePreviewModal application={application} /> <FilePreviewModal application={application} />
</ModalOverlay> </ModalOverlay>

View File

@@ -22,11 +22,7 @@ type Props = {
title: string title: string
close: () => void close: () => void
actions?: ModalAction[] actions?: ModalAction[]
className?: { className?: string
content?: string
description?: string
backdrop?: string
}
customHeader?: ReactNode customHeader?: ReactNode
disableCustomHeader?: boolean disableCustomHeader?: boolean
customFooter?: ReactNode customFooter?: ReactNode
@@ -37,7 +33,7 @@ const Modal = ({
title, title,
close, close,
actions = [], actions = [],
className = {}, className,
customHeader, customHeader,
disableCustomHeader = false, disableCustomHeader = false,
customFooter, customFooter,
@@ -97,133 +93,121 @@ const Modal = ({
return ( return (
<> <>
<ModalAndroidBackHandler close={close} /> <ModalAndroidBackHandler close={close} />
<div {customHeader && !disableCustomHeader ? (
className={classNames('absolute z-0 h-full w-full bg-passive-5 opacity-0 md:opacity-75', className?.backdrop)} customHeader
role="presentation" ) : (
onClick={close} <div
/> className={classNames(
<div 'flex w-full flex-shrink-0 select-none items-center justify-between rounded-t border-b border-solid border-border bg-default px-2 text-text md:px-4.5 md:py-3 md:translucent-ui:bg-transparent',
className={classNames( hasTopInset ? 'pb-1.5 pt-safe-top' : 'py-1.5',
'z-[1] m-0 flex h-full w-full flex-col border-solid border-[--popover-border-color] bg-[--popover-background-color] [backdrop-filter:var(--popover-backdrop-filter)] p-0 md:h-auto md:max-h-[85vh] md:w-160 md:rounded md:border md:shadow-main', )}
className?.content, >
)} <MobileModalHeader className="flex-row items-center justify-between md:flex md:gap-0">
> {leftSlotAction ? (
{customHeader && !disableCustomHeader ? ( <MobileModalAction
customHeader type={leftSlotAction.type}
) : ( action={leftSlotAction.onClick}
<div disabled={leftSlotAction.disabled}
className={classNames( slot="left"
'flex w-full flex-shrink-0 select-none items-center justify-between rounded-t border-b border-solid border-border bg-default px-2 text-text md:px-4.5 md:py-3 md:translucent-ui:bg-transparent',
hasTopInset ? 'pb-1.5 pt-safe-top' : 'py-1.5',
)}
>
<MobileModalHeader className="flex-row items-center justify-between md:flex md:gap-0">
{leftSlotAction ? (
<MobileModalAction
type={leftSlotAction.type}
action={leftSlotAction.onClick}
disabled={leftSlotAction.disabled}
slot="left"
>
{leftSlotAction.label}
</MobileModalAction>
) : (
<div className="md:hidden" />
)}
<div className="flex items-center justify-center gap-2 overflow-hidden text-center font-semibold text-text md:flex-grow md:text-left md:text-lg">
{extraActions.length > 0 && (
<>
<MobileModalAction
type="secondary"
action={() => setShowAdvanced((show) => !show)}
slot="left"
ref={advancedOptionRef}
>
<div className="rounded-full border border-border p-0.5">
<Icon type="more" />
</div>
</MobileModalAction>
<Popover
title="Advanced"
open={showAdvanced}
anchorElement={advancedOptionRef.current}
disableMobileFullscreenTakeover={true}
togglePopover={() => setShowAdvanced((show) => !show)}
align="start"
portal={false}
className="!fixed divide-y divide-border border border-border"
>
{extraActions
.filter((action) => action.type !== 'cancel')
.map((action, index) => (
<button
className={classNames(
'p-2 text-base font-semibold hover:bg-contrast focus:bg-info-backdrop focus:shadow-none focus:outline-none',
action.type === 'destructive' && 'text-danger',
)}
key={index}
onClick={() => {
action.onClick()
setShowAdvanced(false)
}}
disabled={action.disabled}
>
{action.label}
</button>
))}
</Popover>
</>
)}
<span className="overflow-hidden text-ellipsis whitespace-nowrap ">{title}</span>
</div>
<div className="hidden items-center gap-2 md:flex">
<button tabIndex={0} className="ml-2 rounded p-1 font-bold hover:bg-contrast" onClick={close}>
<Icon type="close" />
</button>
</div>
{rightSlotAction ? (
<MobileModalAction
type={rightSlotAction.type}
action={rightSlotAction.onClick}
disabled={rightSlotAction.disabled}
slot="right"
>
{rightSlotAction.label}
</MobileModalAction>
) : null}
</MobileModalHeader>
</div>
)}
<div className={classNames('flex-grow overflow-y-auto', className.description)}>{children}</div>
{customFooter
? customFooter
: sortedActions.length > 0 && (
<div
className={classNames(
'hidden items-center justify-start gap-3 border-t border-border px-2.5 py-2 md:flex md:px-4 md:py-4',
hasBottomInset && 'pb-safe-bottom',
)}
> >
{sortedActions.map((action, index) => ( {leftSlotAction.label}
<Button </MobileModalAction>
primary={action.type === 'primary'} ) : (
colorStyle={action.type === 'destructive' ? 'danger' : undefined} <div className="md:hidden" />
key={index}
onClick={action.onClick}
className={classNames(
action.mobileSlot ? 'hidden md:block' : '',
index === firstPrimaryActionIndex && 'ml-auto',
)}
data-type={action.type}
disabled={action.disabled}
small={isMobileScreen}
>
{action.label}
</Button>
))}
</div>
)} )}
</div> <div className="flex items-center justify-center gap-2 overflow-hidden text-center font-semibold text-text md:flex-grow md:text-left md:text-lg">
{extraActions.length > 0 && (
<>
<MobileModalAction
type="secondary"
action={() => setShowAdvanced((show) => !show)}
slot="left"
ref={advancedOptionRef}
>
<div className="rounded-full border border-border p-0.5">
<Icon type="more" />
</div>
</MobileModalAction>
<Popover
title="Advanced"
open={showAdvanced}
anchorElement={advancedOptionRef.current}
disableMobileFullscreenTakeover={true}
togglePopover={() => setShowAdvanced((show) => !show)}
align="start"
portal={false}
className="!fixed divide-y divide-border border border-border"
>
{extraActions
.filter((action) => action.type !== 'cancel')
.map((action, index) => (
<button
className={classNames(
'p-2 text-base font-semibold hover:bg-contrast focus:bg-info-backdrop focus:shadow-none focus:outline-none',
action.type === 'destructive' && 'text-danger',
)}
key={index}
onClick={() => {
action.onClick()
setShowAdvanced(false)
}}
disabled={action.disabled}
>
{action.label}
</button>
))}
</Popover>
</>
)}
<span className="overflow-hidden text-ellipsis whitespace-nowrap ">{title}</span>
</div>
<div className="hidden items-center gap-2 md:flex">
<button tabIndex={0} className="ml-2 rounded p-1 font-bold hover:bg-contrast" onClick={close}>
<Icon type="close" />
</button>
</div>
{rightSlotAction ? (
<MobileModalAction
type={rightSlotAction.type}
action={rightSlotAction.onClick}
disabled={rightSlotAction.disabled}
slot="right"
>
{rightSlotAction.label}
</MobileModalAction>
) : null}
</MobileModalHeader>
</div>
)}
<div className={classNames('flex-grow overflow-y-auto', className)}>{children}</div>
{customFooter
? customFooter
: sortedActions.length > 0 && (
<div
className={classNames(
'hidden items-center justify-start gap-3 border-t border-border px-2.5 py-2 md:flex md:px-4 md:py-4',
hasBottomInset && 'pb-safe-bottom',
)}
>
{sortedActions.map((action, index) => (
<Button
primary={action.type === 'primary'}
colorStyle={action.type === 'destructive' ? 'danger' : undefined}
key={index}
onClick={action.onClick}
className={classNames(
action.mobileSlot ? 'hidden md:block' : '',
index === firstPrimaryActionIndex && 'ml-auto',
)}
data-type={action.type}
disabled={action.disabled}
small={isMobileScreen}
>
{action.label}
</Button>
))}
</div>
)}
</> </>
) )
} }

View File

@@ -1,22 +1,42 @@
import { mergeRefs } from '@/Hooks/mergeRefs' import { mergeRefs } from '@/Hooks/mergeRefs'
import { Dialog, DialogOptions, useDialogStore } from '@ariakit/react' import { Dialog, DialogOptions, useDialogStore } from '@ariakit/react'
import { ForwardedRef, forwardRef, ReactNode, useCallback } from 'react' import { ForwardedRef, forwardRef, ReactNode, useCallback, useId } from 'react'
import { useModalAnimation } from '../Modal/useModalAnimation' import { useModalAnimation } from '../Modal/useModalAnimation'
import { DialogWithClose } from '@/Utils/CloseOpenModalsAndPopovers' import { DialogWithClose } from '@/Utils/CloseOpenModalsAndPopovers'
import { useMediaQuery, MutuallyExclusiveMediaQueryBreakpoints } from '@/Hooks/useMediaQuery'
import { classNames } from '@standardnotes/snjs'
type Props = { type Props = {
isOpen: boolean isOpen: boolean
children: ReactNode children: ReactNode
animate?: 'mobile' | 'desktop' | 'both'
animationVariant?: 'horizontal' | 'vertical' animationVariant?: 'horizontal' | 'vertical'
close: () => void close: () => void
className?: string
backdropClassName?: string
} }
const ModalOverlay = forwardRef( const ModalOverlay = forwardRef(
( (
{ isOpen, children, animationVariant, close, ...props }: Props & Partial<DialogOptions>, {
isOpen,
children,
animationVariant,
close,
className,
backdropClassName,
animate,
...props
}: Props & Partial<DialogOptions>,
ref: ForwardedRef<HTMLDivElement>, ref: ForwardedRef<HTMLDivElement>,
) => { ) => {
const [isMounted, setElement] = useModalAnimation(isOpen, animationVariant) const isMobileScreen = useMediaQuery(MutuallyExclusiveMediaQueryBreakpoints.sm)
const [isMounted, setElement] = useModalAnimation(
isOpen,
isMobileScreen,
animationVariant,
(animate === 'mobile' && !isMobileScreen) || (animate === 'desktop' && isMobileScreen),
)
const dialog = useDialogStore({ const dialog = useDialogStore({
open: isMounted, open: isMounted,
setOpen: (open) => { setOpen: (open) => {
@@ -24,8 +44,23 @@ const ModalOverlay = forwardRef(
close() close()
} }
}, },
animated: !isMobileScreen,
}) })
const portalId = useId()
const getPortalElement = useCallback(() => {
const id = 'portal/' + portalId
const existing = document.getElementById(id)
if (existing) {
return existing
}
const div = document.createElement('div')
div.id = id
div.className = 'fixed flex items-center justify-center left-0 top-0 z-modal h-full w-full pointer-events-none'
document.body.appendChild(div)
return div
}, [portalId])
const addCloseMethod = useCallback( const addCloseMethod = useCallback(
(element: HTMLDivElement | null) => { (element: HTMLDivElement | null) => {
if (element) { if (element) {
@@ -42,11 +77,25 @@ const ModalOverlay = forwardRef(
return ( return (
<Dialog <Dialog
tabIndex={0} tabIndex={0}
className="fixed flex items-center justify-center left-0 top-0 z-modal h-full w-full" className={classNames(
'pointer-events-auto m-0 flex h-full w-full flex-col border-[--popover-border-color] bg-default md:bg-[--popover-background-color] md:[backdrop-filter:var(--popover-backdrop-filter)] p-0 md:h-auto md:max-h-[85vh] md:w-160 md:rounded md:border md:shadow-main',
className,
)}
backdrop={
<div
className={classNames(
'absolute z-0 h-full w-full bg-passive-5 opacity-0 pointer-events-auto',
'md:transition-opacity md:duration-75 md:opacity-50 [&[data-enter]]:md:opacity-75',
backdropClassName,
)}
onClick={close}
/>
}
ref={mergeRefs([setElement, addCloseMethod, ref])} ref={mergeRefs([setElement, addCloseMethod, ref])}
store={dialog} store={dialog}
modal={false} modal={false}
portal={true} portal={true}
portalElement={getPortalElement}
preventBodyScroll={true} preventBodyScroll={true}
hideOnInteractOutside={false} hideOnInteractOutside={false}
{...props} {...props}

View File

@@ -1,5 +1,4 @@
import { useLifecycleAnimation } from '@/Hooks/useLifecycleAnimation' import { useLifecycleAnimation } from '@/Hooks/useLifecycleAnimation'
import { useMediaQuery, MutuallyExclusiveMediaQueryBreakpoints } from '@/Hooks/useMediaQuery'
export const IosModalAnimationEasing = 'cubic-bezier(.36,.66,.04,1)' export const IosModalAnimationEasing = 'cubic-bezier(.36,.66,.04,1)'
@@ -52,40 +51,80 @@ const Animations = {
transformOrigin: 'right', transformOrigin: 'right',
}, },
}, },
nonMobile: {
enter: {
keyframes: [
{
transform: 'scale(0.95)',
opacity: 0,
},
{
transform: 'scale(1)',
opacity: 1,
},
],
transformOrigin: 'center',
},
exit: {
keyframes: [
{
transform: 'scale(1)',
opacity: 1,
},
{
transform: 'scale(0.95)',
opacity: 0,
},
],
transformOrigin: 'center',
},
},
} }
export const useModalAnimation = (isOpen: boolean, variant: 'horizontal' | 'vertical' = 'vertical') => { const MobileOptions = {
const isMobileScreen = useMediaQuery(MutuallyExclusiveMediaQueryBreakpoints.sm) easing: IosModalAnimationEasing,
duration: 250,
fill: 'forwards',
}
const NonMobileOptions = {
duration: 75,
}
export const useModalAnimation = (
isOpen: boolean,
isMobileScreen: boolean,
variant: 'horizontal' | 'vertical' = 'vertical',
disabled = false,
) => {
return useLifecycleAnimation( return useLifecycleAnimation(
{ {
open: isOpen, open: isOpen,
enter: { enter: {
keyframes: Animations[variant].enter.keyframes, keyframes: isMobileScreen ? Animations[variant].enter.keyframes : Animations.nonMobile.enter.keyframes,
options: { options: isMobileScreen ? MobileOptions : NonMobileOptions,
easing: IosModalAnimationEasing,
duration: 250,
fill: 'forwards',
},
initialStyle: { initialStyle: {
transformOrigin: Animations[variant].enter.transformOrigin, transformOrigin: isMobileScreen
? Animations[variant].enter.transformOrigin
: Animations.nonMobile.enter.transformOrigin,
}, },
}, },
enterCallback: (element) => { enterCallback: (element) => {
if (!isMobileScreen) {
return
}
element.scrollTop = 0 element.scrollTop = 0
}, },
exit: { exit: {
keyframes: Animations[variant].exit.keyframes, keyframes: isMobileScreen ? Animations[variant].exit.keyframes : Animations.nonMobile.exit.keyframes,
options: { options: isMobileScreen ? MobileOptions : NonMobileOptions,
easing: IosModalAnimationEasing,
duration: 250,
fill: 'forwards',
},
initialStyle: { initialStyle: {
transformOrigin: Animations[variant].exit.transformOrigin, transformOrigin: isMobileScreen
? Animations[variant].exit.transformOrigin
: Animations.nonMobile.exit.transformOrigin,
}, },
}, },
}, },
!isMobileScreen, disabled,
) )
} }

View File

@@ -165,10 +165,7 @@ const NoteConflictResolutionModal = ({
return ( return (
<Modal <Modal
title="Resolve conflicts" title="Resolve conflicts"
className={{ className="flex flex-col overflow-x-hidden md:flex-row"
content: 'md:h-full md:w-[70vw]',
description: 'flex flex-col overflow-x-hidden md:flex-row',
}}
actions={actions} actions={actions}
close={close} close={close}
customFooter={ customFooter={

View File

@@ -1031,7 +1031,11 @@ class NoteView extends AbstractComponent<NoteViewProps, State> {
</div> </div>
</div> </div>
<ModalOverlay isOpen={this.state.showConflictResolutionModal} close={this.toggleConflictResolutionModal}> <ModalOverlay
isOpen={this.state.showConflictResolutionModal}
close={this.toggleConflictResolutionModal}
className="md:h-full md:w-[70vw]"
>
<NoteConflictResolutionModal <NoteConflictResolutionModal
currentNote={this.note} currentNote={this.note}
conflictedNotes={this.state.conflictedNotes} conflictedNotes={this.state.conflictedNotes}

View File

@@ -16,9 +16,7 @@ const SuperExportModal = ({ exportNotes, close }: Props) => {
return ( return (
<Modal <Modal
title="Export notes" title="Export notes"
className={{ className="p-4"
description: 'p-4',
}}
close={close} close={close}
actions={[ actions={[
{ {

View File

@@ -35,7 +35,6 @@ const PermissionsModal = ({ callback, component, dismiss, permissionsString }: P
mobileSlot: 'right', mobileSlot: 'right',
}, },
]} ]}
className={{ content: 'md:!w-[350px]' }}
customFooter={ customFooter={
<ModalDialogButtons className="hidden md:flex"> <ModalDialogButtons className="hidden md:flex">
<Button primary fullWidth onClick={accept} className="block"> <Button primary fullWidth onClick={accept} className="block">

View File

@@ -40,7 +40,7 @@ const PermissionsModalWrapper: FunctionComponent<Props> = ({ application }) => {
}, [application, onAppStart]) }, [application, onAppStart])
return ( return (
<ModalOverlay isOpen={!!dialog} close={dismissPermissionsDialog}> <ModalOverlay isOpen={!!dialog} close={dismissPermissionsDialog} className="md:!w-[350px]">
{dialog && ( {dialog && (
<PermissionsModal <PermissionsModal
callback={dialog.callback} callback={dialog.callback}

View File

@@ -7,6 +7,7 @@ import { useModalAnimation } from '../Modal/useModalAnimation'
import MobileModalHeader from '../Modal/MobileModalHeader' import MobileModalHeader from '../Modal/MobileModalHeader'
import { mergeRefs } from '@/Hooks/mergeRefs' import { mergeRefs } from '@/Hooks/mergeRefs'
import { DialogWithClose } from '@/Utils/CloseOpenModalsAndPopovers' import { DialogWithClose } from '@/Utils/CloseOpenModalsAndPopovers'
import { useMediaQuery, MutuallyExclusiveMediaQueryBreakpoints } from '@/Hooks/useMediaQuery'
const DisableScroll = () => { const DisableScroll = () => {
useDisableBodyScrollOnMobile() useDisableBodyScrollOnMobile()
@@ -29,7 +30,8 @@ const MobilePopoverContent = ({
id: string id: string
className?: string className?: string
}) => { }) => {
const [isMounted, setPopoverElement] = useModalAnimation(open) const isMobileScreen = useMediaQuery(MutuallyExclusiveMediaQueryBreakpoints.sm)
const [isMounted, setPopoverElement] = useModalAnimation(open, isMobileScreen)
const addCloseMethod = useCallback( const addCloseMethod = useCallback(
(element: HTMLDivElement | null) => { (element: HTMLDivElement | null) => {

View File

@@ -1,4 +1,4 @@
import { ReactNode, useState, useEffect } from 'react' import { ReactNode, useState, useEffect, useId } from 'react'
import { createPortal } from 'react-dom' import { createPortal } from 'react-dom'
type Props = { type Props = {
@@ -6,18 +6,17 @@ type Props = {
disabled?: boolean disabled?: boolean
} }
const randomPortalId = () => Math.random()
const Portal = ({ children, disabled = false }: Props) => { const Portal = ({ children, disabled = false }: Props) => {
const [container, setContainer] = useState<HTMLElement>() const [container, setContainer] = useState<HTMLElement>()
const id = 'portal/' + useId()
useEffect(() => { useEffect(() => {
const container = document.createElement('div') const container = document.createElement('div')
container.id = `react-portal-${randomPortalId()}` container.id = id
document.body.append(container) document.body.append(container)
setContainer(container) setContainer(container)
return () => container.remove() return () => container.remove()
}, []) }, [id])
if (disabled) { if (disabled) {
return <>{children}</> return <>{children}</>

View File

@@ -60,10 +60,7 @@ const PreferencesView: FunctionComponent<PreferencesProps> = ({ application, clo
<Modal <Modal
close={closePreferences} close={closePreferences}
title="Preferences" title="Preferences"
className={{ className="flex flex-col"
content: 'md:h-full md:!max-h-full md:!w-full',
description: 'flex flex-col',
}}
customHeader={ customHeader={
<div <div
className={classNames( className={classNames(

View File

@@ -47,8 +47,10 @@ const PreferencesViewWrapper: FunctionComponent<PreferencesViewWrapperProps> = (
<ModalOverlay <ModalOverlay
isOpen={application.preferencesController.isOpen} isOpen={application.preferencesController.isOpen}
ref={setElement} ref={setElement}
animate="mobile"
animationVariant="horizontal" animationVariant="horizontal"
close={application.preferencesController.closePreferences} close={application.preferencesController.closePreferences}
className="md:h-full md:!max-h-full md:!w-full"
> >
<PreferencesView <PreferencesView
closePreferences={application.preferencesController.closePreferences} closePreferences={application.preferencesController.closePreferences}

View File

@@ -5,6 +5,7 @@ import HistoryModalDialog from './HistoryModalDialog'
import { RevisionHistoryModalProps } from './RevisionHistoryModalProps' import { RevisionHistoryModalProps } from './RevisionHistoryModalProps'
import { useAndroidBackHandler } from '@/NativeMobileWeb/useAndroidBackHandler' import { useAndroidBackHandler } from '@/NativeMobileWeb/useAndroidBackHandler'
import { useModalAnimation } from '../Modal/useModalAnimation' import { useModalAnimation } from '../Modal/useModalAnimation'
import { useMediaQuery, MutuallyExclusiveMediaQueryBreakpoints } from '@/Hooks/useMediaQuery'
const RevisionHistoryModal: FunctionComponent<RevisionHistoryModalProps> = ({ application }) => { const RevisionHistoryModal: FunctionComponent<RevisionHistoryModalProps> = ({ application }) => {
const addAndroidBackHandler = useAndroidBackHandler() const addAndroidBackHandler = useAndroidBackHandler()
@@ -31,7 +32,8 @@ const RevisionHistoryModal: FunctionComponent<RevisionHistoryModalProps> = ({ ap
} }
}, [addAndroidBackHandler, application, isOpen]) }, [addAndroidBackHandler, application, isOpen])
const [isMounted, setElement] = useModalAnimation(isOpen) const isMobileScreen = useMediaQuery(MutuallyExclusiveMediaQueryBreakpoints.sm)
const [isMounted, setElement] = useModalAnimation(isOpen, isMobileScreen)
if (!isMounted) { if (!isMounted) {
return null return null

View File

@@ -129,14 +129,7 @@ const SessionsModalContent: FunctionComponent<{
return ( return (
<> <>
<Modal <Modal title="Active Sessions" close={application.closeSessionsModal} actions={sessionModalActions}>
title="Active Sessions"
close={application.closeSessionsModal}
actions={sessionModalActions}
className={{
content: 'sessions-modal',
}}
>
<div className="px-4 py-4"> <div className="px-4 py-4">
{refreshing ? ( {refreshing ? (
<div className="flex items-center gap-2"> <div className="flex items-center gap-2">
@@ -215,7 +208,11 @@ const SessionsModal: FunctionComponent<{
application: WebApplication application: WebApplication
}> = ({ application }) => { }> = ({ application }) => {
return ( return (
<ModalOverlay isOpen={application.isSessionsModalVisible} close={application.closeSessionsModal}> <ModalOverlay
isOpen={application.isSessionsModalVisible}
close={application.closeSessionsModal}
className="sessions-modal"
>
<SessionsModalContent application={application} /> <SessionsModalContent application={application} />
</ModalOverlay> </ModalOverlay>
) )

View File

@@ -175,10 +175,7 @@ const SuperNoteConverter = ({
title={`Convert to ${uiFeature.displayName}`} title={`Convert to ${uiFeature.displayName}`}
close={closeDialog} close={closeDialog}
actions={modalActions} actions={modalActions}
className={{ className="flex flex-col !overflow-hidden"
content: 'md:h-full md:max-h-[90%]',
description: 'flex flex-col !overflow-hidden',
}}
> >
{format === 'txt' || format === 'md' ? ( {format === 'txt' || format === 'md' ? (
<div className="flex items-start border-b border-border p-4 text-sm"> <div className="flex items-start border-b border-border p-4 text-sm">