diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml
new file mode 100644
index 0000000..e60ff59
--- /dev/null
+++ b/.github/FUNDING.yml
@@ -0,0 +1,2 @@
+github: [maplibre]
+open_collective: maplibre
diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md
new file mode 100644
index 0000000..f870b43
--- /dev/null
+++ b/.github/pull_request_template.md
@@ -0,0 +1,10 @@
+# Issue/Motivation
+
+What issue is this PR targeting?
+
+## Tasklist
+
+- [ ] Include tests (if applicable) and examples (new or edits)
+- [ ] If there are any visual changes as a result, include before/after screenshots and/or videos
+- [ ] Add #fixes with the issue number that this PR addresses
+- [ ] Update any documentation for affected APIs
diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md
new file mode 100644
index 0000000..aa2ca4f
--- /dev/null
+++ b/CODE_OF_CONDUCT.md
@@ -0,0 +1,2 @@
+# Contributor Covenant
+[](https://github.com/maplibre/maplibre/blob/main/CODE_OF_CONDUCT.md)
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
new file mode 100644
index 0000000..49635f1
--- /dev/null
+++ b/CONTRIBUTING.md
@@ -0,0 +1,49 @@
+# Contributor Guide
+
+This project is a standard Swift package.
+
+## Environment setup
+
+The only special thing you might need besides Xcode is [`swiftformat`](https://github.com/nicklockwood/SwiftFormat).
+We use it to automatically handle basic formatting and to linting
+so the code has a standard style.
+
+Check out the swiftformat [Install Guide](https://github.com/nicklockwood/SwiftFormat?tab=readme-ov-file#how-do-i-install-it)
+to add swiftformat to your machine.
+Once installed, you can autoformat code using the command:
+
+```sh
+swiftformat .
+```
+
+Swiftformat can occasionally poorly resolve a formatting issue (e.g. when you've already line-broken a large comment).
+Issues like this are typically easy to manually correct.
+
+## Structure
+
+This package is structured into a few targets. `InternalUtils` is pretty much what it says. `MapLibreSwiftDSL` and
+`MapLibreSwiftUI` are published products, and make up the bulk of the project. Finally, `Examples` is a collection of
+SwiftUI previews.
+
+The DSL provides a more Swift-y layer on top of the lower level MapLibre APIs, and features a number of
+result builders which enable more modern expressive APIs.
+
+The SwiftUI layer publishes a SwiftUI view with the end goal of being a universal view that can be adapted to a wide
+variety of use cases, much like MapKit's SwiftUI views.
+
+## Testing
+
+We do not currently have full UI tests.
+These are a bit tricky due to the async nature of MapLibre and integrating this into an Xcode UI test is challenging.
+If you have any suggestions, we welcome them!
+
+## PRs
+
+If you're using this project and want to improve it, send us a PR!
+We have a checklist in our PR template to help reviews go smoothly.
+
+NOTE: If possible, enable maintainer edits when you open PRs.
+If your PR is good and just needs a few minor edits to get merged,
+we can often put those finishing touches on for you.
+In order to allow maintainer edits,
+you need to send PRs from a personal fork (org-owned ones have funky auth).
diff --git a/LICENSE.md b/LICENSE.md
index 2f23078..77601ee 100644
--- a/LICENSE.md
+++ b/LICENSE.md
@@ -1,4 +1,4 @@
-Copyright (c) 2023, Stadia Maps, Inc.
+Copyright (c) 2024, MapLibre contributors.
All rights reserved.
@@ -10,7 +10,7 @@ are permitted provided that the following conditions are met:
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
- * Neither the name of MapLibre GL JS nor the names of its contributors
+ * Neither the name of MapLibre nor the names of its contributors
may be used to endorse or promote products derived from this software
without specific prior written permission.
diff --git a/README.md b/README.md
index 88ba675..5c1f4e3 100644
--- a/README.md
+++ b/README.md
@@ -1,3 +1,7 @@
+
+
+
+
# MapLibreSwiftUI
Swift DSLs for [MapLibre Native](https://github.com/maplibre/maplibre-native), a free open-source renderer
@@ -5,27 +9,24 @@ for interactive vector maps, to enable better integration with SwiftUI and gener

-This package is a playground (read: not yet stable) to experiment with Swift DSLs and SwiftUI without constraints.
-As more people try this out with their own use cases, the community should eventuallly stabilize on a
-reasonably optimal DSL for working with MapLibre in Swift. The package name is currently MapLibreSwiftUI, but it's
-possible that the SwiftUI and DSL layers are separable.
-
-If successful, some version this project should eventually either get merged into MapLibre Native or at the least
-merged into the MapLibre organization more formally. It is being developed as a separate package initially so we
-can move fast without breaking anything important.
-
-**NOTE: This currently only works on iOS, as that's the only architecture currently published in the dynamic framework.**
+This package is a reimagining of the MapLibre API with a modern DSLs for SwiftUI.
+The pre-1.0 status means only that we are not yet committed to API stability yet,
+since we care deeply about finding the best way to express things for SwfitUI users.
+The package is robust for the subset of the MapLibre iOS API that it supports.
+Any breaking API changes will be reflected in release notes.
## Goals
-1. Primary: Make common use cases easy and make complicated ones possible
+1. Primary: Make common use cases easy and [make complicated ones possible](Sources/MapLibreSwiftUI/Examples/Other.swift)
* Easy integration of MapLibre into a modern SwiftUI app
- * Add markers and similar annotations
+ * Add [markers](Sources/MapLibreSwiftUI/Examples/Gestures.swift), [polylines](Sources/MapLibreSwiftUI/Examples/Polyline.swift) and similar annotations
+ * Interaction with features through [gestures](Sources/MapLibreSwiftUI/Examples/Gestures.swift)
* Clustering (common use case that's rather difficult for first timers)
- * Overlays
+ * [Overlays]](Sources/MapLibreSwiftUI/Examples/)
* Dynamic styling
- * Camera control / animation??
- * Navigation
+ * [Camera control](Sources/MapLibreSwiftUI/Examples/Camera.swift)
+ * Turn-by-turn Navigation (see the showcase integrations below)
+ * Animation
2. Prevent most common classes of mistakes that users make with the lower level APIs (ex: adding the same source twice)
3. Deeper SwiftUI integration (ex: SwiftUI callout views)
@@ -44,28 +45,104 @@ Then, for each target add either the DSL (for just the DSL) or both (for the Swi
.product(name: "MapLibreSwiftUI", package: "maplibre-swiftui-dsl-playground"),
```
-Check out the (super basic) [previews at the bottom of MapView.swift](Sources/MapLibreSwiftUI/MapView.swift)
-or more detailed [Examples](Sources/MapLibreSwiftUI/Examples) to see how it works in practice.
+Then, you can use it in a SwiftUI view body like this:
+
+```swift
+import MapLibre
+import MapLibreSwiftDSL
+import SwiftUI
+import CoreLocation
+
+struct PolylineMapView: View {
+ // You'll need a MapLibre Style for this to work.
+ // You can use https://demotiles.maplibre.org/style.json for basic testing.
+ // For a list of commercially supported tile providers, check out https://wiki.openstreetmap.org/wiki/Vector_tiles#Providers.
+ // These providers all have their own "house styles" as well as custom styling.
+ // You can create your own style or modify others (subject to license restrictions) using https://maplibre.org/maputnik/.
+ let styleURL: URL
+
+ // Just a list of waypoints (ex: a route to follow)
+ let waypoints: [CLLocationCoordinate2D]
+
+ var body: some View {
+ MapView(styleURL: styleURL,
+ camera: .constant(.center(waypoints.first!, zoom: 14)))
+ {
+ // Define a data source.
+ // It will be automatically if a layer references it.
+ let polylineSource = ShapeSource(identifier: "polyline") {
+ MLNPolylineFeature(coordinates: waypoints)
+ }
+
+ // Add a polyline casing for a stroke effect
+ LineStyleLayer(identifier: "polyline-casing", source: polylineSource)
+ .lineCap(.round)
+ .lineJoin(.round)
+ .lineColor(.white)
+ .lineWidth(interpolatedBy: .zoomLevel,
+ curveType: .exponential,
+ parameters: NSExpression(forConstantValue: 1.5),
+ stops: NSExpression(forConstantValue: [14: 6, 18: 24]))
+
+ // Add an inner (blue) polyline
+ LineStyleLayer(identifier: "polyline-inner", source: polylineSource)
+ .lineCap(.round)
+ .lineJoin(.round)
+ .lineColor(.systemBlue)
+ .lineWidth(interpolatedBy: .zoomLevel,
+ curveType: .exponential,
+ parameters: NSExpression(forConstantValue: 1.5),
+ stops: NSExpression(forConstantValue: [14: 3, 18: 16]))
+ }
+ }
+}
+```
+
+Check out more [Examples](Sources/MapLibreSwiftUI/Examples) to go deeper.
-## Common integrations
+**NOTE: This currently only works on iOS, as the dynamic framework doesn't yet include macOS.**
+
+## How can you help?
+
+The first thing you can do is try it out!
+Check out the [Examples](Sources/MapLibreSwiftUI/Examples) for inspiration,
+swap it into your own SwiftUI app, or check out some showcase integrations for inspiration.
+Putting it "through the paces" is the best way for us to converge on the "right" APIs as a community.
+Your use case probably isn't supported today, in which case you can either open an issue or contribute a PR.
+
+The code has a number of TODOs, most of which can be tackled by any intermediate Swift programmer.
+The important issues should all be tracked in GitHub.
+We also have a `#maplibre-swiftui-compose-playground` channel in the
+[OpenStreetMap US Slack](https://slack.openstreetmap.us/).
+
+The skeleton is already in place for several of the core concepts, including style layers and sources, but
+these are incomplete. You can help by opening a PR that fills these in.
+For example, if you wanted to fill out the API for the line style layer,
+head over to [the docs](https://maplibre.org/maplibre-native/ios/api/Classes/MGLLineStyleLayer.html)
+and just start filling out the remaining properties and modifiers.
+
+## Showcase integrations
### Ferrostar
-[Ferrostar](https://github.com/stadiamaps/ferrostar) has a MapLibre UI module as part of its Swift Package
-which is already built on this!
+[Ferrostar](https://github.com/stadiamaps/ferrostar) has a MapLibre UI module as part of its Swift Package.
+That was actually the impetus for building this package,
+and the core devs are eating their own dogfood.
See the [SwiftUI customization](https://stadiamaps.github.io/ferrostar/swiftui-customization.html)
part of the Ferrostar user guide for details on how to customize the map.
### MapLibre Navigation iOS
-This package can help bridge the gap between MapLibre Navigation iOS and SwiftUI!
+This package also helps to bridge the gap between MapLibre Navigation iOS and SwiftUI!
+Thanks to developers from [HudHud](https://hudhud.sa/en) for their contributions which made this possible!
-Add the Swift Package froh Hudhud (https://github.com/HudHud-Maps/maplibre-navigation-ios.git) to your Package.swift
-and add code like this:
+Add the [Swift Package](https://github.com/maplibre/maplibre-navigation-ios) to your project.
+Then add some code like this:
```swift
import MapboxCoreNavigation
import MapboxNavigation
+import MapLibreSwiftUI
extension NavigationViewController: MapViewHostViewController {
public typealias MapType = NavigationMapView
@@ -78,7 +155,7 @@ extension NavigationViewController: MapViewHostViewController {
@ViewBuilder
var mapView: some View {
MapView(makeViewController: NavigationViewController(dayStyleURL: self.styleURL), styleURL: self.styleURL, camera: self.$mapStore.camera) {
-
+ // TODO: Your customizations here; add more layers or whatever you like!
}
.unsafeMapViewControllerModifier { navigationViewController in
navigationViewController.delegate = self.mapStore
@@ -96,52 +173,3 @@ var mapView: some View {
.cameraModifierDisabled(self.route != nil)
}
```
-
-## Developer Quick Start
-
-This project is a standard Swift package.
-The only special thing you might need besides Xcode is [`swiftformat`](https://github.com/nicklockwood/SwiftFormat).
-We use it to automatically handle basic formatting and to linting
-so the code has a standard style.
-
-Check out the swiftformat [Install Guide](https://github.com/nicklockwood/SwiftFormat?tab=readme-ov-file#how-do-i-install-it)
-to add swiftformat to your machine.
-Once installed, you can autoformat code using the command:
-
-```sh
-swiftformat .
-```
-
-Swiftformat can occasionally poorly resolve a formatting issue (e.g. when you've already line-broken a large comment).
-Issues like this are typically easy to manually correct.
-
-## Structure
-
-This package is structured into a few targets. `InternalUtils` is pretty much what it says. `MapLibreSwiftDSL` and
-`MapLibreSwiftUI` are published products, and make up the bulk of the project. Finally, `Examples` is a collection of
-SwiftUI previews.
-
-The DSL provides a more Swift-y layer on top of the lower level MapLibre APIs, and features a number of
-result builders which enable more modern expressive APIs.
-
-The SwiftUI layer publishes a SwiftUI view with the end goal of being a universal view that can be adapted to a wide
-variety of use cases, much like MapKit's SwiftUI views.
-
-The `Examples` should serve as a rough indication of development progress. While much of the code in the UI layer
-isn't formally tested, this acts as our test, and for all intents and purposes, we're following a practical variant of
-TDD as we build out functionality.
-
-## How can you help?
-
-The first thing you can do is try out the library! Check out the detailed [Examples](Sources/MapLibreSwiftUI/Examples)
-for inspiration. Putting it "through the paces" is the best way for us to converge on the "right" APIs as a community.
-Your use case probably isn't supported today, in which case you can either open an issue or contribute a PR.
-
-The code has a number of TODOs, most of which can be tackled by any intermediate Swift programmer. The important
-issues should all be tracked in GitHub. DISCUSS comments (should migrate to GitHub issues/discussions) are deeper
-questions. Input welcome.
-
-The skeleton is already in place for several of the core concepts, including style layers and sources, but
-these are incomplete. You can help by opening a PR that fills these in. For example, if you wanted to fill out the
-API for the line style layer, head over to [the docs](https://maplibre.org/maplibre-native/ios/api/Classes/MGLLineStyleLayer.html)
-and get to work filling out the remaining properties and modifiers.
diff --git a/SECURITY_POLICY.txt b/SECURITY_POLICY.txt
new file mode 100644
index 0000000..f7e43c5
--- /dev/null
+++ b/SECURITY_POLICY.txt
@@ -0,0 +1,2 @@
+For an up-to-date policy refer to
+https://github.com/maplibre/maplibre/blob/main/SECURITY_POLICY.txt
diff --git a/Sources/MapLibreSwiftUI/Examples/Other.swift b/Sources/MapLibreSwiftUI/Examples/Other.swift
index 5c76bd9..b9df706 100644
--- a/Sources/MapLibreSwiftUI/Examples/Other.swift
+++ b/Sources/MapLibreSwiftUI/Examples/Other.swift
@@ -29,8 +29,10 @@ import SwiftUI
}
.unsafeMapViewControllerModifier { viewController in
// Not all properties have modifiers yet. Until they do, you can use this 'escape hatch' to the underlying
- // MLNMapView. Be careful: if you modify properties that the DSL controls already, they may be overridden. This
- // modifier is a "hack", not a final function.
+ // MLNMapView.
+ // Be careful: if you modify properties that the DSL controls already, they may be overridden!
+ // This modifier is a temporary solution; let us know your use case(s)
+ // so we can build safe support into the DSL.
viewController.mapView.logoView.isHidden = false
viewController.mapView.compassViewPosition = .topLeft
}
diff --git a/Sources/MapLibreSwiftUI/Examples/Polyline.swift b/Sources/MapLibreSwiftUI/Examples/Polyline.swift
index df5c3f9..3b5b6fa 100644
--- a/Sources/MapLibreSwiftUI/Examples/Polyline.swift
+++ b/Sources/MapLibreSwiftUI/Examples/Polyline.swift
@@ -3,22 +3,22 @@ import MapLibre
import MapLibreSwiftDSL
import SwiftUI
-struct PolylinePreview: View {
+struct PolylineMapView: View {
let styleURL: URL
+ let waypoints: [CLLocationCoordinate2D]
var body: some View {
MapView(styleURL: styleURL,
- camera: .constant(.center(samplePedestrianWaypoints.first!, zoom: 14)))
+ camera: .constant(.center(waypoints.first!, zoom: 14)))
{
- // Note: This line does not add the source to the style as if it
- // were a statement in an imperative programming language.
- // The source is added automatically if a layer references it.
- let polylineSource = ShapeSource(identifier: "pedestrian-polyline") {
- MLNPolylineFeature(coordinates: samplePedestrianWaypoints)
+ // Define a data source.
+ // It will be automatically if a layer references it.
+ let polylineSource = ShapeSource(identifier: "polyline") {
+ MLNPolylineFeature(coordinates: waypoints)
}
// Add a polyline casing for a stroke effect
- LineStyleLayer(identifier: "route-line-casing", source: polylineSource)
+ LineStyleLayer(identifier: "polyline-casing", source: polylineSource)
.lineCap(.round)
.lineJoin(.round)
.lineColor(.white)
@@ -28,7 +28,7 @@ struct PolylinePreview: View {
stops: NSExpression(forConstantValue: [14: 6, 18: 24]))
// Add an inner (blue) polyline
- LineStyleLayer(identifier: "route-line-inner", source: polylineSource)
+ LineStyleLayer(identifier: "polyline-inner", source: polylineSource)
.lineCap(.round)
.lineJoin(.round)
.lineColor(.systemBlue)
@@ -37,13 +37,12 @@ struct PolylinePreview: View {
parameters: NSExpression(forConstantValue: 1.5),
stops: NSExpression(forConstantValue: [14: 3, 18: 16]))
}
- .previewDisplayName("Polyline")
}
}
struct Polyline_Previews: PreviewProvider {
static var previews: some View {
- PolylinePreview(styleURL: demoTilesURL)
+ PolylineMapView(styleURL: demoTilesURL, waypoints: samplePedestrianWaypoints)
.ignoresSafeArea(.all)
}
}