expo-duooomi-app/@share/components/Toast.tsx

241 lines
6.3 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import React, { type ReactNode } from 'react'
import { ActivityIndicator } from 'react-native'
import Block from './Block'
import Text from './Text'
// 定义insets接口
interface Insets {
safeAreaInsetsBottom: number
safeAreaInsetsTop: number
safeAreaInsetsLeft: number
safeAreaInsetsRight: number
}
// 定义全局变量接口
declare let global: any
// 参数接口定义
interface ShowParams {
renderContent?: () => ReactNode
title?: string
duration?: number
hideBackdrop?: boolean
onBackButtonPress?: () => void
}
interface ShowActionSheetParams {
itemList?: string[]
renderContent?: () => ReactNode
}
const Toast = (function () {
// 初始化默认insets
let insets: Insets = {
safeAreaInsetsBottom: 0,
safeAreaInsetsTop: 0,
safeAreaInsetsLeft: 0,
safeAreaInsetsRight: 0,
}
// // 使用回调函数获取insets
// StaticSafeAreaInsets.getSafeAreaInsets((staticInsets) => {
// insets = staticInsets
// })
let toastTimer: ReturnType<typeof setTimeout> | null = null
const show = (params?: ShowParams): void => {
const { renderContent, title, duration = 2000, hideBackdrop = true } = params || {}
hide()
const renderBody = (): ReactNode => {
if (renderContent) {
return renderContent()
}
return (
<Block
className="flex w-full border-[3px] border-white bg-black"
style={{ paddingVertical: 14, transform: [{ skewX: '-6deg' }] }}
>
<Block className="flex items-center justify-center">
<Text className="text-[14px] font-black text-white">{title}</Text>
</Block>
</Block>
)
// return title && <Text className="text-[12px] text-white">{title}</Text>
}
global.toast?.show(
<Block className="z-[9999] items-center justify-center">
<Block className="relative mx-[20px] mt-[30px] w-full rounded-[10px] px-[20px] py-[12px]">{renderBody()}</Block>
</Block>,
{
style: { justifyContent: 'flex-start' },
swipeDirection: null,
hideBackdrop,
onBackdropPress: () => {},
entering: false,
exiting: false,
},
)
if (duration > 0) {
toastTimer = setTimeout(() => {
hide()
}, duration)
}
}
const hide = (): void => {
global.toast?.hide()
if (toastTimer) {
clearTimeout(toastTimer)
toastTimer = null
}
}
// loading
let loadingTimer: ReturnType<typeof setTimeout> | null = null
const showLoading = (params?: ShowParams): void => {
const { renderContent, title, duration = 1500, hideBackdrop = false, onBackButtonPress = undefined } = params || {}
hideLoading()
const renderBody = (): ReactNode => {
if (renderContent) {
return renderContent()
}
return (
<>
<ActivityIndicator color={'#FFE500'} size="small" />
{!!title && (
<Block className="mt-[12px] items-center px-[10px]">
<Text className="text-[14px] text-white">{title}</Text>
</Block>
)}
</>
)
}
global.loading?.show(
<Block className="z-[9999] flex items-center justify-center">
<Block className="mt-[-40px] min-h-[100px] min-w-[100px] items-center justify-center overflow-hidden rounded-[8px] bg-black/85 py-[20px]">
{renderBody()}
</Block>
</Block>,
{
style: {},
swipeDirection: null,
hideBackdrop,
backdropColor: 'rgba(0,0,0,0.4)',
onBackdropPress: () => {},
onBackButtonPress: onBackButtonPress,
entering: false,
exiting: false,
},
)
if (duration > 0) {
loadingTimer = setTimeout(() => {
hideLoading()
}, duration)
}
}
const hideLoading = (): void => {
global.loading?.hide()
if (loadingTimer) {
clearTimeout(loadingTimer)
loadingTimer = null
}
}
// modal
const showModal = (ele: ReactNode, config: any = {}): void => {
global.modal?.show(ele, {
swipeDirection: null,
...config,
})
}
const hideModal = (): void => {
global.modal?.hide()
}
// actionsheet
// 兼容半屏组件
const showActionSheet = ({ itemList, renderContent }: ShowActionSheetParams): Promise<number> => {
return new Promise((resolve, reject) => {
const handleSelect = (item: string): void => {
hideActionSheet()
const itemIndex = itemList?.findIndex((i) => i === item) || -1
resolve(itemIndex)
}
const handleCancel = (): void => {
hideActionSheet()
reject()
}
const renderBody = (): ReactNode => {
if (Array.isArray(itemList)) {
return (
<Block className="bg-white2 mb-[-1000px] gap-px overflow-hidden rounded-t-[12px]">
{itemList.map((item, index) => (
<Block
key={index}
className="items-center justify-center bg-white py-[16px]"
onClick={() => handleSelect(item)}
>
<Text className="text-[16px] text-black">{item}</Text>
</Block>
))}
<Block className="bg-white2 mt-[8px] w-full" />
<Block
className="flex items-center justify-center bg-white py-[16px]"
style={{ paddingBottom: insets.safeAreaInsetsBottom + 20 + 1000 }}
onClick={handleCancel}
>
<Text className="text-[16px] text-black"></Text>
</Block>
</Block>
)
}
if (!renderContent) return null
return (
<Block className="">
{/* <ModalHeader /> */}
{/* 安卓闪动向上2px */}
<Block className="mt-[-2px]">{renderContent()}</Block>
<Block
className="mb-[-1000px] w-full bg-white"
style={{ height: insets.safeAreaInsetsBottom + 20 + 1000, position: 'relative' }}
/>
</Block>
)
}
global.actionSheet?.show(<Block className="">{renderBody()}</Block>, {
style: { justifyContent: 'flex-end' },
})
})
}
const hideActionSheet = (): void => {
global.actionSheet?.hide()
}
return {
showActionSheet,
hideActionSheet,
showModal,
hideModal,
showLoading,
hideLoading,
show,
hide,
}
})()
export default Toast