Skip to content

Commit

Permalink
Init package
Browse files Browse the repository at this point in the history
  • Loading branch information
wilmxre committed Jul 29, 2024
1 parent 92ba3bf commit c25c0c0
Show file tree
Hide file tree
Showing 50 changed files with 295 additions and 28 deletions.
Empty file modified .editorconfig
100644 → 100755
Empty file.
Empty file modified .gitattributes
100644 → 100755
Empty file.
Empty file modified .github/actions/setup/action.yml
100644 → 100755
Empty file.
Empty file modified .github/workflows/ci.yml
100644 → 100755
Empty file.
Empty file modified .gitignore
100644 → 100755
Empty file.
Empty file modified .nvmrc
100644 → 100755
Empty file.
Empty file modified .watchmanconfig
100644 → 100755
Empty file.
Empty file modified .yarn/plugins/@yarnpkg/plugin-interactive-tools.cjs
100644 → 100755
Empty file.
Empty file modified .yarn/plugins/@yarnpkg/plugin-workspace-tools.cjs
100644 → 100755
Empty file.
Empty file modified .yarnrc.yml
100644 → 100755
Empty file.
Empty file modified CODE_OF_CONDUCT.md
100644 → 100755
Empty file.
Empty file modified CONTRIBUTING.md
100644 → 100755
Empty file.
Empty file modified LICENSE
100644 → 100755
Empty file.
Empty file modified README.md
100644 → 100755
Empty file.
Empty file modified android/build.gradle
100644 → 100755
Empty file.
Empty file modified android/gradle.properties
100644 → 100755
Empty file.
Empty file modified android/src/main/AndroidManifest.xml
100644 → 100755
Empty file.
Empty file modified android/src/main/AndroidManifestNew.xml
100644 → 100755
Empty file.
Empty file modified android/src/main/java/com/meshgradient/MeshGradientPackage.kt
100644 → 100755
Empty file.
Empty file.
Empty file modified babel.config.js
100644 → 100755
Empty file.
Empty file modified example/.watchmanconfig
100644 → 100755
Empty file.
Empty file modified example/android/build.gradle
100644 → 100755
Empty file.
Empty file modified example/android/gradle.properties
100644 → 100755
Empty file.
Empty file modified example/android/gradle/wrapper/gradle-wrapper.jar
100644 → 100755
Empty file.
Empty file modified example/android/gradle/wrapper/gradle-wrapper.properties
100644 → 100755
Empty file.
Empty file modified example/android/gradlew.bat
100644 → 100755
Empty file.
Empty file modified example/android/settings.gradle
100644 → 100755
Empty file.
Empty file modified example/app.json
100644 → 100755
Empty file.
Empty file modified example/babel.config.js
100644 → 100755
Empty file.
Empty file modified example/index.js
100644 → 100755
Empty file.
Empty file modified example/ios/File.swift
100644 → 100755
Empty file.
Empty file modified example/ios/MeshGradientExample-Bridging-Header.h
100644 → 100755
Empty file.
Empty file modified example/ios/Podfile
100644 → 100755
Empty file.
Empty file modified example/metro.config.js
100644 → 100755
Empty file.
Empty file modified example/package.json
100644 → 100755
Empty file.
Empty file modified example/react-native.config.js
100644 → 100755
Empty file.
Empty file modified example/src/App.tsx
100644 → 100755
Empty file.
Empty file modified ios/MeshGradient-Bridging-Header.h
100644 → 100755
Empty file.
102 changes: 102 additions & 0 deletions ios/MeshGradientView.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
//
// MeshGradientView.swift
// reactnativemeshgradient
//
// Created by wilmxre on 27.07.2024.
//

import ExpoModulesCore
import SwiftUI

