You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
240 lines
5.4 KiB
240 lines
5.4 KiB
'use client';
|
|
import React from 'react';
|
|
import { createToastHook } from '@gluestack-ui/toast';
|
|
import { AccessibilityInfo, Text, View, ViewStyle } from 'react-native';
|
|
import { tva } from '@gluestack-ui/nativewind-utils/tva';
|
|
import { cssInterop } from 'nativewind';
|
|
import {
|
|
Motion,
|
|
AnimatePresence,
|
|
MotionComponentProps,
|
|
} from '@legendapp/motion';
|
|
import {
|
|
withStyleContext,
|
|
useStyleContext,
|
|
} from '@gluestack-ui/nativewind-utils/withStyleContext';
|
|
import type { VariantProps } from '@gluestack-ui/nativewind-utils';
|
|
|
|
type IMotionViewProps = React.ComponentProps<typeof View> &
|
|
MotionComponentProps<typeof View, ViewStyle, unknown, unknown, unknown>;
|
|
|
|
const MotionView = Motion.View as React.ComponentType<IMotionViewProps>;
|
|
|
|
const useToast = createToastHook(MotionView, AnimatePresence);
|
|
const SCOPE = 'TOAST';
|
|
|
|
cssInterop(MotionView, { className: 'style' });
|
|
|
|
const toastStyle = tva({
|
|
base: 'p-4 m-1 rounded-md gap-1 web:pointer-events-auto shadow-hard-5 border-outline-100',
|
|
variants: {
|
|
action: {
|
|
error: 'bg-error-800',
|
|
warning: 'bg-warning-700',
|
|
success: 'bg-success-700',
|
|
info: 'bg-info-700',
|
|
muted: 'bg-background-800',
|
|
},
|
|
|
|
variant: {
|
|
solid: '',
|
|
outline: 'border bg-background-0',
|
|
},
|
|
},
|
|
});
|
|
|
|
const toastTitleStyle = tva({
|
|
base: 'text-typography-0 font-medium font-body tracking-md text-left',
|
|
variants: {
|
|
isTruncated: {
|
|
true: '',
|
|
},
|
|
bold: {
|
|
true: 'font-bold',
|
|
},
|
|
underline: {
|
|
true: 'underline',
|
|
},
|
|
strikeThrough: {
|
|
true: 'line-through',
|
|
},
|
|
size: {
|
|
'2xs': 'text-2xs',
|
|
'xs': 'text-xs',
|
|
'sm': 'text-sm',
|
|
'md': 'text-base',
|
|
'lg': 'text-lg',
|
|
'xl': 'text-xl',
|
|
'2xl': 'text-2xl',
|
|
'3xl': 'text-3xl',
|
|
'4xl': 'text-4xl',
|
|
'5xl': 'text-5xl',
|
|
'6xl': 'text-6xl',
|
|
},
|
|
},
|
|
parentVariants: {
|
|
variant: {
|
|
solid: '',
|
|
outline: '',
|
|
},
|
|
action: {
|
|
error: '',
|
|
warning: '',
|
|
success: '',
|
|
info: '',
|
|
muted: '',
|
|
},
|
|
},
|
|
parentCompoundVariants: [
|
|
{
|
|
variant: 'outline',
|
|
action: 'error',
|
|
class: 'text-error-800',
|
|
},
|
|
{
|
|
variant: 'outline',
|
|
action: 'warning',
|
|
class: 'text-warning-800',
|
|
},
|
|
{
|
|
variant: 'outline',
|
|
action: 'success',
|
|
class: 'text-success-800',
|
|
},
|
|
{
|
|
variant: 'outline',
|
|
action: 'info',
|
|
class: 'text-info-800',
|
|
},
|
|
{
|
|
variant: 'outline',
|
|
action: 'muted',
|
|
class: 'text-background-800',
|
|
},
|
|
],
|
|
});
|
|
|
|
const toastDescriptionStyle = tva({
|
|
base: 'font-normal font-body tracking-md text-left',
|
|
variants: {
|
|
isTruncated: {
|
|
true: '',
|
|
},
|
|
bold: {
|
|
true: 'font-bold',
|
|
},
|
|
underline: {
|
|
true: 'underline',
|
|
},
|
|
strikeThrough: {
|
|
true: 'line-through',
|
|
},
|
|
size: {
|
|
'2xs': 'text-2xs',
|
|
'xs': 'text-xs',
|
|
'sm': 'text-sm',
|
|
'md': 'text-base',
|
|
'lg': 'text-lg',
|
|
'xl': 'text-xl',
|
|
'2xl': 'text-2xl',
|
|
'3xl': 'text-3xl',
|
|
'4xl': 'text-4xl',
|
|
'5xl': 'text-5xl',
|
|
'6xl': 'text-6xl',
|
|
},
|
|
},
|
|
parentVariants: {
|
|
variant: {
|
|
solid: 'text-typography-50',
|
|
outline: 'text-typography-900',
|
|
},
|
|
},
|
|
});
|
|
|
|
const Root = withStyleContext(View, SCOPE);
|
|
type IToastProps = React.ComponentProps<typeof Root> & {
|
|
className?: string;
|
|
} & VariantProps<typeof toastStyle>;
|
|
|
|
const Toast = React.forwardRef<React.ComponentRef<typeof Root>, IToastProps>(
|
|
function Toast(
|
|
{ className, variant = 'solid', action = 'muted', ...props },
|
|
ref
|
|
) {
|
|
return (
|
|
<Root
|
|
ref={ref}
|
|
className={toastStyle({ variant, action, class: className })}
|
|
context={{ variant, action }}
|
|
{...props}
|
|
/>
|
|
);
|
|
}
|
|
);
|
|
|
|
type IToastTitleProps = React.ComponentProps<typeof Text> & {
|
|
className?: string;
|
|
} & VariantProps<typeof toastTitleStyle>;
|
|
|
|
const ToastTitle = React.forwardRef<
|
|
React.ComponentRef<typeof Text>,
|
|
IToastTitleProps
|
|
>(function ToastTitle({ className, size = 'md', children, ...props }, ref) {
|
|
const { variant: parentVariant, action: parentAction } =
|
|
useStyleContext(SCOPE);
|
|
React.useEffect(() => {
|
|
// Issue from react-native side
|
|
// Hack for now, will fix this later
|
|
AccessibilityInfo.announceForAccessibility(children as string);
|
|
}, [children]);
|
|
|
|
return (
|
|
<Text
|
|
{...props}
|
|
ref={ref}
|
|
aria-live="assertive"
|
|
aria-atomic="true"
|
|
role="alert"
|
|
className={toastTitleStyle({
|
|
size,
|
|
class: className,
|
|
parentVariants: {
|
|
variant: parentVariant,
|
|
action: parentAction,
|
|
},
|
|
})}
|
|
>
|
|
{children}
|
|
</Text>
|
|
);
|
|
});
|
|
|
|
type IToastDescriptionProps = React.ComponentProps<typeof Text> & {
|
|
className?: string;
|
|
} & VariantProps<typeof toastDescriptionStyle>;
|
|
|
|
const ToastDescription = React.forwardRef<
|
|
React.ComponentRef<typeof Text>,
|
|
IToastDescriptionProps
|
|
>(function ToastDescription({ className, size = 'md', ...props }, ref) {
|
|
const { variant: parentVariant } = useStyleContext(SCOPE);
|
|
return (
|
|
<Text
|
|
ref={ref}
|
|
{...props}
|
|
className={toastDescriptionStyle({
|
|
size,
|
|
class: className,
|
|
parentVariants: {
|
|
variant: parentVariant,
|
|
},
|
|
})}
|
|
/>
|
|
);
|
|
});
|
|
|
|
Toast.displayName = 'Toast';
|
|
ToastTitle.displayName = 'ToastTitle';
|
|
ToastDescription.displayName = 'ToastDescription';
|
|
|
|
export { useToast, Toast, ToastTitle, ToastDescription };
|