react-native-multi-color-view
Version:
A React Native component for creating multi-color gradient views
101 lines (86 loc) • 2.68 kB
text/typescript
import React from 'react';
import { View, StyleSheet, ViewStyle, ViewProps, StyleProp } from 'react-native';
import Svg, { Defs, LinearGradient, Stop, Rect } from 'react-native-svg';
interface GradientViewProps extends ViewProps {
colors?: string[];
start?: { x: number; y: number };
end?: { x: number; y: number };
style?: StyleProp<ViewStyle>;
children?: React.ReactNode;
}
const borderRadiusProps = [
'borderRadius',
'borderTopLeftRadius',
'borderTopRightRadius',
'borderBottomLeftRadius',
'borderBottomRightRadius',
] as const;
const GradientView: React.FC<GradientViewProps> = ({
colors,
start,
end,
style,
children,
}) => {
const hasValidColors = Array.isArray(colors) && colors.length >= 2;
const gradientStart = start ?? (hasValidColors ? { x: 0, y: 0 } : null);
const gradientEnd = end ?? (hasValidColors ? { x: 0, y: 1 } : null);
if (!hasValidColors) {
const fallbackStyle = colors?.[0]
? [{ backgroundColor: colors[0] }, style]
: [style];
return React.createElement(View, { style: fallbackStyle }, children);
}
const flatStyle = StyleSheet.flatten(style) || {};
const hasOverflow = flatStyle.hasOwnProperty('overflow');
const hasBorderRadius = borderRadiusProps.some(
(prop) => {
const value = flatStyle[prop];
return typeof value === 'number' && value > 0;
}
);
// Conditionally add overflow: 'hidden'
const containerStyle = hasOverflow
? style // user controls overflow explicitly
: hasBorderRadius
? [style, { overflow: 'hidden' as const }] // add overflow hidden if borderRadius exists
: style; // no overflow added if no borderRadius
if (!gradientStart || !gradientEnd) {
return React.createElement(View, { style }, children);
}
const stops = colors.map((color, index) =>
React.createElement(Stop, {
key: index,
offset: `${(index / (colors.length - 1)) * 100}%`,
stopColor: color,
stopOpacity: "1"
})
);
const gradient = React.createElement(
LinearGradient,
{
id: "grad",
x1: `${gradientStart.x * 100}%`,
y1: `${gradientStart.y * 100}%`,
x2: `${gradientEnd.x * 100}%`,
y2: `${gradientEnd.y * 100}%`
},
stops
);
const defs = React.createElement(Defs, null, gradient);
const rect = React.createElement(Rect, {
x: "0",
y: "0",
width: "100%",
height: "100%",
fill: "url(#grad)"
});
const svg = React.createElement(
Svg,
{ style: StyleSheet.absoluteFill, pointerEvents: "none" },
defs,
rect
);
return React.createElement(View, { style: containerStyle }, svg, children);
};
export default GradientView;