@available(iOS 16.0, *)
struct MeshGradientView: View {
var meshWidth: Int
var meshHeight: Int
var points: [SIMD2<Float>]
var primaryColors: [Color]
var secondaryColors: [Color]
var background: Color = .clear
var smoothsColors: Bool
var colorSpace: Gradient.ColorSpace
var borderRadius: CGFloat
var isAnimated: Bool
var animationDuration: TimeInterval
var animationType: String

@State private var isAnimating = false

@State var t: Float = 0.0
@State var timer: Timer?

var body: some View {
ZStack {
if #available(iOS 18.0, *) {
MeshGradient(
width: meshWidth,
height: meshHeight,
points: animationType == "sine"
? [
.init(0, 0), .init(0.5, 0), .init(1, 0),
[
sinInRange(
-0.8...(-0.2), offset: 0.439, timeScale: 0.342, t: t),
sinInRange(0.3...0.7, offset: 3.42, timeScale: 0.984, t: t),
],
[
sinInRange(0.1...0.8, offset: 0.239, timeScale: 0.084, t: t),
sinInRange(0.2...0.8, offset: 5.21, timeScale: 0.242, t: t),
],
[
sinInRange(1.0...1.5, offset: 0.939, timeScale: 0.084, t: t),
sinInRange(0.4...0.8, offset: 0.25, timeScale: 0.642, t: t),
],
[
sinInRange(-0.8...0.0, offset: 1.439, timeScale: 0.442, t: t),
sinInRange(1.4...1.9, offset: 3.42, timeScale: 0.984, t: t),
],
[
sinInRange(0.3...0.6, offset: 0.339, timeScale: 0.784, t: t),
sinInRange(1.0...1.2, offset: 1.22, timeScale: 0.772, t: t),
],
[
sinInRange(1.0...1.5, offset: 0.939, timeScale: 0.056, t: t),
sinInRange(1.3...1.7, offset: 0.47, timeScale: 0.342, t: t),
],
] : points,
colors: isAnimating ? secondaryColors : primaryColors,
background: background,
smoothsColors: smoothsColors,
colorSpace: colorSpace
)
.cornerRadius(borderRadius)
.onAppear {
if isAnimated {
animationType == "sine"
? timer = Timer.scheduledTimer(
withTimeInterval: 0.01, repeats: true
) { _ in
t += 0.02
}
: withAnimation(
.easeInOut(duration: animationDuration).repeatForever(
autoreverses: true)
) {
isAnimating.toggle()
}
}
}
} else {
Text("MeshGradient is not available on this version of iOS.")
}
}

}
}

func sinInRange(
_ range: ClosedRange<Float>, offset: Float, timeScale: Float, t: Float
) -> Float {
let amplitude = (range.upperBound - range.lowerBound) / 2
let midPoint = (range.upperBound + range.lowerBound) / 2
return midPoint + amplitude * sin(timeScale * t + offset)
}
22 changes: 20 additions & 2 deletions ios/MeshGradientViewManager.m
100644 → 100755
Original file line number Diff line number Diff line change
@@ -1,7 +1,25 @@
//
// MeshGradient.m
// reactnativemeshgradient
//
// Created by wilmxore on 27.07.2024.
//

#import <React/RCTViewManager.h>

@interface RCT_EXTERN_MODULE(MeshGradientViewManager, RCTViewManager)

RCT_EXPORT_VIEW_PROPERTY(color, NSString)
RCT_EXPORT_VIEW_PROPERTY(isAnimated, BOOL)
RCT_EXPORT_VIEW_PROPERTY(meshWidth, NSInteger)
RCT_EXPORT_VIEW_PROPERTY(meshHeight, NSInteger)
RCT_EXPORT_VIEW_PROPERTY(points, NSArray)
RCT_EXPORT_VIEW_PROPERTY(primaryColors, NSArray)
RCT_EXPORT_VIEW_PROPERTY(secondaryColors, NSArray)
RCT_EXPORT_VIEW_PROPERTY(background, NSString)
RCT_EXPORT_VIEW_PROPERTY(smoothsColors, BOOL)
RCT_EXPORT_VIEW_PROPERTY(colorSpace, NSString)
RCT_EXPORT_VIEW_PROPERTY(borderRadius, CGFloat)
RCT_EXPORT_VIEW_PROPERTY(animationDuration, NSInteger)
RCT_EXPORT_VIEW_PROPERTY(animationType, NSString)

@end
@end
175 changes: 156 additions & 19 deletions ios/MeshGradientViewManager.swift
100644 → 100755
Original file line number Diff line number Diff line change
@@ -1,36 +1,173 @@
//
// MeshGradientViewManager.swift
// reactnativemeshgradient
//
// Created by wilmxre on 27.07.2024.
//

import ExpoModulesCore
import React
import SwiftUI

