expo-arcgis 0.1.4 → 0.1.6

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.
Files changed (34) hide show
  1. package/android/src/main/java/expo/modules/arcgis/ExpoArcgisExtrasModule.kt +26 -0
  2. package/android/src/main/java/expo/modules/arcgis/ExpoArcgisMapView.kt +20 -0
  3. package/android/src/main/java/expo/modules/arcgis/ExpoArcgisModule.kt +8 -0
  4. package/android/src/main/java/expo/modules/arcgis/ExpoArcgisSceneView.kt +6 -0
  5. package/android/src/main/java/expo/modules/arcgis/GraphicsOverlayRef.kt +26 -0
  6. package/android/src/main/java/expo/modules/arcgis/LayerRef.kt +20 -0
  7. package/android/src/main/java/expo/modules/arcgis/MapRef.kt +13 -0
  8. package/android/src/main/java/expo/modules/arcgis/SceneRef.kt +13 -0
  9. package/android/src/main/java/expo/modules/arcgis/ServiceGeodatabaseRef.kt +78 -0
  10. package/build/DynamicEntityLayer.d.ts.map +1 -1
  11. package/build/ExpoArcgis.types.d.ts +141 -1
  12. package/build/ExpoArcgis.types.d.ts.map +1 -1
  13. package/build/ExpoArcgis.types.js.map +1 -1
  14. package/build/ExpoArcgisModule.d.ts +18 -1
  15. package/build/ExpoArcgisModule.d.ts.map +1 -1
  16. package/build/ExpoArcgisModule.js.map +1 -1
  17. package/build/FeatureLayer.d.ts.map +1 -1
  18. package/build/Graphic.d.ts +7 -2
  19. package/build/Graphic.d.ts.map +1 -1
  20. package/build/Graphic.js +9 -4
  21. package/build/Graphic.js.map +1 -1
  22. package/ios/ExpoArcgisExtrasModule.swift +26 -0
  23. package/ios/ExpoArcgisMapView.swift +26 -0
  24. package/ios/ExpoArcgisModule.swift +8 -0
  25. package/ios/ExpoArcgisSceneView.swift +6 -0
  26. package/ios/GraphicsOverlayRef.swift +22 -0
  27. package/ios/LayerRef.swift +24 -0
  28. package/ios/MapRef.swift +12 -0
  29. package/ios/SceneRef.swift +12 -0
  30. package/ios/ServiceGeodatabaseRef.swift +81 -0
  31. package/package.json +1 -1
  32. package/src/ExpoArcgis.types.ts +136 -1
  33. package/src/ExpoArcgisModule.ts +20 -0
  34. package/src/Graphic.tsx +9 -4
@@ -71,6 +71,9 @@ class ExpoArcgisExtrasModule : Module() {
71
71
  AsyncFunction("updateAttachment") Coroutine { ref: FeatureLayerRef, objectId: Long, attachmentId: Long, name: String, contentType: String, dataBase64: String ->
72
72
  ref.updateAttachment(objectId, attachmentId, name, contentType, dataBase64)
73
73
  }
74
+ AsyncFunction("getServiceGeodatabase") Coroutine { ref: FeatureLayerRef ->
75
+ ref.getServiceGeodatabase()
76
+ }
74
77
  }
75
78
 
76
79
  // Per-service token credential — mint a token for a specific URL and add it to the store.
@@ -98,5 +101,28 @@ class ExpoArcgisExtrasModule : Module() {
98
101
  ref.switchToNextDestination()
99
102
  }
100
103
  }
