@superrouteca/smap-react-native 0.0.0-stage → 1.0.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.
@@ -0,0 +1,243 @@
1
+ import CoreLocation
2
+ import SMap
3
+ import UIKit
4
+
5
+ /// The native side of `<SMap>` on iOS: holds one `SMapView`, created by `start` with the first props (the config is
6
+ /// read then; a new config arrives as a new view). The Fabric component view (`RNSMapNativeView`) forwards props and
7
+ /// commands here and turns `onEvent` calls into React Native events.
8
+ @objc(RNSMapHost)
9
+ public final class RNSMapHost: UIView {
10
+ /// Called with an event name (`mapReady`, `mapError`, `layerTap`, `tokenRequest`) and its payload.
11
+ @objc public var onEvent: ((String, [String: Any]) -> Void)?
12
+
13
+ private var map: SMapView?
14
+ private var appliedStyle = ""
15
+ private var appliedLanguage = ""
16
+ private var appliedCamera = ""
17
+ private var appliedBuildings = false
18
+ private var nextTokenRequest = 0
19
+ private var tokenRequests: [Int: CheckedContinuation<String, Error>] = [:]
20
+
21
+ @objc public var isStarted: Bool { map != nil }
22
+
23
+ /// Creates the map. `config`: JSON {baseUrl, nodes, apiKey, token, nearest, getToken}.
24
+ @objc public func start(config: String, style: String, language: String, camera: String, buildings: Bool) {
25
+ guard map == nil else { return }
26
+ let c = RNSMapHost.object(config)
27
+ let cam = RNSMapHost.object(camera)
28
+ var options = SMapOptions()
29
+ if let base = c["baseUrl"] as? String, let url = URL(string: base) { options.baseURL = url }
30
+ options.nodes = (c["nodes"] as? [String] ?? []).compactMap { URL(string: $0) }
31
+ options.token = (c["token"] as? String).flatMap { $0.isEmpty ? nil : $0 }
32
+ options.apiKey = (c["apiKey"] as? String).flatMap { $0.isEmpty ? nil : $0 }
33
+ options.nearest = c["nearest"] as? Bool ?? true
34
+ if c["getToken"] as? Bool == true {
35
+ options.getToken = { [weak self] in
36
+ guard let self = self else { throw SMapError.notReady }
37
+ return try await self.requestToken()
38
+ }
39
+ }
40
+ options.style = SMapStyle(rawValue: style) ?? .light
41
+ options.language = language.isEmpty ? nil : language
42
+ if let lat = RNSMapHost.number(cam["lat"]), let lng = RNSMapHost.number(cam["lng"]) {
43
+ options.center = CLLocationCoordinate2D(latitude: lat, longitude: lng)
44
+ }
45
+ options.zoom = RNSMapHost.number(cam["zoom"])
46
+ options.bearing = RNSMapHost.number(cam["bearing"]) ?? 0
47
+ options.pitch = RNSMapHost.number(cam["pitch"]) ?? 0
48
+ appliedStyle = style
49
+ appliedLanguage = language
50
+ appliedCamera = camera
51
+ appliedBuildings = buildings
52
+
53
+ let m = SMapView(frame: bounds, options: options)
54
+ m.autoresizingMask = [.flexibleWidth, .flexibleHeight]
55
+ m.onError = { [weak self] error in self?.emit("mapError", ["message": error.localizedDescription]) }
56
+ m.onReady = { [weak self] ready in
57
+ let node = ready.node.map { "\($0.scheme ?? "https")://\($0.host ?? "")" } ?? ""
58
+ self?.emit("mapReady", ["node": node])
59
+ }
60
+ addSubview(m)
61
+ map = m
62
+ if buildings { m.setBuildings3D(true) }
63
+ }
64
+
65
+ /// Applies props that changed since the last call.
66
+ @objc public func update(style: String, language: String, camera: String, buildings: Bool) {
67
+ guard let m = map else { return }
68
+ if style != appliedStyle {
69
+ appliedStyle = style
70
+ m.setStyle(SMapStyle(rawValue: style) ?? .light)
71
+ }
72
+ if language != appliedLanguage {
73
+ appliedLanguage = language
74
+ if !language.isEmpty { m.setLanguage(language) }
75
+ }
76
+ if camera != appliedCamera {
77
+ appliedCamera = camera
78
+ move(m, RNSMapHost.object(camera))
79
+ }
80
+ if buildings != appliedBuildings {
81
+ appliedBuildings = buildings
82
+ m.setBuildings3D(buildings)
83
+ }
84
+ }
85
+
86
+ private func move(_ m: SMapView, _ cam: [String: Any]) {
87
+ let engine = m.mapView
88
+ let camera = engine.camera
89
+ if let lat = RNSMapHost.number(cam["lat"]), let lng = RNSMapHost.number(cam["lng"]) {
90
+ camera.centerCoordinate = CLLocationCoordinate2D(latitude: lat, longitude: lng)
91
+ }
92
+ if let bearing = RNSMapHost.number(cam["bearing"]) { camera.heading = bearing }
93
+ if let pitch = RNSMapHost.number(cam["pitch"]) { camera.pitch = CGFloat(pitch) }
94
+ engine.setCamera(camera, animated: false)
95
+ if let zoom = RNSMapHost.number(cam["zoom"]) { engine.setZoomLevel(zoom, animated: false) }
96
+ }
97
+
98
+ // MARK: - Commands
99
+
100
+ @objc public func addLayer(kind: String, id: String, data: String, options: String) {
101
+ guard let m = map else { return }
102
+ let o = RNSMapHost.object(options)
103
+ let d = SMapData.geoJSON(Data(data.utf8))
104
+ do {
105
+ switch kind {
106
+ case "points": try m.addPoints(id, data: d, options: RNSMapHost.pointOptions(o))
107
+ case "lines": try m.addLines(id, data: d, options: RNSMapHost.lineOptions(o))
108
+ case "polygons": try m.addPolygons(id, data: d, options: RNSMapHost.polygonOptions(o))
109
+ default:
110
+ emit("mapError", ["message": "sMap: unknown layer kind \(kind)"])
111
+ return
112
+ }
113
+ m.onTap(id) { [weak self] properties, coordinate in
114
+ let json = (try? JSONSerialization.data(withJSONObject: RNSMapHost.jsonSafe(properties))).flatMap { String(data: $0, encoding: .utf8) } ?? "{}"
115
+ self?.emit("layerTap", ["layerId": id, "properties": json, "lat": coordinate.latitude, "lng": coordinate.longitude])
116
+ }
117
+ } catch {
118
+ emit("mapError", ["message": error.localizedDescription])
119
+ }
120
+ }
121
+
122
+ @objc public func setData(id: String, data: String) {
123
+ do { try map?.setData(id, data: .geoJSON(Data(data.utf8))) } catch { emit("mapError", ["message": error.localizedDescription]) }
124
+ }
125
+
126
+ @objc public func setVisible(id: String, visible: Bool) { map?.setVisible(id, visible) }
127
+
128
+ @objc public func removeLayer(id: String) { map?.removeLayer(id) }
129
+
130
+ @objc public func fitLayer(id: String, padding: Double, maxZoom: Double) { map?.fitLayer(id, padding: padding, maxZoom: maxZoom) }
131
+
132
+ @objc public func flyTo(lat: Double, lng: Double, zoom: Double) {
133
+ map?.flyTo(CLLocationCoordinate2D(latitude: lat, longitude: lng), zoom: zoom < 0 ? nil : zoom)
134
+ }
135
+
136
+ @objc public func resolveToken(requestId: Int, token: String, error: String) {
137
+ guard let c = tokenRequests.removeValue(forKey: requestId) else { return }
138
+ if token.isEmpty {
139
+ c.resume(throwing: SMapError.network(url: "", message: error.isEmpty ? "no token" : error))
140
+ } else {
141
+ c.resume(returning: token)
142
+ }
143
+ }
144
+
145
+ /// Ends the map and fails any token request still waiting.
146
+ @objc public func stop() {
147
+ for (_, c) in tokenRequests { c.resume(throwing: SMapError.notReady) }
148
+ tokenRequests.removeAll()
149
+ map?.removeFromSuperview()
150
+ map = nil
151
+ }
152
+
153
+ private func requestToken() async throws -> String {
154
+ nextTokenRequest += 1
155
+ let id = nextTokenRequest
156
+ return try await withCheckedThrowingContinuation { c in
157
+ tokenRequests[id] = c
158
+ emit("tokenRequest", ["requestId": id])
159
+ }
160
+ }
161
+
162
+ private func emit(_ name: String, _ payload: [String: Any]) { onEvent?(name, payload) }
163
+
164
+ // MARK: - Options from JSON (the names every sMap SDK uses; `minzoom` / `maxzoom` as in the Web SDK too)
165
+
166
+ static func object(_ json: String) -> [String: Any] {
167
+ guard !json.isEmpty, let data = json.data(using: .utf8),
168
+ let o = try? JSONSerialization.jsonObject(with: data) as? [String: Any] else { return [:] }
169
+ return o
170
+ }
171
+
172
+ static func number(_ v: Any?) -> Double? {
173
+ guard let n = v as? NSNumber, !(v is Bool) else { return nil }
174
+ return n.doubleValue
175
+ }
176
+
177
+ private static func zoom(_ o: [String: Any], _ name: String) -> Double? {
178
+ number(o[name]) ?? number(o[name.lowercased()])
179
+ }
180
+
181
+ private static func color(_ v: Any?) -> UIColor? { (v as? String).map { UIColor(smapHex: $0) } }
182
+
183
+ private static func value(_ v: Any?, _ fallback: Double) -> SMapValue {
184
+ if let s = v as? String { return .property(s) }
185
+ return .number(number(v) ?? fallback)
186
+ }
187
+
188
+ static func pointOptions(_ o: [String: Any]) -> SMapPointOptions {
189
+ var p = SMapPointOptions()
190
+ if let c = o["cluster"] as? [String: Any] {
191
+ p.cluster = SMapCluster(radius: number(c["radius"]) ?? 50, maxZoom: number(c["maxZoom"]) ?? 14)
192
+ } else if o["cluster"] as? Bool == true {
193
+ p.cluster = SMapCluster()
194
+ }
195
+ if let c = color(o["color"]) { p.color = c }
196
+ if let r = number(o["radius"]) { p.radius = r }
197
+ if let c = color(o["strokeColor"]) { p.strokeColor = c }
198
+ if let w = number(o["strokeWidth"]) { p.strokeWidth = w }
199
+ p.icon = o["icon"] as? String
200
+ if let s = number(o["iconSize"]) { p.iconSize = s }
201
+ p.label = o["label"] as? String
202
+ p.minZoom = zoom(o, "minZoom")
203
+ p.maxZoom = zoom(o, "maxZoom")
204
+ p.zIndex = Int(number(o["zIndex"]) ?? 0)
205
+ return p
206
+ }
207
+
208
+ static func lineOptions(_ o: [String: Any]) -> SMapLineOptions {
209
+ var l = SMapLineOptions()
210
+ if let c = color(o["color"]) { l.color = c }
211
+ if let w = number(o["width"]) { l.width = w }
212
+ l.dash = (o["dash"] as? [NSNumber])?.map { $0.doubleValue }
213
+ if let a = number(o["opacity"]) { l.opacity = a }
214
+ l.minZoom = zoom(o, "minZoom")
215
+ l.maxZoom = zoom(o, "maxZoom")
216
+ l.zIndex = Int(number(o["zIndex"]) ?? 0)
217
+ return l
218
+ }
219
+
220
+ static func polygonOptions(_ o: [String: Any]) -> SMapPolygonOptions {
221
+ var p = SMapPolygonOptions()
222
+ if let c = color(o["fill"]) ?? color(o["color"]) { p.fill = c }
223
+ p.opacity = number(o["opacity"])
224
+ p.outline = color(o["outline"])
225
+ if let w = number(o["outlineWidth"]) { p.outlineWidth = w }
226
+ if let e = o["extrude"] as? [String: Any] {
227
+ p.extrude = SMapExtrude(height: value(e["height"], 20), base: value(e["base"], 0))
228
+ }
229
+ p.minZoom = zoom(o, "minZoom")
230
+ p.maxZoom = zoom(o, "maxZoom")
231
+ p.zIndex = Int(number(o["zIndex"]) ?? 0)
232
+ return p
233
+ }
234
+
235
+ private static func jsonSafe(_ value: Any) -> Any {
236
+ switch value {
237
+ case let d as [String: Any]: return d.mapValues { jsonSafe($0) }
238
+ case let a as [Any]: return a.map { jsonSafe($0) }
239
+ case is String, is NSNumber, is NSNull: return value
240
+ default: return String(describing: value)
241
+ }
242
+ }
243
+ }
@@ -0,0 +1,161 @@
1
+ // The Fabric component view of `SMapNativeView`: forwards props and commands to the sMap iOS SDK (through RNSMapHost)
2
+ // and its events to React Native. It has no public header: React Native finds it by name (codegenConfig
3
+ // componentProvider), and a header importing the C++ component headers would break the pod's Swift module.
4
+ #import <React/RCTViewComponentView.h>
5
+ #import <UIKit/UIKit.h>
6
+
7
+ #import <react/renderer/components/SMapReactNativeSpec/ComponentDescriptors.h>
8
+ #import <react/renderer/components/SMapReactNativeSpec/EventEmitters.h>
9
+ #import <react/renderer/components/SMapReactNativeSpec/Props.h>
10
+ #import <react/renderer/components/SMapReactNativeSpec/RCTComponentViewHelpers.h>
11
+
12
+ #import <React/RCTFabricComponentsPlugins.h>
13
+
14
+ #if __has_include(<SMapReactNative/SMapReactNative-Swift.h>)
15
+ #import <SMapReactNative/SMapReactNative-Swift.h>
16
+ #else
17
+ #import "SMapReactNative-Swift.h"
18
+ #endif
19
+
20
+ using namespace facebook::react;
21
+
22
+ static NSString *RNSMapString(const std::string &value)
23
+ {
24
+ return [NSString stringWithUTF8String:value.c_str()] ?: @"";
25
+ }
26
+
27
+ static std::string RNSMapStd(id value)
28
+ {
29
+ NSString *s = [value isKindOfClass:[NSString class]] ? value : @"";
30
+ return std::string([s UTF8String] ?: "");
31
+ }
32
+
33
+ static double RNSMapDouble(id value)
34
+ {
35
+ return [value isKindOfClass:[NSNumber class]] ? [value doubleValue] : 0;
36
+ }
37
+
38
+ @interface RNSMapNativeView : RCTViewComponentView <RCTSMapNativeViewViewProtocol>
39
+ @end
40
+
41
+ @implementation RNSMapNativeView {
42
+ RNSMapHost *_host;
43
+ }
44
+
45
+ + (ComponentDescriptorProvider)componentDescriptorProvider
46
+ {
47
+ return concreteComponentDescriptorProvider<SMapNativeViewComponentDescriptor>();
48
+ }
49
+
50
+ - (instancetype)initWithFrame:(CGRect)frame
51
+ {
52
+ if (self = [super initWithFrame:frame]) {
53
+ static const auto defaultProps = std::make_shared<const SMapNativeViewProps>();
54
+ _props = defaultProps;
55
+ [self makeHost];
56
+ }
57
+ return self;
58
+ }
59
+
60
+ - (void)makeHost
61
+ {
62
+ _host = [[RNSMapHost alloc] initWithFrame:self.bounds];
63
+ __weak RNSMapNativeView *weakSelf = self;
64
+ _host.onEvent = ^(NSString *name, NSDictionary<NSString *, id> *payload) {
65
+ [weakSelf emit:name payload:payload];
66
+ };
67
+ self.contentView = _host;
68
+ }
69
+
70
+ - (void)updateProps:(Props::Shared const &)props oldProps:(Props::Shared const &)oldProps
71
+ {
72
+ const auto &p = *std::static_pointer_cast<SMapNativeViewProps const>(props);
73
+ NSString *style = RNSMapString(p.mapStyle);
74
+ NSString *language = RNSMapString(p.language);
75
+ NSString *camera = RNSMapString(p.camera);
76
+ if (!_host.isStarted) {
77
+ [_host startWithConfig:RNSMapString(p.config) style:style language:language camera:camera buildings:p.buildings3D];
78
+ } else {
79
+ [_host updateWithStyle:style language:language camera:camera buildings:p.buildings3D];
80
+ }
81
+ [super updateProps:props oldProps:oldProps];
82
+ }
83
+
84
+ - (void)prepareForRecycle
85
+ {
86
+ // A recycled view may be given another config: start again from nothing.
87
+ [_host stop];
88
+ [self makeHost];
89
+ [super prepareForRecycle];
90
+ }
91
+
92
+ - (void)emit:(NSString *)name payload:(NSDictionary<NSString *, id> *)payload
93
+ {
94
+ if (!_eventEmitter) {
95
+ return;
96
+ }
97
+ auto emitter = std::static_pointer_cast<const SMapNativeViewEventEmitter>(_eventEmitter);
98
+ if ([name isEqualToString:@"mapReady"]) {
99
+ emitter->onMapReady({.node = RNSMapStd(payload[@"node"])});
100
+ } else if ([name isEqualToString:@"mapError"]) {
101
+ emitter->onMapError({.message = RNSMapStd(payload[@"message"])});
102
+ } else if ([name isEqualToString:@"layerTap"]) {
103
+ emitter->onLayerTap({
104
+ .layerId = RNSMapStd(payload[@"layerId"]),
105
+ .properties = RNSMapStd(payload[@"properties"]),
106
+ .lat = RNSMapDouble(payload[@"lat"]),
107
+ .lng = RNSMapDouble(payload[@"lng"]),
108
+ });
109
+ } else if ([name isEqualToString:@"tokenRequest"]) {
110
+ emitter->onTokenRequest({.requestId = (int)RNSMapDouble(payload[@"requestId"])});
111
+ }
112
+ }
113
+
114
+ #pragma mark - Commands
115
+
116
+ - (void)handleCommand:(const NSString *)commandName args:(const NSArray *)args
117
+ {
118
+ RCTSMapNativeViewHandleCommand(self, commandName, args);
119
+ }
120
+
121
+ - (void)addLayer:(NSString *)kind id:(NSString *)layerId data:(NSString *)data options:(NSString *)options
122
+ {
123
+ [_host addLayerWithKind:kind id:layerId data:data options:options];
124
+ }
125
+
126
+ - (void)setData:(NSString *)layerId data:(NSString *)data
127
+ {
128
+ [_host setDataWithId:layerId data:data];
129
+ }
130
+
131
+ - (void)setVisible:(NSString *)layerId visible:(BOOL)visible
132
+ {
133
+ [_host setVisibleWithId:layerId visible:visible];
134
+ }
135
+
136
+ - (void)removeLayer:(NSString *)layerId
137
+ {
138
+ [_host removeLayerWithId:layerId];
139
+ }
140
+
141
+ - (void)fitLayer:(NSString *)layerId padding:(double)padding maxZoom:(double)maxZoom
142
+ {
143
+ [_host fitLayerWithId:layerId padding:padding maxZoom:maxZoom];
144
+ }
145
+
146
+ - (void)flyTo:(double)lat lng:(double)lng zoom:(double)zoom
147
+ {
148
+ [_host flyToLat:lat lng:lng zoom:zoom];
149
+ }
150
+
151
+ - (void)resolveToken:(NSInteger)requestId token:(NSString *)token error:(NSString *)error
152
+ {
153
+ [_host resolveTokenWithRequestId:requestId token:token error:error];
154
+ }
155
+
156
+ @end
157
+
158
+ Class<RCTComponentViewProtocol> RNSMapNativeViewCls(void)
159
+ {
160
+ return RNSMapNativeView.class;
161
+ }
@@ -0,0 +1,96 @@
1
+ # CocoaPods helpers of @superrouteca/smap-react-native.
2
+ #
3
+ # The sMap iOS SDK is a Swift package (product `SMap`) whose rendering engine is a dynamic binary framework of that
4
+ # package. The pod gets the package through React Native's spm_dependency, which links it, but Xcode embeds a
5
+ # package's binary frameworks only in an app target that depends on the package itself. Linking the package into the
6
+ # app as well would link the SDK twice, so the app target is given a build phase that embeds the engine framework,
7
+ # by `SMapReactNative.post_install(installer)` in the app's Podfile:
8
+ #
9
+ # require Pod::Executable.execute_command('node', ['-p',
10
+ # 'require.resolve("@superrouteca/smap-react-native/ios/smap_react_native.rb", {paths: [process.argv[1]]})',
11
+ # __dir__]).strip
12
+ # ...
13
+ # post_install do |installer|
14
+ # react_native_post_install(installer, ...)
15
+ # SMapReactNative.post_install(installer)
16
+ # end
17
+ #
18
+ # Which package is used: SMAP_IOS_PACKAGE_PATH (a checkout of the Swift package) when set; else, inside the sMap SDK
19
+ # repository, the package next to this one; else the tag of this release from GitHub.
20
+ require "json"
21
+
22
+ module SMapReactNative
23
+ REMOTE = "https://github.com/Goodneo-Solutions/smap-sdk.git".freeze
24
+ PRODUCT = "SMap".freeze
25
+ PHASE = "[sMap] Embed map engine".freeze
26
+ ENGINE = "MapLibre.framework".freeze
27
+
28
+ # Copies the engine framework from the build products (where Xcode puts the package's binary framework) into the
29
+ # app's Frameworks folder and signs it as the app is signed.
30
+ EMBED_SCRIPT = <<~SH.freeze
31
+ set -e
32
+ src="${BUILT_PRODUCTS_DIR}/#{ENGINE}"
33
+ dst="${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}"
34
+ if [ ! -d "$src" ]; then
35
+ echo "error: #{ENGINE} not found in ${BUILT_PRODUCTS_DIR}; run pod install again"
36
+ exit 1
37
+ fi
38
+ mkdir -p "$dst"
39
+ rm -rf "$dst/#{ENGINE}"
40
+ cp -R "$src" "$dst/"
41
+ if [ "${CODE_SIGNING_ALLOWED}" = "YES" ] && [ -n "${EXPANDED_CODE_SIGN_IDENTITY}" ]; then
42
+ codesign --force --sign "${EXPANDED_CODE_SIGN_IDENTITY}" --preserve-metadata=identifier,entitlements "$dst/#{ENGINE}"
43
+ fi
44
+ SH
45
+
46
+ def self.package_root
47
+ File.realpath(File.join(__dir__, ".."))
48
+ end
49
+
50
+ def self.version
51
+ JSON.parse(File.read(File.join(package_root, "package.json")))["version"]
52
+ end
53
+
54
+ # The local Swift package directory, or nil for the published one.
55
+ def self.local_sdk
56
+ env = ENV["SMAP_IOS_PACKAGE_PATH"]
57
+ return File.expand_path(env) if env && !env.empty?
58
+ [File.join(package_root, "..", "ios"), File.join(package_root, "..")].map { |d| File.expand_path(d) }.find do |dir|
59
+ manifest = File.join(dir, "Package.swift")
60
+ File.exist?(manifest) && File.read(manifest).include?(".library(name: \"#{PRODUCT}\"")
61
+ end
62
+ end
63
+
64
+ # Called by the podspec.
65
+ def self.add_to_pod(spec)
66
+ local = local_sdk
67
+ if local
68
+ spm_dependency(spec, url: local, requirement: {}, products: [PRODUCT])
69
+ else
70
+ spm_dependency(spec, url: REMOTE, requirement: { kind: "exactVersion", version: version }, products: [PRODUCT])
71
+ end
72
+ end
73
+
74
+ # Adds the embed phase to every app target of the Podfile (once; kept up to date).
75
+ def self.post_install(installer)
76
+ inputs = ["${BUILT_PRODUCTS_DIR}/#{ENGINE}"]
77
+ outputs = ["${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/#{ENGINE}"]
78
+ installer.aggregate_targets.each do |aggregate|
79
+ project = aggregate.user_project
80
+ next unless project
81
+ changed = false
82
+ aggregate.user_targets.each do |target|
83
+ next unless target.respond_to?(:product_type) && target.product_type == "com.apple.product-type.application"
84
+ phase = target.shell_script_build_phases.find { |p| p.name == PHASE } || target.new_shell_script_build_phase(PHASE)
85
+ next if phase.shell_script == EMBED_SCRIPT && phase.input_paths == inputs && phase.output_paths == outputs
86
+ phase.shell_path = "/bin/sh"
87
+ phase.shell_script = EMBED_SCRIPT
88
+ phase.input_paths = inputs
89
+ phase.output_paths = outputs
90
+ Pod::UI.puts "[sMap] #{target.name} embeds the map engine framework"
91
+ changed = true
92
+ end
93
+ project.save if changed
94
+ end
95
+ end
96
+ end
package/package.json CHANGED
@@ -1,6 +1,69 @@
1
1
  {
2
2
  "name": "@superrouteca/smap-react-native",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
6
- }
3
+ "version": "1.0.1",
4
+ "description": "sMap for React Native: a map view for Superroute's sMap service, over the sMap Android and iOS SDKs.",
5
+ "license": "MIT",
6
+ "author": "Goodneo Solutions",
7
+ "homepage": "https://github.com/Goodneo-Solutions/smap-sdk/tree/main/react-native#readme",
8
+ "repository": {
9
+ "type": "git",
10
+ "url": "git+https://github.com/Goodneo-Solutions/smap-sdk.git",
11
+ "directory": "react-native"
12
+ },
13
+ "keywords": ["react-native", "map", "maps", "smap", "superroute", "ios", "android"],
14
+ "main": "src/index.tsx",
15
+ "types": "src/index.tsx",
16
+ "react-native": "src/index.tsx",
17
+ "source": "src/index.tsx",
18
+ "files": [
19
+ "src",
20
+ "!src/__tests__",
21
+ "android/build.gradle",
22
+ "android/src",
23
+ "ios",
24
+ "SMapReactNative.podspec",
25
+ "README.md",
26
+ "CHANGELOG.md",
27
+ "LICENSE"
28
+ ],
29
+ "scripts": {
30
+ "test": "jest",
31
+ "typecheck": "tsc --noEmit",
32
+ "prepack": "cp ../LICENSE LICENSE"
33
+ },
34
+ "peerDependencies": {
35
+ "react": ">=18",
36
+ "react-native": ">=0.81"
37
+ },
38
+ "devDependencies": {
39
+ "@babel/core": "7.29.7",
40
+ "@react-native/babel-preset": "0.88.0",
41
+ "@react-native/jest-preset": "0.88.0",
42
+ "@types/jest": "29.5.14",
43
+ "@types/react": "19.3.0",
44
+ "@types/react-test-renderer": "19.3.0",
45
+ "jest": "29.7.0",
46
+ "react": "19.3.0",
47
+ "react-native": "0.88.0",
48
+ "react-test-renderer": "19.3.0",
49
+ "typescript": "6.0.3"
50
+ },
51
+ "jest": {
52
+ "preset": "@react-native/jest-preset",
53
+ "roots": ["<rootDir>/src"],
54
+ "modulePathIgnorePatterns": ["<rootDir>/example/"]
55
+ },
56
+ "codegenConfig": {
57
+ "name": "SMapReactNativeSpec",
58
+ "type": "components",
59
+ "jsSrcsDir": "src",
60
+ "android": {
61
+ "javaPackageName": "ca.superroute.smap.reactnative"
62
+ },
63
+ "ios": {
64
+ "componentProvider": {
65
+ "SMapNativeView": "RNSMapNativeView"
66
+ }
67
+ }
68
+ }
69
+ }