All files / components/dialogs DialogFooter.tsx

75% Statements 3/4
75.75% Branches 25/33
100% Functions 1/1
75% Lines 3/4

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116                                                                            4x                             4x   4x                                                                                                                        
/**
 * DialogFooter - 弹窗底部操作区组件
 */
 
import React from 'react';
import { XStack, YStack } from 'tamagui';
import { Button } from '@/src/design-system/components';
import { IconSymbol } from '@/src/components/ui/IconSymbol';
import { DIALOG_COLORS, SPACING, BORDER_RADIUS } from './constants';
 
interface DialogFooterProps {
  cancelText?: string;
  confirmText?: string;
  onCancel?: () => void;
  onConfirm?: () => void;
  confirmDisabled?: boolean;
  confirmLoading?: boolean;
  confirmDestructive?: boolean;
  layout?: 'horizontal' | 'vertical';
  fullWidth?: boolean;
  children?: React.ReactNode;
  testID?: string;
}
 
export function DialogFooter({
  cancelText = '取消',
  confirmText = '确定',
  onCancel,
  onConfirm,
  confirmDisabled = false,
  confirmLoading = false,
  confirmDestructive = false,
  layout = 'horizontal',
  fullWidth = true,
  children,
  testID,
}: DialogFooterProps) {
  // 如果提供了自定义内容,直接渲染
  Iif (children) {
    return (
      <YStack
        testID={testID}
        paddingHorizontal={SPACING.lg}
        paddingVertical={SPACING.lg}
        borderTopWidth={1}
        borderTopColor={DIALOG_COLORS.neutral[200]}
        backgroundColor={DIALOG_COLORS.background}
      >
        {children}
      </YStack>
    );
  }
 
  const Container = layout === 'horizontal' ? XStack : YStack;
 
  return (
    <Container
      testID={testID}
      gap={SPACING.md}
      paddingHorizontal={SPACING.lg}
      paddingVertical={SPACING.lg}
      borderTopWidth={1}
      borderTopColor={DIALOG_COLORS.neutral[200]}
      backgroundColor={DIALOG_COLORS.background}
    >
      {/* 取消按钮 */}
      {onCancel && (
        <Button
          testID="footer-cancel"
          flex={fullWidth ? 1 : undefined}
          size="$4"
          height={48}
          onPress={onCancel}
          backgroundColor={DIALOG_COLORS.neutral[100]}
          color={DIALOG_COLORS.text}
          borderRadius={BORDER_RADIUS.medium}
          fontWeight="600"
          fontSize={16}
          pressStyle={{ scale: 0.97, opacity: 0.8 }}
          disabled={confirmLoading}
        >
          {cancelText}
        </Button>
      )}
 
      {/* 确认按钮 */}
      {onConfirm && (
        <Button
          testID="footer-confirm"
          flex={fullWidth ? 1 : undefined}
          size="$4"
          height={48}
          backgroundColor={confirmDestructive ? DIALOG_COLORS.error : DIALOG_COLORS.primary}
          color="white"
          borderRadius={BORDER_RADIUS.medium}
          fontWeight="700"
          fontSize={16}
          onPress={onConfirm}
          disabled={confirmDisabled || confirmLoading}
          opacity={confirmDisabled || confirmLoading ? 0.6 : 1}
          pressStyle={{ scale: 0.97, opacity: 0.9 }}
          icon={
            confirmLoading ? undefined : confirmDestructive ? (
              <IconSymbol name="trash.fill" size={18} color="white" />
            ) : (
              <IconSymbol name="checkmark.circle.fill" size={20} color="white" />
            )
          }
        >
          {confirmLoading ? 'Loading...' : confirmText}
        </Button>
      )}
    </Container>
  );
}