104
+
105
+ // Branch versioning — a service geodatabase handle obtained from FeatureLayerRef.getServiceGeodatabase().
106
+ Class(ServiceGeodatabaseRef::class) {
107
+ AsyncFunction("fetchVersions") Coroutine { ref: ServiceGeodatabaseRef ->
108
+ ref.fetchVersions()
109
+ }
110
+ AsyncFunction("createVersion") Coroutine { ref: ServiceGeodatabaseRef, params: Map<String, Any?> ->
111
+ ref.createVersion(params)
112
+ }
113
+ AsyncFunction("switchVersion") Coroutine { ref: ServiceGeodatabaseRef, name: String ->
114
+ ref.switchVersion(name)
115
+ }
116
+ AsyncFunction("applyEdits") Coroutine { ref: ServiceGeodatabaseRef ->
117
+ ref.applyEdits()
118
+ }
119
+ AsyncFunction("undoLocalEdits") Coroutine { ref: ServiceGeodatabaseRef ->
120
+ ref.undoLocalEdits()
121
+ }
122
+ Function("hasLocalEdits") { ref: ServiceGeodatabaseRef -> ref.hasLocalEdits() }
123
+ Function("getVersionName") { ref: ServiceGeodatabaseRef -> ref.getVersionName() }
124
+ Function("getDefaultVersionName") { ref: ServiceGeodatabaseRef -> ref.getDefaultVersionName() }
125
+ Function("supportsBranchVersioning") { ref: ServiceGeodatabaseRef -> ref.supportsBranchVersioning() }
126
+ }
101
127
  }
102
128
  }
@@ -140,6 +140,12 @@ class ExpoArcgisMapView(context: Context, appContext: AppContext) : ExpoView(con
140
140
  scope.launch { mapView.setViewpointAnimated(Viewpoint(lat, lon, scale), 0.5f) }
141
141
  }
142
142
 
143
+ /** Sets the coordinate grid overlay from JS (null hides it). */
144
+ fun setGrid(config: Map<String, Any?>?) {
145
+ mapView.grid = buildGrid(config)
146
+ ?: com.arcgismaps.mapping.view.LatitudeLongitudeGrid().apply { isVisible = false }
147
+ }
148
+
143
149
  /** Enables/configures the device location display from JS (null disables it). */
144
150
  fun setLocationDisplay(config: Map<String, Any?>?) {
145
151
  val locationDisplay = mapView.locationDisplay
@@ -251,3 +257,17 @@ private fun autoPanMode(mode: String?): LocationDisplayAutoPanMode = when (mode)
251
257
  "compassNavigation" -> LocationDisplayAutoPanMode.CompassNavigation
252
258
  else -> LocationDisplayAutoPanMode.Off
253
259
  }
260
+
261
+ /// Builds an ArcGIS coordinate grid from a JS config (`{ type, visible? }`); null = no grid.
262
+ /// Shared by `ExpoArcgisMapView` and `ExpoArcgisSceneView`.
263
+ internal fun buildGrid(config: Map<String, Any?>?): com.arcgismaps.mapping.view.Grid? {
264
+ val type = config?.get("type") as? String ?: return null
265
+ val grid: com.arcgismaps.mapping.view.Grid = when (type) {
266
+ "mgrs" -> com.arcgismaps.mapping.view.MgrsGrid()
267
+ "utm" -> com.arcgismaps.mapping.view.UtmGrid()
268
+ "usng" -> com.arcgismaps.mapping.view.UsngGrid()
269
+ else -> com.arcgismaps.mapping.view.LatitudeLongitudeGrid()
270
+ }
271
+ (config["visible"] as? Boolean)?.let { grid.isVisible = it }
272
+ return grid
273
+ }
@@ -405,6 +405,10 @@ class ExpoArcgisModule : Module() {
405
405
  view.setGeometryEditor(ref)
406
406
  }
407
407
 
408
+ Prop("grid") { view: ExpoArcgisMapView, grid: Map<String, Any?>? ->
409
+ view.setGrid(grid)
410
+ }
411
+
408
412
  AsyncFunction("identify") { view: ExpoArcgisMapView, screenPoint: Map<String, Any?>, options: Map<String, Any?>?, promise: Promise ->
409
413
  view.identify(screenPoint, options, promise)
410
414
  }
@@ -443,6 +447,10 @@ class ExpoArcgisModule : Module() {
443
447
  view.setCameraController(value)
444
448
  }
445
449
 
450
+ Prop("grid") { view: ExpoArcgisSceneView, grid: Map<String, Any?>? ->
451
+ view.setGrid(grid)
452
+ }
453
+
446
454
  Prop("sunLighting") { view: ExpoArcgisSceneView, value: String? ->
447
455
  view.setSunLighting(value)
448
456
  }
