cdb8d4bfb8
Co-authored-by: DS Boyce <260543580+ds-boyce@users.noreply.github.com> Co-authored-by: Samuel Newman <mozzius@protonmail.com> Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
91 lines
2.4 KiB
TypeScript
91 lines
2.4 KiB
TypeScript
import {useCallback, useEffect, useState} from 'react'
|
|
import {type GestureResponderEvent, View} from 'react-native'
|
|
import Animated, {
|
|
FadeOutUp,
|
|
useReducedMotion,
|
|
ZoomIn,
|
|
} from 'react-native-reanimated'
|
|
import * as Clipboard from 'expo-clipboard'
|
|
import {Trans} from '@lingui/react/macro'
|
|
|
|
import {atoms as a, useTheme} from '#/alf'
|
|
import {Button, ButtonIcon, type ButtonProps} from '#/components/Button'
|
|
import {SquareBehindSquare_Stroke2_Corner2_Rounded as CopyIcon} from '#/components/icons/SquareBehindSquare4'
|
|
import {Text} from '#/components/Typography'
|
|
|
|
export function CopyTextButton({
|
|
children,
|
|
disabled,
|
|
style,
|
|
value,
|
|
onPress: onPressProp,
|
|
...props
|
|
}: ButtonProps & {value: string}) {
|
|
const t = useTheme()
|
|
|
|
const [hasBeenCopied, setHasBeenCopied] = useState(false)
|
|
|
|
const isReducedMotionEnabled = useReducedMotion()
|
|
|
|
useEffect(() => {
|
|
if (hasBeenCopied) {
|
|
const timeout = setTimeout(
|
|
() => setHasBeenCopied(false),
|
|
isReducedMotionEnabled ? 2000 : 100,
|
|
)
|
|
return () => clearTimeout(timeout)
|
|
}
|
|
}, [hasBeenCopied, isReducedMotionEnabled])
|
|
|
|
const onPress = useCallback(
|
|
(evt: GestureResponderEvent) => {
|
|
void Clipboard.setStringAsync(value)
|
|
setHasBeenCopied(true)
|
|
onPressProp?.(evt)
|
|
},
|
|
[value, onPressProp],
|
|
)
|
|
|
|
return (
|
|
<View style={[a.relative]}>
|
|
{hasBeenCopied && (
|
|
<Animated.View
|
|
entering={ZoomIn.duration(100)}
|
|
exiting={FadeOutUp.duration(2000)}
|
|
style={[
|
|
a.absolute,
|
|
{bottom: '100%', right: 0},
|
|
a.justify_center,
|
|
a.gap_sm,
|
|
a.z_10,
|
|
a.pb_sm,
|
|
]}
|
|
pointerEvents="none">
|
|
<Text
|
|
style={[
|
|
a.font_medium,
|
|
a.text_right,
|
|
a.text_sm,
|
|
t.atoms.text_contrast_high,
|
|
]}>
|
|
<Trans>Copied!</Trans>
|
|
</Text>
|
|
</Animated.View>
|
|
)}
|
|
<Button
|
|
color="secondary"
|
|
disabled={disabled}
|
|
style={[a.flex_1, a.justify_between, {borderRadius: 10}, style]}
|
|
onPress={onPress}
|
|
{...props}>
|
|
{context => (
|
|
<View style={[a.flex_1, a.flex_row, a.justify_between, a.p_md]}>
|
|
{typeof children === 'function' ? children(context) : children}
|
|
{disabled ? null : <ButtonIcon icon={CopyIcon} size="lg" />}
|
|
</View>
|
|
)}
|
|
</Button>
|
|
</View>
|
|
)
|
|
}
|