dedupe some shared hooks
This commit is contained in:
@@ -31,9 +31,7 @@ import {msg} from '@lingui/core/macro'
|
||||
import {useLingui} from '@lingui/react'
|
||||
|
||||
import {ScrollProvider} from '#/lib/ScrollContext'
|
||||
import {logger} from '#/logger'
|
||||
import {useA11y} from '#/state/a11y'
|
||||
import {useDialogStateControlContext} from '#/state/dialogs'
|
||||
import {List, type ListMethods, type ListProps} from '#/view/com/util/List'
|
||||
import {android, atoms as a, ios, platform, tokens, useTheme} from '#/alf'
|
||||
import {useThemeName} from '#/alf/util/useColorModeTheme'
|
||||
@@ -43,6 +41,7 @@ import {
|
||||
type DialogInnerProps,
|
||||
type DialogOuterProps,
|
||||
} from '#/components/Dialog/types'
|
||||
import {useDialogCallbackQueue} from '#/components/Dialog/utils'
|
||||
import {createInput} from '#/components/forms/TextField'
|
||||
import {useOnKeyboard} from '#/components/hooks/useOnKeyboard'
|
||||
import {IS_ANDROID, IS_IOS, IS_LIQUID_GLASS} from '#/env'
|
||||
@@ -74,50 +73,29 @@ function OuterAlert({
|
||||
testID,
|
||||
}: React.PropsWithChildren<DialogOuterProps>) {
|
||||
const t = useTheme()
|
||||
const [isOpen, setIsOpen] = React.useState(false)
|
||||
const closeCallbacks = React.useRef<(() => void)[]>([])
|
||||
const {setDialogIsOpen} = useDialogStateControlContext()
|
||||
|
||||
const callQueuedCallbacks = React.useCallback(() => {
|
||||
for (const cb of closeCallbacks.current) {
|
||||
try {
|
||||
cb()
|
||||
} catch (e: any) {
|
||||
logger.error(e || 'Error running close callback')
|
||||
}
|
||||
}
|
||||
closeCallbacks.current = []
|
||||
}, [])
|
||||
|
||||
const open = React.useCallback<DialogControlProps['open']>(() => {
|
||||
callQueuedCallbacks()
|
||||
setDialogIsOpen(control.id, true)
|
||||
setIsOpen(true)
|
||||
}, [setDialogIsOpen, control.id, callQueuedCallbacks])
|
||||
|
||||
const close = React.useCallback<DialogControlProps['close']>(cb => {
|
||||
if (typeof cb === 'function') {
|
||||
closeCallbacks.current.push(cb)
|
||||
}
|
||||
setIsOpen(false)
|
||||
}, [])
|
||||
|
||||
const onDismiss = React.useCallback(() => {
|
||||
setDialogIsOpen(control.id, false)
|
||||
callQueuedCallbacks()
|
||||
onClose?.()
|
||||
}, [callQueuedCallbacks, control.id, onClose, setDialogIsOpen])
|
||||
|
||||
useImperativeHandle(
|
||||
control.ref,
|
||||
() => ({
|
||||
open,
|
||||
close,
|
||||
}),
|
||||
[open, close],
|
||||
const [isOpen, setIsOpen] = useState(false)
|
||||
const {enqueueCallback, handleOpen, handleClose} = useDialogCallbackQueue(
|
||||
control,
|
||||
onClose,
|
||||
)
|
||||
|
||||
const context = React.useMemo(
|
||||
const open: DialogControlProps['open'] = () => {
|
||||
handleOpen()
|
||||
setIsOpen(true)
|
||||
}
|
||||
|
||||
const close: DialogControlProps['close'] = cb => {
|
||||
enqueueCallback(cb)
|
||||
setIsOpen(false)
|
||||
}
|
||||
|
||||
const onDismiss = () => {
|
||||
handleClose()
|
||||
}
|
||||
|
||||
useImperativeHandle(control.ref, () => ({open, close}), [open, close])
|
||||
|
||||
const context = useMemo(
|
||||
() => ({
|
||||
close,
|
||||
isNativeDialog: true,
|
||||
@@ -175,9 +153,8 @@ function OuterSheet({
|
||||
const themeName = useThemeName()
|
||||
const t = useTheme(themeName)
|
||||
const ref = useRef<BottomSheetNativeComponent>(null)
|
||||
const closeCallbacks = useRef<(() => void)[]>([])
|
||||
const {setDialogIsOpen, setFullyExpandedCount} =
|
||||
useDialogStateControlContext()
|
||||
const {enqueueCallback, handleOpen, handleClose, setFullyExpandedCount} =
|
||||
useDialogCallbackQueue(control, onClose)
|
||||
|
||||
const prevSnapPoint = useRef<BottomSheetSnapPoint>(
|
||||
BottomSheetSnapPoint.Hidden,
|
||||
@@ -188,42 +165,20 @@ function OuterSheet({
|
||||
BottomSheetSnapPoint.Partial,
|
||||
)
|
||||
|
||||
const callQueuedCallbacks = useCallback(() => {
|
||||
for (const cb of closeCallbacks.current) {
|
||||
try {
|
||||
cb()
|
||||
} catch (e: any) {
|
||||
logger.error(e || 'Error running close callback')
|
||||
}
|
||||
}
|
||||
|
||||
closeCallbacks.current = []
|
||||
}, [])
|
||||
|
||||
const open = useCallback<DialogControlProps['open']>(() => {
|
||||
// Run any leftover callbacks that might have been queued up before calling `.open()`
|
||||
callQueuedCallbacks()
|
||||
setDialogIsOpen(control.id, true)
|
||||
const open: DialogControlProps['open'] = () => {
|
||||
handleOpen()
|
||||
ref.current?.present()
|
||||
}, [setDialogIsOpen, control.id, callQueuedCallbacks])
|
||||
}
|
||||
|
||||
// This is the function that we call when we want to dismiss the dialog.
|
||||
const close = useCallback<DialogControlProps['close']>(cb => {
|
||||
if (typeof cb === 'function') {
|
||||
closeCallbacks.current.push(cb)
|
||||
}
|
||||
const close: DialogControlProps['close'] = cb => {
|
||||
enqueueCallback(cb)
|
||||
ref.current?.dismiss()
|
||||
}, [])
|
||||
}
|
||||
|
||||
// This is the actual thing we are doing once we "confirm" the dialog. We want the dialog's close animation to
|
||||
// happen before we run this. It is passed to the `BottomSheet` component.
|
||||
const onCloseAnimationComplete = useCallback(() => {
|
||||
// This removes the dialog from our list of stored dialogs. Not super necessary on iOS, but on Android this
|
||||
// tells us that we need to toggle the accessibility overlay setting
|
||||
setDialogIsOpen(control.id, false)
|
||||
callQueuedCallbacks()
|
||||
onClose?.()
|
||||
}, [callQueuedCallbacks, control.id, onClose, setDialogIsOpen])
|
||||
// Runs after the bottom sheet close animation completes.
|
||||
const onCloseAnimationComplete = () => {
|
||||
handleClose()
|
||||
}
|
||||
|
||||
const onSnapPointChange = (e: BottomSheetSnapPointChangeEvent) => {
|
||||
const {snapPoint} = e.nativeEvent
|
||||
@@ -254,14 +209,7 @@ function OuterSheet({
|
||||
}
|
||||
}
|
||||
|
||||
useImperativeHandle(
|
||||
control.ref,
|
||||
() => ({
|
||||
open,
|
||||
close,
|
||||
}),
|
||||
[open, close],
|
||||
)
|
||||
useImperativeHandle(control.ref, () => ({open, close}), [open, close])
|
||||
|
||||
const context = useMemo(
|
||||
() => ({
|
||||
|
||||
@@ -1,7 +1,53 @@
|
||||
import {useEffect} from 'react'
|
||||
import {useEffect, useRef} from 'react'
|
||||
|
||||
import {logger} from '#/logger'
|
||||
import {useDialogStateControlContext} from '#/state/dialogs'
|
||||
import {type DialogControlProps} from '#/components/Dialog/types'
|
||||
|
||||
export function useDialogCallbackQueue(
|
||||
control: DialogControlProps,
|
||||
onClose?: () => void,
|
||||
) {
|
||||
const closeCallbacks = useRef<(() => void)[]>([])
|
||||
const {setDialogIsOpen, setFullyExpandedCount} =
|
||||
useDialogStateControlContext()
|
||||
|
||||
const callQueuedCallbacks = () => {
|
||||
for (const cb of closeCallbacks.current) {
|
||||
try {
|
||||
cb()
|
||||
} catch (e: any) {
|
||||
logger.error(e || 'Error running close callback')
|
||||
}
|
||||
}
|
||||
closeCallbacks.current = []
|
||||
}
|
||||
|
||||
const enqueueCallback = (cb?: () => void) => {
|
||||
if (typeof cb === 'function') {
|
||||
closeCallbacks.current.push(cb)
|
||||
}
|
||||
}
|
||||
|
||||
const handleOpen = () => {
|
||||
callQueuedCallbacks()
|
||||
setDialogIsOpen(control.id, true)
|
||||
}
|
||||
|
||||
const handleClose = () => {
|
||||
setDialogIsOpen(control.id, false)
|
||||
callQueuedCallbacks()
|
||||
onClose?.()
|
||||
}
|
||||
|
||||
return {
|
||||
enqueueCallback,
|
||||
handleOpen,
|
||||
handleClose,
|
||||
setFullyExpandedCount,
|
||||
}
|
||||
}
|
||||
|
||||
export function useAutoOpen(control: DialogControlProps, showTimeout?: number) {
|
||||
useEffect(() => {
|
||||
if (showTimeout) {
|
||||
|
||||
Reference in New Issue
Block a user