ReviewOS

also looking at this

craft-native/craft

feat(maps): add key-free native Android maps and shared map controls

#363
Merged chris wants to merge codex/wildloop-native-map-providers into main
28 files +1857 -481

Review threads live on the whole diff, not on one commit, so none are shown here - a thread's line means something in the branch's final form, and painting it into an intermediate step would put it on code it is not about.

docs/guides/native-stx.mdmodified+15-6
Changes to docs/guides/native-stx.md
@@ -154,7 +154,7 @@ next route.
154154| `Image` | `UIImageView` | `ImageView` |
155155| `ImageBackground` | `CraftNativeImageBackgroundView` | `CraftNativeImageBackgroundView` |
156156| `Video` | `CraftNativeVideoView` (`AVPlayerViewController`) | `CraftNativeVideoView` (`VideoView`) |
157| `Map` | `CraftNativeMapView` (`MKMapView`) | `CraftNativeMapView` (`GoogleMap`) |
157| `Map` | `CraftNativeMapView` (`MKMapView`) | `CraftNativeMapView` (native MapLibre or Google Maps) |
158158| `MapPolyline`, `MapMarker` | overlays inside `CraftNativeMapView` | overlays inside `CraftNativeMapView` |
159159| `Svg` | `CraftNativeSvgView` | `CraftNativeSvgView` |
160160| `G`, `SvgText` | drawn inside `CraftNativeSvgView` | drawn inside `CraftNativeSvgView` |
@@ -228,12 +228,21 @@ or `fitToBounds`, which recenters only when its overlay geometry changes. Explic
228228authored camera bounds on both hosts; only `fitToBounds` adds framing padding. A marker's `onPress` or
229229`onMarkerPress` receives `nativeEvent.id`; a marker's own handler wins, and the map-level handler is
230230used as a fallback when the marker has no non-empty handler.
231It is backed by MapKit on iOS and the Google Maps SDK on
232Android; the Android template adds that dependency only for screens that opt
233into the native map host. The shared `mapType` values are `standard`,
231It is backed by MapKit on iOS and the configured native provider on Android.
232Set the Craft Android config's `mapProvider` to `maplibre` for a key-free native
233GL view; `google` preserves the existing Google Maps host. Only the selected
234provider's SDK is included in the generated Android project. These STX map
235components do not use the DOM-based `@craft-native/ts-maps` adapter.
236The shared `mapType` values are `standard`,
234237`satellite`, and `hybrid`; Android's terrain-only style is intentionally not
235part of the cross-platform contract. Tile styling, clustering, directions, and
236offline tiles remain outside this contract. Set `showsUserLocation` to opt into the
238part of the cross-platform contract. `tileOverlay` accepts an HTTPS raster URL
239template and its visible provider attribution. `edgePadding` reserves logical
240points around a fitted route for floating controls. `pitchEnabled` controls
241tilt gestures; `cameraPitch` and `cameraHeading` set the camera explicitly.
242Markers accept `pinColor` for trailheads and inspected profile positions, or
243`bearing` for a contrasting route-direction sign. Clustering, turn-by-turn
244directions, and offline tile downloads remain outside this view contract.
245Set `showsUserLocation` to opt into the
237246platform location dot; the host only enables it when the app's existing
238247location permission is already granted, and never prompts from a renderer
239248pass. Android also forwards `MapView` start/stop lifecycle callbacks as map
packages/android/README.mdmodified+15-5
Changes to packages/android/README.md
@@ -140,18 +140,28 @@ craft android build --native-bundle ../native-screen.js
140140Native mode maps STX `View`, `SafeAreaView`, `KeyboardAvoidingView`, `StatusBar`,
141141`RefreshControl`, `Text`, `Button`, `Link`, `Icon`,
142142`Pressable`, `TouchableOpacity`, `TouchableHighlight`, `Checkbox`, `TextInput`, `Picker`, `DatePicker`, `Modal`, `Switch`, `Slider`, `ActivityIndicator`, `Image`, `ImageBackground`, `Video`, `Svg`, `G`, `SvgText`, `ScrollView`,
143`Map`, `SectionList`, and `FlatList` to Android views. `Map` uses the Google
144Maps SDK for trail polylines and marker taps; its overlays carry flat
143`Map`, `SectionList`, and `FlatList` to Android views. `Map` uses the configured
144native map provider for trail polylines and marker taps; its overlays carry flat
145145latitude/longitude `geometry` arrays, `strokeWidth` is expressed in logical
146146points, and the camera supports controlled `region`, one-time `initialRegion`,
147and `fitToBounds`. Set `mapsApiKey` in the Android config to emit the SDK manifest key;
147and `fitToBounds`. Select `mapProvider: 'maplibre'` for the key-free native
148MapLibre renderer. It uses native GL views and needs neither a Google map SDK
149dependency nor a Google map key. `mapProvider: 'google'` retains the existing
150Google Maps host and uses `mapsApiKey` for its SDK manifest key; Google remains
151the default for compatibility with existing projects.
152
148153Coordinates must be JSON numbers (numeric strings are not coerced), are
149154range-checked at the native boundary, and invalid points or pole-crossing
150155regions are ignored. `fitToBounds` waits for the map viewport to
151156be measured before caching a successful camera fit, so an early map callback
152157does not lose the initial route framing.
153without it, the native map remains an explicit opt-in integration that needs
154the app's own Maps credentials. `SectionList` uses the same
158The shared controls include `showsCompass`, `showsScale`, `pitchEnabled`,
159`cameraPitch`, `cameraHeading`, and floating-control `edgePadding`. Markers
160accept `pinColor` and route-direction `bearing`. The builder's
161`nativeMapProviders` export advertises the providers it actually implements,
162so a build orchestrator can refuse an unsupported explicit choice.
163
164`SectionList` uses the same
155165native scroll host for ordinary `.stx` slot children; grouped section data
156166should use `FlatList` until the section-data protocol is available. The
157167generated host routes both list names through `CraftNativeScrollView` for this
packages/ts-maps/README.mdmodified+8-1
Changes to packages/ts-maps/README.md
@@ -2,7 +2,14 @@
22
33Craft SDK bindings for the [ts-maps](https://github.com/stacksjs/ts-maps) interactive map runtime.
44
5This package is the TypeScript side of `MapProvider.ts_maps` in Craft's Zig core. It ships a `MapView` component you can drop into any Craft app (desktop, mobile, WebView) to get a cross-platform interactive map with zero API keys.
5This package is the TypeScript side of `MapProvider.ts_maps` in Craft's Zig core.
6Its `MapView` owns a DOM container and renders ts-maps inside a browser or
7WebView, with zero API keys. It is not the STX native `Map` component.
8
9For a fully native STX screen, use `Map`, `MapMarker`, and `MapPolyline`.
10Craft renders them with MapKit on iOS and the configured native Android map
11provider. Android's `mapProvider: 'maplibre'` selects a key-free native GL view;
12it does not mount this package's DOM adapter.
613
714## Install
815
packages/ts-maps/src/MapView.tsmodified+2-2
Changes to packages/ts-maps/src/MapView.ts
@@ -1,6 +1,6 @@
11/**
2 * `MapView` — Craft-native interactive map component backed by the
3 * ts-maps runtime. Instances are WebView-hosted; in native Craft apps
2 * `MapView` — Craft WebView map component backed by the
3 * ts-maps runtime. Instances own a DOM container; in Craft apps
44 * the Zig core drives them via the `ts_maps` bridge namespace.
55 *
66 * @module @craft-native/ts-maps/MapView