@objc(MeshGradientViewManager)
class MeshGradientViewManager: RCTViewManager {

override func view() -> (MeshGradientView) {
return MeshGradientView()
override func view() -> UIView! {
if #available(iOS 16.0, *) {
return MeshGradientUIView()
} else {
return UIView()
}
}

@objc override static func requiresMainQueueSetup() -> Bool {
return false
override static func requiresMainQueueSetup() -> Bool {
return true
}
}

class MeshGradientView : UIView {
@available(iOS 16.0, *)
class MeshGradientUIView: UIView {
private var hostingController: UIHostingController<MeshGradientView>?

@objc var color: String = "" {
@objc var meshWidth: Int = 3 {
didSet {
self.backgroundColor = hexStringToUIColor(hexColor: color)
updateView()
}
}

func hexStringToUIColor(hexColor: String) -> UIColor {
let stringScanner = Scanner(string: hexColor)
@objc var meshHeight: Int = 3 {
didSet {
updateView()
}
}

if(hexColor.hasPrefix("#")) {
stringScanner.scanLocation = 1
@objc var points: [[NSNumber]] = [] {
didSet {
updateView()
}
var color: UInt32 = 0
stringScanner.scanHexInt32(&color)
}

let r = CGFloat(Int(color >> 16) & 0x000000FF)
let g = CGFloat(Int(color >> 8) & 0x000000FF)
let b = CGFloat(Int(color) & 0x000000FF)
@objc var primaryColors: [NSString] = [] {
didSet {
updateView()
}
}

return UIColor(red: r / 255.0, green: g / 255.0, blue: b / 255.0, alpha: 1)
@objc var secondaryColors: [NSString] = [] {
didSet {
updateView()
}
}
}

@objc var background: NSString = "" {
didSet {
updateView()
}
}

@objc var smoothsColors: Bool = true {
didSet {
updateView()
}
}

@objc var colorSpace: NSString = "device" {
didSet {
updateView()
}
}

@objc var isAnimated: Bool = false {
didSet {
updateView()
}
}

@objc var animationDuration: TimeInterval = 5 {
didSet {
updateView()
}
}

@objc var animationType: String = "sine" {
didSet {
updateView()
}
}

@objc var borderRadius: CGFloat = 0 {
didSet {
updateView()
}
}

private func colorFromHexString(hexString: NSString) -> UIColor {
var cString: String = hexString.trimmingCharacters(
in: .whitespacesAndNewlines
).uppercased()

if cString.hasPrefix("#") {
cString.remove(at: cString.startIndex)
}

if cString.count != 6 {
return UIColor.white
}

var rgbValue: UInt64 = 0
Scanner(string: cString).scanHexInt64(&rgbValue)

return UIColor(
red: CGFloat((rgbValue & 0xFF0000) >> 16) / 255.0,
green: CGFloat((rgbValue & 0x00FF00) >> 8) / 255.0,
blue: CGFloat(rgbValue & 0x0000FF) / 255.0,
alpha: CGFloat(1.0)
)
}

private func updateView() {

let pointsSIMD = points.map {
SIMD2<Float>(Float(truncating: $0[0]), Float(truncating: $0[1]))
}
let primaryColorsSwiftUI = primaryColors.map {
Color(colorFromHexString(hexString: $0))
}
let secondaryColorsSwiftUI = secondaryColors.map {
Color(colorFromHexString(hexString: $0))
}
let backgroundColor = Color(colorFromHexString(hexString: background))
let colorSpaceEnum: Gradient.ColorSpace =
colorSpace == "perceptual" ? .perceptual : .device

let meshGradientView = MeshGradientView(
meshWidth: meshWidth,
meshHeight: meshHeight,
points: pointsSIMD,
primaryColors: primaryColorsSwiftUI,
secondaryColors: secondaryColorsSwiftUI,
background: backgroundColor,
smoothsColors: smoothsColors,
colorSpace: colorSpaceEnum,
borderRadius: borderRadius,
isAnimated: isAnimated,
animationDuration: animationDuration,
animationType: animationType
)

if hostingController == nil {
hostingController = UIHostingController(rootView: meshGradientView)
if let hostingView = hostingController?.view {
addSubview(hostingView)
hostingView.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
hostingView.topAnchor.constraint(equalTo: topAnchor),
hostingView.bottomAnchor.constraint(equalTo: bottomAnchor),
hostingView.leadingAnchor.constraint(equalTo: leadingAnchor),
hostingView.trailingAnchor.constraint(equalTo: trailingAnchor),
])
}
} else {
hostingController?.rootView = meshGradientView
}
}
}
Empty file modified lefthook.yml
100644 → 100755
Empty file.
Empty file modified package.json
100644 → 100755
Empty file.
Empty file modified react-native-mesh-gradient.podspec
100644 → 100755
Empty file.
Empty file modified src/__tests__/index.test.tsx
100644 → 100755
Empty file.
24 changes: 17 additions & 7 deletions src/index.tsx
100644 → 100755
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import {
requireNativeComponent,
UIManager,
Platform,
type ViewStyle,
type ViewProps,
} from 'react-native';

const LINKING_ERROR =
Expand All @@ -11,16 +11,26 @@ const LINKING_ERROR =
'- You rebuilt the app after installing the package\n' +
'- You are not using Expo Go\n';

type MeshGradientProps = {
color: string;
style: ViewStyle;
};

export type MeshGradientProps = ViewProps & {
meshWidth: number;
meshHeight: number;
points: number[][];
primaryColors: string[];
secondaryColors: string[];
background?: string;
smoothsColors?: boolean;
colorSpace?: "device" | "perceptual";
isAnimated?: boolean;
borderRadius?: number;
animationDuration?: number;
animationType?: "sine" | "easeInOut";
};

const ComponentName = 'MeshGradientView';

export const MeshGradientView =
UIManager.getViewManagerConfig(ComponentName) != null
? requireNativeComponent<MeshGradientProps>(ComponentName)
: () => {
throw new Error(LINKING_ERROR);
};
};
Empty file modified tsconfig.build.json
100644 → 100755
Empty file.
Empty file modified tsconfig.json
100644 → 100755
Empty file.
Empty file modified turbo.json
100644 → 100755
Empty file.

0 comments on commit c25c0c0

Please sign in to comment.