@@ -167,6 +167,12 @@ class ExpoArcgisSceneView(context: Context, appContext: AppContext) : ExpoView(c
167
167
  }
168
168
  }
169
169
 
170
+ /** Sets the coordinate grid overlay from JS (null hides it). */
171
+ fun setGrid(config: Map<String, Any?>?) {
172
+ sceneView.grid = buildGrid(config)
173
+ ?: com.arcgismaps.mapping.view.LatitudeLongitudeGrid().apply { isVisible = false }
174
+ }
175
+
170
176
  /** Sun lighting mode (shadows). */
171
177
  fun setSunLighting(s: String?) {
172
178
  sceneView.sunLighting = when (s) {
@@ -20,8 +20,10 @@ import com.arcgismaps.mapping.symbology.DistanceCompositeSceneSymbol
20
20
  import com.arcgismaps.mapping.symbology.DistanceSymbolRange
21
21
  import com.arcgismaps.mapping.symbology.SimpleMarkerSceneSymbol
22
22
  import com.arcgismaps.mapping.symbology.SimpleMarkerSceneSymbolStyle
23
+ import com.arcgismaps.mapping.symbology.MultilayerPointSymbol
23
24
  import com.arcgismaps.mapping.symbology.PictureFillSymbol
24
25
  import com.arcgismaps.mapping.symbology.PictureMarkerSymbol
26
+ import com.arcgismaps.mapping.symbology.PictureMarkerSymbolLayer
25
27
  import com.arcgismaps.mapping.symbology.SimpleMarkerSymbol
26
28
  import com.arcgismaps.mapping.symbology.SimpleMarkerSymbolStyle
27
29
  import com.arcgismaps.mapping.symbology.SimpleRenderer
@@ -372,6 +374,30 @@ private fun buildSymbol(s: Map<*, *>): Symbol? = when (s["type"]) {
372
374
  }
373
375
  CompositeSymbol(symbolList)
374
376
  }
377
+ "multilayer-point" -> {
378
+ // Build each picture-marker symbol layer and assemble a MultilayerPointSymbol.
379
+ // symbolLayers on MultilayerSymbol is a mutable List — populated via the constructor.
380
+ // DEFER: vector-marker layers (VectorMarkerSymbolLayer) require VectorMarkerSymbolElement
381
+ // from geometry+symbol objects and cannot be cleanly constructed from a plain dict; skip.
382
+ val layerDicts = s["symbolLayers"] as? List<*> ?: emptyList<Any>()
383
+ val symbolLayers = layerDicts.mapNotNull { ld ->
384
+ val ldMap = ld as? Map<*, *> ?: return@mapNotNull null
385
+ when (ldMap["type"]) {
386
+ "picture-marker" -> {
387
+ val url = ldMap["url"] as? String ?: return@mapNotNull null
388
+ PictureMarkerSymbolLayer(url).apply {
389
+ (ldMap["size"] as? Number)?.toDouble()?.let { size = it }
390
+ (ldMap["width"] as? Number)?.toDouble()?.let { size = it }
391
+ (ldMap["height"] as? Number)?.toDouble()?.let { size = it }
392
+ (ldMap["offsetX"] as? Number)?.toDouble()?.let { offsetX = it }
393
+ (ldMap["offsetY"] as? Number)?.toDouble()?.let { offsetY = it }
394
+ }
395
+ }
396
+ else -> null
397
+ }
398
+ }
399
+ MultilayerPointSymbol(symbolLayers)
400
+ }
375
401
  else -> null
376
402
  }
377
403
 
@@ -82,6 +82,9 @@ class FeatureLayerRef(appContext: AppContext, props: Map<String, Any?>) : LayerR
82
82
  override val layer: FeatureLayer = FeatureLayer.createWithFeatureTable(table)
83
83
  private val scope = CoroutineScope(Dispatchers.Main + SupervisorJob())
84
84
 
85
+ /** Lazily-built branch-versioning handle for this layer's service geodatabase (cached). */
86
+ private var cachedServiceGeodatabase: ServiceGeodatabaseRef? = null
87
+
85
88
  /** Returns the features matching `query` (all features when null). Loads attributes in full. */
