react-native-svg
Version:
SVG library for react-native
105 lines (95 loc) • 2.8 kB
text/typescript
import type { ReactElement } from 'react';
import * as React from 'react';
import { Children } from 'react';
import { processColor } from 'react-native';
import extractOpacity from './extractOpacity';
import extractTransform from './extractTransform';
import type { TransformProps } from './types';
import units from '../units';
const percentReg = /^([+-]?\d+(?:\.\d+)?(?:[eE][+-]?\d+)?)(%?)$/;
function percentToFloat(
percent:
| number
| string
| {
__getAnimatedValue: () => number;
}
): number {
if (typeof percent === 'number') {
return percent;
}
if (
typeof percent === 'object' &&
typeof percent.__getAnimatedValue === 'function'
) {
return percent.__getAnimatedValue();
}
const matched = typeof percent === 'string' && percent.match(percentReg);
if (!matched) {
console.warn(`"${percent}" is not a valid number or percentage string.`);
return 0;
}
return matched[2] ? +matched[1] / 100 : +matched[1];
}
const offsetComparator = (object: number[], other: number[]) =>
object[0] - other[0];
export default function extractGradient(
props: {
id?: string;
children?: ReactElement[];
transform?: TransformProps['transform'];
gradientTransform?: TransformProps['transform'];
gradientUnits?: 'objectBoundingBox' | 'userSpaceOnUse';
} & TransformProps,
parent: unknown
) {
const { id, children, gradientTransform, transform, gradientUnits } = props;
if (!id) {
return null;
}
const stops = [];
const childArray = children
? Children.map(children, (child) =>
React.cloneElement(child, {
parent,
})
)
: [];
const l = childArray.length;
for (let i = 0; i < l; i++) {
const {
props: {
style,
offset = style && style.offset,
stopColor = (style && style.stopColor) || '#000',
stopOpacity = style && style.stopOpacity,
},
} = childArray[i];
const offsetNumber = percentToFloat(offset || 0);
const color = stopColor && processColor(stopColor);
if (typeof color !== 'number' || isNaN(offsetNumber)) {
console.warn(
`"${stopColor}" is not a valid color or "${offset}" is not a valid offset`
);
continue;
}
const alpha = Math.round(extractOpacity(stopOpacity) * 255);
stops.push([offsetNumber, (color & 0x00ffffff) | (alpha << 24)]);
}
stops.sort(offsetComparator);
const gradient = [];
const k = stops.length;
for (let j = 0; j < k; j++) {
const s = stops[j];
gradient.push(s[0], s[1]);
}
return {
name: id,
gradient,
children: childArray,
gradientUnits: (gradientUnits && units[gradientUnits]) || 0,
gradientTransform: extractTransform(
gradientTransform || transform || props
),
};
}