squircle-view 0.0.0-stage → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (115) hide show
  1. package/LICENSE +20 -0
  2. package/README.md +82 -2
  3. package/SquircleView.podspec +22 -0
  4. package/android/CMakeLists.txt +17 -0
  5. package/android/build.gradle +78 -0
  6. package/android/src/main/AndroidManifest.xml +2 -0
  7. package/android/src/main/cpp/SquircleGeometryJni.cpp +52 -0
  8. package/android/src/main/java/com/squircleview/SquircleViewManager.kt +72 -0
  9. package/android/src/main/java/com/squircleview/SquircleViewPackage.kt +16 -0
  10. package/android/src/main/java/com/squircleview/geometry/SquircleGeometry.kt +58 -0
  11. package/android/src/main/java/com/squircleview/style/SquircleStyle.kt +142 -0
  12. package/android/src/main/java/com/squircleview/views/SquircleView.kt +361 -0
  13. package/common/cpp/SquircleGeometry.cpp +248 -0
  14. package/common/cpp/SquircleGeometry.h +75 -0
  15. package/ios/Geometry/SquirclePath.h +21 -0
  16. package/ios/Geometry/SquirclePath.mm +39 -0
  17. package/ios/Layers/SquircleBorderLayer.h +24 -0
  18. package/ios/Layers/SquircleBorderLayer.m +102 -0
  19. package/ios/Views/SquircleView.h +16 -0
  20. package/ios/Views/SquircleView.mm +337 -0
  21. package/lib/module/components/index.js +4 -0
  22. package/lib/module/components/index.js.map +1 -0
  23. package/lib/module/components/squircle-view.js +22 -0
  24. package/lib/module/components/squircle-view.js.map +1 -0
  25. package/lib/module/components/squircle-view.native.js +23 -0
  26. package/lib/module/components/squircle-view.native.js.map +1 -0
  27. package/lib/module/constants/index.js +5 -0
  28. package/lib/module/constants/index.js.map +1 -0
  29. package/lib/module/constants/native.constants.js +10 -0
  30. package/lib/module/constants/native.constants.js.map +1 -0
  31. package/lib/module/constants/squircle.constants.js +5 -0
  32. package/lib/module/constants/squircle.constants.js.map +1 -0
  33. package/lib/module/index.js +4 -0
  34. package/lib/module/index.js.map +1 -0
  35. package/lib/module/interfaces/index.js +5 -0
  36. package/lib/module/interfaces/index.js.map +1 -0
  37. package/lib/module/interfaces/squircle-style.interface.js +4 -0
  38. package/lib/module/interfaces/squircle-style.interface.js.map +1 -0
  39. package/lib/module/interfaces/squircle-view.interface.js +4 -0
  40. package/lib/module/interfaces/squircle-view.interface.js.map +1 -0
  41. package/lib/module/package.json +1 -0
  42. package/lib/module/root/index.js +4 -0
  43. package/lib/module/root/index.js.map +1 -0
  44. package/lib/module/types/index.js +5 -0
  45. package/lib/module/types/index.js.map +1 -0
  46. package/lib/module/types/native-component-registry.d.js +2 -0
  47. package/lib/module/types/native-component-registry.d.js.map +1 -0
  48. package/lib/module/types/native.types.js +4 -0
  49. package/lib/module/types/native.types.js.map +1 -0
  50. package/lib/module/types/squircle.types.js +4 -0
  51. package/lib/module/types/squircle.types.js.map +1 -0
  52. package/lib/module/utils/index.js +4 -0
  53. package/lib/module/utils/index.js.map +1 -0
  54. package/lib/module/utils/style.utils.js +22 -0
  55. package/lib/module/utils/style.utils.js.map +1 -0
  56. package/lib/module/views/SquircleViewNativeComponent.ts +12 -0
  57. package/lib/module/views/index.js +15 -0
  58. package/lib/module/views/index.js.map +1 -0
  59. package/lib/typescript/package.json +1 -0
  60. package/lib/typescript/src/components/index.d.ts +2 -0
  61. package/lib/typescript/src/components/index.d.ts.map +1 -0
  62. package/lib/typescript/src/components/squircle-view.d.ts +5 -0
  63. package/lib/typescript/src/components/squircle-view.d.ts.map +1 -0
  64. package/lib/typescript/src/components/squircle-view.native.d.ts +5 -0
  65. package/lib/typescript/src/components/squircle-view.native.d.ts.map +1 -0
  66. package/lib/typescript/src/constants/index.d.ts +3 -0
  67. package/lib/typescript/src/constants/index.d.ts.map +1 -0
  68. package/lib/typescript/src/constants/native.constants.d.ts +8 -0
  69. package/lib/typescript/src/constants/native.constants.d.ts.map +1 -0
  70. package/lib/typescript/src/constants/squircle.constants.d.ts +3 -0
  71. package/lib/typescript/src/constants/squircle.constants.d.ts.map +1 -0
  72. package/lib/typescript/src/index.d.ts +2 -0
  73. package/lib/typescript/src/index.d.ts.map +1 -0
  74. package/lib/typescript/src/interfaces/index.d.ts +3 -0
  75. package/lib/typescript/src/interfaces/index.d.ts.map +1 -0
  76. package/lib/typescript/src/interfaces/squircle-style.interface.d.ts +7 -0
  77. package/lib/typescript/src/interfaces/squircle-style.interface.d.ts.map +1 -0
  78. package/lib/typescript/src/interfaces/squircle-view.interface.d.ts +10 -0
  79. package/lib/typescript/src/interfaces/squircle-view.interface.d.ts.map +1 -0
  80. package/lib/typescript/src/root/index.d.ts +6 -0
  81. package/lib/typescript/src/root/index.d.ts.map +1 -0
  82. package/lib/typescript/src/types/index.d.ts +3 -0
  83. package/lib/typescript/src/types/index.d.ts.map +1 -0
  84. package/lib/typescript/src/types/native.types.d.ts +5 -0
  85. package/lib/typescript/src/types/native.types.d.ts.map +1 -0
  86. package/lib/typescript/src/types/squircle.types.d.ts +6 -0
  87. package/lib/typescript/src/types/squircle.types.d.ts.map +1 -0
  88. package/lib/typescript/src/utils/index.d.ts +2 -0
  89. package/lib/typescript/src/utils/index.d.ts.map +1 -0
  90. package/lib/typescript/src/utils/style.utils.d.ts +6 -0
  91. package/lib/typescript/src/utils/style.utils.d.ts.map +1 -0
  92. package/lib/typescript/src/views/SquircleViewNativeComponent.d.ts +8 -0
  93. package/lib/typescript/src/views/SquircleViewNativeComponent.d.ts.map +1 -0
  94. package/lib/typescript/src/views/index.d.ts +7 -0
  95. package/lib/typescript/src/views/index.d.ts.map +1 -0
  96. package/package.json +200 -4
  97. package/src/components/index.ts +1 -0
  98. package/src/components/squircle-view.native.tsx +34 -0
  99. package/src/components/squircle-view.tsx +24 -0
  100. package/src/constants/index.ts +2 -0
  101. package/src/constants/native.constants.ts +9 -0
  102. package/src/constants/squircle.constants.ts +3 -0
  103. package/src/index.ts +1 -0
  104. package/src/interfaces/index.ts +2 -0
  105. package/src/interfaces/squircle-style.interface.ts +8 -0
  106. package/src/interfaces/squircle-view.interface.ts +11 -0
  107. package/src/root/index.ts +5 -0
  108. package/src/types/index.ts +2 -0
  109. package/src/types/native-component-registry.d.ts +15 -0
  110. package/src/types/native.types.ts +8 -0
  111. package/src/types/squircle.types.ts +7 -0
  112. package/src/utils/index.ts +1 -0
  113. package/src/utils/style.utils.ts +17 -0
  114. package/src/views/SquircleViewNativeComponent.ts +12 -0
  115. package/src/views/index.ts +27 -0
