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>
118 lines
2.6 KiB
TypeScript
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%',
|
|
},
|
|
});
|