react-native-squircle-skia
Version:
Skia based squircle for React Native. draws with Figma squirce style
172 lines (158 loc) • 5.63 kB
JavaScript
function _extends() { _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }
import { Canvas, Path, usePath } from '@shopify/react-native-skia';
import React, { useMemo, useState } from 'react';
import { StyleSheet, View } from 'react-native';
import { getPathParamsForCorner } from '../utils';
const Squircle = _ref => {
let {
smoothing = 1,
style,
children,
color,
...otherProps
} = _ref;
const flattenStyle = useMemo(() => StyleSheet.flatten(style), [style]);
const {
borderRadius,
borderTopLeftRadius = borderRadius,
borderTopRightRadius = borderRadius,
borderBottomLeftRadius = borderRadius,
borderBottomRightRadius = borderRadius,
borderWidth,
borderColor,
borderStyle,
backgroundColor,
...otherStyles
} = flattenStyle;
if (borderRadius === undefined || borderTopLeftRadius === undefined && borderTopRightRadius === undefined && borderBottomLeftRadius === undefined && borderBottomRightRadius === undefined) {
throw new Error('react-native-squircle-skia: No borderRadius provided in Squircle style');
}
if (borderWidth !== undefined || borderColor !== undefined || borderStyle !== undefined) {
throw new Error('react-native-squircle-skia: Setting border is not supported.');
}
const [width, setWidth] = useState(0);
const [height, setHeight] = useState(0);
const pathColor = useMemo(() => {
return color || backgroundColor || 'transparent';
}, [backgroundColor, color]);
const drawTopRightCornerPath = path => {
if (borderTopRightRadius) {
const {
a,
b,
c,
d,
p,
circularSectionLength
} = getPathParamsForCorner({
width,
height,
cornerRadius: borderTopRightRadius,
cornerSmoothing: smoothing
});
path.moveTo(Math.max(width / 2, width - p), 0);
path.cubicTo(width - (p - a), 0, width - (p - a - b), 0, width - (p - a - b - c), d);
path.rArcTo(borderTopRightRadius, borderTopRightRadius, 0, true, false, circularSectionLength, circularSectionLength);
path.cubicTo(width, p - a - b, width, p - a, width, Math.min(height / 2, p));
} else {
path.moveTo(width / 2, 0);
path.lineTo(width, 0);
path.lineTo(width, height / 2);
}
};
const drawBottomRightCornerPath = path => {
if (borderBottomRightRadius) {
const {
a,
b,
c,
d,
p,
circularSectionLength
} = getPathParamsForCorner({
width,
height,
cornerRadius: borderBottomRightRadius,
cornerSmoothing: smoothing
});
path.lineTo(width, Math.max(height / 2, height - p));
path.cubicTo(width, height - (p - a), width, height - (p - a - b), width - d, height - (p - a - b - c));
path.rArcTo(borderBottomRightRadius, borderBottomRightRadius, 0, true, false, -circularSectionLength, circularSectionLength);
path.cubicTo(width - (p - a - b), height, width - (p - a), height, Math.max(width / 2, width - p), height);
} else {
path.lineTo(width, height);
path.lineTo(width / 2, height);
}
};
const drawBottomLeftCornerPath = path => {
if (borderBottomLeftRadius) {
const {
a,
b,
c,
d,
p,
circularSectionLength
} = getPathParamsForCorner({
width,
height,
cornerRadius: borderBottomLeftRadius,
cornerSmoothing: smoothing
});
path.lineTo(Math.min(width / 2, p), height);
path.cubicTo(p - a, height, p - a - b, height, p - a - b - c, height - d);
path.rArcTo(borderBottomLeftRadius, borderBottomLeftRadius, 0, true, false, -circularSectionLength, -circularSectionLength);
path.cubicTo(0, height - (p - a - b), 0, height - (p - a), 0, Math.max(height / 2, height - p));
} else {
path.lineTo(0, height);
path.lineTo(0, height / 2);
}
};
const drawTopLeftCornerPath = path => {
if (borderTopLeftRadius) {
const {
a,
b,
c,
d,
p,
circularSectionLength
} = getPathParamsForCorner({
width,
height,
cornerRadius: borderTopLeftRadius,
cornerSmoothing: smoothing
});
path.lineTo(0, Math.min(height / 2, p));
path.cubicTo(0, p - a, 0, p - a - b, d, p - a - b - c);
path.rArcTo(borderTopLeftRadius, borderTopLeftRadius, 0, true, false, circularSectionLength, -circularSectionLength);
path.cubicTo(p - a - b, 0, p - a, 0, Math.min(width / 2, p), 0);
} else {
path.lineTo(0, 0);
}
path.close();
};
const _path = usePath(path => {
drawTopRightCornerPath(path);
drawBottomRightCornerPath(path);
drawBottomLeftCornerPath(path);
drawTopLeftCornerPath(path);
return path;
}, [smoothing, borderRadius, width, height]);
const handleLayout = event => {
setWidth(event.nativeEvent.layout.width);
setHeight(event.nativeEvent.layout.height);
};
return /*#__PURE__*/React.createElement(View, _extends({
style: [otherStyles]
}, otherProps, {
onLayout: handleLayout
}), /*#__PURE__*/React.createElement(Canvas, {
style: StyleSheet.absoluteFill
}, /*#__PURE__*/React.createElement(Path, {
path: _path,
color: pathColor
})), children);
};
export default Squircle;
//# sourceMappingURL=Squircle.js.map