86
89
  suspend fun queryFeatures(query: Map<String, Any?>?): List<Map<String, Any?>> {
87
90
  val params = buildQueryParameters(query)
@@ -154,6 +157,23 @@ class FeatureLayerRef(appContext: AppContext, props: Map<String, Any?>) : LayerR
154
157
  (table as? ServiceFeatureTable)?.undoLocalEdits()?.getOrThrow()
155
158
  }
156
159
 
160
+ /**
161
+ * Returns the branch-versioning handle for this layer's service geodatabase. Loads the table
162
+ * first (so the geodatabase is populated). Throws if the layer is not backed by a feature
163
+ * service. The same handle is returned on repeat calls.
164
+ */
165
+ suspend fun getServiceGeodatabase(): ServiceGeodatabaseRef {
166
+ cachedServiceGeodatabase?.let { return it }
167
+ val serviceTable = table as? ServiceFeatureTable
168
+ ?: throw IllegalStateException("Layer is not backed by a service feature table")
169
+ serviceTable.load().getOrThrow()
170
+ val geodatabase = serviceTable.serviceGeodatabase
171
+ ?: throw IllegalStateException("Service geodatabase unavailable for this layer")
172
+ cachedServiceGeodatabase?.let { return it } // guard the load race
173
+ val ctx = appContext ?: throw IllegalStateException("No app context")
174
+ return ServiceGeodatabaseRef(ctx, geodatabase).also { cachedServiceGeodatabase = it }
175
+ }
176
+
157
177
  /** Queries features related to `objectId` (across all relationships); returns groups by relationship. */
158
178
  suspend fun queryRelatedFeatures(objectId: Long): List<Map<String, Any?>> {
159
179
  val arcgisTable = table as? ArcGISFeatureTable ?: return emptyList()
@@ -3,6 +3,7 @@ package expo.modules.arcgis
3
3
  import com.arcgismaps.geometry.Envelope
4
4
  import com.arcgismaps.mapping.ArcGISMap
5
5
  import com.arcgismaps.mapping.Basemap
6
+ import com.arcgismaps.mapping.Bookmark
6
7
  import com.arcgismaps.mapping.BasemapStyle
7
8
  import com.arcgismaps.mapping.BasemapStyleLanguageStrategy
8
9
  import com.arcgismaps.mapping.BasemapStyleParameters
@@ -71,6 +72,18 @@ class MapRef(appContext: AppContext, portalItem: Map<String, Any?>? = null) : Sh
71
72
  map.initialViewpoint = Viewpoint(lat, lon, scale)
72
73
  }
73
74
  }
75
+ "bookmarks" -> (value as? List<*>)?.let { entries ->
76
+ map.bookmarks.clear()
77
+ for (entry in entries) {
78
+ val e = entry as? Map<*, *> ?: continue
79
+ val name = e["name"] as? String ?: continue
80
+ val vp = e["viewpoint"] as? Map<*, *> ?: continue
81
+ val lat = (vp["latitude"] as? Number)?.toDouble() ?: continue
82
+ val lon = (vp["longitude"] as? Number)?.toDouble() ?: continue
83
+ val scale = (vp["scale"] as? Number)?.toDouble() ?: continue
84
+ map.bookmarks.add(Bookmark(name, Viewpoint(lat, lon, scale)))
85
+ }
86
+ }
74
87
  "mobileMapPackagePath" -> (value as? String)?.let { loadMobileMapPackage(it) }
75
88
  "referenceScale" -> (value as? Number)?.let { map.referenceScale = it.toDouble() }
76
89
  "maxExtent" -> (value as? Map<*, *>)?.let { dict ->
@@ -4,6 +4,7 @@ import com.arcgismaps.geometry.Point
4
4
  import com.arcgismaps.geometry.SpatialReference
5
5
  import com.arcgismaps.mapping.ArcGISScene
6
6
  import com.arcgismaps.mapping.ArcGISTiledElevationSource
7
+ import com.arcgismaps.mapping.Bookmark
7
8
  import com.arcgismaps.mapping.Basemap
8
9
  import com.arcgismaps.mapping.BasemapStyle
9
10
  import com.arcgismaps.mapping.MobileScenePackage
@@ -80,6 +81,18 @@ class SceneRef(appContext: AppContext, portalItem: Map<String, Any?>? = null) :
80
81
  scene.initialViewpoint = Viewpoint(point, camera)
81
82
  }
