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 {useLingui} from '@lingui/react'
|
||||||
|
|
||||||
import {ScrollProvider} from '#/lib/ScrollContext'
|
import {ScrollProvider} from '#/lib/ScrollContext'
|
||||||
import {logger} from '#/logger'
|
|
||||||
import {useA11y} from '#/state/a11y'
|
import {useA11y} from '#/state/a11y'
|
||||||
import {useDialogStateControlContext} from '#/state/dialogs'
|
|
||||||
import {List, type ListMethods, type ListProps} from '#/view/com/util/List'
|
import {List, type ListMethods, type ListProps} from '#/view/com/util/List'
|
||||||
import {android, atoms as a, ios, platform, tokens, useTheme} from '#/alf'
|
import {android, atoms as a, ios, platform, tokens, useTheme} from '#/alf'
|
||||||
import {useThemeName} from '#/alf/util/useColorModeTheme'
|
import {useThemeName} from '#/alf/util/useColorModeTheme'
|
||||||
@@ -43,6 +41,7 @@ import {
|
|||||||
type DialogInnerProps,
|
type DialogInnerProps,
|
||||||
type DialogOuterProps,
|
type DialogOuterProps,
|
||||||
} from '#/components/Dialog/types'
|
} from '#/components/Dialog/types'
|
||||||
|
import {useDialogCallbackQueue} from '#/components/Dialog/utils'
|
||||||
import {createInput} from '#/components/forms/TextField'
|
import {createInput} from '#/components/forms/TextField'
|
||||||
import {useOnKeyboard} from '#/components/hooks/useOnKeyboard'
|
import {useOnKeyboard} from '#/components/hooks/useOnKeyboard'
|
||||||
import {IS_ANDROID, IS_IOS, IS_LIQUID_GLASS} from '#/env'
|
import {IS_ANDROID, IS_IOS, IS_LIQUID_GLASS} from '#/env'
|
||||||
@@ -74,50 +73,29 @@ function OuterAlert({
|
|||||||
testID,
|
testID,
|
||||||
}: React.PropsWithChildren<DialogOuterProps>) {
|
}: React.PropsWithChildren<DialogOuterProps>) {
|
||||||
const t = useTheme()
|
const t = useTheme()
|
||||||
const [isOpen, setIsOpen] = React.useState(false)
|
const [isOpen, setIsOpen] = useState(false)
|
||||||
const closeCallbacks = React.useRef<(() => void)[]>([])
|
const {enqueueCallback, handleOpen, handleClose} = useDialogCallbackQueue(
|
||||||
const {setDialogIsOpen} = useDialogStateControlContext()
|
control,
|
||||||
|
onClose,
|
||||||
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 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,
|
close,
|
||||||
isNativeDialog: true,
|
isNativeDialog: true,
|
||||||
@@ -175,9 +153,8 @@ function OuterSheet({
|
|||||||
const themeName = useThemeName()
|
const themeName = useThemeName()
|
||||||
const t = useTheme(themeName)
|
const t = useTheme(themeName)
|
||||||
const ref = useRef<BottomSheetNativeComponent>(null)
|
const ref = useRef<BottomSheetNativeComponent>(null)
|
||||||
const closeCallbacks = useRef<(() => void)[]>([])
|
const {enqueueCallback, handleOpen, handleClose, setFullyExpandedCount} =
|
||||||
const {setDialogIsOpen, setFullyExpandedCount} =
|
useDialogCallbackQueue(control, onClose)
|
||||||
useDialogStateControlContext()
|
|
||||||
|
|
||||||
const prevSnapPoint = useRef<BottomSheetSnapPoint>(
|
const prevSnapPoint = useRef<BottomSheetSnapPoint>(
|
||||||
BottomSheetSnapPoint.Hidden,
|
BottomSheetSnapPoint.Hidden,
|
||||||
@@ -188,42 +165,20 @@ function OuterSheet({
|
|||||||
BottomSheetSnapPoint.Partial,
|
BottomSheetSnapPoint.Partial,
|
||||||
)
|
)
|
||||||
|
|
||||||
const callQueuedCallbacks = useCallback(() => {
|
const open: DialogControlProps['open'] = () => {
|
||||||
for (const cb of closeCallbacks.current) {
|
handleOpen()
|
||||||
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)
|
|
||||||
ref.current?.present()
|
ref.current?.present()
|
||||||
}, [setDialogIsOpen, control.id, callQueuedCallbacks])
|
}
|
||||||
|
|
||||||
// This is the function that we call when we want to dismiss the dialog.
|
const close: DialogControlProps['close'] = cb => {
|
||||||
const close = useCallback<DialogControlProps['close']>(cb => {
|
enqueueCallback(cb)
|
||||||
if (typeof cb === 'function') {
|
|
||||||
closeCallbacks.current.push(cb)
|
|
||||||
}
|
|
||||||
ref.current?.dismiss()
|
ref.current?.dismiss()
|
||||||
}, [])
|
}
|
||||||
|
|
||||||
// This is the actual thing we are doing once we "confirm" the dialog. We want the dialog's close animation to
|
// Runs after the bottom sheet close animation completes.
|
||||||
// happen before we run this. It is passed to the `BottomSheet` component.
|
const onCloseAnimationComplete = () => {
|
||||||
const onCloseAnimationComplete = useCallback(() => {
|
handleClose()
|
||||||
// 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])
|
|
||||||
|
|
||||||
const onSnapPointChange = (e: BottomSheetSnapPointChangeEvent) => {
|
const onSnapPointChange = (e: BottomSheetSnapPointChangeEvent) => {
|
||||||
const {snapPoint} = e.nativeEvent
|
const {snapPoint} = e.nativeEvent
|
||||||
@@ -254,14 +209,7 @@ function OuterSheet({
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
useImperativeHandle(
|
useImperativeHandle(control.ref, () => ({open, close}), [open, close])
|
||||||
control.ref,
|
|
||||||
() => ({
|
|
||||||
open,
|
|
||||||
close,
|
|
||||||
}),
|
|
||||||
[open, close],
|
|
||||||
)
|
|
||||||
|
|
||||||
const context = useMemo(
|
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'
|
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) {
|
export function useAutoOpen(control: DialogControlProps, showTimeout?: number) {
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (showTimeout) {
|
if (showTimeout) {
|
||||||
|
|||||||
Reference in New Issue
Block a user