@whitemordred/react-native-bootstrap5
Version:
A complete React Native library that replicates Bootstrap 5.3 with 100% feature parity, full theming support, CSS variables, and dark/light mode
293 lines (290 loc) • 10.6 kB
JavaScript
;
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
var ownKeys = function(o) {
ownKeys = Object.getOwnPropertyNames || function (o) {
var ar = [];
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
return ar;
};
return ownKeys(o);
};
return function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
__setModuleDefault(result, mod);
return result;
};
})();
Object.defineProperty(exports, "__esModule", { value: true });
exports.useToast = exports.Toast = exports.ToastContainer = exports.ToastBody = exports.ToastHeader = void 0;
const react_1 = __importStar(require("react"));
const react_native_1 = require("react-native");
const ThemeProvider_1 = require("../theme/ThemeProvider");
const ToastHeader = ({ children, style }) => {
const { theme } = (0, ThemeProvider_1.useTheme)();
return (<react_native_1.View style={[styles.toastHeader, { borderBottomColor: theme.colors.gray[200] }, style]}>
{children}
</react_native_1.View>);
};
exports.ToastHeader = ToastHeader;
const ToastBody = ({ children, style }) => {
return (<react_native_1.View style={[styles.toastBody, style]}>
{children}
</react_native_1.View>);
};
exports.ToastBody = ToastBody;
const ToastContainer = ({ children, position = 'top-right', style, }) => {
const getPositionStyles = () => {
const { width, height } = react_native_1.Dimensions.get('window');
const margin = 20;
switch (position) {
case 'top-left':
return { top: margin, left: margin };
case 'top-center':
return { top: margin, left: width / 2 - 150 };
case 'top-right':
return { top: margin, right: margin };
case 'bottom-left':
return { bottom: margin, left: margin };
case 'bottom-center':
return { bottom: margin, left: width / 2 - 150 };
case 'bottom-right':
return { bottom: margin, right: margin };
default:
return { top: margin, right: margin };
}
};
return (<react_native_1.View style={[styles.toastContainer, getPositionStyles(), style]}>
{children}
</react_native_1.View>);
};
exports.ToastContainer = ToastContainer;
const Toast = ({ visible, message, variant = 'primary', position = 'top', duration = 4000, onHide, closable = true, title, children, style, textStyle, }) => {
const [fadeAnim] = (0, react_1.useState)(new react_native_1.Animated.Value(0));
const [slideAnim] = (0, react_1.useState)(new react_native_1.Animated.Value(-100));
const { theme } = (0, ThemeProvider_1.useTheme)();
(0, react_1.useEffect)(() => {
if (visible) {
// Fade in and slide in animation
react_native_1.Animated.parallel([
react_native_1.Animated.timing(fadeAnim, {
toValue: 1,
duration: 300,
useNativeDriver: true,
}),
react_native_1.Animated.timing(slideAnim, {
toValue: 0,
duration: 300,
useNativeDriver: true,
}),
]).start();
// Auto hide after duration
if (duration > 0) {
const timer = setTimeout(() => {
hideToast();
}, duration);
return () => clearTimeout(timer);
}
}
else {
hideToast();
}
return undefined;
}, [visible, duration]);
const hideToast = () => {
react_native_1.Animated.parallel([
react_native_1.Animated.timing(fadeAnim, {
toValue: 0,
duration: 300,
useNativeDriver: true,
}),
react_native_1.Animated.timing(slideAnim, {
toValue: position === 'bottom' ? 100 : -100,
duration: 300,
useNativeDriver: true,
}),
]).start(() => {
onHide === null || onHide === void 0 ? void 0 : onHide();
});
};
const getVariantStyles = () => {
const variantColors = theme.colors[variant];
const backgroundColor = typeof variantColors === 'string'
? variantColors
: (variantColors === null || variantColors === void 0 ? void 0 : variantColors[500]) || theme.colors.primary;
return {
backgroundColor,
borderLeftColor: backgroundColor,
};
};
const getPositionStyles = () => {
const { width, height } = react_native_1.Dimensions.get('window');
const margin = 20;
switch (position) {
case 'center':
return {
position: 'absolute',
top: height / 2 - 50,
left: width / 2 - 150,
};
case 'bottom':
return {
position: 'absolute',
bottom: margin,
left: margin,
right: margin,
};
default: // top
return {
position: 'absolute',
top: margin,
left: margin,
right: margin,
};
}
};
const [isVisible, setIsVisible] = (0, react_1.useState)(false);
(0, react_1.useEffect)(() => {
setIsVisible(visible);
}, [visible]);
if (!isVisible) {
return null;
}
return (<react_native_1.Animated.View style={[
styles.toast,
getVariantStyles(),
getPositionStyles(),
{
opacity: fadeAnim,
transform: [{ translateY: slideAnim }],
},
style,
]}>
{title && (<react_native_1.View style={styles.toastHeader}>
<react_native_1.Text style={[styles.toastTitle, { color: theme.colors.white }]}>
{title}
</react_native_1.Text>
{closable && (<react_native_1.TouchableOpacity onPress={hideToast} style={styles.closeButton}>
<react_native_1.Text style={[styles.closeText, { color: theme.colors.white }]}>×</react_native_1.Text>
</react_native_1.TouchableOpacity>)}
</react_native_1.View>)}
<react_native_1.View style={styles.toastContent}>
{children || (<react_native_1.Text style={[styles.toastMessage, { color: theme.colors.white }, textStyle]}>
{message}
</react_native_1.Text>)}
{!title && closable && (<react_native_1.TouchableOpacity onPress={hideToast} style={styles.closeButton}>
<react_native_1.Text style={[styles.closeText, { color: theme.colors.white }]}>×</react_native_1.Text>
</react_native_1.TouchableOpacity>)}
</react_native_1.View>
</react_native_1.Animated.View>);
};
exports.Toast = Toast;
// Hook for managing toasts
const useToast = () => {
const [toasts, setToasts] = (0, react_1.useState)([]);
const showToast = (toastProps) => {
const id = Date.now().toString();
const newToast = Object.assign(Object.assign({}, toastProps), { id, visible: true, onHide: () => removeToast(id) });
setToasts(prev => [...prev, newToast]);
return id;
};
const removeToast = (id) => {
setToasts(prev => prev.filter(toast => toast.id !== id));
};
const showSuccess = (message, options) => {
return showToast(Object.assign(Object.assign({}, options), { message, variant: 'success' }));
};
const showError = (message, options) => {
return showToast(Object.assign(Object.assign({}, options), { message, variant: 'danger' }));
};
const showWarning = (message, options) => {
return showToast(Object.assign(Object.assign({}, options), { message, variant: 'warning' }));
};
const showInfo = (message, options) => {
return showToast(Object.assign(Object.assign({}, options), { message, variant: 'info' }));
};
return {
toasts,
showToast,
removeToast,
showSuccess,
showError,
showWarning,
showInfo,
};
};
exports.useToast = useToast;
const styles = react_native_1.StyleSheet.create({
toastContainer: {
position: 'absolute',
zIndex: 9999,
width: 300,
},
toast: {
minWidth: 250,
maxWidth: 350,
backgroundColor: '#007bff',
borderRadius: 8,
borderLeftWidth: 4,
marginVertical: 4,
elevation: 6,
shadowColor: '#000',
shadowOffset: { width: 0, height: 3 },
shadowOpacity: 0.27,
shadowRadius: 4.65,
zIndex: 9999,
},
toastHeader: {
flexDirection: 'row',
justifyContent: 'space-between',
alignItems: 'center',
paddingHorizontal: 16,
paddingVertical: 12,
borderBottomWidth: 1,
},
toastTitle: {
fontSize: 16,
fontWeight: '600',
flex: 1,
},
toastContent: {
flexDirection: 'row',
alignItems: 'center',
paddingHorizontal: 16,
paddingVertical: 12,
},
toastBody: {
flex: 1,
},
toastMessage: {
fontSize: 14,
flex: 1,
lineHeight: 20,
},
closeButton: {
marginLeft: 12,
padding: 4,
},
closeText: {
fontSize: 20,
fontWeight: 'bold',
},
});
exports.default = exports.Toast;