82
83
  }
84
+ "bookmarks" -> (value as? List<*>)?.let { entries ->
85
+ scene.bookmarks.clear()
86
+ for (entry in entries) {
87
+ val e = entry as? Map<*, *> ?: continue
88
+ val name = e["name"] as? String ?: continue
89
+ val vp = e["viewpoint"] as? Map<*, *> ?: continue
90
+ val lat = (vp["latitude"] as? Number)?.toDouble() ?: continue
91
+ val lon = (vp["longitude"] as? Number)?.toDouble() ?: continue
92
+ val scale = (vp["scale"] as? Number)?.toDouble() ?: continue
93
+ scene.bookmarks.add(Bookmark(name, Viewpoint(lat, lon, scale)))
94
+ }
95
+ }
83
96
  "mobileScenePackagePath" -> (value as? String)?.let { loadMobileScenePackage(it) }
84
97
  }
85
98
  }
@@ -0,0 +1,78 @@
1
+ package expo.modules.arcgis
2
+
3
+ import com.arcgismaps.arcgisservices.ServiceVersionInfo
4
+ import com.arcgismaps.arcgisservices.ServiceVersionParameters
5
+ import com.arcgismaps.arcgisservices.VersionAccess
6
+ import com.arcgismaps.data.ServiceGeodatabase
7
+ import expo.modules.kotlin.AppContext
8
+ import expo.modules.kotlin.sharedobjects.SharedObject
9
+
10
+ /**
11
+ * Branch-versioning handle over a [ServiceGeodatabase]. Built by `FeatureLayerRef.getServiceGeodatabase()`
12
+ * (never constructed from JS). Manages named branch versions and pushes the service-wide local edits
13
+ * (across every connected table) to the active version.
14
+ */
15
+ class ServiceGeodatabaseRef(appContext: AppContext, private val geodatabase: ServiceGeodatabase) :
16
+ SharedObject(appContext) {
17
+
18
+ /** Lists every branch version defined on the service. */
19
+ suspend fun fetchVersions(): List<Map<String, Any?>> =
20
+ geodatabase.fetchVersions().getOrThrow().map { serializeVersionInfo(it) }
21
+
22
+ /** Creates a new branch version from `{ name, description?, access? }` and returns its info. */
23
+ suspend fun createVersion(params: Map<String, Any?>): Map<String, Any?> {
24
+ val parameters = ServiceVersionParameters().apply {
25
+ (params["name"] as? String)?.let { name = it }
26
+ (params["description"] as? String)?.let { description = it }
27
+ access = versionAccess(params["access"] as? String)
28
+ }
29
+ return serializeVersionInfo(geodatabase.createVersion(parameters).getOrThrow())
30
+ }
31
+
32
+ /** Switches the active version (requires no outstanding local edits). */
33
+ suspend fun switchVersion(name: String) {
34
+ geodatabase.switchVersion(name).getOrThrow()
35
+ }
36
+
37
+ /** Pushes all connected tables' local edits to the active version; returns each edit's result. */
38
+ suspend fun applyEdits(): List<Map<String, Any?>> =
39
+ geodatabase.applyEdits().getOrThrow().flatMap { it.editResults }.map {
40
+ mapOf("objectId" to it.objectId, "completedWithErrors" to it.completedWithErrors)
41
+ }
42
+
43
+ /** Discards all local edits across the connected tables. */
44
+ suspend fun undoLocalEdits() {
45
+ geodatabase.undoLocalEdits().getOrThrow()
46
+ }
47
+
48
+ fun hasLocalEdits(): Boolean = geodatabase.hasLocalEdits()
49
+ fun getVersionName(): String = geodatabase.versionName
50
+ fun getDefaultVersionName(): String = geodatabase.defaultVersionName
51
+ fun supportsBranchVersioning(): Boolean = geodatabase.supportsBranchVersioning
52
+ }
53
+
54
+ /** Serializes a [ServiceVersionInfo] to a JS-friendly map. */
55
+ private fun serializeVersionInfo(info: ServiceVersionInfo): Map<String, Any?> {
56
+ val dict = mutableMapOf<String, Any?>(
57
+ "name" to info.name,
58
+ "description" to info.description,
59
+ "access" to accessString(info.access),
60
+ "isOwner" to info.isOwner,
61
+ )
62
+ info.versionId?.toString()?.let { dict["versionId"] = it }
63
+ return dict
64
+ }
65
+
66
+ /** Native [VersionAccess] -> JS string. */
67
+ private fun accessString(access: VersionAccess): String = when (access) {
68
+ is VersionAccess.Protected -> "protected"
69
+ is VersionAccess.Private -> "private"
70
+ else -> "public"
71
+ }
72
+
73
+ /** JS string -> native [VersionAccess] (defaults to public). */
74
+ private fun versionAccess(string: String?): VersionAccess = when (string) {
75
+ "protected" -> VersionAccess.Protected
76
+ "private" -> VersionAccess.Private
77
+ else -> VersionAccess.Public
78
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"DynamicEntityLayer.d.ts","sourceRoot":"","sources":["../src/DynamicEntityLayer.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EACV,gBAAgB,EAChB,mBAAmB,EACnB,wBAAwB,EAEzB,MAAM,oBAAoB,CAAC;AAO5B;;;;;GAKG;AACH,eAAO,MAAM,kBAAkB;;;;;mBAwD2i3B,CAAC;gBAAkB,CAAC;;;;;;;4DAD7l3B,CAAC"}
1
+ {"version":3,"file":"DynamicEntityLayer.d.ts","sourceRoot":"","sources":["../src/DynamicEntityLayer.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EACV,gBAAgB,EAChB,mBAAmB,EACnB,wBAAwB,EAEzB,MAAM,oBAAoB,CAAC;AAO5B;;;;;GAKG;AACH,eAAO,MAAM,kBAAkB;;;;;mBAwD489B,CAAC;gBAAkB,CAAC;;;;;;;4DAD9/9B,CAAC"}
@@ -63,6 +63,19 @@ export type MapProps = {
63
63
  * map appears once ready.
64
64
  */
65
65
  mobileMapPackagePath?: string;
66
+ /**
67
+ * Named saved viewpoints stored on the map. Replaces the map's bookmark list each time the prop
68
+ * changes. Each entry creates a native `Bookmark(name, Viewpoint(latitude, longitude, scale))`.
69
+ * Navigation to a bookmark is done separately via the `<MapView viewpoint>` prop.
70
+ */
71
+ bookmarks?: {
72
+ name: string;
73
+ viewpoint: {
74
+ latitude: number;
75
+ longitude: number;
76
+ scale: number;
77
+ };
78
+ }[];
66
79
  };
67
80
  export type MapLoadedEventPayload = {
68
81
  /** WKID of the loaded map's spatial reference, or null if unavailable. */
@@ -134,6 +147,15 @@ export type MapViewProps = {
134
147
  onLocationChange?: (event: {
135
148
  nativeEvent: LocationEventPayload;
136
149
  }) => void;
150
+ /** Coordinate-grid overlay (MGRS / UTM / USNG / latitude-longitude). `null` / omitted = none. */
151
+ grid?: GridConfig | null;
152
+ };
153
+ /** A coordinate-grid overlay for a `<MapView>` / `<SceneView>`. */
154
+ export type GridConfig = {
155
+ /** Grid type: military grid (MGRS), UTM, US National Grid, or latitude-longitude. */
156
+ type: 'mgrs' | 'utm' | 'usng' | 'latitude-longitude';
157
+ /** Whether the grid is drawn. Defaults to `true`. */
158
+ visible?: boolean;
137
159
  };
138
160
  /** Common operational-layer props (subset of ArcGIS layer properties). */
139
161
  export type LayerProps = {
@@ -520,6 +542,63 @@ export type FeatureLayerHandle = {
520
542
  * @param dataBase64 New base64-encoded file contents.
521
543
  */
522
544
  updateAttachment(objectId: number, attachmentId: number, name: string, contentType: string, dataBase64: string): Promise<void>;
545
+ /**
546
+ * Returns the branch-versioning handle for this layer's service geodatabase (ArcGIS Enterprise
547
+ * branch-versioned services only). Loads the table first; rejects if the layer is not a service
548
+ * feature layer. The same handle is returned on repeat calls.
549
+ */
550
+ getServiceGeodatabase(): Promise<ServiceGeodatabaseHandle>;
551
+ };
552
+ /** Branch-version access level. */
553
+ export type VersionAccess = 'public' | 'protected' | 'private';
554
+ /** Metadata for one branch version of a service geodatabase. */
555
+ export type ServiceVersionInfo = {
556
+ /** Fully-qualified version name (e.g. `"OWNER.versionName"`). */
557
+ name: string;
558
+ /** Free-text description. */
559
+ description: string;
560
+ /** Who may see / edit the version. */
561
+ access: VersionAccess;
562
+ /** Whether the current user owns this version. */
563
+ isOwner: boolean;
564
+ /** Server-assigned version GUID, when available. */
565
+ versionId?: string;
566
+ };
567
+ /** Parameters for creating a new branch version. */
568
+ export type CreateVersionParams = {
569
+ /** Short version name (the server prefixes the owner). */
570
+ name: string;
571
+ /** Optional description. */
572
+ description?: string;
573
+ /** Access level. Defaults to `"public"`. */
574
+ access?: VersionAccess;
575
+ };
576
+ /**
577
+ * Handle to a service geodatabase's branch-versioning surface, from
578
+ * `FeatureLayerHandle.getServiceGeodatabase()`. Manages named versions and pushes the service-wide
579
+ * local edits (across every connected table) to the active version. Edit features through the
580
+ * `<FeatureLayer>` handle with `apply: false`, then call `applyEdits()` here to push them — distinct
581
+ * from the table-level `FeatureLayerHandle.applyEdits()`, which pushes only this layer's table.
582
+ */
583
+ export type ServiceGeodatabaseHandle = {
584
+ /** Lists all branch versions on the service. */
585
+ fetchVersions(): Promise<ServiceVersionInfo[]>;
586
+ /** Creates a new branch version and resolves with its info. */
587
+ createVersion(params: CreateVersionParams): Promise<ServiceVersionInfo>;
588
+ /** Switches the active version (rejects if there are outstanding local edits). */
589
+ switchVersion(name: string): Promise<void>;
590
+ /** Pushes all connected tables' local edits to the active version in one batch. */
591
+ applyEdits(): Promise<EditResult[]>;
592
+ /** Discards all local edits across connected tables. */
593
+ undoLocalEdits(): Promise<void>;
594
+ /** Whether any connected table has unsaved local edits. */
595
+ hasLocalEdits(): boolean;
596
+ /** The active version's name. */
597
+ getVersionName(): string;
598
+ /** The default version name (e.g. `"sde.DEFAULT"`). */
599
+ getDefaultVersionName(): string;
600
+ /** Whether the service supports branch versioning. */
601
+ supportsBranchVersioning(): boolean;
523
602
  };
524
603
  /** A label rule for a `<FeatureLayer>` — mirrors the native `LabelDefinition`. */
525
604
  export type LabelDefinition = {
@@ -1588,8 +1667,54 @@ export type CompositeSymbolType = {
1588
1667
  /** The symbols to stack, drawn in order (first = bottom, last = top). */
1589
1668
  symbols: Symbol[];
1590
1669
  };
1670
+ /**
1671
+ * One picture-marker symbol layer within a `MultilayerPointSymbolType`.
1672
+ * Mirrors the native `PictureMarkerSymbolLayer`.
1673
+ *
1674
+ * NOTE: `size` sets a uniform size (overrides `width`/`height` when all three are supplied).
1675
+ * `width` and `height` are applied in order, so supplying both sets size to the last one;
1676
+ * use `size` for a uniform value. `offsetX`/`offsetY` shift the layer in points.
1677
+ *
1678
+ * DEFER: `VectorMarkerSymbolLayer` (the vector-marker kind) requires constructing
1679
+ * `VectorMarkerSymbolElement` objects from geometry + symbol objects, which cannot be
1680
+ * expressed as a plain flat dict. It is not yet implemented.
1681
+ */
1682
+ export type PictureMarkerSymbolLayerSpec = {
1683
+ type: 'picture-marker';
1684
+ /** Image URL (remote `http(s)` or a local file URL). */
1685
+ url: string;
1686
+ /** Uniform size in points (sets both width and height). */
1687
+ size?: number;
1688
+ /** Display width in points. */
1689
+ width?: number;
1690
+ /** Display height in points. */
1691
+ height?: number;
1692
+ /** Horizontal offset of the layer, in points. */
1693
+ offsetX?: number;
1694
+ /** Vertical offset of the layer, in points. */
1695
+ offsetY?: number;
1696
+ };
1697
+ /** Union of all supported symbol layer kinds within a `MultilayerPointSymbolType`. */
1698
+ export type SymbolLayerSpec = PictureMarkerSymbolLayerSpec;
1699
+ /**
1700
+ * A multilayer point symbol composed of one or more symbol layers.
1701
+ * Mirrors the native `MultilayerPointSymbol`. Useful for rich point icons built from stacked
1702
+ * picture images (e.g. a pin body + a badge overlay at different offsets).
1703
+ *
1704
+ * @example
1705
+ * ```ts
1706
+ * { type: 'multilayer-point', symbolLayers: [
1707
+ * { type: 'picture-marker', url: 'https://example.com/pin.png', width: 30, height: 30 },
1708
+ * ] }
1709
+ * ```
1710
+ */
1711
+ export type MultilayerPointSymbolType = {
1712
+ type: 'multilayer-point';
1713
+ /** The symbol layers to compose, rendered in list order. */
1714
+ symbolLayers: SymbolLayerSpec[];
1715
+ };
1591
1716
  /** Any symbol usable by a `<Graphic>`. Mirrors the native `Symbol` hierarchy. */
1592
- export type Symbol = SimpleMarkerSymbol | SimpleLineSymbol | SimpleFillSymbol | TextSymbol | SimpleMarkerSceneSymbol | PictureMarkerSymbol | PictureFillSymbol | DistanceCompositeSceneSymbol | CompositeSymbolType;
1717
+ export type Symbol = SimpleMarkerSymbol | SimpleLineSymbol | SimpleFillSymbol | TextSymbol | SimpleMarkerSceneSymbol | PictureMarkerSymbol | PictureFillSymbol | DistanceCompositeSceneSymbol | CompositeSymbolType | MultilayerPointSymbolType;
1593
1718
  /** One stop in a `SizeVisualVariable` stops array. */
1594
1719
  export type SizeStop = {
1595
1720
  value: number;
@@ -1774,6 +1899,19 @@ export type SceneProps = {
1774
1899
  portalItem?: PortalItem;
1775
1900
  /** Local path to a mobile scene package (`.mspk`); its first scene is shown when loaded. */
1776
1901
  mobileScenePackagePath?: string;
1902
+ /**
1903
+ * Named saved viewpoints stored on the scene. Replaces the scene's bookmark list each time the
1904
+ * prop changes. Each entry creates a native `Bookmark(name, Viewpoint(latitude, longitude, scale))`.
1905
+ * Navigation to a bookmark is done separately via the `<SceneView camera>` prop.
1906
+ */
1907
+ bookmarks?: {
1908
+ name: string;
1909
+ viewpoint: {
1910
+ latitude: number;
1911
+ longitude: number;
1912
+ scale: number;
1913
+ };
1914
+ }[];
1777
1915
  };
1778
1916
  /** Sun lighting mode for a 3D scene view (controls shadows). */
1779
1917
  export type SunLighting = 'off' | 'light' | 'lightAndShadows';
@@ -1804,6 +1942,8 @@ export type SceneViewProps = {
1804
1942
  * - `{ type: 'globe' }` — free globe navigation.
1805
1943
  */
1806
1944
  cameraController?: CameraController | null;
1945
+ /** Coordinate-grid overlay (MGRS / UTM / USNG / latitude-longitude). `null` / omitted = none. */
1946
+ grid?: GridConfig | null;
1807
1947
  /** Sun lighting mode (shadows). Defaults to `off`. */
1808
1948
  sunLighting?: SunLighting;
1809
1949
  /** Atmosphere rendering. Defaults to `horizonOnly`. */