Files
dt-design-system/packages/react-native/src/components/DTModal.tsx
michael 47e8085581 Make RN components fully theme-driven for multi-brand support
Refactor all 18 React Native components from static DTColors imports to
dynamic useDTTheme() context, enabling proper visual differentiation
when switching between DT and Classic brands.

Key changes:
- Replace static DTColors with theme context in all components
- Add shape tokens (bevel/radius) to DTExtendedTheme interface
- Conditionally render SVG bevels (DT) vs borderRadius (Classic)
- Configure fonts per brand (Tektur for DT, system sans-serif for Classic)
- Update buildThemeFromBrand to parse shape and typography tokens
- Fix Metro config for monorepo singleton resolution

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-06 10:18:39 -08:00

118 lines
2.6 KiB
TypeScript

/**
* DT Modal Component
*
* Wraps React Native Paper's Modal + Portal with the Dangerous Things
* aesthetic. Content is rendered inside a DTCard for the beveled look.
*
* Web CSS reference (Modal.tsx):
* - Centered overlay with dark backdrop
* - Content in beveled card container
*/
import {StyleSheet, ViewStyle, StyleProp, KeyboardAvoidingView, Platform} from 'react-native';
import {Portal, Modal} from 'react-native-paper';
import {useDTTheme} from '../theme/DTThemeProvider';
import {type DTVariant} from '../utils/variantColors';
import {DTCard} from './DTCard';
interface DTModalProps {
/**
* Whether the modal is visible
*/
visible: boolean;
/**
* Called when the modal is dismissed
*/
onDismiss: () => void;
/**
* Optional title for the modal header
*/
title?: string;
/**
* Visual variant
* @default 'normal'
*/
variant?: DTVariant;
/**
* Modal content
*/
children: React.ReactNode;
/**
* Whether the modal can be dismissed by tapping the backdrop
* @default true
*/
dismissable?: boolean;
/**
* Additional styles for the card content area
*/
contentStyle?: StyleProp<ViewStyle>;
/**
* Additional styles for the modal container
*/
style?: StyleProp<ViewStyle>;
}
/**
* DT-styled Modal wrapping React Native Paper Modal + Portal
*
* @example
* <DTModal visible={showModal} onDismiss={() => setShowModal(false)} title="Confirm">
* <Text>Are you sure?</Text>
* </DTModal>
*
* @example
* <DTModal visible={isOpen} onDismiss={close} variant="warning" title="Error">
* <Text>Something went wrong</Text>
* </DTModal>
*/
export function DTModal({
visible,
onDismiss,
title,
variant = 'normal',
children,
dismissable = true,
contentStyle,
style,
}: DTModalProps) {
const theme = useDTTheme();
return (
<Portal>
<Modal
visible={visible}
onDismiss={onDismiss}
dismissable={dismissable}
contentContainerStyle={[styles.container, style]}
style={styles.modal}
theme={{
colors: {
backdrop: theme.colors.backdrop,
},
}}>
<KeyboardAvoidingView
behavior={Platform.OS === 'ios' ? 'padding' : undefined}
style={styles.keyboardAvoid}>
<DTCard
mode={variant}
title={title}
showHeader={!!title}
contentStyle={contentStyle}>
{children}
</DTCard>
</KeyboardAvoidingView>
</Modal>
</Portal>
);
}
const styles = StyleSheet.create({
modal: {},
container: {
marginHorizontal: 24,
},
keyboardAvoid: {
width: '100%',
},
});