react-native-linear-gradient-fabric 0.1.0 → 0.1.1

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.
@@ -67,7 +67,7 @@ class LinearGradientView(context: Context) : FrameLayout(context) {
67
67
  }
68
68
 
69
69
  override fun onDraw(canvas: Canvas) {
70
- if (colors.size < 2 || width == 0 || height == 0) {
70
+ if (colors.size < 2 || width <= 0 || height <= 0) {
71
71
  super.onDraw(canvas)
72
72
  return
73
73
  }
@@ -10,6 +10,7 @@
10
10
  if (self = [super initWithFrame:frame]) {
11
11
  _gradientLayer = [CAGradientLayer layer];
12
12
  _gradientLayer.frame = self.bounds;
13
+ _gradientLayer.zPosition = -1000;
13
14
  [self.layer insertSublayer:_gradientLayer atIndex:0];
14
15
 
15
16
  // Set default values
@@ -26,6 +27,7 @@
26
27
  {
27
28
  [super layoutSubviews];
28
29
  _gradientLayer.frame = self.bounds;
30
+ [self updateGradient];
29
31
  }
30
32
 
31
33
  - (void)setColors:(NSArray<NSNumber *> *)colors
@@ -72,6 +74,11 @@
72
74
 
73
75
  - (void)updateGradient
74
76
  {
77
+ // Guard against zero-dimension bounds (iOS 17+ crash fix, see issue #652)
78
+ if (self.bounds.size.width <= 0 || self.bounds.size.height <= 0) {
79
+ return;
80
+ }
81
+
75
82
  if (!_colors || _colors.count == 0) {
76
83
  return;
77
84
  }
@@ -40,6 +40,7 @@ using namespace facebook::react;
40
40
 
41
41
  _gradientLayer = [CAGradientLayer layer];
42
42
  _gradientLayer.frame = self.bounds;
43
+ _gradientLayer.zPosition = -1000;
43
44
  [self.layer insertSublayer:_gradientLayer atIndex:0];
44
45
 
45
46
  // Set default values
@@ -59,6 +60,7 @@ using namespace facebook::react;
59
60
  {
60
61
  [super layoutSubviews];
61
62
  _gradientLayer.frame = self.bounds;
63
+ [self updateGradient];
62
64
  }
63
65
 
64
66
  - (void)updateProps:(Props::Shared const &)props oldProps:(Props::Shared const &)oldProps
@@ -98,6 +100,11 @@ using namespace facebook::react;
98
100
 
99
101
  - (void)updateGradient
100
102
  {
103
+ // Guard against zero-dimension bounds (iOS 17+ crash fix, see issue #652)
104
+ if (self.bounds.size.width <= 0 || self.bounds.size.height <= 0) {
105
+ return;
106
+ }
107
+
101
108
  if (_colors.empty()) {
102
109
  return;
103
110
  }
@@ -1 +1 @@
1
- {"version":3,"names":["_codegenNativeComponent","_interopRequireDefault","require","e","__esModule","default","_default","exports","codegenNativeComponent"],"sourceRoot":"../../src","sources":["LinearGradientNativeComponent.ts"],"mappings":";;;;;;AACA,IAAAA,uBAAA,GAAAC,sBAAA,CAAAC,OAAA;AAA6F,SAAAD,uBAAAE,CAAA,WAAAA,CAAA,IAAAA,CAAA,CAAAC,UAAA,GAAAD,CAAA,KAAAE,OAAA,EAAAF,CAAA;AAAA,IAAAG,QAAA,GAAAC,OAAA,CAAAF,OAAA,GAuC9E,IAAAG,+BAAsB,EACnC,oBACF,CAAC","ignoreList":[]}
1
+ {"version":3,"names":["_codegenNativeComponent","_interopRequireDefault","require","e","__esModule","default","_default","exports","codegenNativeComponent"],"sourceRoot":"../../src","sources":["LinearGradientNativeComponent.ts"],"mappings":";;;;;;AAEA,IAAAA,uBAAA,GAAAC,sBAAA,CAAAC,OAAA;AAA6F,SAAAD,uBAAAE,CAAA,WAAAA,CAAA,IAAAA,CAAA,CAAAC,UAAA,GAAAD,CAAA,KAAAE,OAAA,EAAAF,CAAA;AAAA,IAAAG,QAAA,GAAAC,OAAA,CAAAF,OAAA,GAsC9E,IAAAG,+BAAsB,EACnC,oBACF,CAAC","ignoreList":[]}
@@ -23,14 +23,96 @@ const DEFAULT_ANGLE_CENTER = {
23
23
  x: 0.5,
24
24
  y: 0.5
25
25
  };
26
+
27
+ /**
28
+ * Check if a processed color has zero alpha (fully transparent).
29
+ * React Native processColor returns ARGB format where alpha is in the highest byte.
30
+ */
31
+ function isTransparentColor(colorInt) {
32
+ // Extract alpha from ARGB format (bits 24-31)
33
+ const alpha = colorInt >>> 24 & 0xff;
34
+ return alpha === 0;
35
+ }
36
+
37
+ /**
38
+ * Get the RGB components from a processed color (ARGB format).
39
+ */
40
+ function getRGB(colorInt) {
41
+ return {
42
+ r: colorInt >>> 16 & 0xff,
43
+ g: colorInt >>> 8 & 0xff,
44
+ b: colorInt & 0xff
45
+ };
46
+ }
47
+
48
+ /**
49
+ * Create a color with specified RGB and alpha=0 (fully transparent).
50
+ */
51
+ function createTransparentColor(r, g, b) {
52
+ // ARGB format: alpha=0 in highest byte
53
+ return (0 << 24 | r << 16 | g << 8 | b) >>> 0;
54
+ }
55
+
56
+ /**
57
+ * Fix transparent colors in gradients to avoid grey interpolation artifacts.
58
+ *
59
+ * When interpolating from 'transparent' (rgba(0,0,0,0)) to a color like white,
60
+ * the gradient interpolates all RGBA channels, resulting in grey midtones.
61
+ * This function replaces fully transparent colors with transparent versions
62
+ * of their nearest opaque neighbor, ensuring smooth color transitions.
63
+ *
64
+ * See: https://github.com/react-native-linear-gradient/react-native-linear-gradient/issues/691
65
+ */
66
+ function fixTransparentColors(colors) {
67
+ const result = [...colors];
68
+ for (let i = 0; i < result.length; i++) {
69
+ const currentColor = result[i];
70
+ if (currentColor !== undefined && isTransparentColor(currentColor)) {
71
+ // Find nearest non-transparent color to inherit RGB from
72
+ let nearestOpaqueIdx = -1;
73
+ let minDistance = Infinity;
74
+ for (let j = 0; j < result.length; j++) {
75
+ const candidateColor = result[j];
76
+ if (i !== j && candidateColor !== undefined && !isTransparentColor(candidateColor)) {
77
+ const distance = Math.abs(i - j);
78
+ if (distance < minDistance) {
79
+ minDistance = distance;
80
+ nearestOpaqueIdx = j;
81
+ }
82
+ }
83
+ }
84
+
85
+ // If we found a non-transparent color, use its RGB values
86
+ const nearestColor = nearestOpaqueIdx !== -1 ? result[nearestOpaqueIdx] : undefined;
87
+ if (nearestColor !== undefined) {
88
+ const {
89
+ r,
90
+ g,
91
+ b
92
+ } = getRGB(nearestColor);
93
+ result[i] = createTransparentColor(r, g, b);
94
+ }
95
+ // If all colors are transparent, leave as-is (nothing to fix)
96
+ }
97
+ }
98
+ return result;
99
+ }
26
100
  function processColors(colors) {
27
- return colors.map(color => {
28
- const processed = (0, _reactNative.processColor)(color);
29
- if (processed === null || processed === undefined) {
101
+ const processed = colors.map(color => {
102
+ const result = (0, _reactNative.processColor)(color);
103
+ if (result === null || result === undefined) {
30
104
  throw new Error(`Invalid color value: ${String(color)}`);
31
105
  }
32
- return typeof processed === 'number' ? processed : 0;
106
+ if (typeof result === 'number') {
107
+ return result;
108
+ }
109
+ // OpaqueColorValue (symbol type) or other non-number values
110
+ // This can happen with platform-specific color types
111
+ throw new Error(`Unsupported color type: ${String(color)}. Only standard color values are supported.`);
33
112
  });
113
+
114
+ // Fix transparent colors to prevent grey gradient artifacts
115
+ return fixTransparentColors(processed);
34
116
  }
35
117
  function validateLocations(locations, colorsLength) {
36
118
  if (!locations) {
@@ -39,7 +121,9 @@ function validateLocations(locations, colorsLength) {
39
121
  if (locations.length !== colorsLength) {
40
122
  console.warn(`LinearGradient: locations array length (${locations.length}) does not match colors array length (${colorsLength})`);
41
123
  }
42
- return locations;
124
+
125
+ // Clamp location values to [0, 1] range for iOS CAGradientLayer compatibility
126
+ return locations.map(value => Math.max(0, Math.min(1, value)));
43
127
  }
44
128
  function LinearGradient({
45
129
  colors,
@@ -1 +1 @@
1
- {"version":3,"names":["React","_interopRequireWildcard","require","_reactNative","_LinearGradientNativeComponent","_interopRequireDefault","e","__esModule","default","t","WeakMap","r","n","o","i","f","__proto__","has","get","set","hasOwnProperty","call","Object","defineProperty","getOwnPropertyDescriptor","_extends","assign","bind","arguments","length","apply","DEFAULT_START","x","y","DEFAULT_END","DEFAULT_ANGLE_CENTER","processColors","colors","map","color","processed","processColor","undefined","Error","String","validateLocations","locations","colorsLength","console","warn","LinearGradient","start","end","useAngle","angle","angleCenter","style","children","rest","processedColors","useMemo","validatedLocations","createElement","StyleSheet","flatten","startPoint","endPoint","_default","exports"],"sourceRoot":"../../src","sources":["index.tsx"],"mappings":"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","ignoreList":[]}
1
+ {"version":3,"names":["React","_interopRequireWildcard","require","_reactNative","_LinearGradientNativeComponent","_interopRequireDefault","e","__esModule","default","t","WeakMap","r","n","o","i","f","__proto__","has","get","set","hasOwnProperty","call","Object","defineProperty","getOwnPropertyDescriptor","_extends","assign","bind","arguments","length","apply","DEFAULT_START","x","y","DEFAULT_END","DEFAULT_ANGLE_CENTER","isTransparentColor","colorInt","alpha","getRGB","g","b","createTransparentColor","fixTransparentColors","colors","result","currentColor","undefined","nearestOpaqueIdx","minDistance","Infinity","j","candidateColor","distance","Math","abs","nearestColor","processColors","processed","map","color","processColor","Error","String","validateLocations","locations","colorsLength","console","warn","value","max","min","LinearGradient","start","end","useAngle","angle","angleCenter","style","children","rest","processedColors","useMemo","validatedLocations","createElement","StyleSheet","flatten","startPoint","endPoint","_default","exports"],"sourceRoot":"../../src","sources":["index.tsx"],"mappings":"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","ignoreList":[]}
@@ -1 +1 @@
1
- {"version":3,"names":["codegenNativeComponent"],"sourceRoot":"../../src","sources":["LinearGradientNativeComponent.ts"],"mappings":"AACA,OAAOA,sBAAsB,MAAM,yDAAyD;AAuC5F,eAAeA,sBAAsB,CACnC,oBACF,CAAC","ignoreList":[]}
1
+ {"version":3,"names":["codegenNativeComponent"],"sourceRoot":"../../src","sources":["LinearGradientNativeComponent.ts"],"mappings":"AAEA,OAAOA,sBAAsB,MAAM,yDAAyD;AAsC5F,eAAeA,sBAAsB,CACnC,oBACF,CAAC","ignoreList":[]}
@@ -14,14 +14,96 @@ const DEFAULT_ANGLE_CENTER = {
14
14
  x: 0.5,
15
15
  y: 0.5
16
16
  };
17
+
18
+ /**
19
+ * Check if a processed color has zero alpha (fully transparent).
20
+ * React Native processColor returns ARGB format where alpha is in the highest byte.
21
+ */
22
+ function isTransparentColor(colorInt) {
23
+ // Extract alpha from ARGB format (bits 24-31)
24
+ const alpha = colorInt >>> 24 & 0xff;
25
+ return alpha === 0;
26
+ }
27
+
28
+ /**
29
+ * Get the RGB components from a processed color (ARGB format).
30
+ */
31
+ function getRGB(colorInt) {
32
+ return {
33
+ r: colorInt >>> 16 & 0xff,
34
+ g: colorInt >>> 8 & 0xff,
35
+ b: colorInt & 0xff
36
+ };
37
+ }
38
+
39
+ /**
40
+ * Create a color with specified RGB and alpha=0 (fully transparent).
41
+ */
42
+ function createTransparentColor(r, g, b) {
43
+ // ARGB format: alpha=0 in highest byte
44
+ return (0 << 24 | r << 16 | g << 8 | b) >>> 0;
45
+ }
46
+
47
+ /**
48
+ * Fix transparent colors in gradients to avoid grey interpolation artifacts.
49
+ *
50
+ * When interpolating from 'transparent' (rgba(0,0,0,0)) to a color like white,
51
+ * the gradient interpolates all RGBA channels, resulting in grey midtones.
52
+ * This function replaces fully transparent colors with transparent versions
53
+ * of their nearest opaque neighbor, ensuring smooth color transitions.
54
+ *
55
+ * See: https://github.com/react-native-linear-gradient/react-native-linear-gradient/issues/691
56
+ */
57
+ function fixTransparentColors(colors) {
58
+ const result = [...colors];
59
+ for (let i = 0; i < result.length; i++) {
60
+ const currentColor = result[i];
61
+ if (currentColor !== undefined && isTransparentColor(currentColor)) {
62
+ // Find nearest non-transparent color to inherit RGB from
63
+ let nearestOpaqueIdx = -1;
64
+ let minDistance = Infinity;
65
+ for (let j = 0; j < result.length; j++) {
66
+ const candidateColor = result[j];
67
+ if (i !== j && candidateColor !== undefined && !isTransparentColor(candidateColor)) {
68
+ const distance = Math.abs(i - j);
69
+ if (distance < minDistance) {
70
+ minDistance = distance;
71
+ nearestOpaqueIdx = j;
72
+ }
73
+ }
74
+ }
75
+
76
+ // If we found a non-transparent color, use its RGB values
77
+ const nearestColor = nearestOpaqueIdx !== -1 ? result[nearestOpaqueIdx] : undefined;
78
+ if (nearestColor !== undefined) {
79
+ const {
80
+ r,
81
+ g,
82
+ b
83
+ } = getRGB(nearestColor);
84
+ result[i] = createTransparentColor(r, g, b);
85
+ }
86
+ // If all colors are transparent, leave as-is (nothing to fix)
87
+ }
88
+ }
89
+ return result;
90
+ }
17
91
  function processColors(colors) {
18
- return colors.map(color => {
19
- const processed = processColor(color);
20
- if (processed === null || processed === undefined) {
92
+ const processed = colors.map(color => {
93
+ const result = processColor(color);
94
+ if (result === null || result === undefined) {
21
95
  throw new Error(`Invalid color value: ${String(color)}`);
22
96
  }
23
- return typeof processed === 'number' ? processed : 0;
97
+ if (typeof result === 'number') {
98
+ return result;
99
+ }
100
+ // OpaqueColorValue (symbol type) or other non-number values
101
+ // This can happen with platform-specific color types
102
+ throw new Error(`Unsupported color type: ${String(color)}. Only standard color values are supported.`);
24
103
  });
104
+
105
+ // Fix transparent colors to prevent grey gradient artifacts
106
+ return fixTransparentColors(processed);
25
107
  }
26
108
  function validateLocations(locations, colorsLength) {
27
109
  if (!locations) {
@@ -30,7 +112,9 @@ function validateLocations(locations, colorsLength) {
30
112
  if (locations.length !== colorsLength) {
31
113
  console.warn(`LinearGradient: locations array length (${locations.length}) does not match colors array length (${colorsLength})`);
32
114
  }
33
- return locations;
115
+
116
+ // Clamp location values to [0, 1] range for iOS CAGradientLayer compatibility
117
+ return locations.map(value => Math.max(0, Math.min(1, value)));
34
118
  }
35
119
  export function LinearGradient({
36
120
  colors,
@@ -1 +1 @@
1
- {"version":3,"names":["React","processColor","StyleSheet","LinearGradientNativeComponent","DEFAULT_START","x","y","DEFAULT_END","DEFAULT_ANGLE_CENTER","processColors","colors","map","color","processed","undefined","Error","String","validateLocations","locations","colorsLength","length","console","warn","LinearGradient","start","end","useAngle","angle","angleCenter","style","children","rest","processedColors","useMemo","validatedLocations","createElement","_extends","flatten","startPoint","endPoint"],"sourceRoot":"../../src","sources":["index.tsx"],"mappings":";AAAA,OAAO,KAAKA,KAAK,MAAM,OAAO;AAE9B,SAASC,YAAY,EAAEC,UAAU,QAAQ,cAAc;AAEvD,OAAOC,6BAA6B,MAAM,iCAAiC;AAqD3E,MAAMC,aAAoB,GAAG;EAAEC,CAAC,EAAE,GAAG;EAAEC,CAAC,EAAE;AAAE,CAAC;AAC7C,MAAMC,WAAkB,GAAG;EAAEF,CAAC,EAAE,GAAG;EAAEC,CAAC,EAAE;AAAE,CAAC;AAC3C,MAAME,oBAA2B,GAAG;EAAEH,CAAC,EAAE,GAAG;EAAEC,CAAC,EAAE;AAAI,CAAC;AAEtD,SAASG,aAAaA,CAACC,MAAoB,EAAY;EACrD,OAAOA,MAAM,CAACC,GAAG,CAAEC,KAAK,IAAK;IAC3B,MAAMC,SAAS,GAAGZ,YAAY,CAACW,KAAK,CAAC;IACrC,IAAIC,SAAS,KAAK,IAAI,IAAIA,SAAS,KAAKC,SAAS,EAAE;MACjD,MAAM,IAAIC,KAAK,CAAC,wBAAwBC,MAAM,CAACJ,KAAK,CAAC,EAAE,CAAC;IAC1D;IACA,OAAO,OAAOC,SAAS,KAAK,QAAQ,GAAGA,SAAS,GAAG,CAAC;EACtD,CAAC,CAAC;AACJ;AAEA,SAASI,iBAAiBA,CACxBC,SAA+B,EAC/BC,YAAoB,EACE;EACtB,IAAI,CAACD,SAAS,EAAE;IACd,OAAOJ,SAAS;EAClB;EAEA,IAAII,SAAS,CAACE,MAAM,KAAKD,YAAY,EAAE;IACrCE,OAAO,CAACC,IAAI,CACV,2CAA2CJ,SAAS,CAACE,MAAM,yCAAyCD,YAAY,GAClH,CAAC;EACH;EAEA,OAAOD,SAAS;AAClB;AAEA,OAAO,SAASK,cAAcA,CAAC;EAC7Bb,MAAM;EACNQ,SAAS;EACTM,KAAK,GAAGpB,aAAa;EACrBqB,GAAG,GAAGlB,WAAW;EACjBmB,QAAQ,GAAG,KAAK;EAChBC,KAAK,GAAG,CAAC;EACTC,WAAW,GAAGpB,oBAAoB;EAClCqB,KAAK;EACLC,QAAQ;EACR,GAAGC;AACgB,CAAC,EAAsB;EAC1C,IAAIrB,MAAM,CAACU,MAAM,GAAG,CAAC,EAAE;IACrB,MAAM,IAAIL,KAAK,CAAC,2CAA2C,CAAC;EAC9D;EAEA,MAAMiB,eAAe,GAAGhC,KAAK,CAACiC,OAAO,CAAC,MAAMxB,aAAa,CAACC,MAAM,CAAC,EAAE,CAACA,MAAM,CAAC,CAAC;EAC5E,MAAMwB,kBAAkB,GAAGlC,KAAK,CAACiC,OAAO,CACtC,MAAMhB,iBAAiB,CAACC,SAAS,EAAER,MAAM,CAACU,MAAM,CAAC,EACjD,CAACF,SAAS,EAAER,MAAM,CAACU,MAAM,CAC3B,CAAC;EAED,oBACEpB,KAAA,CAAAmC,aAAA,CAAChC,6BAA6B,EAAAiC,QAAA,KACxBL,IAAI;IACRF,KAAK,EAAE3B,UAAU,CAACmC,OAAO,CAACR,KAAK,CAAE;IACjCnB,MAAM,EAAEsB,eAAgB;IACxBd,SAAS,EAAEgB,kBAAmB;IAC9BI,UAAU,EAAEd,KAAM;IAClBe,QAAQ,EAAEd,GAAI;IACdC,QAAQ,EAAEA,QAAS;IACnBC,KAAK,EAAEA,KAAM;IACbC,WAAW,EAAEA;EAAY,IAExBE,QAC4B,CAAC;AAEpC;AAEA,eAAeP,cAAc","ignoreList":[]}
1
+ {"version":3,"names":["React","processColor","StyleSheet","LinearGradientNativeComponent","DEFAULT_START","x","y","DEFAULT_END","DEFAULT_ANGLE_CENTER","isTransparentColor","colorInt","alpha","getRGB","r","g","b","createTransparentColor","fixTransparentColors","colors","result","i","length","currentColor","undefined","nearestOpaqueIdx","minDistance","Infinity","j","candidateColor","distance","Math","abs","nearestColor","processColors","processed","map","color","Error","String","validateLocations","locations","colorsLength","console","warn","value","max","min","LinearGradient","start","end","useAngle","angle","angleCenter","style","children","rest","processedColors","useMemo","validatedLocations","createElement","_extends","flatten","startPoint","endPoint"],"sourceRoot":"../../src","sources":["index.tsx"],"mappings":"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","ignoreList":[]}
@@ -1 +1 @@
1
- {"version":3,"file":"LinearGradientNativeComponent.d.ts","sourceRoot":"","sources":["../../../src/LinearGradientNativeComponent.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAE9C,OAAO,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,2CAA2C,CAAC;AAE9E,MAAM,WAAW,yBAAyB;IACxC,CAAC,EAAE,KAAK,CAAC;IACT,CAAC,EAAE,KAAK,CAAC;CACV;AAED,MAAM,WAAW,yBAA0B,SAAQ,SAAS;IAC1D;;OAEG;IACH,MAAM,EAAE,aAAa,CAAC,KAAK,CAAC,CAAC;IAC7B;;OAEG;IACH,SAAS,CAAC,EAAE,aAAa,CAAC,KAAK,CAAC,CAAC;IACjC;;OAEG;IACH,UAAU,CAAC,EAAE,yBAAyB,CAAC;IACvC;;OAEG;IACH,QAAQ,CAAC,EAAE,yBAAyB,CAAC;IACrC;;OAEG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB;;OAEG;IACH,KAAK,CAAC,EAAE,KAAK,CAAC;IACd;;OAEG;IACH,WAAW,CAAC,EAAE,yBAAyB,CAAC;CACzC;;AAED,wBAEE"}
1
+ {"version":3,"file":"LinearGradientNativeComponent.d.ts","sourceRoot":"","sources":["../../../src/LinearGradientNativeComponent.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAC9C,OAAO,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,2CAA2C,CAAC;AAG9E,MAAM,WAAW,yBAAyB;IACxC,CAAC,EAAE,KAAK,CAAC;IACT,CAAC,EAAE,KAAK,CAAC;CACV;AAED,MAAM,WAAW,yBAA0B,SAAQ,SAAS;IAC1D;;OAEG;IACH,MAAM,EAAE,aAAa,CAAC,KAAK,CAAC,CAAC;IAC7B;;OAEG;IACH,SAAS,CAAC,EAAE,aAAa,CAAC,KAAK,CAAC,CAAC;IACjC;;OAEG;IACH,UAAU,CAAC,EAAE,yBAAyB,CAAC;IACvC;;OAEG;IACH,QAAQ,CAAC,EAAE,yBAAyB,CAAC;IACrC;;OAEG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB;;OAEG;IACH,KAAK,CAAC,EAAE,KAAK,CAAC;IACd;;OAEG;IACH,WAAW,CAAC,EAAE,yBAAyB,CAAC;CACzC;;AAED,wBAEE"}
@@ -1,10 +1,10 @@
1
1
  import * as React from 'react';
2
- import type { ColorValue, StyleProp, ViewStyle } from 'react-native';
2
+ import type { ColorValue, ViewProps } from 'react-native';
3
3
  export interface Point {
4
4
  x: number;
5
5
  y: number;
6
6
  }
7
- export interface LinearGradientProps {
7
+ export interface LinearGradientProps extends ViewProps {
8
8
  /**
9
9
  * An array of at least 2 colors that represent gradient colors
10
10
  */
@@ -40,14 +40,6 @@ export interface LinearGradientProps {
40
40
  * Default: { x: 0.5, y: 0.5 }
41
41
  */
42
42
  angleCenter?: Point;
43
- /**
44
- * Style for the gradient view
45
- */
46
- style?: StyleProp<ViewStyle>;
47
- /**
48
- * Children elements to render on top of the gradient
49
- */
50
- children?: React.ReactNode;
51
43
  }
52
44
  export declare function LinearGradient({ colors, locations, start, end, useAngle, angle, angleCenter, style, children, ...rest }: LinearGradientProps): React.ReactElement;
53
45
  export default LinearGradient;
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/index.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAC/B,OAAO,KAAK,EAAE,UAAU,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAKrE,MAAM,WAAW,KAAK;IACpB,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;CACX;AAED,MAAM,WAAW,mBAAmB;IAClC;;OAEG;IACH,MAAM,EAAE,UAAU,EAAE,CAAC;IACrB;;;OAGG;IACH,SAAS,CAAC,EAAE,MAAM,EAAE,CAAC;IACrB;;;OAGG;IACH,KAAK,CAAC,EAAE,KAAK,CAAC;IACd;;;OAGG;IACH,GAAG,CAAC,EAAE,KAAK,CAAC;IACZ;;;OAGG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB;;;;OAIG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IACf;;;OAGG;IACH,WAAW,CAAC,EAAE,KAAK,CAAC;IACpB;;OAEG;IACH,KAAK,CAAC,EAAE,SAAS,CAAC,SAAS,CAAC,CAAC;IAC7B;;OAEG;IACH,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;CAC5B;AAiCD,wBAAgB,cAAc,CAAC,EAC7B,MAAM,EACN,SAAS,EACT,KAAqB,EACrB,GAAiB,EACjB,QAAgB,EAChB,KAAS,EACT,WAAkC,EAClC,KAAK,EACL,QAAQ,EACR,GAAG,IAAI,EACR,EAAE,mBAAmB,GAAG,KAAK,CAAC,YAAY,CA0B1C;AAED,eAAe,cAAc,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/index.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAC/B,OAAO,KAAK,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAK1D,MAAM,WAAW,KAAK;IACpB,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;CACX;AAED,MAAM,WAAW,mBAAoB,SAAQ,SAAS;IACpD;;OAEG;IACH,MAAM,EAAE,UAAU,EAAE,CAAC;IACrB;;;OAGG;IACH,SAAS,CAAC,EAAE,MAAM,EAAE,CAAC;IACrB;;;OAGG;IACH,KAAK,CAAC,EAAE,KAAK,CAAC;IACd;;;OAGG;IACH,GAAG,CAAC,EAAE,KAAK,CAAC;IACZ;;;OAGG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB;;;;OAIG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IACf;;;OAGG;IACH,WAAW,CAAC,EAAE,KAAK,CAAC;CACrB;AA0HD,wBAAgB,cAAc,CAAC,EAC7B,MAAM,EACN,SAAS,EACT,KAAqB,EACrB,GAAiB,EACjB,QAAgB,EAChB,KAAS,EACT,WAAkC,EAClC,KAAK,EACL,QAAQ,EACR,GAAG,IAAI,EACR,EAAE,mBAAmB,GAAG,KAAK,CAAC,YAAY,CA0B1C;AAED,eAAe,cAAc,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-native-linear-gradient-fabric",
3
- "version": "0.1.0",
3
+ "version": "0.1.1",
4
4
  "description": "A modern replacement for react-native-linear-gradient with full Fabric support",
5
5
  "main": "lib/commonjs/index",
6
6
  "module": "lib/module/index",
@@ -1,6 +1,6 @@
1
1
  import type { ViewProps } from 'react-native';
2
- import codegenNativeComponent from 'react-native/Libraries/Utilities/codegenNativeComponent';
3
2
  import type { Float, Int32 } from 'react-native/Libraries/Types/CodegenTypes';
3
+ import codegenNativeComponent from 'react-native/Libraries/Utilities/codegenNativeComponent';
4
4
 
5
5
  export interface NativeLinearGradientPoint {
6
6
  x: Float;
package/src/index.tsx CHANGED
@@ -1,5 +1,5 @@
1
1
  import * as React from 'react';
2
- import type { ColorValue, StyleProp, ViewStyle } from 'react-native';
2
+ import type { ColorValue, ViewProps } from 'react-native';
3
3
  import { processColor, StyleSheet } from 'react-native';
4
4
 
5
5
  import LinearGradientNativeComponent from './LinearGradientNativeComponent';
@@ -9,7 +9,7 @@ export interface Point {
9
9
  y: number;
10
10
  }
11
11
 
12
- export interface LinearGradientProps {
12
+ export interface LinearGradientProps extends ViewProps {
13
13
  /**
14
14
  * An array of at least 2 colors that represent gradient colors
15
15
  */
@@ -45,28 +45,108 @@ export interface LinearGradientProps {
45
45
  * Default: { x: 0.5, y: 0.5 }
46
46
  */
47
47
  angleCenter?: Point;
48
- /**
49
- * Style for the gradient view
50
- */
51
- style?: StyleProp<ViewStyle>;
52
- /**
53
- * Children elements to render on top of the gradient
54
- */
55
- children?: React.ReactNode;
56
48
  }
57
49
 
58
50
  const DEFAULT_START: Point = { x: 0.5, y: 0 };
59
51
  const DEFAULT_END: Point = { x: 0.5, y: 1 };
60
52
  const DEFAULT_ANGLE_CENTER: Point = { x: 0.5, y: 0.5 };
61
53
 
54
+ /**
55
+ * Check if a processed color has zero alpha (fully transparent).
56
+ * React Native processColor returns ARGB format where alpha is in the highest byte.
57
+ */
58
+ function isTransparentColor(colorInt: number): boolean {
59
+ // Extract alpha from ARGB format (bits 24-31)
60
+ const alpha = (colorInt >>> 24) & 0xff;
61
+ return alpha === 0;
62
+ }
63
+
64
+ /**
65
+ * Get the RGB components from a processed color (ARGB format).
66
+ */
67
+ function getRGB(colorInt: number): { r: number; g: number; b: number } {
68
+ return {
69
+ r: (colorInt >>> 16) & 0xff,
70
+ g: (colorInt >>> 8) & 0xff,
71
+ b: colorInt & 0xff,
72
+ };
73
+ }
74
+
75
+ /**
76
+ * Create a color with specified RGB and alpha=0 (fully transparent).
77
+ */
78
+ function createTransparentColor(r: number, g: number, b: number): number {
79
+ // ARGB format: alpha=0 in highest byte
80
+ return ((0 << 24) | (r << 16) | (g << 8) | b) >>> 0;
81
+ }
82
+
83
+ /**
84
+ * Fix transparent colors in gradients to avoid grey interpolation artifacts.
85
+ *
86
+ * When interpolating from 'transparent' (rgba(0,0,0,0)) to a color like white,
87
+ * the gradient interpolates all RGBA channels, resulting in grey midtones.
88
+ * This function replaces fully transparent colors with transparent versions
89
+ * of their nearest opaque neighbor, ensuring smooth color transitions.
90
+ *
91
+ * See: https://github.com/react-native-linear-gradient/react-native-linear-gradient/issues/691
92
+ */
93
+ function fixTransparentColors(colors: number[]): number[] {
94
+ const result = [...colors];
95
+
96
+ for (let i = 0; i < result.length; i++) {
97
+ const currentColor = result[i];
98
+ if (currentColor !== undefined && isTransparentColor(currentColor)) {
99
+ // Find nearest non-transparent color to inherit RGB from
100
+ let nearestOpaqueIdx = -1;
101
+ let minDistance = Infinity;
102
+
103
+ for (let j = 0; j < result.length; j++) {
104
+ const candidateColor = result[j];
105
+ if (
106
+ i !== j &&
107
+ candidateColor !== undefined &&
108
+ !isTransparentColor(candidateColor)
109
+ ) {
110
+ const distance = Math.abs(i - j);
111
+ if (distance < minDistance) {
112
+ minDistance = distance;
113
+ nearestOpaqueIdx = j;
114
+ }
115
+ }
116
+ }
117
+
118
+ // If we found a non-transparent color, use its RGB values
119
+ const nearestColor =
120
+ nearestOpaqueIdx !== -1 ? result[nearestOpaqueIdx] : undefined;
121
+ if (nearestColor !== undefined) {
122
+ const { r, g, b } = getRGB(nearestColor);
123
+ result[i] = createTransparentColor(r, g, b);
124
+ }
125
+ // If all colors are transparent, leave as-is (nothing to fix)
126
+ }
127
+ }
128
+
129
+ return result;
130
+ }
131
+
62
132
  function processColors(colors: ColorValue[]): number[] {
63
- return colors.map((color) => {
64
- const processed = processColor(color);
65
- if (processed === null || processed === undefined) {
133
+ const processed = colors.map((color) => {
134
+ const result = processColor(color);
135
+ if (result === null || result === undefined) {
66
136
  throw new Error(`Invalid color value: ${String(color)}`);
67
137
  }
68
- return typeof processed === 'number' ? processed : 0;
138
+ if (typeof result === 'number') {
139
+ return result;
140
+ }
141
+ // OpaqueColorValue (symbol type) or other non-number values
142
+ // This can happen with platform-specific color types
143
+ throw new Error(
144
+ `Unsupported color type: ${String(color)}. Only standard color values are supported.`
145
+ );
69
146
  });
147
+
148
+ // Fix transparent colors to prevent grey gradient artifacts
149
+ return fixTransparentColors(processed);
70
150
  }
71
151
 
72
152
  function validateLocations(
@@ -83,7 +163,8 @@ function validateLocations(
83
163
  );
84
164
  }
85
165
 
86
- return locations;
166
+ // Clamp location values to [0, 1] range for iOS CAGradientLayer compatibility
167
+ return locations.map((value) => Math.max(0, Math.min(1, value)));
87
168
  }
88
169
 
89
170
  export function LinearGradient({