Initial commit

This commit is contained in:
marianesaldana
2026-05-23 08:59:34 -06:00
commit 80dbd947e5
36446 changed files with 3729147 additions and 0 deletions

View File

@@ -0,0 +1,2 @@
// @generated by expo-module-scripts
module.exports = require('expo-module-scripts/eslintrc.base.js');

250
frontend/node_modules/expo-linear-gradient/CHANGELOG.md generated vendored Normal file
View File

@@ -0,0 +1,250 @@
# Changelog
## Unpublished
### 🛠 Breaking changes
### 🎉 New features
### 🐛 Bug fixes
### 💡 Others
## 13.0.2 — 2024-05-01
### 💡 Others
- Changed type of `colors` and `locations` array to readonly ([#28450](https://github.com/expo/expo/pull/28450) by [@kowczarz](https://github.com/kowczarz))
## 13.0.1 — 2024-04-23
_This version does not introduce any user-facing changes._
## 13.0.0 — 2024-04-18
- Added support for Paint dithering on Android. ([#27153](https://github.com/expo/expo/pull/27153) by [@alexandrius](https://github.com/alexandrius))
### 🎉 New features
- Mark React client components with "use client" directives. ([#27300](https://github.com/expo/expo/pull/27300) by [@EvanBacon](https://github.com/EvanBacon))
### 💡 Others
- Removed deprecated backward compatible Gradle settings. ([#28083](https://github.com/expo/expo/pull/28083) by [@kudo](https://github.com/kudo))
## 12.7.2 - 2024-02-16
### 🎉 New features
- Added support for Apple tvOS. ([#26965](https://github.com/expo/expo/pull/26965) by [@douglowder](https://github.com/douglowder))
## 12.7.1 - 2024-01-23
### 💡 Others
- On `Android`, remove type annotation on `View`. ([#26545](https://github.com/expo/expo/pull/26545) by [@alanjhughes](https://github.com/alanjhughes))
## 12.7.0 — 2023-11-14
### 🛠 Breaking changes
- Bumped iOS deployment target to 13.4. ([#25063](https://github.com/expo/expo/pull/25063) by [@gabrieldonadel](https://github.com/gabrieldonadel))
- On `Android` bump `compileSdkVersion` and `targetSdkVersion` to `34`. ([#24708](https://github.com/expo/expo/pull/24708) by [@alanjhughes](https://github.com/alanjhughes))
## 12.6.0 — 2023-10-17
### 🛠 Breaking changes
- Dropped support for Android SDK 21 and 22. ([#24201](https://github.com/expo/expo/pull/24201) by [@behenate](https://github.com/behenate))
### 💡 Others
- Ship untranspiled JSX to support custom handling of `jsx` and `createElement`. ([#24889](https://github.com/expo/expo/pull/24889) by [@EvanBacon](https://github.com/EvanBacon))
## 12.5.0 — 2023-09-04
### 🎉 New features
- Added support for React Native 0.73. ([#24018](https://github.com/expo/expo/pull/24018) by [@kudo](https://github.com/kudo))
## 12.4.0 — 2023-08-02
_This version does not introduce any user-facing changes._
## 12.3.0 — 2023-06-21
### 🐛 Bug fixes
- Fixed Android build warnings for Gradle version 8. ([#22537](https://github.com/expo/expo/pull/22537), [#22609](https://github.com/expo/expo/pull/22609) by [@kudo](https://github.com/kudo))
## 12.2.0 — 2023-05-08
_This version does not introduce any user-facing changes._
## 12.1.2 - 2023-03-08
### 🐛 Bug fixes
- Fixed crashes when R8 or Proguard is enabled. ([#21580](https://github.com/expo/expo/pull/21580) by [@kudo](https://github.com/kudo))
## 12.1.1 — 2023-02-09
_This version does not introduce any user-facing changes._
## 12.1.0 — 2023-02-03
### 💡 Others
- On Android bump `compileSdkVersion` and `targetSdkVersion` to `33`. ([#20721](https://github.com/expo/expo/pull/20721) by [@lukmccall](https://github.com/lukmccall))
## 12.0.1 — 2022-11-02
_This version does not introduce any user-facing changes._
## 12.0.0 — 2022-10-25
### 🐛 Bug fixes
- Fix default start and end points on Android. ([#19460](https://github.com/expo/expo/pull/19460) by [@tsapeta](https://github.com/tsapeta))
## 12.0.0-beta.1 — 2022-10-06
### 🛠 Breaking changes
- Bumped iOS deployment target to 13.0 and deprecated support for iOS 12. ([#18873](https://github.com/expo/expo/pull/18873) by [@tsapeta](https://github.com/tsapeta))
## 11.4.0 — 2022-07-07
### 💡 Others
- Migrated Expo modules definitions to the new naming convention. ([#17193](https://github.com/expo/expo/pull/17193) by [@tsapeta](https://github.com/tsapeta))
## 11.3.0 — 2022-04-18
### 🐛 Bug fixes
- Extract `react-native-web` internals into package to minimize bundler setup. ([#16098](https://github.com/expo/expo/pull/16098) by [@EvanBacon](https://github.com/EvanBacon))
- Fix `Plugin with id 'maven' not found` build error from Android Gradle 7. ([#16080](https://github.com/expo/expo/pull/16080) by [@kudo](https://github.com/kudo))
- Fixed the component not rendering correctly when the border radius style is set. ([#16671](https://github.com/expo/expo/pull/16671) by [@tsapeta](https://github.com/tsapeta))
### ⚠️ Notices
- On Android bump `compileSdkVersion` to `31`, `targetSdkVersion` to `31` and `Java` version to `11`. ([#16941](https://github.com/expo/expo/pull/16941) by [@bbarthec](https://github.com/bbarthec))
## 11.2.0 — 2022-01-26
### 🐛 Bug fixes
- Fix display issue on iOS when more than 2 colors are used without explicit locations. ([#15955](https://github.com/expo/expo/pull/15955) by [@kbrandwijk](https://github.com/kbrandwijk))
## 11.1.0 — 2022-01-26
### 🐛 Bug fixes
- Prevent crashes by adding unimplemented `CALayer` initializer `init(layer:)`. ([#15843](https://github.com/expo/expo/pull/15843) by [@dillonhafer](https://github.com/dillonhafer))
## 11.0.3 — 2022-02-06
### 🐛 Bug fixes
- Prevent crashes by adding unimplemented `CALayer` initializer `init(layer:)`. ([#15843](https://github.com/expo/expo/pull/15843) by [@dillonhafer](https://github.com/dillonhafer))
## 11.0.2 — 2022-02-01
### 🐛 Bug fixes
- Fix `Plugin with id 'maven' not found` build error from Android Gradle 7. ([#16080](https://github.com/expo/expo/pull/16080) by [@kudo](https://github.com/kudo))
## 11.0.1 — 2022-01-27
### 🐛 Bug fixes
- Fix display issue on iOS when more than 2 colors are used without explicit locations. ([#15955](https://github.com/expo/expo/pull/15955) by [@kbrandwijk](https://github.com/kbrandwijk))
## 11.0.0 — 2021-12-03
### 💡 Others
- Rewrote code to Swift, removed legacy Objective-C module implementation and changed the pod name to `ExpoLinearGradient`. ([#15168](https://github.com/expo/expo/pull/15168) by [@tsapeta](https://github.com/tsapeta))
- Rewrote module using Sweet API on Android. ([#15166](https://github.com/expo/expo/pull/15166) by [@lukmccall](https://github.com/lukmccall))
## 10.0.1 — 2021-10-01
_This version does not introduce any user-facing changes._
## 10.0.0 — 2021-09-28
### 🛠 Breaking changes
- Dropped support for iOS 11.0 ([#14383](https://github.com/expo/expo/pull/14383) by [@cruzach](https://github.com/cruzach))
### 🐛 Bug fixes
- Fix building errors from use_frameworks! in Podfile. ([#14523](https://github.com/expo/expo/pull/14523) by [@kudo](https://github.com/kudo))
## 9.3.0-alpha.0 — 2021-08-17
### 💡 Others
- Migrated from `@unimodules/core` to `expo-modules-core`. (by [@tsapeta](https://github.com/tsapeta))
- Experimental Swift implementation using Sweet API. (by [@tsapeta](https://github.com/tsapeta))
## 9.2.0 — 2021-06-16
### 🐛 Bug fixes
- Enable kotlin in all modules. ([#12716](https://github.com/expo/expo/pull/12716) by [@wschurman](https://github.com/wschurman))
### 💡 Others
- Build Android code using Java 8 to fix Android instrumented test build error. ([#12939](https://github.com/expo/expo/pull/12939) by [@kudo](https://github.com/kudo))
## 9.1.0 — 2021-03-10
### 🎉 New features
- Updated Android build configuration to target Android 11 (added support for Android SDK 30). ([#11647](https://github.com/expo/expo/pull/11647) by [@bbarthec](https://github.com/bbarthec))
### 🐛 Bug fixes
- Remove peerDependencies and unimodulePeerDependencies from Expo modules. ([#11980](https://github.com/expo/expo/pull/11980) by [@brentvatne](https://github.com/brentvatne))
## 9.0.0 — 2021-01-15
### 🛠 Breaking changes
- Dropped support for iOS 10.0 ([#11344](https://github.com/expo/expo/pull/11344) by [@tsapeta](https://github.com/tsapeta))
## 8.4.0 — 2020-11-25
### 🐛 Bug fixes
- Revert to class component. ([#11111](https://github.com/expo/expo/pull/11111) by [@EvanBacon](https://github.com/EvanBacon))
## 8.3.1 — 2020-09-23
### 🐛 Bug fixes
- Added `children` property to `LinearGradient` component ([#10227](https://github.com/expo/expo/pull/10227) by [@sjchmiela](https://github.com/sjchmiela))
## 8.3.0 — 2020-08-18
_This version does not introduce any user-facing changes._
## 8.2.2 — 2020-07-29
### 🎉 New features
- Remove `prop-types` ([#8681](https://github.com/expo/expo/pull/8681) by [@EvanBacon](https://github.com/EvanBacon))
### 🐛 Bug fixes
- Renamed type export `LinearGradienPoint` to `LinearGradientPoint`. ([#8673](https://github.com/expo/expo/pull/8673) by [@EvanBacon](https://github.com/EvanBacon))
## 8.2.1 — 2020-05-29
_This version does not introduce any user-facing changes._
## 8.2.0 — 2020-05-27
_This version does not introduce any user-facing changes._

41
frontend/node_modules/expo-linear-gradient/README.md generated vendored Normal file
View File

@@ -0,0 +1,41 @@
<p>
<a href="https://docs.expo.dev/versions/latest/sdk/linear-gradient/">
<img
src="../../.github/resources/expo-linear-gradient.svg"
alt="expo-linear-gradient"
height="64" />
</a>
</p>
Provides a React component that renders a gradient view.
# API documentation
- [Documentation for the main branch](https://github.com/expo/expo/blob/main/docs/pages/versions/unversioned/sdk/linear-gradient.mdx)
- [Documentation for the latest stable release](https://docs.expo.dev/versions/latest/sdk/linear-gradient/)
# Installation in managed Expo projects
For [managed](https://docs.expo.dev/archive/managed-vs-bare/) Expo projects, please follow the installation instructions in the [API documentation for the latest stable release](https://docs.expo.dev/versions/latest/sdk/linear-gradient/).
# Installation in bare React Native projects
For bare React Native projects, you must ensure that you have [installed and configured the `expo` package](https://docs.expo.dev/bare/installing-expo-modules/) before continuing.
### Add the package to your npm dependencies
```
npx expo install expo-linear-gradient
```
### Configure for iOS
Run `npx pod-install` after installing the npm package.
### Configure for Android
No additional set up necessary.
# Contributing
Contributions are very welcome! Please refer to guidelines described in the [contributing guide](https://github.com/expo/expo#contributing).

View File

@@ -0,0 +1,19 @@
apply plugin: 'com.android.library'
group = 'host.exp.exponent'
version = '13.0.2'
def expoModulesCorePlugin = new File(project(":expo-modules-core").projectDir.absolutePath, "ExpoModulesCorePlugin.gradle")
apply from: expoModulesCorePlugin
applyKotlinExpoModulesCorePlugin()
useCoreDependencies()
useDefaultAndroidSdkVersions()
useExpoPublishing()
android {
namespace "expo.modules.lineargradient"
defaultConfig {
versionCode 17
versionName "13.0.2"
}
}

View File

@@ -0,0 +1,3 @@
<manifest>
</manifest>

View File

@@ -0,0 +1,38 @@
package expo.modules.lineargradient
import expo.modules.kotlin.modules.Module
import expo.modules.kotlin.modules.ModuleDefinition
class LinearGradientModule : Module() {
override fun definition() = ModuleDefinition {
Name("ExpoLinearGradient")
View(LinearGradientView::class) {
Prop("colors") { view, colors: IntArray ->
view.setColors(colors)
}
Prop("locations") { view, locations: FloatArray? ->
locations?.let {
view.setLocations(it)
}
}
Prop("startPoint") { view, startPoint: Pair<Float, Float>? ->
view.setStartPosition(startPoint?.first ?: 0.5f, startPoint?.second ?: 0f)
}
Prop("endPoint") { view, endPoint: Pair<Float, Float>? ->
view.setEndPosition(endPoint?.first ?: 0.5f, endPoint?.second ?: 1f)
}
Prop("borderRadii") { view, borderRadii: FloatArray? ->
view.setBorderRadii(borderRadii ?: FloatArray(8) { 0f })
}
Prop("dither") { view, dither: Boolean? ->
view.setDither(dither ?: true)
}
}
}
}

View File

@@ -0,0 +1,122 @@
package expo.modules.lineargradient;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.LinearGradient;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.RectF;
import android.graphics.Shader;
import android.util.TypedValue;
import android.view.View;
import expo.modules.core.interfaces.DoNotStrip;
public class LinearGradientView extends View {
private final Paint mPaint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.DITHER_FLAG);
private Path mPathForBorderRadius;
private RectF mTempRectForBorderRadius;
private float[] mLocations;
private float[] mStartPos = {0.5F, 0};
private float[] mEndPos = {0.5F, 1};
private int[] mColors;
private int[] mSize = {0, 0};
private float[] mBorderRadii = {0, 0, 0, 0, 0, 0, 0, 0};
// Keeps this primary constructor from Proguard/R8 for ViewDefinitionBuilder
@DoNotStrip
public LinearGradientView(Context context) {
super(context);
}
public void setStartPosition(final float x, final float y) {
mStartPos = new float[]{x, y};
drawGradient();
}
public void setEndPosition(final float x, final float y) {
mEndPos = new float[]{x, y};
drawGradient();
}
public void setColors(final int[] colors) {
mColors = colors;
drawGradient();
}
public void setLocations(final float[] locations) {
mLocations = locations;
drawGradient();
}
public void setBorderRadii(final float[] borderRadii) {
for (int i = 0; i < borderRadii.length; i++) {
borderRadii[i] = toPixelFromDIP(borderRadii[i]);
}
mBorderRadii = borderRadii;
updatePath();
drawGradient();
}
public void setDither(final boolean dither){
mPaint.setDither(dither);
drawGradient();
}
// Copied from RN PixelUtil
// We might want to expose display metrics on @unimodules/core somewhere to avoid
// having code similar to this littered throughout modules
private float toPixelFromDIP(float value) {
return TypedValue.applyDimension(
TypedValue.COMPLEX_UNIT_DIP,
value,
getContext().getResources().getDisplayMetrics()
);
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
mSize = new int[]{w, h};
updatePath();
drawGradient();
}
private void drawGradient() {
// guard against crashes happening while multiple properties are updated
if (mColors == null || (mLocations != null && mColors.length != mLocations.length))
return;
LinearGradient mShader = new LinearGradient(
mStartPos[0] * mSize[0],
mStartPos[1] * mSize[1],
mEndPos[0] * mSize[0],
mEndPos[1] * mSize[1],
mColors,
mLocations,
Shader.TileMode.CLAMP);
mPaint.setShader(mShader);
invalidate();
}
private void updatePath() {
if (mPathForBorderRadius == null) {
mPathForBorderRadius = new Path();
mTempRectForBorderRadius = new RectF();
}
mPathForBorderRadius.reset();
mTempRectForBorderRadius.set(0f, 0f, (float) mSize[0], (float) mSize[1]);
mPathForBorderRadius.addRoundRect(
mTempRectForBorderRadius,
mBorderRadii,
Path.Direction.CW);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
if (mPathForBorderRadius == null) {
canvas.drawPaint(mPaint);
} else {
canvas.drawPath(mPathForBorderRadius, mPaint);
}
}
}

View File

@@ -0,0 +1,67 @@
import * as React from 'react';
import { ViewProps } from 'react-native';
import { NativeLinearGradientPoint } from './NativeLinearGradient.types';
/**
* An object `{ x: number; y: number }` or array `[x, y]` that represents the point
* at which the gradient starts or ends, as a fraction of the overall size of the gradient ranging
* from `0` to `1`, inclusive.
*/
export type LinearGradientPoint = {
/**
* A number ranging from `0` to `1`, representing the position of gradient transformation.
*/
x: number;
/**
* A number ranging from `0` to `1`, representing the position of gradient transformation.
*/
y: number;
} | NativeLinearGradientPoint;
export type LinearGradientProps = ViewProps & {
/**
* A readonly array of colors that represent stops in the gradient. At least two colors are required
* (for a single-color background, use the `style.backgroundColor` prop on a `View` component).
*/
colors: readonly string[];
/**
* A readonly array that contains `number`s ranging from `0` to `1`, inclusive, and is the same length as the `colors` property.
* Each number indicates a color-stop location where each respective color should be located.
* If not specified, the colors will be distributed evenly across the gradient.
*
* For example, `[0.5, 0.8]` would render:
* - the first color, solid, from the beginning of the gradient view to 50% through (the middle);
* - a gradient from the first color to the second from the 50% point to the 80% point; and
* - the second color, solid, from the 80% point to the end of the gradient view.
*
* > The color-stop locations must be ascending from least to greatest.
* @default []
*/
locations?: readonly number[] | null;
/**
* For example, `{ x: 0.1, y: 0.2 }` means that the gradient will start `10%` from the left and `20%` from the top.
*
* **On web**, this only changes the angle of the gradient because CSS gradients don't support changing the starting position.
* @default { x: 0.5, y: 0.0 }
*/
start?: LinearGradientPoint | null;
/**
* For example, `{ x: 0.1, y: 0.2 }` means that the gradient will end `10%` from the left and `20%` from the bottom.
*
* **On web**, this only changes the angle of the gradient because CSS gradients don't support changing the end position.
* @default { x: 0.5, y: 1.0 }
*/
end?: LinearGradientPoint | null;
/**
* Enables or disables paint dithering. Dithering can reduce the gradient color banding issue.
* Setting `false` may improve gradient rendering performance.
* @default true
* @platform android
*/
dither?: boolean;
};
/**
* Renders a native view that transitions between multiple colors in a linear direction.
*/
export declare class LinearGradient extends React.Component<LinearGradientProps> {
render(): JSX.Element;
}
//# sourceMappingURL=LinearGradient.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"LinearGradient.d.ts","sourceRoot":"","sources":["../src/LinearGradient.tsx"],"names":[],"mappings":"AAIA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAC/B,OAAO,EAA0B,SAAS,EAAE,MAAM,cAAc,CAAC;AAGjE,OAAO,EAAE,yBAAyB,EAAE,MAAM,8BAA8B,CAAC;AAGzE;;;;GAIG;AACH,MAAM,MAAM,mBAAmB,GAC3B;IACE;;OAEG;IACH,CAAC,EAAE,MAAM,CAAC;IACV;;OAEG;IACH,CAAC,EAAE,MAAM,CAAC;CACX,GACD,yBAAyB,CAAC;AAG9B,MAAM,MAAM,mBAAmB,GAAG,SAAS,GAAG;IAC5C;;;OAGG;IACH,MAAM,EAAE,SAAS,MAAM,EAAE,CAAC;IAC1B;;;;;;;;;;;;OAYG;IACH,SAAS,CAAC,EAAE,SAAS,MAAM,EAAE,GAAG,IAAI,CAAC;IACrC;;;;;OAKG;IACH,KAAK,CAAC,EAAE,mBAAmB,GAAG,IAAI,CAAC;IACnC;;;;;OAKG;IACH,GAAG,CAAC,EAAE,mBAAmB,GAAG,IAAI,CAAC;IAEjC;;;;;OAKG;IACH,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB,CAAC;AAEF;;GAEG;AACH,qBAAa,cAAe,SAAQ,KAAK,CAAC,SAAS,CAAC,mBAAmB,CAAC;IACtE,MAAM;CAsBP"}

View File

@@ -0,0 +1,33 @@
// Copyright © 2024 650 Industries.
'use client';
import * as React from 'react';
import { Platform, processColor } from 'react-native';
import NativeLinearGradient from './NativeLinearGradient';
/**
* Renders a native view that transitions between multiple colors in a linear direction.
*/
export class LinearGradient extends React.Component {
render() {
const { colors, locations, start, end, dither, ...props } = this.props;
let resolvedLocations = locations;
if (locations && colors.length !== locations.length) {
console.warn('LinearGradient colors and locations props should be arrays of the same length');
resolvedLocations = locations.slice(0, colors.length);
}
return (<NativeLinearGradient {...props} colors={Platform.select({
web: colors,
default: colors.map(processColor),
})} dither={Platform.select({ android: dither })} locations={resolvedLocations} startPoint={_normalizePoint(start)} endPoint={_normalizePoint(end)}/>);
}
}
function _normalizePoint(point) {
if (!point) {
return undefined;
}
if (Array.isArray(point) && point.length !== 2) {
console.warn('start and end props for LinearGradient must be of the format [x,y] or {x, y}');
return undefined;
}
return Array.isArray(point) ? point : [point.x, point.y];
}
//# sourceMappingURL=LinearGradient.js.map

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,4 @@
import * as React from 'react';
import { NativeLinearGradientProps } from './NativeLinearGradient.types';
export default function NativeLinearGradient({ colors, locations, startPoint, endPoint, children, style, dither, ...props }: NativeLinearGradientProps): React.ReactElement;
//# sourceMappingURL=NativeLinearGradient.android.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"NativeLinearGradient.android.d.ts","sourceRoot":"","sources":["../src/NativeLinearGradient.android.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAG/B,OAAO,EAAE,yBAAyB,EAAE,MAAM,8BAA8B,CAAC;AAEzE,MAAM,CAAC,OAAO,UAAU,oBAAoB,CAAC,EAC3C,MAAM,EACN,SAAS,EACT,UAAU,EACV,QAAQ,EACR,QAAQ,EACR,KAAK,EACL,MAAM,EACN,GAAG,KAAK,EACT,EAAE,yBAAyB,GAAG,KAAK,CAAC,YAAY,CAiChD"}

View File

@@ -0,0 +1,27 @@
import { requireNativeViewManager } from 'expo-modules-core';
import * as React from 'react';
import { StyleSheet, View } from 'react-native';
export default function NativeLinearGradient({ colors, locations, startPoint, endPoint, children, style, dither, ...props }) {
// TODO: revisit whether we need to inherit the container's borderRadius since this issue has
// been resolved: https://github.com/facebook/react-native/issues/3198
const flatStyle = StyleSheet.flatten(style) ?? {};
const borderRadius = flatStyle.borderRadius ?? 0;
// This is the format from:
// https://developer.android.com/reference/android/graphics/Path.html#addRoundRect(android.graphics.RectF,%20float[],%20android.graphics.Path.Direction)
const borderRadiiPerCorner = [
flatStyle.borderTopLeftRadius ?? borderRadius,
flatStyle.borderTopLeftRadius ?? borderRadius,
flatStyle.borderTopRightRadius ?? borderRadius,
flatStyle.borderTopRightRadius ?? borderRadius,
flatStyle.borderBottomRightRadius ?? borderRadius,
flatStyle.borderBottomRightRadius ?? borderRadius,
flatStyle.borderBottomLeftRadius ?? borderRadius,
flatStyle.borderBottomLeftRadius ?? borderRadius,
];
return (<View {...props} style={style}>
<BaseNativeLinearGradient style={StyleSheet.absoluteFill} colors={colors} startPoint={startPoint} endPoint={endPoint} locations={locations} borderRadii={borderRadiiPerCorner} dither={dither}/>
{children}
</View>);
}
const BaseNativeLinearGradient = requireNativeViewManager('ExpoLinearGradient');
//# sourceMappingURL=NativeLinearGradient.android.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"NativeLinearGradient.android.js","sourceRoot":"","sources":["../src/NativeLinearGradient.android.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,wBAAwB,EAAE,MAAM,mBAAmB,CAAC;AAC7D,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAC/B,OAAO,EAAE,UAAU,EAAE,IAAI,EAAE,MAAM,cAAc,CAAC;AAIhD,MAAM,CAAC,OAAO,UAAU,oBAAoB,CAAC,EAC3C,MAAM,EACN,SAAS,EACT,UAAU,EACV,QAAQ,EACR,QAAQ,EACR,KAAK,EACL,MAAM,EACN,GAAG,KAAK,EACkB;IAC1B,6FAA6F;IAC7F,sEAAsE;IACtE,MAAM,SAAS,GAAG,UAAU,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC;IAClD,MAAM,YAAY,GAAG,SAAS,CAAC,YAAY,IAAI,CAAC,CAAC;IAEjD,2BAA2B;IAC3B,wJAAwJ;IACxJ,MAAM,oBAAoB,GAAG;QAC3B,SAAS,CAAC,mBAAmB,IAAI,YAAY;QAC7C,SAAS,CAAC,mBAAmB,IAAI,YAAY;QAC7C,SAAS,CAAC,oBAAoB,IAAI,YAAY;QAC9C,SAAS,CAAC,oBAAoB,IAAI,YAAY;QAC9C,SAAS,CAAC,uBAAuB,IAAI,YAAY;QACjD,SAAS,CAAC,uBAAuB,IAAI,YAAY;QACjD,SAAS,CAAC,sBAAsB,IAAI,YAAY;QAChD,SAAS,CAAC,sBAAsB,IAAI,YAAY;KACjD,CAAC;IAEF,OAAO,CACL,CAAC,IAAI,CAAC,IAAI,KAAK,CAAC,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,CAC5B;MAAA,CAAC,wBAAwB,CACvB,KAAK,CAAC,CAAC,UAAU,CAAC,YAAY,CAAC,CAC/B,MAAM,CAAC,CAAC,MAAM,CAAC,CACf,UAAU,CAAC,CAAC,UAAU,CAAC,CACvB,QAAQ,CAAC,CAAC,QAAQ,CAAC,CACnB,SAAS,CAAC,CAAC,SAAS,CAAC,CACrB,WAAW,CAAC,CAAC,oBAAoB,CAAC,CAClC,MAAM,CAAC,CAAC,MAAM,CAAC,EAEjB;MAAA,CAAC,QAAQ,CACX;IAAA,EAAE,IAAI,CAAC,CACR,CAAC;AACJ,CAAC;AAED,MAAM,wBAAwB,GAAG,wBAAwB,CAAC,oBAAoB,CAAC,CAAC","sourcesContent":["import { requireNativeViewManager } from 'expo-modules-core';\nimport * as React from 'react';\nimport { StyleSheet, View } from 'react-native';\n\nimport { NativeLinearGradientProps } from './NativeLinearGradient.types';\n\nexport default function NativeLinearGradient({\n colors,\n locations,\n startPoint,\n endPoint,\n children,\n style,\n dither,\n ...props\n}: NativeLinearGradientProps): React.ReactElement {\n // TODO: revisit whether we need to inherit the container's borderRadius since this issue has\n // been resolved: https://github.com/facebook/react-native/issues/3198\n const flatStyle = StyleSheet.flatten(style) ?? {};\n const borderRadius = flatStyle.borderRadius ?? 0;\n\n // This is the format from:\n // https://developer.android.com/reference/android/graphics/Path.html#addRoundRect(android.graphics.RectF,%20float[],%20android.graphics.Path.Direction)\n const borderRadiiPerCorner = [\n flatStyle.borderTopLeftRadius ?? borderRadius,\n flatStyle.borderTopLeftRadius ?? borderRadius,\n flatStyle.borderTopRightRadius ?? borderRadius,\n flatStyle.borderTopRightRadius ?? borderRadius,\n flatStyle.borderBottomRightRadius ?? borderRadius,\n flatStyle.borderBottomRightRadius ?? borderRadius,\n flatStyle.borderBottomLeftRadius ?? borderRadius,\n flatStyle.borderBottomLeftRadius ?? borderRadius,\n ];\n\n return (\n <View {...props} style={style}>\n <BaseNativeLinearGradient\n style={StyleSheet.absoluteFill}\n colors={colors}\n startPoint={startPoint}\n endPoint={endPoint}\n locations={locations}\n borderRadii={borderRadiiPerCorner}\n dither={dither}\n />\n {children}\n </View>\n );\n}\n\nconst BaseNativeLinearGradient = requireNativeViewManager('ExpoLinearGradient');\n"]}

View File

@@ -0,0 +1,4 @@
import * as React from 'react';
import { NativeLinearGradientProps } from './NativeLinearGradient.types';
export default function NativeLinearGradient(props: NativeLinearGradientProps): React.ReactElement;
//# sourceMappingURL=NativeLinearGradient.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"NativeLinearGradient.d.ts","sourceRoot":"","sources":["../src/NativeLinearGradient.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAG/B,OAAO,EAAE,yBAAyB,EAAE,MAAM,8BAA8B,CAAC;AAIzE,MAAM,CAAC,OAAO,UAAU,oBAAoB,CAAC,KAAK,EAAE,yBAAyB,GAAG,KAAK,CAAC,YAAY,CAIjG"}

View File

@@ -0,0 +1,5 @@
import * as React from 'react';
import { NativeLinearGradientProps } from './NativeLinearGradient.types';
declare const NativeLinearGradient: React.FC<NativeLinearGradientProps>;
export default NativeLinearGradient;
//# sourceMappingURL=NativeLinearGradient.ios.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"NativeLinearGradient.ios.d.ts","sourceRoot":"","sources":["../src/NativeLinearGradient.ios.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAE/B,OAAO,EAAE,yBAAyB,EAAE,MAAM,8BAA8B,CAAC;AAEzE,QAAA,MAAM,oBAAoB,qCAEc,CAAC;AAEzC,eAAe,oBAAoB,CAAC"}

View File

@@ -0,0 +1,4 @@
import { requireNativeViewManager } from 'expo-modules-core';
const NativeLinearGradient = requireNativeViewManager('ExpoLinearGradient');
export default NativeLinearGradient;
//# sourceMappingURL=NativeLinearGradient.ios.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"NativeLinearGradient.ios.js","sourceRoot":"","sources":["../src/NativeLinearGradient.ios.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,wBAAwB,EAAE,MAAM,mBAAmB,CAAC;AAK7D,MAAM,oBAAoB,GAAG,wBAAwB,CACnD,oBAAoB,CACkB,CAAC;AAEzC,eAAe,oBAAoB,CAAC","sourcesContent":["import { requireNativeViewManager } from 'expo-modules-core';\nimport * as React from 'react';\n\nimport { NativeLinearGradientProps } from './NativeLinearGradient.types';\n\nconst NativeLinearGradient = requireNativeViewManager(\n 'ExpoLinearGradient'\n) as React.FC<NativeLinearGradientProps>;\n\nexport default NativeLinearGradient;\n"]}

View File

@@ -0,0 +1,10 @@
import * as React from 'react';
import { View } from 'react-native';
// This is a shim view for platforms that aren't supported by Expo.
// The component and prop types should match all of the other platform variations.
export default function NativeLinearGradient(props) {
const { colors, locations, startPoint, endPoint, ...viewProps } = props;
console.warn('LinearGradient is not available on this platform');
return <View {...viewProps}/>;
}
//# sourceMappingURL=NativeLinearGradient.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"NativeLinearGradient.js","sourceRoot":"","sources":["../src/NativeLinearGradient.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAC/B,OAAO,EAAE,IAAI,EAAE,MAAM,cAAc,CAAC;AAIpC,mEAAmE;AACnE,kFAAkF;AAClF,MAAM,CAAC,OAAO,UAAU,oBAAoB,CAAC,KAAgC;IAC3E,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,UAAU,EAAE,QAAQ,EAAE,GAAG,SAAS,EAAE,GAAG,KAAK,CAAC;IACxE,OAAO,CAAC,IAAI,CAAC,kDAAkD,CAAC,CAAC;IACjE,OAAO,CAAC,IAAI,CAAC,IAAK,SAAiB,CAAC,EAAG,CAAC;AAC1C,CAAC","sourcesContent":["import * as React from 'react';\nimport { View } from 'react-native';\n\nimport { NativeLinearGradientProps } from './NativeLinearGradient.types';\n\n// This is a shim view for platforms that aren't supported by Expo.\n// The component and prop types should match all of the other platform variations.\nexport default function NativeLinearGradient(props: NativeLinearGradientProps): React.ReactElement {\n const { colors, locations, startPoint, endPoint, ...viewProps } = props;\n console.warn('LinearGradient is not available on this platform');\n return <View {...(viewProps as any)} />;\n}\n"]}

View File

@@ -0,0 +1,12 @@
import { PropsWithChildren } from 'react';
import { ViewProps } from 'react-native';
export type NativeLinearGradientProps = ViewProps & PropsWithChildren<{
colors: readonly number[];
locations?: readonly number[] | null;
startPoint?: NativeLinearGradientPoint | null;
endPoint?: NativeLinearGradientPoint | null;
dither?: boolean;
}>;
export type getLinearGradientBackgroundImage = (colors: readonly number[], width?: number, height?: number, locations?: readonly number[] | null, startPoint?: NativeLinearGradientPoint | null, endPoint?: NativeLinearGradientPoint | null) => string;
export type NativeLinearGradientPoint = [number, number];
//# sourceMappingURL=NativeLinearGradient.types.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"NativeLinearGradient.types.d.ts","sourceRoot":"","sources":["../src/NativeLinearGradient.types.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,OAAO,CAAC;AAC1C,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAEzC,MAAM,MAAM,yBAAyB,GAAG,SAAS,GAC/C,iBAAiB,CAAC;IAChB,MAAM,EAAE,SAAS,MAAM,EAAE,CAAC;IAC1B,SAAS,CAAC,EAAE,SAAS,MAAM,EAAE,GAAG,IAAI,CAAC;IACrC,UAAU,CAAC,EAAE,yBAAyB,GAAG,IAAI,CAAC;IAC9C,QAAQ,CAAC,EAAE,yBAAyB,GAAG,IAAI,CAAC;IAC5C,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB,CAAC,CAAC;AAEL,MAAM,MAAM,gCAAgC,GAAG,CAC7C,MAAM,EAAE,SAAS,MAAM,EAAE,EACzB,KAAK,CAAC,EAAE,MAAM,EACd,MAAM,CAAC,EAAE,MAAM,EACf,SAAS,CAAC,EAAE,SAAS,MAAM,EAAE,GAAG,IAAI,EACpC,UAAU,CAAC,EAAE,yBAAyB,GAAG,IAAI,EAC7C,QAAQ,CAAC,EAAE,yBAAyB,GAAG,IAAI,KACxC,MAAM,CAAC;AAEZ,MAAM,MAAM,yBAAyB,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC"}

View File

@@ -0,0 +1,2 @@
export {};
//# sourceMappingURL=NativeLinearGradient.types.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"NativeLinearGradient.types.js","sourceRoot":"","sources":["../src/NativeLinearGradient.types.ts"],"names":[],"mappings":"","sourcesContent":["import { PropsWithChildren } from 'react';\nimport { ViewProps } from 'react-native';\n\nexport type NativeLinearGradientProps = ViewProps &\n PropsWithChildren<{\n colors: readonly number[];\n locations?: readonly number[] | null;\n startPoint?: NativeLinearGradientPoint | null;\n endPoint?: NativeLinearGradientPoint | null;\n dither?: boolean;\n }>;\n\nexport type getLinearGradientBackgroundImage = (\n colors: readonly number[],\n width?: number,\n height?: number,\n locations?: readonly number[] | null,\n startPoint?: NativeLinearGradientPoint | null,\n endPoint?: NativeLinearGradientPoint | null\n) => string;\n\nexport type NativeLinearGradientPoint = [number, number];\n"]}

View File

@@ -0,0 +1,8 @@
import * as React from 'react';
import { NativeLinearGradientPoint, NativeLinearGradientProps } from './NativeLinearGradient.types';
export default function NativeLinearGradient({ colors, locations, startPoint, endPoint, ...props }: NativeLinearGradientProps): React.ReactElement;
/**
* Extracted to a separate function in order to be able to test logic independently.
*/
export declare function getLinearGradientBackgroundImage(colors: readonly number[] | string[], locations?: readonly number[] | null, startPoint?: NativeLinearGradientPoint | null, endPoint?: NativeLinearGradientPoint | null, width?: number, height?: number): string;
//# sourceMappingURL=NativeLinearGradient.web.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"NativeLinearGradient.web.d.ts","sourceRoot":"","sources":["../src/NativeLinearGradient.web.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAG/B,OAAO,EAAE,yBAAyB,EAAE,yBAAyB,EAAE,MAAM,8BAA8B,CAAC;AAGpG,MAAM,CAAC,OAAO,UAAU,oBAAoB,CAAC,EAC3C,MAAM,EACN,SAAS,EACT,UAAU,EACV,QAAQ,EACR,GAAG,KAAK,EACT,EAAE,yBAAyB,GAAG,KAAK,CAAC,YAAY,CAsChD;AAED;;GAEG;AACH,wBAAgB,gCAAgC,CAC9C,MAAM,EAAE,SAAS,MAAM,EAAE,GAAG,MAAM,EAAE,EACpC,SAAS,CAAC,EAAE,SAAS,MAAM,EAAE,GAAG,IAAI,EACpC,UAAU,CAAC,EAAE,yBAAyB,GAAG,IAAI,EAC7C,QAAQ,CAAC,EAAE,yBAAyB,GAAG,IAAI,EAC3C,KAAK,GAAE,MAAU,EACjB,MAAM,GAAE,MAAU,UAKnB"}

View File

@@ -0,0 +1,79 @@
import * as React from 'react';
import { View } from 'react-native';
import { normalizeColor } from './normalizeColor';
export default function NativeLinearGradient({ colors, locations, startPoint, endPoint, ...props }) {
const [{ height, width }, setLayout] = React.useState({
height: 1,
width: 1,
});
// TODO(Bacon): In the future we could consider adding `backgroundRepeat: "no-repeat"`. For more
// browser support.
const linearGradientBackgroundImage = React.useMemo(() => {
return getLinearGradientBackgroundImage(colors, locations, startPoint, endPoint, width, height);
}, [colors, locations, startPoint, endPoint, width, height]);
return (<View {...props} style={[
props.style,
// @ts-ignore: [ts] Property 'backgroundImage' does not exist on type 'ViewStyle'.
{ backgroundImage: linearGradientBackgroundImage },
]} onLayout={(event) => {
const { width, height } = event.nativeEvent.layout;
setLayout((oldLayout) => {
// don't set new layout state unless the layout has actually changed
if (width !== oldLayout.width || height !== oldLayout.height) {
return { height, width };
}
return oldLayout;
});
if (props.onLayout) {
props.onLayout(event);
}
}}/>);
}
/**
* Extracted to a separate function in order to be able to test logic independently.
*/
export function getLinearGradientBackgroundImage(colors, locations, startPoint, endPoint, width = 1, height = 1) {
const gradientColors = calculateGradientColors(colors, locations);
const angle = calculatePseudoAngle(width, height, startPoint, endPoint);
return `linear-gradient(${angle}deg, ${gradientColors.join(', ')})`;
}
function calculatePseudoAngle(width, height, startPoint, endPoint) {
const getControlPoints = () => {
let correctedStartPoint = [0, 0];
if (Array.isArray(startPoint)) {
correctedStartPoint = [
startPoint[0] != null ? startPoint[0] : 0.0,
startPoint[1] != null ? startPoint[1] : 0.0,
];
}
let correctedEndPoint = [0.0, 1.0];
if (Array.isArray(endPoint)) {
correctedEndPoint = [
endPoint[0] != null ? endPoint[0] : 0.0,
endPoint[1] != null ? endPoint[1] : 1.0,
];
}
return [correctedStartPoint, correctedEndPoint];
};
const [start, end] = getControlPoints();
start[0] *= width;
end[0] *= width;
start[1] *= height;
end[1] *= height;
const py = end[1] - start[1];
const px = end[0] - start[0];
return 90 + (Math.atan2(py, px) * 180) / Math.PI;
}
function calculateGradientColors(colors, locations) {
return colors.map((color, index) => {
const output = normalizeColor(color);
if (locations && locations[index]) {
const location = Math.max(0, Math.min(1, locations[index]));
// Convert 0...1 to 0...100
const percentage = location * 100;
return `${output} ${percentage}%`;
}
return output;
});
}
//# sourceMappingURL=NativeLinearGradient.web.js.map

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,2 @@
export declare function normalizeColor(color?: number | string, opacity?: number): void | string;
//# sourceMappingURL=normalizeColor.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"normalizeColor.d.ts","sourceRoot":"","sources":["../src/normalizeColor.ts"],"names":[],"mappings":"AAeA,wBAAgB,cAAc,CAAC,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,OAAO,GAAE,MAAU,GAAG,IAAI,GAAG,MAAM,CAgB1F"}

View File

@@ -0,0 +1,29 @@
/**
* Copyright (c) Expo.
* Copyright (c) Nicolas Gallagher.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
import { processColor } from 'react-native';
const isWebColor = (color) => color === 'currentcolor' ||
color === 'currentColor' ||
color === 'inherit' ||
color.indexOf('var(') === 0;
export function normalizeColor(color, opacity = 1) {
if (color == null)
return;
if (typeof color === 'string' && isWebColor(color)) {
return color;
}
const colorInt = processColor(color);
if (colorInt != null) {
const r = (colorInt >> 16) & 255;
const g = (colorInt >> 8) & 255;
const b = colorInt & 255;
const a = ((colorInt >> 24) & 255) / 255;
const alpha = (a * opacity).toFixed(2);
return `rgba(${r},${g},${b},${alpha})`;
}
}
//# sourceMappingURL=normalizeColor.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"normalizeColor.js","sourceRoot":"","sources":["../src/normalizeColor.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAE5C,MAAM,UAAU,GAAG,CAAC,KAAa,EAAW,EAAE,CAC5C,KAAK,KAAK,cAAc;IACxB,KAAK,KAAK,cAAc;IACxB,KAAK,KAAK,SAAS;IACnB,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;AAE9B,MAAM,UAAU,cAAc,CAAC,KAAuB,EAAE,UAAkB,CAAC;IACzE,IAAI,KAAK,IAAI,IAAI;QAAE,OAAO;IAE1B,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,UAAU,CAAC,KAAK,CAAC,EAAE;QAClD,OAAO,KAAK,CAAC;KACd;IAED,MAAM,QAAQ,GAAG,YAAY,CAAC,KAAK,CAAuB,CAAC;IAC3D,IAAI,QAAQ,IAAI,IAAI,EAAE;QACpB,MAAM,CAAC,GAAG,CAAC,QAAQ,IAAI,EAAE,CAAC,GAAG,GAAG,CAAC;QACjC,MAAM,CAAC,GAAG,CAAC,QAAQ,IAAI,CAAC,CAAC,GAAG,GAAG,CAAC;QAChC,MAAM,CAAC,GAAG,QAAQ,GAAG,GAAG,CAAC;QACzB,MAAM,CAAC,GAAG,CAAC,CAAC,QAAQ,IAAI,EAAE,CAAC,GAAG,GAAG,CAAC,GAAG,GAAG,CAAC;QACzC,MAAM,KAAK,GAAG,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;QACvC,OAAO,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,KAAK,GAAG,CAAC;KACxC;AACH,CAAC","sourcesContent":["/**\n * Copyright (c) Expo.\n * Copyright (c) Nicolas Gallagher.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n */\nimport { processColor } from 'react-native';\n\nconst isWebColor = (color: string): boolean =>\n color === 'currentcolor' ||\n color === 'currentColor' ||\n color === 'inherit' ||\n color.indexOf('var(') === 0;\n\nexport function normalizeColor(color?: number | string, opacity: number = 1): void | string {\n if (color == null) return;\n\n if (typeof color === 'string' && isWebColor(color)) {\n return color;\n }\n\n const colorInt = processColor(color) as number | undefined;\n if (colorInt != null) {\n const r = (colorInt >> 16) & 255;\n const g = (colorInt >> 8) & 255;\n const b = colorInt & 255;\n const a = ((colorInt >> 24) & 255) / 255;\n const alpha = (a * opacity).toFixed(2);\n return `rgba(${r},${g},${b},${alpha})`;\n }\n}\n"]}

View File

@@ -0,0 +1,10 @@
{
"name": "expo-linear-gradient",
"platforms": ["ios", "tvos", "android"],
"ios": {
"modulesClassNames": ["LinearGradientModule"]
},
"android": {
"modulesClassNames": ["expo.modules.lineargradient.LinearGradientModule"]
}
}

View File

@@ -0,0 +1,32 @@
require 'json'
package = JSON.parse(File.read(File.join(__dir__, '..', 'package.json')))
Pod::Spec.new do |s|
s.name = 'ExpoLinearGradient'
s.version = package['version']
s.summary = package['description']
s.description = package['description']
s.license = package['license']
s.author = package['author']
s.homepage = package['homepage']
s.platforms = { :ios => '13.4', :tvos => '13.4' }
s.swift_version = '5.4'
s.source = { git: 'https://github.com/expo/expo.git' }
s.static_framework = true
s.dependency 'ExpoModulesCore'
# Swift/Objective-C compatibility
s.pod_target_xcconfig = {
'DEFINES_MODULE' => 'YES',
'SWIFT_COMPILATION_MODE' => 'wholemodule'
}
if !$ExpoUseSources&.include?(package['name']) && ENV['EXPO_USE_SOURCE'].to_i == 0 && File.exist?("#{s.name}.xcframework") && Gem::Version.new(Pod::VERSION) >= Gem::Version.new('1.10.0')
s.source_files = "**/*.h"
s.vendored_frameworks = "#{s.name}.xcframework"
else
s.source_files = "**/*.{h,m,swift}"
end
end

View File

@@ -0,0 +1,107 @@
// Copyright 2021-present 650 Industries. All rights reserved.
import QuartzCore
import CoreGraphics
var defaultStartPoint = CGPoint(x: 0.5, y: 0.0)
var defaultEndPoint = CGPoint(x: 0.5, y: 1.0)
var defaultLocations: [CGFloat] = []
final class LinearGradientLayer: CALayer {
var colors = [CGColor]()
var startPoint = defaultStartPoint
var endPoint = defaultEndPoint
var locations = defaultLocations
override init() {
super.init()
self.needsDisplayOnBoundsChange = true
self.masksToBounds = true
}
override init(layer: Any) {
super.init(layer: layer)
self.needsDisplayOnBoundsChange = true
self.masksToBounds = true
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
func setColors(_ colors: [CGColor]) {
self.colors = colors
setNeedsDisplay()
}
func setStartPoint(_ startPoint: CGPoint?) {
self.startPoint = startPoint ?? defaultStartPoint
setNeedsDisplay()
}
func setEndPoint(_ endPoint: CGPoint?) {
self.endPoint = endPoint ?? defaultEndPoint
setNeedsDisplay()
}
func setLocations(_ locations: [CGFloat]?) {
self.locations = locations ?? defaultLocations
setNeedsDisplay()
}
override func display() {
super.display()
if colors.isEmpty || bounds.size.width.isZero || bounds.size.height.isZero {
return
}
let hasAlpha = colors.reduce(false) { result, color in
return result || color.alpha < 1.0
}
UIGraphicsBeginImageContextWithOptions(bounds.size, !hasAlpha, 0.0)
guard let contextRef = UIGraphicsGetCurrentContext() else {
return
}
draw(in: contextRef)
guard let image = UIGraphicsGetImageFromCurrentImageContext() else {
return
}
self.contents = image.cgImage
self.contentsScale = image.scale
UIGraphicsEndImageContext()
}
override func draw(in ctx: CGContext) {
super.draw(in: ctx)
ctx.saveGState()
let colorSpace = CGColorSpaceCreateDeviceRGB()
let locations = colors.enumerated().map { (offset: Int, _: CGColor) -> CGFloat in
if self.locations.count > offset {
return self.locations[offset]
} else {
return CGFloat(offset) / CGFloat(colors.count - 1)
}
}
if let gradient = CGGradient(colorsSpace: colorSpace, colors: colors as CFArray, locations: locations) {
let size = bounds.size
ctx.drawLinearGradient(
gradient,
start: CGPoint(x: startPoint.x * size.width, y: startPoint.y * size.height),
end: CGPoint(x: endPoint.x * size.width, y: endPoint.y * size.height),
options: [.drawsBeforeStartLocation, .drawsAfterEndLocation]
)
}
ctx.restoreGState()
}
}

View File

@@ -0,0 +1,28 @@
// Copyright 2021-present 650 Industries. All rights reserved.
import CoreGraphics
import ExpoModulesCore
public class LinearGradientModule: Module {
public func definition() -> ModuleDefinition {
Name("ExpoLinearGradient")
View(LinearGradientView.self) {
Prop("colors") { (view: LinearGradientView, colors: [CGColor]) in
view.gradientLayer.setColors(colors)
}
Prop("startPoint") { (view: LinearGradientView, startPoint: CGPoint?) in
view.gradientLayer.setStartPoint(startPoint)
}
Prop("endPoint") { (view: LinearGradientView, endPoint: CGPoint?) in
view.gradientLayer.setEndPoint(endPoint)
}
Prop("locations") { (view: LinearGradientView, locations: [CGFloat]?) in
view.gradientLayer.setLocations(locations)
}
}
}
}

View File

@@ -0,0 +1,14 @@
// Copyright 2021-present 650 Industries. All rights reserved.
import UIKit
import ExpoModulesCore
final class LinearGradientView: ExpoView {
override class var layerClass: AnyClass {
return LinearGradientLayer.self
}
public var gradientLayer: LinearGradientLayer {
return layer as! LinearGradientLayer
}
}

View File

@@ -0,0 +1,46 @@
{
"name": "expo-linear-gradient",
"version": "13.0.2",
"description": "Provides a React component that renders a gradient view.",
"main": "build/LinearGradient.js",
"types": "build/LinearGradient.d.ts",
"sideEffects": false,
"scripts": {
"build": "expo-module build",
"clean": "expo-module clean",
"lint": "expo-module lint",
"test": "expo-module test",
"prepare": "expo-module prepare",
"prepublishOnly": "expo-module prepublishOnly",
"expo-module": "expo-module"
},
"keywords": [
"react-native",
"expo",
"gradient"
],
"jest": {
"preset": "expo-module-scripts"
},
"repository": {
"type": "git",
"url": "https://github.com/expo/expo.git",
"directory": "packages/expo-linear-gradient"
},
"bugs": {
"url": "https://github.com/expo/expo/issues"
},
"author": "650 Industries, Inc.",
"license": "MIT",
"homepage": "https://docs.expo.dev/versions/latest/sdk/linear-gradient/",
"devDependencies": {
"@testing-library/jest-dom": "^5.16.5",
"@testing-library/react": "^13.4.0",
"@testing-library/react-native": "^11.3.0",
"expo-module-scripts": "^3.0.0"
},
"peerDependencies": {
"expo": "*"
},
"gitHead": "470464ab5c25ae8bd45eb2a94d221ce51a8b2560"
}

View File

@@ -0,0 +1,116 @@
// Copyright © 2024 650 Industries.
'use client';
import * as React from 'react';
import { Platform, processColor, ViewProps } from 'react-native';
import NativeLinearGradient from './NativeLinearGradient';
import { NativeLinearGradientPoint } from './NativeLinearGradient.types';
// @needsAudit
/**
* An object `{ x: number; y: number }` or array `[x, y]` that represents the point
* at which the gradient starts or ends, as a fraction of the overall size of the gradient ranging
* from `0` to `1`, inclusive.
*/
export type LinearGradientPoint =
| {
/**
* A number ranging from `0` to `1`, representing the position of gradient transformation.
*/
x: number;
/**
* A number ranging from `0` to `1`, representing the position of gradient transformation.
*/
y: number;
}
| NativeLinearGradientPoint;
// @needsAudit
export type LinearGradientProps = ViewProps & {
/**
* A readonly array of colors that represent stops in the gradient. At least two colors are required
* (for a single-color background, use the `style.backgroundColor` prop on a `View` component).
*/
colors: readonly string[];
/**
* A readonly array that contains `number`s ranging from `0` to `1`, inclusive, and is the same length as the `colors` property.
* Each number indicates a color-stop location where each respective color should be located.
* If not specified, the colors will be distributed evenly across the gradient.
*
* For example, `[0.5, 0.8]` would render:
* - the first color, solid, from the beginning of the gradient view to 50% through (the middle);
* - a gradient from the first color to the second from the 50% point to the 80% point; and
* - the second color, solid, from the 80% point to the end of the gradient view.
*
* > The color-stop locations must be ascending from least to greatest.
* @default []
*/
locations?: readonly number[] | null;
/**
* For example, `{ x: 0.1, y: 0.2 }` means that the gradient will start `10%` from the left and `20%` from the top.
*
* **On web**, this only changes the angle of the gradient because CSS gradients don't support changing the starting position.
* @default { x: 0.5, y: 0.0 }
*/
start?: LinearGradientPoint | null;
/**
* For example, `{ x: 0.1, y: 0.2 }` means that the gradient will end `10%` from the left and `20%` from the bottom.
*
* **On web**, this only changes the angle of the gradient because CSS gradients don't support changing the end position.
* @default { x: 0.5, y: 1.0 }
*/
end?: LinearGradientPoint | null;
/**
* Enables or disables paint dithering. Dithering can reduce the gradient color banding issue.
* Setting `false` may improve gradient rendering performance.
* @default true
* @platform android
*/
dither?: boolean;
};
/**
* Renders a native view that transitions between multiple colors in a linear direction.
*/
export class LinearGradient extends React.Component<LinearGradientProps> {
render() {
const { colors, locations, start, end, dither, ...props } = this.props;
let resolvedLocations = locations;
if (locations && colors.length !== locations.length) {
console.warn('LinearGradient colors and locations props should be arrays of the same length');
resolvedLocations = locations.slice(0, colors.length);
}
return (
<NativeLinearGradient
{...props}
colors={Platform.select({
web: colors as any,
default: colors.map(processColor),
})}
dither={Platform.select({ android: dither })}
locations={resolvedLocations}
startPoint={_normalizePoint(start)}
endPoint={_normalizePoint(end)}
/>
);
}
}
function _normalizePoint(
point: LinearGradientPoint | null | undefined
): NativeLinearGradientPoint | undefined {
if (!point) {
return undefined;
}
if (Array.isArray(point) && point.length !== 2) {
console.warn('start and end props for LinearGradient must be of the format [x,y] or {x, y}');
return undefined;
}
return Array.isArray(point) ? point : [point.x, point.y];
}

View File

@@ -0,0 +1,51 @@
import { requireNativeViewManager } from 'expo-modules-core';
import * as React from 'react';
import { StyleSheet, View } from 'react-native';
import { NativeLinearGradientProps } from './NativeLinearGradient.types';
export default function NativeLinearGradient({
colors,
locations,
startPoint,
endPoint,
children,
style,
dither,
...props
}: NativeLinearGradientProps): React.ReactElement {
// TODO: revisit whether we need to inherit the container's borderRadius since this issue has
// been resolved: https://github.com/facebook/react-native/issues/3198
const flatStyle = StyleSheet.flatten(style) ?? {};
const borderRadius = flatStyle.borderRadius ?? 0;
// This is the format from:
// https://developer.android.com/reference/android/graphics/Path.html#addRoundRect(android.graphics.RectF,%20float[],%20android.graphics.Path.Direction)
const borderRadiiPerCorner = [
flatStyle.borderTopLeftRadius ?? borderRadius,
flatStyle.borderTopLeftRadius ?? borderRadius,
flatStyle.borderTopRightRadius ?? borderRadius,
flatStyle.borderTopRightRadius ?? borderRadius,
flatStyle.borderBottomRightRadius ?? borderRadius,
flatStyle.borderBottomRightRadius ?? borderRadius,
flatStyle.borderBottomLeftRadius ?? borderRadius,
flatStyle.borderBottomLeftRadius ?? borderRadius,
];
return (
<View {...props} style={style}>
<BaseNativeLinearGradient
style={StyleSheet.absoluteFill}
colors={colors}
startPoint={startPoint}
endPoint={endPoint}
locations={locations}
borderRadii={borderRadiiPerCorner}
dither={dither}
/>
{children}
</View>
);
}
const BaseNativeLinearGradient = requireNativeViewManager('ExpoLinearGradient');

View File

@@ -0,0 +1,10 @@
import { requireNativeViewManager } from 'expo-modules-core';
import * as React from 'react';
import { NativeLinearGradientProps } from './NativeLinearGradient.types';
const NativeLinearGradient = requireNativeViewManager(
'ExpoLinearGradient'
) as React.FC<NativeLinearGradientProps>;
export default NativeLinearGradient;

View File

@@ -0,0 +1,12 @@
import * as React from 'react';
import { View } from 'react-native';
import { NativeLinearGradientProps } from './NativeLinearGradient.types';
// This is a shim view for platforms that aren't supported by Expo.
// The component and prop types should match all of the other platform variations.
export default function NativeLinearGradient(props: NativeLinearGradientProps): React.ReactElement {
const { colors, locations, startPoint, endPoint, ...viewProps } = props;
console.warn('LinearGradient is not available on this platform');
return <View {...(viewProps as any)} />;
}

View File

@@ -0,0 +1,22 @@
import { PropsWithChildren } from 'react';
import { ViewProps } from 'react-native';
export type NativeLinearGradientProps = ViewProps &
PropsWithChildren<{
colors: readonly number[];
locations?: readonly number[] | null;
startPoint?: NativeLinearGradientPoint | null;
endPoint?: NativeLinearGradientPoint | null;
dither?: boolean;
}>;
export type getLinearGradientBackgroundImage = (
colors: readonly number[],
width?: number,
height?: number,
locations?: readonly number[] | null,
startPoint?: NativeLinearGradientPoint | null,
endPoint?: NativeLinearGradientPoint | null
) => string;
export type NativeLinearGradientPoint = [number, number];

View File

@@ -0,0 +1,118 @@
import * as React from 'react';
import { View } from 'react-native';
import { NativeLinearGradientPoint, NativeLinearGradientProps } from './NativeLinearGradient.types';
import { normalizeColor } from './normalizeColor';
export default function NativeLinearGradient({
colors,
locations,
startPoint,
endPoint,
...props
}: NativeLinearGradientProps): React.ReactElement {
const [{ height, width }, setLayout] = React.useState({
height: 1,
width: 1,
});
// TODO(Bacon): In the future we could consider adding `backgroundRepeat: "no-repeat"`. For more
// browser support.
const linearGradientBackgroundImage = React.useMemo(() => {
return getLinearGradientBackgroundImage(colors, locations, startPoint, endPoint, width, height);
}, [colors, locations, startPoint, endPoint, width, height]);
return (
<View
{...props}
style={[
props.style,
// @ts-ignore: [ts] Property 'backgroundImage' does not exist on type 'ViewStyle'.
{ backgroundImage: linearGradientBackgroundImage },
]}
onLayout={(event) => {
const { width, height } = event.nativeEvent.layout;
setLayout((oldLayout) => {
// don't set new layout state unless the layout has actually changed
if (width !== oldLayout.width || height !== oldLayout.height) {
return { height, width };
}
return oldLayout;
});
if (props.onLayout) {
props.onLayout(event);
}
}}
/>
);
}
/**
* Extracted to a separate function in order to be able to test logic independently.
*/
export function getLinearGradientBackgroundImage(
colors: readonly number[] | string[],
locations?: readonly number[] | null,
startPoint?: NativeLinearGradientPoint | null,
endPoint?: NativeLinearGradientPoint | null,
width: number = 1,
height: number = 1
) {
const gradientColors = calculateGradientColors(colors, locations);
const angle = calculatePseudoAngle(width, height, startPoint, endPoint);
return `linear-gradient(${angle}deg, ${gradientColors.join(', ')})`;
}
function calculatePseudoAngle(
width: number,
height: number,
startPoint?: NativeLinearGradientPoint | null,
endPoint?: NativeLinearGradientPoint | null
) {
const getControlPoints = (): NativeLinearGradientPoint[] => {
let correctedStartPoint: NativeLinearGradientPoint = [0, 0];
if (Array.isArray(startPoint)) {
correctedStartPoint = [
startPoint[0] != null ? startPoint[0] : 0.0,
startPoint[1] != null ? startPoint[1] : 0.0,
];
}
let correctedEndPoint: NativeLinearGradientPoint = [0.0, 1.0];
if (Array.isArray(endPoint)) {
correctedEndPoint = [
endPoint[0] != null ? endPoint[0] : 0.0,
endPoint[1] != null ? endPoint[1] : 1.0,
];
}
return [correctedStartPoint, correctedEndPoint];
};
const [start, end] = getControlPoints();
start[0] *= width;
end[0] *= width;
start[1] *= height;
end[1] *= height;
const py = end[1] - start[1];
const px = end[0] - start[0];
return 90 + (Math.atan2(py, px) * 180) / Math.PI;
}
function calculateGradientColors(
colors: readonly number[] | string[],
locations?: readonly number[] | null
) {
return colors.map((color: number | string, index: number): string | void => {
const output = normalizeColor(color);
if (locations && locations[index]) {
const location = Math.max(0, Math.min(1, locations[index]));
// Convert 0...1 to 0...100
const percentage = location * 100;
return `${output} ${percentage}%`;
}
return output;
});
}

View File

@@ -0,0 +1,32 @@
/**
* Copyright (c) Expo.
* Copyright (c) Nicolas Gallagher.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
import { processColor } from 'react-native';
const isWebColor = (color: string): boolean =>
color === 'currentcolor' ||
color === 'currentColor' ||
color === 'inherit' ||
color.indexOf('var(') === 0;
export function normalizeColor(color?: number | string, opacity: number = 1): void | string {
if (color == null) return;
if (typeof color === 'string' && isWebColor(color)) {
return color;
}
const colorInt = processColor(color) as number | undefined;
if (colorInt != null) {
const r = (colorInt >> 16) & 255;
const g = (colorInt >> 8) & 255;
const b = colorInt & 255;
const a = ((colorInt >> 24) & 255) / 255;
const alpha = (a * opacity).toFixed(2);
return `rgba(${r},${g},${b},${alpha})`;
}
}

View File

@@ -0,0 +1,9 @@
// @generated by expo-module-scripts
{
"extends": "expo-module-scripts/tsconfig.base",
"compilerOptions": {
"outDir": "./build"
},
"include": ["./src"],
"exclude": ["**/__mocks__/*", "**/__tests__/*"]
}