241 lines
6.3 KiB
TypeScript
241 lines
6.3 KiB
TypeScript
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
|