diff --git a/README.md b/README.md index 46738aa..5fd0c0c 100644 --- a/README.md +++ b/README.md @@ -22,13 +22,15 @@ React-native wrapper for android & IOS google maps sdk yarn add react-native-google-maps-plus react-native-nitro-modules ``` -Dependencies +# Dependencies -This package builds on native SVG rendering libraries: +This package builds on native libraries for SVG rendering and Google Maps integration: -iOS: [SVGKit](https://github.com/SVGKit/SVGKit) - -Android: [AndroidSVG](https://bigbadaboom.github.io/androidsvg/) +- **iOS**: [SVGKit](https://github.com/SVGKit/SVGKit) +- **Android**: [AndroidSVG](https://bigbadaboom.github.io/androidsvg/) +- **iOS Maps SDK**: [Google Maps SDK for iOS](https://developers.google.com/maps/documentation/ios-sdk) +- **Android Maps SDK**: [Google Maps SDK for Android](https://developers.google.com/maps/documentation/android-sdk) +- **Maps Utility Libraries**: [Google Maps Utils for iOS](https://developers.google.com/maps/documentation/ios-sdk/utility) and [Google Maps Utils for Android](https://developers.google.com/maps/documentation/android-sdk/utility) These are automatically linked when you install the package, but you may need to clean/rebuild your native projects after first install. diff --git a/RNGoogleMapsPlus.podspec b/RNGoogleMapsPlus.podspec index 094ce18..7f279db 100644 --- a/RNGoogleMapsPlus.podspec +++ b/RNGoogleMapsPlus.podspec @@ -26,7 +26,8 @@ Pod::Spec.new do |s| s.dependency 'React-jsi' s.dependency 'React-callinvoker' - s.dependency 'GoogleMaps', '10.3.0' + s.dependency 'GoogleMaps', '10.4.0' + s.dependency 'Google-Maps-iOS-Utils', '6.1.3' s.dependency 'SVGKit', '3.0.0' load 'nitrogen/generated/ios/RNGoogleMapsPlus+autolinking.rb' diff --git a/android/src/main/java/com/rngooglemapsplus/GoogleMapsViewImpl.kt b/android/src/main/java/com/rngooglemapsplus/GoogleMapsViewImpl.kt index d24d0e9..5979c6a 100644 --- a/android/src/main/java/com/rngooglemapsplus/GoogleMapsViewImpl.kt +++ b/android/src/main/java/com/rngooglemapsplus/GoogleMapsViewImpl.kt @@ -25,6 +25,8 @@ import com.google.android.gms.maps.model.Polygon import com.google.android.gms.maps.model.PolygonOptions import com.google.android.gms.maps.model.Polyline import com.google.android.gms.maps.model.PolylineOptions +import com.google.android.gms.maps.model.TileOverlay +import com.google.android.gms.maps.model.TileOverlayOptions import com.rngooglemapsplus.extensions.toGooglePriority import com.rngooglemapsplus.extensions.toLocationErrorCode @@ -52,11 +54,13 @@ class GoogleMapsViewImpl( private val pendingPolylines = mutableListOf>() private val pendingPolygons = mutableListOf>() private val pendingCircles = mutableListOf>() + private val pendingHeatmaps = mutableListOf>() private val markersById = mutableMapOf() private val polylinesById = mutableMapOf() private val polygonsById = mutableMapOf() private val circlesById = mutableMapOf() + private val heatmapsById = mutableMapOf() private var cameraMoveReason = -1 private var lastSubmittedLocation: Location? = null @@ -332,6 +336,13 @@ class GoogleMapsViewImpl( } pendingCircles.clear() } + + if (pendingHeatmaps.isNotEmpty()) { + pendingHeatmaps.forEach { (id, opts) -> + internalAddHeatmap(id, opts) + } + pendingHeatmaps.clear() + } } var uiSettings: RNMapUiSettings? = null @@ -772,6 +783,48 @@ class GoogleMapsViewImpl( pendingCircles.clear() } + fun addHeatmap( + id: String, + opts: TileOverlayOptions, + ) { + if (googleMap == null) { + pendingHeatmaps.add(id to opts) + return + } + + onUi { + heatmapsById.remove(id)?.remove() + } + internalAddHeatmap(id, opts) + } + + private fun internalAddHeatmap( + id: String, + opts: TileOverlayOptions, + ) { + onUi { + val heatmap = + googleMap?.addTileOverlay(opts) + if (heatmap != null) { + heatmapsById[id] = heatmap + } + } + } + + fun removeHeatmap(id: String) { + onUi { + heatmapsById.remove(id)?.remove() + } + } + + fun clearHeatmaps() { + onUi { + heatmapsById.values.forEach { it.remove() } + } + circlesById.clear() + pendingHeatmaps.clear() + } + fun destroyInternal() { onUi { markerBuilder.cancelAllJobs() @@ -779,6 +832,7 @@ class GoogleMapsViewImpl( clearPolylines() clearPolygons() clearCircles() + clearHeatmaps() locationHandler.stop() googleMap?.apply { setOnCameraMoveStartedListener(null) diff --git a/android/src/main/java/com/rngooglemapsplus/MapHeatmapBuilder.kt b/android/src/main/java/com/rngooglemapsplus/MapHeatmapBuilder.kt new file mode 100644 index 0000000..4346c14 --- /dev/null +++ b/android/src/main/java/com/rngooglemapsplus/MapHeatmapBuilder.kt @@ -0,0 +1,31 @@ +package com.rngooglemapsplus + +import com.facebook.react.uimanager.PixelUtil.dpToPx +import com.google.android.gms.maps.model.TileOverlayOptions +import com.google.maps.android.heatmaps.Gradient +import com.google.maps.android.heatmaps.HeatmapTileProvider +import com.rngooglemapsplus.extensions.toColor +import com.rngooglemapsplus.extensions.toWeightedLatLngs + +class MapHeatmapBuilder { + fun build(heatmap: RNHeatmap): TileOverlayOptions { + val provider = + HeatmapTileProvider + .Builder() + .apply { + weightedData(heatmap.weightedData.toWeightedLatLngs()) + heatmap.radius?.let { radius(it.dpToPx().toInt().coerceIn(10, 50)) } + heatmap.opacity?.let { opacity(it) } + heatmap.gradient?.let { + val colors = it.colors.map { c -> c.toColor() }.toIntArray() + val startPoints = it.startPoints.map { p -> p.toFloat() }.toFloatArray() + gradient(Gradient(colors, startPoints)) + } + }.build() + + return TileOverlayOptions().apply { + tileProvider(provider) + heatmap.zIndex?.let { zIndex(it.toFloat()) } + } + } +} diff --git a/android/src/main/java/com/rngooglemapsplus/RNGoogleMapsPlusView.kt b/android/src/main/java/com/rngooglemapsplus/RNGoogleMapsPlusView.kt index 173a918..40ed111 100644 --- a/android/src/main/java/com/rngooglemapsplus/RNGoogleMapsPlusView.kt +++ b/android/src/main/java/com/rngooglemapsplus/RNGoogleMapsPlusView.kt @@ -25,6 +25,7 @@ class RNGoogleMapsPlusView( private val polylineBuilder = MapPolylineBuilder() private val polygonBuilder = MapPolygonBuilder() private val circleBuilder = MapCircleBuilder() + private val heatmapBuilder = MapHeatmapBuilder() override val view = GoogleMapsViewImpl(context, locationHandler, playServiceHandler, markerBuilder) @@ -218,6 +219,21 @@ class RNGoogleMapsPlusView( } } + override var heatmaps: Array? = null + set(value) { + if (field.contentEquals(value)) return + val prevById = field?.associateBy { it.id } ?: emptyMap() + val nextById = value?.associateBy { it.id } ?: emptyMap() + field = value + (prevById.keys - nextById.keys).forEach { id -> + view.removeHeatmap(id) + } + + nextById.forEach { (id, next) -> + view.addHeatmap(id, heatmapBuilder.build(next)) + } + } + override var locationConfig: RNLocationConfig? = null set(value) { if (field == value) return diff --git a/android/src/main/java/com/rngooglemapsplus/extensions/RNHeatmapPointExtension.kt b/android/src/main/java/com/rngooglemapsplus/extensions/RNHeatmapPointExtension.kt new file mode 100644 index 0000000..4ac8504 --- /dev/null +++ b/android/src/main/java/com/rngooglemapsplus/extensions/RNHeatmapPointExtension.kt @@ -0,0 +1,9 @@ +package com.rngooglemapsplus.extensions + +import com.google.android.gms.maps.model.LatLng +import com.google.maps.android.heatmaps.WeightedLatLng +import com.rngooglemapsplus.RNHeatmapPoint + +fun RNHeatmapPoint.toWeightedLatLng(): WeightedLatLng = WeightedLatLng(LatLng(latitude, longitude), weight) + +fun Array.toWeightedLatLngs(): Collection = map { it.toWeightedLatLng() } diff --git a/example/ios/Podfile.lock b/example/ios/Podfile.lock index 6b7e06e..7755d98 100644 --- a/example/ios/Podfile.lock +++ b/example/ios/Podfile.lock @@ -8,9 +8,11 @@ PODS: - FBLazyVector (0.82.0) - fmt (11.0.2) - glog (0.3.5) - - GoogleMaps (10.3.0): - - GoogleMaps/Maps (= 10.3.0) - - GoogleMaps/Maps (10.3.0) + - Google-Maps-iOS-Utils (6.1.3): + - GoogleMaps (~> 10.0) + - GoogleMaps (10.4.0): + - GoogleMaps/Maps (= 10.4.0) + - GoogleMaps/Maps (10.4.0) - hermes-engine (0.82.0): - hermes-engine/Pre-built (= 0.82.0) - hermes-engine/Pre-built (0.82.0) @@ -2362,7 +2364,8 @@ PODS: - fast_float - fmt - glog - - GoogleMaps (= 10.3.0) + - Google-Maps-iOS-Utils (= 6.1.3) + - GoogleMaps (= 10.4.0) - hermes-engine - NitroModules - RCT-Folly @@ -2475,6 +2478,7 @@ DEPENDENCIES: SPEC REPOS: trunk: - CocoaLumberjack + - Google-Maps-iOS-Utils - GoogleMaps - SocketRocket - SVGKit @@ -2640,7 +2644,8 @@ SPEC CHECKSUMS: FBLazyVector: 41b4dd99afd0aad861444ee141abdedaa6c3d238 fmt: a40bb5bd0294ea969aaaba240a927bd33d878cdd glog: 5683914934d5b6e4240e497e0f4a3b42d1854183 - GoogleMaps: 197af8911284ddf36db063c74faee4c4ab15e9d9 + Google-Maps-iOS-Utils: bed22fa703c919259b3901449434d60d994fae20 + GoogleMaps: a40d3b1f511f0fa2036e7b08c920c33279b1d5fd hermes-engine: 8642d8f14a548ab718ec112e9bebdfdd154138b5 NitroModules: 73c42f3089bd74f411172ea8e69024aac4a2ac9f RCT-Folly: 846fda9475e61ec7bcbf8a3fe81edfcaeb090669 @@ -2708,7 +2713,7 @@ SPEC CHECKSUMS: ReactAppDependencyProvider: c5c4f5280e4ae0f9f4a739c64c4260fe0b3edaf1 ReactCodegen: 3873d7ac09960375f7845384ff47d53e478462dc ReactCommon: f5527f5d97a9957ab46eb5db78875d3579e03b97 - RNGoogleMapsPlus: 4f8dd1f33c906f62e877f1aa65cd8ac5ec6b020b + RNGoogleMapsPlus: 9b638ea84ab0231430a8b5a109a20130ad4a722a SocketRocket: d4aabe649be1e368d1318fdf28a022d714d65748 SVGKit: 1ad7513f8c74d9652f94ed64ddecda1a23864dea Yoga: ce55ebb197c21e22b6700cd36e3f36b7ec26e6f8 diff --git a/example/src/App.tsx b/example/src/App.tsx index 6b858a0..4597e37 100644 --- a/example/src/App.tsx +++ b/example/src/App.tsx @@ -19,6 +19,7 @@ import type { RNRegion, RNLatLng, RNCircle, + RNHeatmap, } from '../../src'; import { GoogleMapsView, GoogleMapsModule } from '../../src'; import { callback } from 'react-native-nitro-modules'; @@ -204,6 +205,16 @@ const randomCoordinates = ( longitude: baseLng + (Math.random() - 0.5) * offset, }); +const randomWeightedCoordinates = ( + baseLat: number, + baseLng: number, + offset = 0.01 +) => ({ + latitude: baseLat + (Math.random() - 0.5) * offset, + longitude: baseLng + (Math.random() - 0.5) * offset, + weight: Math.floor(Math.random() * (100 - 10 + 1)) + 10, +}); + const makePolygon = (id: number): RNPolygon => ({ id: id.toString(), zIndex: id, @@ -246,6 +257,27 @@ const makeCircle = (id: number): RNCircle => ({ fillColor: '#0000ff', }); +const makeHeatmap = (id: number): RNHeatmap => ({ + id: id.toString(), + zIndex: id, + weightedData: [ + randomWeightedCoordinates(37.7749, -122.4194, 0.02), + randomWeightedCoordinates(37.7749, -122.4194, 0.03), + randomWeightedCoordinates(37.7749, -122.4194, 0.05), + randomWeightedCoordinates(37.7749, -122.4194, 0.01), + randomWeightedCoordinates(37.7749, -122.4194, 0.08), + randomWeightedCoordinates(37.7749, -122.4194, 0.03), + randomWeightedCoordinates(37.7749, -122.4194, 0.09), + ], + gradient: { + colors: ['#00f', '#0ff', '#0f0', '#ff0', '#f00'], + startPoints: [0.1, 0.3, 0.5, 0.7, 1], + colorMapSize: 256, + }, + radius: 100, + opacity: 1, +}); + export const makeMarker = (id: number): RNMarker => ({ id: id.toString(), zIndex: id, @@ -333,6 +365,10 @@ export default function App() { Array.from({ length: 1 }, (_, i) => makeCircle(i + 1)) ); + const [heatmaps] = useState( + Array.from({ length: 1 }, (_, i) => makeHeatmap(i + 1)) + ); + useEffect(() => { if (!stressTest) return; @@ -506,6 +542,7 @@ export default function App() { polygons={polygons} polylines={polylines} circles={circles} + heatmaps={heatmaps} /> diff --git a/ios/.swiftlint.yml b/ios/.swiftlint.yml index 86952cf..8d80b0f 100644 --- a/ios/.swiftlint.yml +++ b/ios/.swiftlint.yml @@ -2,6 +2,8 @@ disabled_rules: - file_length - type_body_length - cyclomatic_complexity + - function_body_length + - closure_parameter_position - todo identifier_name: diff --git a/ios/GoogleMapViewImpl.swift b/ios/GoogleMapViewImpl.swift index f1b12ef..91387f2 100644 --- a/ios/GoogleMapViewImpl.swift +++ b/ios/GoogleMapViewImpl.swift @@ -1,5 +1,6 @@ import CoreLocation import GoogleMaps +import GoogleMapsUtils import UIKit final class GoogleMapsViewImpl: UIView, GMSMapViewDelegate { @@ -14,11 +15,13 @@ final class GoogleMapsViewImpl: UIView, GMSMapViewDelegate { private var pendingPolylines: [(id: String, polyline: GMSPolyline)] = [] private var pendingPolygons: [(id: String, polygon: GMSPolygon)] = [] private var pendingCircles: [(id: String, circle: GMSCircle)] = [] + private var pendingHeatmaps: [(id: String, heatmap: GMUHeatmapTileLayer)] = [] private var markersById: [String: GMSMarker] = [:] private var polylinesById: [String: GMSPolyline] = [:] private var polygonsById: [String: GMSPolygon] = [:] private var circlesById: [String: GMSCircle] = [:] + private var heatmapsById: [String: GMUHeatmapTileLayer] = [:] private var cameraMoveReasonIsGesture: Bool = false private var lastSubmittedCameraPosition: GMSCameraPosition? @@ -148,30 +151,32 @@ final class GoogleMapsViewImpl: UIView, GMSMapViewDelegate { $0.ios?.desiredAccuracy?.toCLLocationAccuracy locationHandler.distanceFilterMeters = $0.ios?.distanceFilterMeters } - if !pendingMarkers.isEmpty { pendingMarkers.forEach { addMarkerInternal(id: $0.id, marker: $0.marker) } pendingMarkers.removeAll() } - if !pendingPolylines.isEmpty { pendingPolylines.forEach { addPolylineInternal(id: $0.id, polyline: $0.polyline) } pendingPolylines.removeAll() } - if !pendingPolygons.isEmpty { pendingPolygons.forEach { addPolygonInternal(id: $0.id, polygon: $0.polygon) } pendingPolygons.removeAll() } - if !pendingCircles.isEmpty { pendingCircles.forEach { addCircleInternal(id: $0.id, circle: $0.circle) } pendingCircles.removeAll() } + if !pendingHeatmaps.isEmpty { + pendingHeatmaps.forEach { + addHeatmapInternal(id: $0.id, heatmap: $0.heatmap) + } + pendingHeatmaps.removeAll() + } } var currentCamera: GMSCameraPosition? { @@ -491,12 +496,41 @@ final class GoogleMapsViewImpl: UIView, GMSMapViewDelegate { pendingCircles.removeAll() } + @MainActor + func addHeatmap(id: String, heatmap: GMUHeatmapTileLayer) { + if mapView == nil { + pendingHeatmaps.append((id, heatmap)) + return + } + heatmapsById.removeValue(forKey: id).map { $0.map = nil } + addHeatmapInternal(id: id, heatmap: heatmap) + } + + @MainActor + private func addHeatmapInternal(id: String, heatmap: GMUHeatmapTileLayer) { + heatmap.map = mapView + heatmapsById[id] = heatmap + } + + @MainActor + func removeHeatmap(id: String) { + heatmapsById.removeValue(forKey: id).map { $0.map = nil } + } + + @MainActor + func clearHeatmaps() { + heatmapsById.values.forEach { $0.map = nil } + heatmapsById.removeAll() + pendingHeatmaps.removeAll() + } + func deinitInternal() { markerBuilder.cancelAllIconTasks() clearMarkers() clearPolylines() clearPolygons() clearCircles() + clearHeatmaps() locationHandler.stop() mapView?.clear() mapView?.delegate = nil diff --git a/ios/MapHeatmapBuilder.swift b/ios/MapHeatmapBuilder.swift new file mode 100644 index 0000000..07ea637 --- /dev/null +++ b/ios/MapHeatmapBuilder.swift @@ -0,0 +1,27 @@ +import Foundation +import GoogleMaps +import GoogleMapsUtils +import UIKit + +final class MapHeatmapBuilder { + func build(_ h: RNHeatmap) -> GMUHeatmapTileLayer { + let heatmap = GMUHeatmapTileLayer() + heatmap.weightedData = h.weightedData.toWeightedLatLngs() + + h.radius.map { heatmap.radius = UInt($0) } + h.opacity.map { heatmap.opacity = Float($0) } + h.zIndex.map { heatmap.zIndex = Int32($0) } + + h.gradient.map { g in + let colors = g.colors.map { $0.toUIColor() } + let startPoints = g.startPoints.map { NSNumber(value: $0) } + heatmap.gradient = GMUGradient( + colors: colors, + startPoints: startPoints, + colorMapSize: 256 + ) + } + + return heatmap + } +} diff --git a/ios/RNGoogleMapsPlusView.swift b/ios/RNGoogleMapsPlusView.swift index e7ce775..47edfd3 100644 --- a/ios/RNGoogleMapsPlusView.swift +++ b/ios/RNGoogleMapsPlusView.swift @@ -12,6 +12,7 @@ final class RNGoogleMapsPlusView: HybridRNGoogleMapsPlusViewSpec { private let polylineBuilder = MapPolylineBuilder() private let polygonBuilder = MapPolygonBuilder() private let circleBuilder = MapCircleBuilder() + private let heatmapBuilder = MapHeatmapBuilder() private let impl: GoogleMapsViewImpl @@ -234,6 +235,27 @@ final class RNGoogleMapsPlusView: HybridRNGoogleMapsPlusViewSpec { } } + @MainActor + var heatmaps: [RNHeatmap]? { + didSet { + let prevById = Dictionary( + (oldValue ?? []).map { ($0.id, $0) }, + uniquingKeysWith: { _, new in new } + ) + let nextById = Dictionary( + (heatmaps ?? []).map { ($0.id, $0) }, + uniquingKeysWith: { _, new in new } + ) + + let removed = Set(prevById.keys).subtracting(nextById.keys) + removed.forEach { impl.removeHeatmap(id: $0) } + + for (id, next) in nextById { + impl.addHeatmap(id: id, heatmap: heatmapBuilder.build(next)) + } + } + } + @MainActor var locationConfig: RNLocationConfig? { didSet { impl.locationConfig = locationConfig diff --git a/ios/extensions/RNHeatmap+Extension.swift b/ios/extensions/RNHeatmap+Extension.swift new file mode 100644 index 0000000..e143ea2 --- /dev/null +++ b/ios/extensions/RNHeatmap+Extension.swift @@ -0,0 +1,16 @@ +import CoreLocation +import Foundation +import GoogleMapsUtils + +extension RNHeatmapPoint { + func toWeightedLatLng() -> GMUWeightedLatLng { + let coord = CLLocationCoordinate2D(latitude: latitude, longitude: longitude) + return GMUWeightedLatLng(coordinate: coord, intensity: Float(weight)) + } +} + +extension Array where Element == RNHeatmapPoint { + func toWeightedLatLngs() -> [GMUWeightedLatLng] { + map { $0.toWeightedLatLng() } + } +} diff --git a/package.json b/package.json index fb733e3..dc095f8 100644 --- a/package.json +++ b/package.json @@ -93,7 +93,7 @@ "eslint-plugin-prettier": "5.5.4", "jest": "30.2.0", "lefthook": "1.13.6", - "nitrogen": "0.29.8", + "nitrogen": "0.29.6", "prettier": "3.6.2", "react": "19.2.0", "react-native": "0.82.0", diff --git a/src/RNGoogleMapsPlusView.nitro.ts b/src/RNGoogleMapsPlusView.nitro.ts index 5c2778b..dc29a66 100644 --- a/src/RNGoogleMapsPlusView.nitro.ts +++ b/src/RNGoogleMapsPlusView.nitro.ts @@ -22,6 +22,7 @@ import type { RNMapUiSettings, RNLocationConfig, RNMapZoomConfig, + RNHeatmap, } from './types'; export interface RNGoogleMapsPlusViewProps extends HybridViewProps { @@ -40,6 +41,7 @@ export interface RNGoogleMapsPlusViewProps extends HybridViewProps { polygons?: RNPolygon[]; polylines?: RNPolyline[]; circles?: RNCircle[]; + heatmaps?: RNHeatmap[]; locationConfig?: RNLocationConfig; onMapError?: (error: RNMapErrorCode) => void; onMapReady?: (ready: boolean) => void; diff --git a/src/types.ts b/src/types.ts index 46ca2b7..5a6d9e5 100644 --- a/src/types.ts +++ b/src/types.ts @@ -177,6 +177,28 @@ export type RNCircle = { fillColor?: string; }; +export type RNHeatmap = { + id: string; + pressable?: boolean; + zIndex?: number; + weightedData: RNHeatmapPoint[]; + radius?: number; + opacity?: number; + gradient?: RNHeatmapGradient; +}; + +export type RNHeatmapPoint = { + latitude: number; + longitude: number; + weight: number; +}; + +export type RNHeatmapGradient = { + colors: string[]; + startPoints: number[]; + colorMapSize: number; +}; + export type RNLocationConfig = { android?: RNAndroidLocationConfig; ios?: RNIOSLocationConfig; diff --git a/yarn.lock b/yarn.lock index d5096ea..d2c4e1e 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3555,14 +3555,14 @@ __metadata: languageName: node linkType: hard -"@ts-morph/common@npm:~0.28.0": - version: 0.28.0 - resolution: "@ts-morph/common@npm:0.28.0" +"@ts-morph/common@npm:~0.26.0": + version: 0.26.1 + resolution: "@ts-morph/common@npm:0.26.1" dependencies: - minimatch: ^10.0.1 + fast-glob: ^3.3.2 + minimatch: ^9.0.4 path-browserify: ^1.0.1 - tinyglobby: ^0.2.14 - checksum: fe4bd0a2eecaf9a81586816da7f3a8a9dcc6505d1146a9772bda06f76fae55fa05bd28996c545faf90f89ac92b9ed7f2a6319af53f3ee4f7adc99789e7c6e0a0 + checksum: 010fc76f6a3347bfcbeee43303d7390accc14fdfd9de65f6aa771e67180c8f1f65ad8e136287517287359a9d2512abcd635bd0102e7af937f6ab1f721f0aa10d languageName: node linkType: hard @@ -9976,7 +9976,7 @@ __metadata: languageName: node linkType: hard -"minimatch@npm:^10.0.1, minimatch@npm:^10.0.3": +"minimatch@npm:^10.0.3": version: 10.0.3 resolution: "minimatch@npm:10.0.3" dependencies: @@ -10187,18 +10187,18 @@ __metadata: languageName: node linkType: hard -"nitrogen@npm:0.29.8": - version: 0.29.8 - resolution: "nitrogen@npm:0.29.8" +"nitrogen@npm:0.29.6": + version: 0.29.6 + resolution: "nitrogen@npm:0.29.6" dependencies: chalk: ^5.3.0 - react-native-nitro-modules: ^0.29.8 - ts-morph: ^27.0.0 + react-native-nitro-modules: ^0.29.6 + ts-morph: ^25.0.0 yargs: ^17.7.2 zod: ^4.0.5 bin: nitrogen: lib/index.js - checksum: ec56919ee570e1a9475ec95a90ed3779110bf9139811102d63d3b40a9b2747ab54962c081ff4f0cc5f0df83f06719f020d55489ce8d4f2a7a08ea1d0299a1977 + checksum: ea6a5f1228388d65e334da9ff071b7bfda94a81af1917f0ce95fceb99bfe02104d8ff0a1c82e4a0f433ca3355e20fc16cb367fb6926a1f49e470b771cb6f7431 languageName: node linkType: hard @@ -11486,7 +11486,7 @@ __metadata: eslint-plugin-prettier: 5.5.4 jest: 30.2.0 lefthook: 1.13.6 - nitrogen: 0.29.8 + nitrogen: 0.29.6 prettier: 3.6.2 react: 19.2.0 react-native: 0.82.0 @@ -11521,7 +11521,7 @@ __metadata: languageName: node linkType: hard -"react-native-nitro-modules@npm:0.29.8, react-native-nitro-modules@npm:^0.29.8": +"react-native-nitro-modules@npm:0.29.8, react-native-nitro-modules@npm:^0.29.6": version: 0.29.8 resolution: "react-native-nitro-modules@npm:0.29.8" peerDependencies: @@ -12910,7 +12910,7 @@ __metadata: languageName: node linkType: hard -"tinyglobby@npm:^0.2.12, tinyglobby@npm:^0.2.14": +"tinyglobby@npm:^0.2.12": version: 0.2.15 resolution: "tinyglobby@npm:0.2.15" dependencies: @@ -12966,13 +12966,13 @@ __metadata: languageName: node linkType: hard -"ts-morph@npm:^27.0.0": - version: 27.0.0 - resolution: "ts-morph@npm:27.0.0" +"ts-morph@npm:^25.0.0": + version: 25.0.1 + resolution: "ts-morph@npm:25.0.1" dependencies: - "@ts-morph/common": ~0.28.0 + "@ts-morph/common": ~0.26.0 code-block-writer: ^13.0.3 - checksum: 8e61a3819fc15018ab3a00716388a84e26128e275fa9a5e930739fcda4f8bb8f9f33cbfca56b0c593bba91c8c3fcdf6bf45e67d82104e28de1a11b22b2d83c85 + checksum: 6370c653824ac5d4cc44571cb6b770d7b6e2a6c5d1910e538012f98f4e26c2e5d3f900d9cdd3c9f65301415e2cb4cd263774de97ec153ea99f4d9ce4b0a1dd37 languageName: node linkType: hard