@@ -0,0 +1,39 @@
1
+ //
2
+ // SquirclePath.mm
3
+ // Pods
4
+ //
5
+ // Created by rit3zh CX on 10/7/26.
6
+ //
7
+
8
+ #import "SquirclePath.h"
9
+
10
+ void SquirclePathAppend(
11
+ CGMutablePathRef path,
12
+ const squircle::Rect &rect,
13
+ const squircle::CornerRadii &radii,
14
+ double smoothing) {
15
+ for (const auto &element : squircle::buildPath(rect, radii, smoothing)) {
16
+ const auto &points = element.points;
17
+ switch (element.verb) {
18
+ case squircle::Verb::Move:
19
+ CGPathMoveToPoint(path, NULL, points[0].x, points[0].y);
20
+ break;
21
+ case squircle::Verb::Line:
22
+ CGPathAddLineToPoint(path, NULL, points[0].x, points[0].y);
23
+ break;
24
+ case squircle::Verb::Cubic:
25
+ CGPathAddCurveToPoint(
26
+ path, NULL, points[0].x, points[0].y, points[1].x, points[1].y, points[2].x, points[2].y);
27
+ break;
28
+ case squircle::Verb::Close:
29
+ CGPathCloseSubpath(path);
30
+ break;
31
+ }
32
+ }
33
+ }
34
+
35
+ CGPathRef SquirclePathCreate(const squircle::Rect &rect, const squircle::CornerRadii &radii, double smoothing) {
36
+ CGMutablePathRef path = CGPathCreateMutable();
37
+ SquirclePathAppend(path, rect, radii, smoothing);
38
+ return path;
39
+ }
@@ -0,0 +1,24 @@
1
+ //
2
+ // SquircleBorderLayer.h
3
+ // Pods
4
+ //
5
+ // Created by rit3zh CX on 10/7/26.
6
+ //
7
+
8
+ #import <QuartzCore/QuartzCore.h>
9
+ #import <UIKit/UIKit.h>
10
+
11
+ NS_ASSUME_NONNULL_BEGIN
12
+
13
+ @interface SquircleBorderLayer : CALayer
14
+
15
+ - (void)updateWithBorderPath:(CGPathRef)borderPath
16
+ insets:(UIEdgeInsets)insets
17
+ topColor:(UIColor *)topColor
18
+ rightColor:(UIColor *)rightColor
19
+ bottomColor:(UIColor *)bottomColor
20
+ leftColor:(UIColor *)leftColor;
21
+
22
+ @end
23
+
24
+ NS_ASSUME_NONNULL_END
@@ -0,0 +1,102 @@
1
+ //
2
+ // SquircleBorderLayer.m
3
+ // Pods
4
+ //
5
+ // Created by rit3zh CX on 10/7/26.
6
+ //
7
+
8
+ #import "SquircleBorderLayer.h"
9
+
10
+ static CGPoint SquircleSpokePoint(CGPoint corner, CGFloat dx, CGFloat dy, CGSize half) {
11
+ CGFloat scale = CGFLOAT_MAX;
12
+ if (dx != 0) {
13
+ scale = MIN(scale, half.width / fabs(dx));
14
+ }
15
+ if (dy != 0) {
16
+ scale = MIN(scale, half.height / fabs(dy));
17
+ }
18
+ if (scale == CGFLOAT_MAX) {
19
+ return corner;
20
+ }
21
+ return CGPointMake(corner.x + dx * scale, corner.y + dy * scale);
22
+ }
23
+
24
+ static void SquircleFillWedge(CGContextRef context, UIColor *color, const CGPoint points[5]) {
25
+ CGContextSetFillColorWithColor(context, color.CGColor);
26
+ CGContextBeginPath(context);
27
+ CGContextAddLines(context, points, 5);
28
+ CGContextClosePath(context);
29
+ CGContextFillPath(context);
30
+ }
31
+
32
+ @implementation SquircleBorderLayer {
33
+ CGPathRef _borderPath;
34
+ UIEdgeInsets _insets;
35
+ UIColor *_topColor;
36
+ UIColor *_rightColor;
37
+ UIColor *_bottomColor;
38
+ UIColor *_leftColor;
39
+ }
40
+
41
+ - (instancetype)init {
42
+ if (self = [super init]) {
43
+ self.needsDisplayOnBoundsChange = YES;
44
+ }
45
+ return self;
46
+ }
47
+
48
+ - (void)dealloc {
49
+ CGPathRelease(_borderPath);
50
+ }
51
+
52
+ - (void)updateWithBorderPath:(CGPathRef)borderPath
53
+ insets:(UIEdgeInsets)insets
54
+ topColor:(UIColor *)topColor
55
+ rightColor:(UIColor *)rightColor
56
+ bottomColor:(UIColor *)bottomColor
57
+ leftColor:(UIColor *)leftColor {
58
+ if (_borderPath != borderPath) {
59
+ CGPathRelease(_borderPath);
60
+ _borderPath = CGPathRetain(borderPath);
61
+ }
62
+ _insets = insets;
63
+ _topColor = topColor;
64
+ _rightColor = rightColor;
65
+ _bottomColor = bottomColor;
66
+ _leftColor = leftColor;
67
+ [self setNeedsDisplay];
68
+ }
69
+
70
+ - (void)drawInContext:(CGContextRef)context {
71
+ if (_borderPath == NULL) {
72
+ return;
73
+ }
74
+
75
+ const CGSize size = self.bounds.size;
76
+ const CGSize half = CGSizeMake(size.width / 2, size.height / 2);
77
+ const CGPoint center = CGPointMake(half.width, half.height);
78
+ const CGPoint topLeft = CGPointZero;
79
+ const CGPoint topRight = CGPointMake(size.width, 0);
80
+ const CGPoint bottomRight = CGPointMake(size.width, size.height);
81
+ const CGPoint bottomLeft = CGPointMake(0, size.height);
82
+
83
+ const CGPoint topLeftSpoke = SquircleSpokePoint(topLeft, _insets.left, _insets.top, half);
84
+ const CGPoint topRightSpoke = SquircleSpokePoint(topRight, -_insets.right, _insets.top, half);
85
+ const CGPoint bottomRightSpoke = SquircleSpokePoint(bottomRight, -_insets.right, -_insets.bottom, half);
86
+ const CGPoint bottomLeftSpoke = SquircleSpokePoint(bottomLeft, _insets.left, -_insets.bottom, half);
87
+
88
+ CGContextAddPath(context, _borderPath);
89
+ CGContextEOClip(context);
90
+
91
+ const CGPoint top[5] = {topLeft, topRight, topRightSpoke, center, topLeftSpoke};
92
+ const CGPoint right[5] = {topRight, bottomRight, bottomRightSpoke, center, topRightSpoke};
93
+ const CGPoint bottom[5] = {bottomRight, bottomLeft, bottomLeftSpoke, center, bottomRightSpoke};
94
+ const CGPoint left[5] = {bottomLeft, topLeft, topLeftSpoke, center, bottomLeftSpoke};
95
+
96
+ SquircleFillWedge(context, _topColor, top);
97
+ SquircleFillWedge(context, _rightColor, right);
98
+ SquircleFillWedge(context, _bottomColor, bottom);
99
+ SquircleFillWedge(context, _leftColor, left);
100
+ }
101
+
102
+ @end
@@ -0,0 +1,16 @@
1
+ //
2
+ // SquircleView.h
3
+ // Pods
4
+ //
5
+ // Created by rit3zh CX on 10/7/26.
6
+ //
7
+
8
+ #import <React/RCTViewComponentView.h>
9
+ #import <UIKit/UIKit.h>
10
+
11
+ NS_ASSUME_NONNULL_BEGIN
12
+
13
+ @interface SquircleView : RCTViewComponentView
14
+ @end
15
+
16
+ NS_ASSUME_NONNULL_END
@@ -0,0 +1,337 @@
1
+ //
2
+ // SquircleView.mm
3
+ // Pods
4
+ //
5
+ // Created by rit3zh CX on 10/7/26.
6
+ //
7
+
8
+ #import "SquircleView.h"
9
+
10
+ #import <objc/runtime.h>
11
+
12
+ #import <optional>
13
+
14
+ #import <React/RCTConversions.h>
15
+ #import <React/RCTUtils.h>
16
+ #import <react/featureflags/ReactNativeFeatureFlags.h>
17
+ #import <react/renderer/components/SquircleViewSpec/ComponentDescriptors.h>
18
+ #import <react/renderer/components/SquircleViewSpec/Props.h>
19
+
20
+ #import "SquircleBorderLayer.h"
21
+ #import "SquirclePath.h"
22
+
23
+ using namespace facebook::react;
24
+
25
+ static const CGFloat SquircleBackgroundZPosition = -1024;
26
+ static const CGFloat SquircleBorderZPosition = -1023;
27
+
28
+ @interface RCTViewComponentView (SquircleView)
29
+ - (UIView *)currentContainerView;
30
+ - (void)invalidateLayer;
31
+ @end
32
+
33
+ namespace {
34
+
35
+ struct SquircleGeometryKey {
36
+ squircle::Rect bounds;
37
+ squircle::CornerRadii radii;
38
+ squircle::Insets insets;
39
+ double smoothing;
40
+
41
+ bool operator==(const SquircleGeometryKey &other) const = default;
42
+ };
43
+
44
+ squircle::CornerRadii SquircleCornerRadiiFromBorderRadii(const BorderRadii &radii) {
45
+ return {
46
+ {radii.topLeft.horizontal, radii.topLeft.vertical},
47
+ {radii.topRight.horizontal, radii.topRight.vertical},
48
+ {radii.bottomRight.horizontal, radii.bottomRight.vertical},
49
+ {radii.bottomLeft.horizontal, radii.bottomLeft.vertical}};
50
+ }
51
+
52
+ squircle::Insets SquircleInsetsFromBorderWidths(const BorderWidths &widths) {
53
+ return {widths.top, widths.right, widths.bottom, widths.left};
54
+ }
55
+
56
+ UIColor *SquircleResolvedColor(const SharedColor &color, UITraitCollection *traitCollection) {
57
+ UIColor *resolved = RCTUIColorFromSharedColor(color) ?: UIColor.blackColor;
58
+ return [resolved resolvedColorWithTraitCollection:traitCollection];
59
+ }
60
+
61
+ } // namespace
62
+
63
+ @implementation SquircleView {
64
+ CGFloat _borderSmoothing;
65
+ BOOL _needsSquircleUpdate;
66
+ std::optional<SquircleGeometryKey> _geometryKey;
67
+ CGPathRef _outerPath;
68
+ CGPathRef _innerPath;
69
+ CGPathRef _borderPath;
70
+ CGPathRef _strokePath;
71
+ CAShapeLayer *_backgroundLayer;
72
+ CAShapeLayer *_borderShapeLayer;
73
+ SquircleBorderLayer *_multicolorBorderLayer;
74
+ CAShapeLayer *_clipLayer;
75
+ }
76
+
77
+ + (ComponentDescriptorProvider)componentDescriptorProvider {
78
+ return concreteComponentDescriptorProvider<SquircleViewComponentDescriptor>();
79
+ }
80
+
81
+ - (instancetype)initWithFrame:(CGRect)frame {
82
+ if (self = [super initWithFrame:frame]) {
83
+ static const auto defaultProps = std::make_shared<const SquircleViewProps>();
84
+ _props = defaultProps;
85
+ }
86
+ return self;
87
+ }
88
+
89
+ - (void)dealloc {
90
+ [self releasePaths];
91
+ }
92
+
93
+ #pragma mark - RCTComponentViewProtocol
94
+
95
+ - (void)updateProps:(const Props::Shared &)props oldProps:(const Props::Shared &)oldProps {
96
+ const auto &newProps = static_cast<const SquircleViewProps &>(*props);
97
+ const CGFloat smoothing = squircle::clampSmoothing(newProps.borderSmoothing);
98
+ if (smoothing != _borderSmoothing) {
99
+ _borderSmoothing = smoothing;
100
+ _needsSquircleUpdate = YES;
101
+ }
102
+
103
+ [super updateProps:props oldProps:oldProps];
104
+ }
105
+
106
+ - (void)finalizeUpdates:(RNComponentViewUpdateMask)updateMask {
107
+ [super finalizeUpdates:updateMask];
108
+
109
+ if (_needsSquircleUpdate) {
110
+ [self invalidateLayer];
111
+ }
112
+ }
113
+
114
+ - (void)prepareForRecycle {
115
+ [super prepareForRecycle];
116
+
117
+ _borderSmoothing = 0;
118
+ _needsSquircleUpdate = NO;
119
+ [self removeSquircleLayers];
120
+ }
121
+
122
+ #pragma mark - Layer
123
+
124
+ - (void)invalidateLayer {
125
+ _needsSquircleUpdate = NO;
126
+
127
+ const auto borderMetrics = _props->resolveBorderMetrics(_layoutMetrics);
128
+ const auto radii = SquircleCornerRadiiFromBorderRadii(borderMetrics.borderRadii);
129
+ const CGSize size = self.layer.bounds.size;
130
+
131
+ if (_borderSmoothing <= 0 || !squircle::hasRoundedCorner(radii) || size.width <= 0 || size.height <= 0) {
132
+ [self removeSquircleLayers];
133
+ [super invalidateLayer];
134
+ return;
135
+ }
136
+
137
+ UIColor *backgroundColor = self.backgroundColor;
138
+ self.backgroundColor = nil;
139
+ [super invalidateLayer];
140
+ self.backgroundColor = backgroundColor;
141
+
142
+ const SquircleGeometryKey key{
143
+ .bounds = {0, 0, size.width, size.height},
144
+ .radii = radii,
145
+ .insets = SquircleInsetsFromBorderWidths(borderMetrics.borderWidths),
146
+ .smoothing = _borderSmoothing,
147
+ };
148
+ [self updateGeometry:key];
149
+
150
+ [CATransaction begin];
151
+ [CATransaction setDisableActions:YES];
152
+ [self hideDefaultBackgroundAndBorder];
153
+ [self updateBackgroundWithColor:backgroundColor];
154
+ [self updateBorderWithMetrics:borderMetrics];
155
+ [self updateClipping];
156
+ [CATransaction commit];
157
+ }
158
+
159
+ - (void)updateGeometry:(const SquircleGeometryKey &)key {
160
+ if (_geometryKey == key) {
161
+ return;
162
+ }
163
+
164
+ [self releasePaths];
165
+ _geometryKey = key;
166
+
167
+ const auto innerRect = squircle::insetRect(key.bounds, key.insets);
168
+ const auto innerRadii = squircle::insetRadii(key.radii, key.insets);
169
+
170
+ _outerPath = SquirclePathCreate(key.bounds, key.radii, key.smoothing);
171
+ _innerPath = SquirclePathCreate(innerRect, innerRadii, key.smoothing);
172
+
173
+ CGMutablePathRef borderPath = CGPathCreateMutableCopy(_outerPath);
174
+ SquirclePathAppend(borderPath, innerRect, innerRadii, key.smoothing);
175
+ _borderPath = borderPath;
176
+ }
177
+
178
+ - (CGPathRef)strokePath {
179
+ if (_strokePath == NULL && _geometryKey) {
180
+ const auto &key = *_geometryKey;
181
+ const squircle::Insets half{
182
+ key.insets.top / 2, key.insets.right / 2, key.insets.bottom / 2, key.insets.left / 2};
183
+ _strokePath = SquirclePathCreate(
184
+ squircle::insetRect(key.bounds, half), squircle::insetRadii(key.radii, half), key.smoothing);
185
+ }
186
+ return _strokePath;
187
+ }
188
+
189
+ - (void)releasePaths {
190
+ CGPathRelease(_outerPath);
191
+ CGPathRelease(_innerPath);
192
+ CGPathRelease(_borderPath);
193
+ CGPathRelease(_strokePath);
194
+ _outerPath = NULL;
195
+ _innerPath = NULL;
196
+ _borderPath = NULL;
197
+ _strokePath = NULL;
198
+ _geometryKey.reset();
199
+ }
200
+
201
+ // RCTViewComponentView draws non-uniform borders into a private sublayer; it has to be hidden
202
+ // while the squircle border is rendered in its place.
203
+ - (nullable CALayer *)defaultBorderLayer {
204
+ static Ivar ivar = class_getInstanceVariable([RCTViewComponentView class], "_borderLayer");
205
+ return ivar != nullptr ? object_getIvar(self, ivar) : nil;
206
+ }
207
+
208
+ - (void)hideDefaultBackgroundAndBorder {
209
+ CALayer *layer = self.layer;
210
+ layer.backgroundColor = nil;
211
+ layer.borderWidth = 0;
212
+ layer.borderColor = nil;
213
+ layer.cornerRadius = 0;
214
+ [self defaultBorderLayer].hidden = YES;
215
+ }
216
+
217
+ - (void)updateBackgroundWithColor:(nullable UIColor *)backgroundColor {
218
+ CALayer *layer = self.layer;
219
+ UIColor *color = [backgroundColor resolvedColorWithTraitCollection:self.traitCollection];
220
+ const CGFloat alpha = color != nil ? CGColorGetAlpha(color.CGColor) : 0;
221
+
222
+ if (alpha > 0) {
223
+ if (_backgroundLayer == nil) {
224
+ _backgroundLayer = [CAShapeLayer layer];
225
+ _backgroundLayer.zPosition = SquircleBackgroundZPosition;
226
+ [layer addSublayer:_backgroundLayer];
227
+ }
228
+ _backgroundLayer.frame = layer.bounds;
229
+ _backgroundLayer.path = _outerPath;
230
+ _backgroundLayer.fillColor = color.CGColor;
231
+ } else {
232
+ [_backgroundLayer removeFromSuperlayer];
233
+ _backgroundLayer = nil;
234
+ }
235
+
236
+ const BOOL hasShadow = layer.shadowOpacity > 0 && CGColorGetAlpha(layer.shadowColor) > 0;
237
+ layer.shadowPath = hasShadow && alpha > 0.999 ? _outerPath : nil;
238
+ }
239
+
240
+ - (void)updateBorderWithMetrics:(const BorderMetrics &)metrics {
241
+ const auto &widths = metrics.borderWidths;
242
+ if (widths.left <= 0 && widths.top <= 0 && widths.right <= 0 && widths.bottom <= 0) {
243
+ [self removeBorderLayers];
244
+ return;
245
+ }
246
+
247
+ CALayer *layer = self.layer;
248
+ UITraitCollection *traitCollection = self.traitCollection;
249
+ UIColor *top = SquircleResolvedColor(metrics.borderColors.top, traitCollection);
250
+ UIColor *right = SquircleResolvedColor(metrics.borderColors.right, traitCollection);
251
+ UIColor *bottom = SquircleResolvedColor(metrics.borderColors.bottom, traitCollection);
252
+ UIColor *left = SquircleResolvedColor(metrics.borderColors.left, traitCollection);
253
+
254
+ const BOOL uniformColor = CGColorEqualToColor(top.CGColor, right.CGColor) &&
255
+ CGColorEqualToColor(top.CGColor, bottom.CGColor) && CGColorEqualToColor(top.CGColor, left.CGColor);
256
+
257
+ if (!uniformColor) {
258
+ [_borderShapeLayer removeFromSuperlayer];
259
+ _borderShapeLayer = nil;
260
+
261
+ if (_multicolorBorderLayer == nil) {
262
+ _multicolorBorderLayer = [SquircleBorderLayer layer];
263
+ _multicolorBorderLayer.zPosition = SquircleBorderZPosition;
264
+ _multicolorBorderLayer.contentsScale = RCTScreenScale();
265
+ [layer addSublayer:_multicolorBorderLayer];
266
+ }
267
+ _multicolorBorderLayer.frame = layer.bounds;
268
+ [_multicolorBorderLayer updateWithBorderPath:_borderPath
269
+ insets:UIEdgeInsetsMake(widths.top, widths.left, widths.bottom, widths.right)
270
+ topColor:top
271
+ rightColor:right
272
+ bottomColor:bottom
273
+ leftColor:left];
274
+ return;
275
+ }
276
+
277
+ [_multicolorBorderLayer removeFromSuperlayer];
278
+ _multicolorBorderLayer = nil;
279
+
280
+ if (_borderShapeLayer == nil) {
281
+ _borderShapeLayer = [CAShapeLayer layer];
282
+ _borderShapeLayer.zPosition = SquircleBorderZPosition;
283
+ [layer addSublayer:_borderShapeLayer];
284
+ }
285
+ _borderShapeLayer.frame = layer.bounds;
286
+
287
+ const BorderStyle style = metrics.borderStyles.left;
288
+ if (style != BorderStyle::Solid && metrics.borderStyles.isUniform() && widths.isUniform()) {
289
+ const CGFloat width = widths.left;
290
+ const BOOL dotted = style == BorderStyle::Dotted;
291
+ _borderShapeLayer.path = [self strokePath];
292
+ _borderShapeLayer.fillColor = nil;
293
+ _borderShapeLayer.strokeColor = top.CGColor;
294
+ _borderShapeLayer.lineWidth = width;
295
+ _borderShapeLayer.lineCap = dotted ? kCALineCapRound : kCALineCapButt;
296
+ _borderShapeLayer.lineDashPattern = dotted ? @[ @0, @(width * 2) ] : @[ @(width * 3), @(width * 3) ];
297
+ } else {
298
+ _borderShapeLayer.path = _borderPath;
299
+ _borderShapeLayer.fillRule = kCAFillRuleEvenOdd;
300
+ _borderShapeLayer.fillColor = top.CGColor;
301
+ _borderShapeLayer.strokeColor = nil;
302
+ _borderShapeLayer.lineDashPattern = nil;
303
+ }
304
+ }
305
+
306
+ - (void)updateClipping {
307
+ UIView *containerView = self.currentContainerView;
308
+ if (!containerView.clipsToBounds) {
309
+ return;
310
+ }
311
+
312
+ if (_clipLayer == nil) {
313
+ _clipLayer = [CAShapeLayer layer];
314
+ }
315
+ _clipLayer.frame = containerView.bounds;
316
+ _clipLayer.path = ReactNativeFeatureFlags::enableIOSViewClipToPaddingBox() ? _innerPath : _outerPath;
317
+ containerView.layer.cornerRadius = 0;
318
+ containerView.layer.mask = _clipLayer;
319
+ }
320
+
321
+ - (void)removeBorderLayers {
322
+ [_borderShapeLayer removeFromSuperlayer];
323
+ _borderShapeLayer = nil;
324
+ [_multicolorBorderLayer removeFromSuperlayer];
325
+ _multicolorBorderLayer = nil;
326
+ }
327
+
328
+ - (void)removeSquircleLayers {
329
+ [_backgroundLayer removeFromSuperlayer];
330
+ _backgroundLayer = nil;
331
+ [self removeBorderLayers];
332
+ _clipLayer = nil;
333
+ [self defaultBorderLayer].hidden = NO;
334
+ [self releasePaths];
335
+ }
336
+
337
+ @end
@@ -0,0 +1,4 @@
1
+ "use strict";
2
+
3
+ export { SquircleView } from './squircle-view';
4
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":["SquircleView"],"sourceRoot":"../../../src","sources":["components/index.ts"],"mappings":";;AAAA,SAASA,YAAY,QAAQ,iBAAiB","ignoreList":[]}
@@ -0,0 +1,22 @@
1
+ "use strict";
2
+
3
+ import * as React from 'react';
4
+ import { useMemo } from 'react';
5
+ import { View } from 'react-native';
6
+ import { COMPONENT_NAMES } from "../constants/index.js";
7
+ import { splitSquircleStyle } from "../utils/index.js";
8
+ import { jsx as _jsx } from "react/jsx-runtime";
9
+ const SquircleView = ({
10
+ style,
11
+ borderSmoothing: _borderSmoothing,
12
+ ...rest
13
+ }) => {
14
+ const squircleStyle = useMemo(() => splitSquircleStyle(style), [style]);
15
+ return /*#__PURE__*/_jsx(View, {
16
+ ...rest,
17
+ style: squircleStyle.style
18
+ });
19
+ };
20
+ SquircleView.displayName = COMPONENT_NAMES.SQUIRCLE_VIEW;
21
+ export { SquircleView };
22
+ //# sourceMappingURL=squircle-view.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":["React","useMemo","View","COMPONENT_NAMES","splitSquircleStyle","jsx","_jsx","SquircleView","style","borderSmoothing","_borderSmoothing","rest","squircleStyle","displayName","SQUIRCLE_VIEW"],"sourceRoot":"../../../src","sources":["components/squircle-view.tsx"],"mappings":";;AAAA,OAAO,KAAKA,KAAK,MAAM,OAAO;AAC9B,SAASC,OAAO,QAAQ,OAAO;AAC/B,SAASC,IAAI,QAAwB,cAAc;AACnD,SAASC,eAAe,QAAQ,uBAAc;AAE9C,SAASC,kBAAkB,QAAQ,mBAAU;AAAC,SAAAC,GAAA,IAAAC,IAAA;AAG9C,MAAMC,YAA0C,GAAGA,CAAC;EAClDC,KAAK;EACLC,eAAe,EAAEC,gBAAgB;EACjC,GAAGC;AACe,CAAC,KAA0C;EAC7D,MAAMC,aAAa,GAAGX,OAAO,CAC3B,MAAMG,kBAAkB,CAAgCI,KAAK,CAAC,EAC9D,CAACA,KAAK,CACR,CAAC;EAED,oBAAOF,IAAA,CAACJ,IAAI;IAAA,GAAKS,IAAI;IAAEH,KAAK,EAAEI,aAAa,CAACJ;EAAM,CAAE,CAAC;AACvD,CAAC;AAEDD,YAAY,CAACM,WAAW,GAAGV,eAAe,CAACW,aAAa;AAExD,SAASP,YAAY","ignoreList":[]}
@@ -0,0 +1,23 @@
1
+ "use strict";
2
+
3
+ import * as React from 'react';
4
+ import { useMemo } from 'react';
5
+ import { COMPONENT_NAMES, DEFAULT_BORDER_SMOOTHING } from "../constants/index.js";
6
+ import { splitSquircleStyle } from "../utils/index.js";
7
+ import { NativeSquircleView } from "../views/index.js";
8
+ import { jsx as _jsx } from "react/jsx-runtime";
9
+ const SquircleView = ({
10
+ style,
11
+ borderSmoothing,
12
+ ...rest
13
+ }) => {
14
+ const squircleStyle = useMemo(() => splitSquircleStyle(style), [style]);
15
+ return /*#__PURE__*/_jsx(NativeSquircleView, {
16
+ ...rest,
17
+ style: squircleStyle.style,
18
+ borderSmoothing: squircleStyle.borderSmoothing ?? borderSmoothing ?? DEFAULT_BORDER_SMOOTHING
19
+ });
20
+ };
21
+ SquircleView.displayName = COMPONENT_NAMES.SQUIRCLE_VIEW;
22
+ export { SquircleView };
23
+ //# sourceMappingURL=squircle-view.native.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":["React","useMemo","COMPONENT_NAMES","DEFAULT_BORDER_SMOOTHING","splitSquircleStyle","NativeSquircleView","jsx","_jsx","SquircleView","style","borderSmoothing","rest","squircleStyle","displayName","SQUIRCLE_VIEW"],"sourceRoot":"../../../src","sources":["components/squircle-view.native.tsx"],"mappings":";;AAAA,OAAO,KAAKA,KAAK,MAAM,OAAO;AAC9B,SAASC,OAAO,QAAQ,OAAO;AAE/B,SAASC,eAAe,EAAEC,wBAAwB,QAAQ,uBAAc;AAExE,SAASC,kBAAkB,QAAQ,mBAAU;AAC7C,SAASC,kBAAkB,QAAQ,mBAAU;AAAC,SAAAC,GAAA,IAAAC,IAAA;AAE9C,MAAMC,YAA0C,GAAGA,CAAC;EAClDC,KAAK;EACLC,eAAe;EACf,GAAGC;AACe,CAAC,KAAwB;EAC3C,MAAMC,aAAa,GAAGX,OAAO,CAC3B,MAAMG,kBAAkB,CAACK,KAAK,CAAC,EAC/B,CAACA,KAAK,CACR,CAAC;EAED,oBACEF,IAAA,CAACF,kBAAkB;IAAA,GACbM,IAAI;IACRF,KAAK,EAAEG,aAAa,CAACH,KAAM;IAC3BC,eAAe,EACbE,aAAa,CAACF,eAAe,IAC7BA,eAAe,IACfP;EACD,CACF,CAAC;AAEN,CAAC;AAEDK,YAAY,CAACK,WAAW,GAAGX,eAAe,CAACY,aAAa;AAExD,SAASN,YAAY","ignoreList":[]}
@@ -0,0 +1,5 @@
1
+ "use strict";
2
+
3
+ export * from "./native.constants.js";
4
+ export * from "./squircle.constants.js";
5
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":[],"sourceRoot":"../../../src","sources":["constants/index.ts"],"mappings":";;AAAA,cAAc,uBAAoB;AAClC,cAAc,yBAAsB","ignoreList":[]}
@@ -0,0 +1,10 @@
1
+ "use strict";
2
+
3
+ const NATIVE_VIEW_NAMES = {
4
+ SQUIRCLE_VIEW: 'SquircleView'
5
+ };
6
+ const COMPONENT_NAMES = {
7
+ SQUIRCLE_VIEW: 'SquircleView'
8
+ };
9
+ export { NATIVE_VIEW_NAMES, COMPONENT_NAMES };
10
+ //# sourceMappingURL=native.constants.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":["NATIVE_VIEW_NAMES","SQUIRCLE_VIEW","COMPONENT_NAMES"],"sourceRoot":"../../../src","sources":["constants/native.constants.ts"],"mappings":";;AAAA,MAAMA,iBAAiB,GAAG;EACxBC,aAAa,EAAE;AACjB,CAA2C;AAE3C,MAAMC,eAAe,GAAG;EACtBD,aAAa,EAAE;AACjB,CAA2C;AAE3C,SAASD,iBAAiB,EAAEE,eAAe","ignoreList":[]}
@@ -0,0 +1,5 @@
1
+ "use strict";
2
+
3
+ const DEFAULT_BORDER_SMOOTHING = 0;
4
+ export { DEFAULT_BORDER_SMOOTHING };
5
+ //# sourceMappingURL=squircle.constants.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":["DEFAULT_BORDER_SMOOTHING"],"sourceRoot":"../../../src","sources":["constants/squircle.constants.ts"],"mappings":";;AAAA,MAAMA,wBAAgC,GAAG,CAAC;AAE1C,SAASA,wBAAwB","ignoreList":[]}
@@ -0,0 +1,4 @@
1
+ "use strict";
2
+
3
+ export * from "./root/index.js";
4
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":[],"sourceRoot":"../../src","sources":["index.ts"],"mappings":";;AAAA,cAAc,iBAAQ","ignoreList":[]}
@@ -0,0 +1,5 @@
1
+ "use strict";
2
+
3
+ export * from "./squircle-style.interface.js";
4
+ export * from "./squircle-view.interface.js";
5
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":[],"sourceRoot":"../../../src","sources":["interfaces/index.ts"],"mappings":";;AAAA,cAAc,+BAA4B;AAC1C,cAAc,8BAA2B","ignoreList":[]}
@@ -0,0 +1,4 @@
1
+ "use strict";
2
+
3
+ export {};
4
+ //# sourceMappingURL=squircle-style.interface.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":[],"sourceRoot":"../../../src","sources":["interfaces/squircle-style.interface.ts"],"mappings":"","ignoreList":[]}
@@ -0,0 +1,4 @@
1
+ "use strict";
2
+
3
+ export {};
4
+ //# sourceMappingURL=squircle-view.interface.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":[],"sourceRoot":"../../../src","sources":["interfaces/squircle-view.interface.ts"],"mappings":"","ignoreList":[]}
@@ -0,0 +1 @@
1
+ {"type":"module"}
@@ -0,0 +1,4 @@
1
+ "use strict";
2
+
3
+ export { SquircleView } from "../components/index.js";
4
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":["SquircleView"],"sourceRoot":"../../../src","sources":["root/index.ts"],"mappings":";;AAAA,SAASA,YAAY,QAAQ,wBAAe","ignoreList":[]}