@tileflow/react-native 0.1.0-alpha.2 → 0.1.0-alpha.4
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.
- package/README.md +9 -3
- package/TileflowNativeAdmission.podspec +1 -1
- package/android/build.gradle +3 -3
- package/dist/{contract-Bwl-gB-I.d.ts → contract-Bp-Im7tj.d.ts} +1 -0
- package/dist/index.d.ts +2 -2
- package/dist/index.js +34 -29
- package/dist/internal/camera.d.ts +1 -1
- package/dist/internal/hosted-binding.js +3 -1
- package/dist/internal/initial-view.d.ts +1 -1
- package/dist/internal/interactions.js +10 -13
- package/dist/internal/native-admission-bridge.d.ts +2 -2
- package/dist/internal/native-admission-bridge.js +2 -4
- package/dist/internal/native-admission.d.ts +2 -2
- package/dist/internal/native-admission.js +5 -4
- package/dist/internal/native-appearance.d.ts +1 -1
- package/dist/internal/native-configuration-bridge.js +3 -1
- package/dist/internal/source-state.d.ts +1 -1
- package/dist/{native-admission-contract-k7LKE1vW.d.ts → native-admission-contract-DFLfUP9X.d.ts} +1 -1
- package/docs/native-admission.md +2 -2
- package/ios/tileflow_native_admission.rb +2 -2
- package/package.json +5 -5
package/README.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
`@tileflow/react-native` provides a Tileflow `Map` backed by MapLibre Native on iOS and Android. It is pre-release. The first alpha release requires the bootstrap and Trusted Publisher checks in the [publishing guide](https://github.com/tileflow/tileflow-sdk/blob/main/PUBLISHING.md).
|
|
4
4
|
|
|
5
|
-
The package targets exactly React 19.2.0, React Native 0.83.10 and `@maplibre/maplibre-react-native` 11.
|
|
5
|
+
The package targets exactly React 19.2.0, React Native 0.83.10 and `@maplibre/maplibre-react-native` 11.5.0, with MapLibre Native Android 13.6.1 and iOS 6.31.0 through the pinned integration below. Expo consumers use Expo 55.0.31 with a native development build; Expo Go does not contain the required native modules.
|
|
6
6
|
|
|
7
7
|
> Related packages and guides: [documentation index](https://raw.githubusercontent.com/tileflow/tileflow-sdk/main/llms.txt).
|
|
8
8
|
|
|
@@ -11,7 +11,7 @@ The package targets exactly React 19.2.0, React Native 0.83.10 and `@maplibre/ma
|
|
|
11
11
|
Start with an Expo development build or a bare React Native application matching those peers. Once the first alpha is available, install the package and its direct dependencies:
|
|
12
12
|
|
|
13
13
|
```sh
|
|
14
|
-
npm install --save-exact @tileflow/react-native@alpha @tileflow/core@alpha @tileflow/interactions@alpha @maplibre/maplibre-react-native@11.
|
|
14
|
+
npm install --save-exact @tileflow/react-native@alpha @tileflow/core@alpha @tileflow/interactions@alpha @maplibre/maplibre-react-native@11.5.0
|
|
15
15
|
```
|
|
16
16
|
|
|
17
17
|
Keep the lockfile. Complete the [native integration](#native-integration) before building the application. Source on `main` can precede npm; installation or local checks do not establish Hosted availability or physical-device acceptance.
|
|
@@ -87,6 +87,12 @@ and protected delivery still require HTTPS.
|
|
|
87
87
|
|
|
88
88
|
## Theme transitions and blends
|
|
89
89
|
|
|
90
|
+
Add `timeOfDay="dusk"` beside `theme` to select a map's optional `day`, `dawn`, `dusk`, or
|
|
91
|
+
`night` preset. For Streets, `theme="light"` with this preset selects the existing `dusk` palette.
|
|
92
|
+
Maps without this capability ignore the option; omitting it keeps the selected theme unchanged.
|
|
93
|
+
Changing it uses the existing theme transition. `themeBlend` takes precedence. See the
|
|
94
|
+
[authoring contract](https://github.com/tileflow/tileflow-sdk/blob/main/packages/core/README.md#style-with-themes-and-semantic-modules).
|
|
95
|
+
|
|
90
96
|
`themeTransition={{duration: 450}}` cross-fades theme changes: a snapshot of the drawn map covers it, follows the camera and fades out once the new theme is drawn. `themeBlend={{themes: ['night', 'dusk', 'day'], position}}` shows a continuous blend of the map's themes instead of `theme`; position 0 is the first theme and 1.5 is halfway from the second to the third:
|
|
91
97
|
|
|
92
98
|
```tsx
|
|
@@ -174,7 +180,7 @@ The public lifecycle surface remains:
|
|
|
174
180
|
|
|
175
181
|
## Native integration
|
|
176
182
|
|
|
177
|
-
Autolinking registers the private Android/iOS modules used by the mounted lifecycle. Android depends on the exact MapLibre React Native project and MapLibre Native 13.
|
|
183
|
+
Autolinking registers the private Android/iOS modules used by the mounted lifecycle. Android depends on the exact MapLibre React Native project and MapLibre Native 13.6.1. iOS uses the existing MapLibre React Native CocoaPod plus the exact MapLibre Native 6.31.0 Swift Package Manager product.
|
|
178
184
|
|
|
179
185
|
For the iOS post-install integration, retain the host's normal React Native/MapLibre setup and then call:
|
|
180
186
|
|
|
@@ -18,7 +18,7 @@ Pod::Spec.new do |s|
|
|
|
18
18
|
s.frameworks = 'Foundation', 'UIKit'
|
|
19
19
|
s.libraries = 'c++'
|
|
20
20
|
s.dependency 'React-Core', '0.83.10'
|
|
21
|
-
s.dependency 'MapLibreReactNative', '11.
|
|
21
|
+
s.dependency 'MapLibreReactNative', '11.5.0'
|
|
22
22
|
# Surface integration consumes only the pinned peer's private native view/camera headers.
|
|
23
23
|
# No Tileflow native header is promoted to a public CocoaPods header.
|
|
24
24
|
s.pod_target_xcconfig = {
|
package/android/build.gradle
CHANGED
|
@@ -6,9 +6,9 @@ if (agpMajor < 9 || (agpMajor == 9 && !providers.gradleProperty('android.builtIn
|
|
|
6
6
|
apply plugin: 'org.jetbrains.kotlin.android'
|
|
7
7
|
}
|
|
8
8
|
|
|
9
|
-
def nativeVersion = rootProject.ext.has('org.maplibre.reactnative.nativeVersion') ? rootProject.ext.get('org.maplibre.reactnative.nativeVersion').toString() : '13.
|
|
9
|
+
def nativeVersion = rootProject.ext.has('org.maplibre.reactnative.nativeVersion') ? rootProject.ext.get('org.maplibre.reactnative.nativeVersion').toString() : '13.6.1'
|
|
10
10
|
def nativeVariant = rootProject.ext.has('org.maplibre.reactnative.nativeVariant') ? rootProject.ext.get('org.maplibre.reactnative.nativeVariant').toString() : 'opengl'
|
|
11
|
-
if (nativeVersion != '13.
|
|
11
|
+
if (nativeVersion != '13.6.1') throw new GradleException('Tileflow native admission requires MapLibre Native 13.6.1')
|
|
12
12
|
|
|
13
13
|
android {
|
|
14
14
|
namespace 'dev.tileflow.reactnative'
|
|
@@ -35,7 +35,7 @@ repositories {
|
|
|
35
35
|
dependencies {
|
|
36
36
|
implementation project(':maplibre_maplibre-react-native')
|
|
37
37
|
implementation('com.facebook.react:react-android:0.83.10') { version { strictly '0.83.10' } }
|
|
38
|
-
implementation("org.maplibre.gl:android-sdk-${nativeVariant}:13.
|
|
38
|
+
implementation("org.maplibre.gl:android-sdk-${nativeVariant}:13.6.1") { version { strictly '13.6.1' } }
|
|
39
39
|
implementation('com.squareup.okhttp3:okhttp:4.12.0') { version { strictly '4.12.0' } }
|
|
40
40
|
testImplementation 'junit:junit:4.13.2'
|
|
41
41
|
testImplementation 'org.robolectric:robolectric:4.14.1'
|
|
@@ -49,6 +49,7 @@ type MapThemeBlend = Readonly<{
|
|
|
49
49
|
type MapSourceProps = Readonly<{
|
|
50
50
|
source: MapSource;
|
|
51
51
|
theme?: MapThemeSelection;
|
|
52
|
+
timeOfDay?: TileflowNativeSourceOptions['timeOfDay'];
|
|
52
53
|
/** Cross-fades theme changes, including entering and leaving a blend. */
|
|
53
54
|
themeTransition?: MapThemeTransition;
|
|
54
55
|
/**
|
package/dist/index.d.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { ReactElement } from 'react';
|
|
2
2
|
import { TileflowAnnotation } from '@tileflow/interactions';
|
|
3
3
|
export { TileflowAnnotation, TileflowInteractionBinding, TileflowInteractionCoordinate, TileflowInteractionDiagnostic, TileflowPoiCategory, TileflowResolvedAnnotationTarget, TileflowResolvedPoiFeatureTarget } from '@tileflow/interactions';
|
|
4
|
-
import { d as MapProps } from './contract-
|
|
5
|
-
export { e as MapBaseProps, c as MapCameraProps, f as MapColorScheme, g as MapErrorEvent, h as MapEventHandlers, b as MapInitialViewInputs, i as MapInteractionEvent, j as MapInteractionProps, k as MapLoadEvent, l as MapMarkerRenderContext, m as MapMarkerRenderer, n as MapOptions, o as MapPresentationProps, p as MapReadinessChangeEvent, q as MapRef, r as MapSelection, s as MapSource, t as MapSourceError, u as MapSourceProps, v as MapSourceState, w as MapTheme, x as MapThemeBlend, y as MapThemeChangeEvent, z as MapThemeSelection, A as MapThemeTransition, M as MapView, a as MapViewChangeEvent } from './contract-
|
|
4
|
+
import { d as MapProps } from './contract-Bp-Im7tj.js';
|
|
5
|
+
export { e as MapBaseProps, c as MapCameraProps, f as MapColorScheme, g as MapErrorEvent, h as MapEventHandlers, b as MapInitialViewInputs, i as MapInteractionEvent, j as MapInteractionProps, k as MapLoadEvent, l as MapMarkerRenderContext, m as MapMarkerRenderer, n as MapOptions, o as MapPresentationProps, p as MapReadinessChangeEvent, q as MapRef, r as MapSelection, s as MapSource, t as MapSourceError, u as MapSourceProps, v as MapSourceState, w as MapTheme, x as MapThemeBlend, y as MapThemeChangeEvent, z as MapThemeSelection, A as MapThemeTransition, M as MapView, a as MapViewChangeEvent } from './contract-Bp-Im7tj.js';
|
|
6
6
|
import '@maplibre/maplibre-react-native';
|
|
7
7
|
import 'react-native';
|
|
8
8
|
import '@tileflow/core/native';
|
package/dist/index.js
CHANGED
|
@@ -253,7 +253,7 @@ function parseManifest(style) {
|
|
|
253
253
|
if (nativeInteractionField(style, "version") !== 8) throw new Error();
|
|
254
254
|
const metadata = nativeInteractionField(style, "metadata");
|
|
255
255
|
const artifact = snapshotNativeInteractionJson(nativeInteractionField(metadata, "tileflow:interaction-manifest"));
|
|
256
|
-
if (nativeInteractionField(artifact, "version") !==
|
|
256
|
+
if (nativeInteractionField(artifact, "version") !== 3) throw new Error();
|
|
257
257
|
const poi = nativeInteractionField(nativeInteractionField(artifact, "domains"), "poi");
|
|
258
258
|
if (nativeInteractionField(poi, "identity") !== "maplibre-feature-id-if-present") throw new Error();
|
|
259
259
|
const hitTesting = nativeInteractionField(poi, "hitTesting");
|
|
@@ -296,10 +296,9 @@ function parseManifest(style) {
|
|
|
296
296
|
const layerId = nativeInteractionField(input, "layerId");
|
|
297
297
|
const source = nativeInteractionField(input, "source");
|
|
298
298
|
const sourceLayer = nativeInteractionField(input, "sourceLayer");
|
|
299
|
-
const layerCategory = nativeInteractionField(input, "category");
|
|
300
299
|
const kind = nativeInteractionField(input, "representation");
|
|
301
300
|
const priority = nativeInteractionField(input, "priority");
|
|
302
|
-
if (!name(layerId) || !name(source) || sourceLayer !== void 0 && !name(sourceLayer) || !
|
|
301
|
+
if (!name(layerId) || !name(source) || sourceLayer !== void 0 && !name(sourceLayer) || !representation(kind) || typeof priority !== "number" || !Number.isSafeInteger(priority) || priority < 0 || priority > 1e5 || ids.has(layerId) || nativeInteractionField(input, "anchor") !== "pointer-coordinate")
|
|
303
302
|
throw new Error();
|
|
304
303
|
const actual = physical.get(layerId);
|
|
305
304
|
if (!actual || nativeInteractionField(actual, "source") !== source || nativeInteractionField(actual, "source-layer") !== sourceLayer)
|
|
@@ -313,7 +312,6 @@ function parseManifest(style) {
|
|
|
313
312
|
layerId,
|
|
314
313
|
source,
|
|
315
314
|
...sourceLayer === void 0 ? {} : { sourceLayer },
|
|
316
|
-
category: layerCategory,
|
|
317
315
|
representation: kind,
|
|
318
316
|
priority
|
|
319
317
|
});
|
|
@@ -367,8 +365,11 @@ function choose(features, manifest, bindings, coordinate2, queried) {
|
|
|
367
365
|
if (!layer || !allowed2.has(layer.layerId)) continue;
|
|
368
366
|
if (nativeInteractionField(feature, "source") !== layer.source || nativeInteractionField(feature, "sourceLayer") !== layer.sourceLayer)
|
|
369
367
|
throw new Error();
|
|
368
|
+
const featureProperties = properties(nativeInteractionField(feature, "properties"), manifest.fields);
|
|
369
|
+
const featureCategory = featureProperties.category;
|
|
370
|
+
if (!category(featureCategory)) throw new Error();
|
|
370
371
|
const binding = bindings.find(
|
|
371
|
-
(value) => value.target.kind === "semantic-feature" && value.target.domain === "poi" && (!value.target.categories || value.target.categories.includes(
|
|
372
|
+
(value) => value.target.kind === "semantic-feature" && value.target.domain === "poi" && (!value.target.categories || value.target.categories.includes(featureCategory))
|
|
372
373
|
);
|
|
373
374
|
if (!binding) continue;
|
|
374
375
|
const stable = featureId(nativeInteractionField(feature, "id"));
|
|
@@ -378,9 +379,9 @@ function choose(features, manifest, bindings, coordinate2, queried) {
|
|
|
378
379
|
coordinate: coordinate2,
|
|
379
380
|
bindingId: binding.id,
|
|
380
381
|
feature: {
|
|
381
|
-
category:
|
|
382
|
+
category: featureCategory,
|
|
382
383
|
...stable === void 0 ? {} : { id: stable },
|
|
383
|
-
properties:
|
|
384
|
+
properties: featureProperties
|
|
384
385
|
}
|
|
385
386
|
});
|
|
386
387
|
const candidate = { layer, renderedIndex, match: Object.freeze({ binding, target }) };
|
|
@@ -443,7 +444,7 @@ function createNativePoiAdapter() {
|
|
|
443
444
|
},
|
|
444
445
|
supports(target) {
|
|
445
446
|
const parsed = manifest;
|
|
446
|
-
return !!parsed && inspect(lease, generation) === "current" && manifest === parsed && parsed.layers.
|
|
447
|
+
return !!parsed && inspect(lease, generation) === "current" && manifest === parsed && parsed.layers.length > 0 && category(target.feature.category);
|
|
447
448
|
},
|
|
448
449
|
replaceStyle(next) {
|
|
449
450
|
if (disposed) return emptyDiagnostics;
|
|
@@ -499,11 +500,7 @@ function createNativePoiAdapter() {
|
|
|
499
500
|
if (!owner || !selected) return answer(failure());
|
|
500
501
|
const ownership = inspect(owner, expected);
|
|
501
502
|
if (ownership !== "current") return answer(ownership === "error" ? failure() : stale);
|
|
502
|
-
const layers = selected.layers.
|
|
503
|
-
(layer) => bindings.some(
|
|
504
|
-
(binding) => binding.target.kind === "semantic-feature" && (!binding.target.categories || binding.target.categories.includes(layer.category))
|
|
505
|
-
)
|
|
506
|
-
).map((layer) => layer.layerId);
|
|
503
|
+
const layers = selected.layers.map((layer) => layer.layerId);
|
|
507
504
|
if (!layers.length) return answer(miss);
|
|
508
505
|
if (!invocationIsLive()) return Promise.resolve(stale);
|
|
509
506
|
const request = Object.freeze({
|
|
@@ -849,7 +846,7 @@ function requestedLayers(style, request) {
|
|
|
849
846
|
const physical = array2(nativeInteractionField(style, "layers"), 4096);
|
|
850
847
|
const sources = nativeInteractionField(style, "sources");
|
|
851
848
|
const artifact = nativeInteractionField(nativeInteractionField(style, "metadata"), "tileflow:interaction-manifest");
|
|
852
|
-
if (nativeInteractionField(artifact, "version") !==
|
|
849
|
+
if (nativeInteractionField(artifact, "version") !== 3) throw new Error();
|
|
853
850
|
const semantic = array2(nativeInteractionField(nativeInteractionField(nativeInteractionField(artifact, "domains"), "poi"), "layers"), 256);
|
|
854
851
|
let previous = physical.length;
|
|
855
852
|
return requested.map((id) => {
|
|
@@ -2933,10 +2930,11 @@ function createNativeAdmissionOwner(options) {
|
|
|
2933
2930
|
if (options.sessionFetch) boundFetch = options.sessionFetch(registered.context);
|
|
2934
2931
|
let retirement;
|
|
2935
2932
|
let retirementNotified = false;
|
|
2936
|
-
const catalog = createNativeAdmissionCatalog(
|
|
2937
|
-
|
|
2938
|
-
|
|
2939
|
-
|
|
2933
|
+
const catalog = createNativeAdmissionCatalog(
|
|
2934
|
+
resources,
|
|
2935
|
+
registered.context,
|
|
2936
|
+
(additions) => bridge.extendContext(ack.installation, registered.context, additions)
|
|
2937
|
+
);
|
|
2940
2938
|
const context = {
|
|
2941
2939
|
id: registered.context,
|
|
2942
2940
|
generation: registered.generation,
|
|
@@ -3444,7 +3442,9 @@ function snapshotHostedNativeManifestIdentity(source) {
|
|
|
3444
3442
|
if (sourceUrl !== expected || finalUrl !== expected) throw new Error();
|
|
3445
3443
|
const manifest = field(source, "manifest");
|
|
3446
3444
|
const maps = field(manifest, "maps");
|
|
3447
|
-
|
|
3445
|
+
const manifestVersion = field(manifest, "version");
|
|
3446
|
+
if (manifestVersion !== 1 && manifestVersion !== 2 || names(maps, 1)[0] !== name3)
|
|
3447
|
+
throw new Error();
|
|
3448
3448
|
const declared = field(maps, name3);
|
|
3449
3449
|
if (field(declared, "mapId") !== mapId || field(declared, "usageMode") !== "session")
|
|
3450
3450
|
throw new Error();
|
|
@@ -5133,9 +5133,7 @@ function owned(url, scope, policy) {
|
|
|
5133
5133
|
let tilesetId;
|
|
5134
5134
|
const base = /^\/base\/[0-9a-f]{64}\/(.+)$/u.exec(path)?.[1];
|
|
5135
5135
|
if (scope === "style") {
|
|
5136
|
-
|
|
5137
|
-
const legacy = path.startsWith(prefix) && /^[a-z0-9][a-z0-9-]{0,63}\.json$/u.test(path.slice(prefix.length));
|
|
5138
|
-
if (!legacy && !nativeVersionedStyleMatchesMap(url, policy.mapId)) throw invalid3();
|
|
5136
|
+
if (!nativeVersionedStyleMatchesMap(url, policy.mapId)) throw invalid3();
|
|
5139
5137
|
} else if (scope === "tilejson" || scope === "tile") {
|
|
5140
5138
|
const match = /^\/(?:v1\/)?tiles\/([A-Za-z0-9._:-]{1,255})\/(.+)$/u.exec(path);
|
|
5141
5139
|
if (!match || !policy.tilesetIds.includes(match[1])) throw invalid3();
|
|
@@ -5575,6 +5573,8 @@ function createMountedMapOwner(ports2) {
|
|
|
5575
5573
|
let sourceKey;
|
|
5576
5574
|
let sourceObject;
|
|
5577
5575
|
let selectedTheme;
|
|
5576
|
+
let selectedTimeOfDay;
|
|
5577
|
+
const timeSelection = () => !blendSelection && props?.timeOfDay !== void 0 ? { timeOfDay: props.timeOfDay } : {};
|
|
5578
5578
|
let colorScheme;
|
|
5579
5579
|
let appearanceRelease;
|
|
5580
5580
|
let appearanceEpoch = 0;
|
|
@@ -5892,7 +5892,13 @@ function createMountedMapOwner(ports2) {
|
|
|
5892
5892
|
cancelJob(epoch);
|
|
5893
5893
|
epoch.cache.clear();
|
|
5894
5894
|
if (!disposed && foreground && current === epoch && epoch.live && props) {
|
|
5895
|
-
track(
|
|
5895
|
+
track(
|
|
5896
|
+
core.replace(props.source, {
|
|
5897
|
+
theme: selectionTheme(),
|
|
5898
|
+
colorScheme,
|
|
5899
|
+
...timeSelection()
|
|
5900
|
+
})
|
|
5901
|
+
);
|
|
5896
5902
|
}
|
|
5897
5903
|
return;
|
|
5898
5904
|
}
|
|
@@ -5929,7 +5935,7 @@ function createMountedMapOwner(ports2) {
|
|
|
5929
5935
|
function select() {
|
|
5930
5936
|
if (disposed || !props || !current?.live) return;
|
|
5931
5937
|
current.hosted.select();
|
|
5932
|
-
track(core.replace(props.source, { theme: selectionTheme(), colorScheme }));
|
|
5938
|
+
track(core.replace(props.source, { theme: selectionTheme(), colorScheme, ...timeSelection() }));
|
|
5933
5939
|
}
|
|
5934
5940
|
function appearance(theme) {
|
|
5935
5941
|
if (theme === "system" === Boolean(appearanceRelease)) return;
|
|
@@ -6008,7 +6014,7 @@ function createMountedMapOwner(ports2) {
|
|
|
6008
6014
|
if (changedBlend || !blend) blendTheme = nearest;
|
|
6009
6015
|
const key2 = source && JSON.stringify(source);
|
|
6010
6016
|
const changedSource = !initialized || key2 !== sourceKey || key2 === void 0 && sourceObject !== next.source;
|
|
6011
|
-
const changedTheme = !initialized || !blend && next.theme !== selectedTheme;
|
|
6017
|
+
const changedTheme = !initialized || !blend && (next.theme !== selectedTheme || next.timeOfDay !== selectedTimeOfDay);
|
|
6012
6018
|
const changedOptions = JSON.stringify(options) !== JSON.stringify(mapOptions);
|
|
6013
6019
|
camera = input;
|
|
6014
6020
|
mapOptions = options;
|
|
@@ -6021,6 +6027,7 @@ function createMountedMapOwner(ports2) {
|
|
|
6021
6027
|
sourceObject = next.source;
|
|
6022
6028
|
}
|
|
6023
6029
|
selectedTheme = next.theme;
|
|
6030
|
+
selectedTimeOfDay = next.timeOfDay;
|
|
6024
6031
|
initialized = true;
|
|
6025
6032
|
try {
|
|
6026
6033
|
appearance(next.theme);
|
|
@@ -6221,10 +6228,7 @@ function createNativeAdmissionWire(native, listen) {
|
|
|
6221
6228
|
return Object.freeze({ installation: ack.installation });
|
|
6222
6229
|
},
|
|
6223
6230
|
registerContext: (id, registration) => safe(() => native.registerContext(id, registration)),
|
|
6224
|
-
extendContext: (id, context, resources) => safe(() =>
|
|
6225
|
-
if (!native.extendContext) throw unavailable();
|
|
6226
|
-
return native.extendContext(id, context, resources);
|
|
6227
|
-
}),
|
|
6231
|
+
extendContext: (id, context, resources) => safe(() => native.extendContext(id, context, resources)),
|
|
6228
6232
|
retireContext(id, context) {
|
|
6229
6233
|
if (id === installation2?.id) retireContext(context);
|
|
6230
6234
|
return safe(() => native.retireContext(id, context));
|
|
@@ -6371,6 +6375,7 @@ function createReactNativeAdmissionTransport() {
|
|
|
6371
6375
|
for (const name3 of [
|
|
6372
6376
|
"install",
|
|
6373
6377
|
"registerContext",
|
|
6378
|
+
"extendContext",
|
|
6374
6379
|
"retireContext",
|
|
6375
6380
|
"completeBatch",
|
|
6376
6381
|
"remove",
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { M as MapView, a as MapViewChangeEvent, b as MapInitialViewInputs, c as MapCameraProps } from '../contract-
|
|
1
|
+
import { M as MapView, a as MapViewChangeEvent, b as MapInitialViewInputs, c as MapCameraProps } from '../contract-Bp-Im7tj.js';
|
|
2
2
|
import '@maplibre/maplibre-react-native';
|
|
3
3
|
import 'react';
|
|
4
4
|
import 'react-native';
|
|
@@ -140,7 +140,9 @@ function snapshotHostedNativeManifestIdentity(source) {
|
|
|
140
140
|
if (sourceUrl !== expected || finalUrl !== expected) throw new Error();
|
|
141
141
|
const manifest = field(source, "manifest");
|
|
142
142
|
const maps = field(manifest, "maps");
|
|
143
|
-
|
|
143
|
+
const manifestVersion = field(manifest, "version");
|
|
144
|
+
if (manifestVersion !== 1 && manifestVersion !== 2 || names(maps, 1)[0] !== name)
|
|
145
|
+
throw new Error();
|
|
144
146
|
const declared = field(maps, name);
|
|
145
147
|
if (field(declared, "mapId") !== mapId || field(declared, "usageMode") !== "session")
|
|
146
148
|
throw new Error();
|
|
@@ -226,7 +226,7 @@ function parseManifest(style) {
|
|
|
226
226
|
if (nativeInteractionField(style, "version") !== 8) throw new Error();
|
|
227
227
|
const metadata = nativeInteractionField(style, "metadata");
|
|
228
228
|
const artifact = snapshotNativeInteractionJson(nativeInteractionField(metadata, "tileflow:interaction-manifest"));
|
|
229
|
-
if (nativeInteractionField(artifact, "version") !==
|
|
229
|
+
if (nativeInteractionField(artifact, "version") !== 3) throw new Error();
|
|
230
230
|
const poi = nativeInteractionField(nativeInteractionField(artifact, "domains"), "poi");
|
|
231
231
|
if (nativeInteractionField(poi, "identity") !== "maplibre-feature-id-if-present") throw new Error();
|
|
232
232
|
const hitTesting = nativeInteractionField(poi, "hitTesting");
|
|
@@ -269,10 +269,9 @@ function parseManifest(style) {
|
|
|
269
269
|
const layerId = nativeInteractionField(input, "layerId");
|
|
270
270
|
const source = nativeInteractionField(input, "source");
|
|
271
271
|
const sourceLayer = nativeInteractionField(input, "sourceLayer");
|
|
272
|
-
const layerCategory = nativeInteractionField(input, "category");
|
|
273
272
|
const kind = nativeInteractionField(input, "representation");
|
|
274
273
|
const priority = nativeInteractionField(input, "priority");
|
|
275
|
-
if (!name(layerId) || !name(source) || sourceLayer !== void 0 && !name(sourceLayer) || !
|
|
274
|
+
if (!name(layerId) || !name(source) || sourceLayer !== void 0 && !name(sourceLayer) || !representation(kind) || typeof priority !== "number" || !Number.isSafeInteger(priority) || priority < 0 || priority > 1e5 || ids.has(layerId) || nativeInteractionField(input, "anchor") !== "pointer-coordinate")
|
|
276
275
|
throw new Error();
|
|
277
276
|
const actual = physical.get(layerId);
|
|
278
277
|
if (!actual || nativeInteractionField(actual, "source") !== source || nativeInteractionField(actual, "source-layer") !== sourceLayer)
|
|
@@ -286,7 +285,6 @@ function parseManifest(style) {
|
|
|
286
285
|
layerId,
|
|
287
286
|
source,
|
|
288
287
|
...sourceLayer === void 0 ? {} : { sourceLayer },
|
|
289
|
-
category: layerCategory,
|
|
290
288
|
representation: kind,
|
|
291
289
|
priority
|
|
292
290
|
});
|
|
@@ -340,8 +338,11 @@ function choose(features, manifest, bindings, coordinate, queried) {
|
|
|
340
338
|
if (!layer || !allowed.has(layer.layerId)) continue;
|
|
341
339
|
if (nativeInteractionField(feature, "source") !== layer.source || nativeInteractionField(feature, "sourceLayer") !== layer.sourceLayer)
|
|
342
340
|
throw new Error();
|
|
341
|
+
const featureProperties = properties(nativeInteractionField(feature, "properties"), manifest.fields);
|
|
342
|
+
const featureCategory = featureProperties.category;
|
|
343
|
+
if (!category(featureCategory)) throw new Error();
|
|
343
344
|
const binding = bindings.find(
|
|
344
|
-
(value) => value.target.kind === "semantic-feature" && value.target.domain === "poi" && (!value.target.categories || value.target.categories.includes(
|
|
345
|
+
(value) => value.target.kind === "semantic-feature" && value.target.domain === "poi" && (!value.target.categories || value.target.categories.includes(featureCategory))
|
|
345
346
|
);
|
|
346
347
|
if (!binding) continue;
|
|
347
348
|
const stable = featureId(nativeInteractionField(feature, "id"));
|
|
@@ -351,9 +352,9 @@ function choose(features, manifest, bindings, coordinate, queried) {
|
|
|
351
352
|
coordinate,
|
|
352
353
|
bindingId: binding.id,
|
|
353
354
|
feature: {
|
|
354
|
-
category:
|
|
355
|
+
category: featureCategory,
|
|
355
356
|
...stable === void 0 ? {} : { id: stable },
|
|
356
|
-
properties:
|
|
357
|
+
properties: featureProperties
|
|
357
358
|
}
|
|
358
359
|
});
|
|
359
360
|
const candidate = { layer, renderedIndex, match: Object.freeze({ binding, target }) };
|
|
@@ -416,7 +417,7 @@ function createNativePoiAdapter() {
|
|
|
416
417
|
},
|
|
417
418
|
supports(target) {
|
|
418
419
|
const parsed = manifest;
|
|
419
|
-
return !!parsed && inspect(lease, generation) === "current" && manifest === parsed && parsed.layers.
|
|
420
|
+
return !!parsed && inspect(lease, generation) === "current" && manifest === parsed && parsed.layers.length > 0 && category(target.feature.category);
|
|
420
421
|
},
|
|
421
422
|
replaceStyle(next) {
|
|
422
423
|
if (disposed) return emptyDiagnostics;
|
|
@@ -472,11 +473,7 @@ function createNativePoiAdapter() {
|
|
|
472
473
|
if (!owner || !selected) return answer(failure());
|
|
473
474
|
const ownership = inspect(owner, expected);
|
|
474
475
|
if (ownership !== "current") return answer(ownership === "error" ? failure() : stale);
|
|
475
|
-
const layers = selected.layers.
|
|
476
|
-
(layer) => bindings.some(
|
|
477
|
-
(binding) => binding.target.kind === "semantic-feature" && (!binding.target.categories || binding.target.categories.includes(layer.category))
|
|
478
|
-
)
|
|
479
|
-
).map((layer) => layer.layerId);
|
|
476
|
+
const layers = selected.layers.map((layer) => layer.layerId);
|
|
480
477
|
if (!layers.length) return answer(miss);
|
|
481
478
|
if (!invocationIsLive()) return Promise.resolve(stale);
|
|
482
479
|
const request = Object.freeze({
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { HostedNativeSessionFetch } from './session.js';
|
|
2
|
-
import { N as NativeAdmissionEvent, a as NativeAdmissionResource, b as NativeContextAck, c as NativeAdmissionResult, d as NativeRemovalAck } from '../native-admission-contract-
|
|
2
|
+
import { N as NativeAdmissionEvent, a as NativeAdmissionResource, b as NativeContextAck, c as NativeAdmissionResult, d as NativeRemovalAck } from '../native-admission-contract-DFLfUP9X.js';
|
|
3
3
|
|
|
4
4
|
declare function createReactNativeAdmissionTransport(): Readonly<{
|
|
5
5
|
bridge: Readonly<{
|
|
@@ -11,7 +11,7 @@ declare function createReactNativeAdmissionTransport(): Readonly<{
|
|
|
11
11
|
mapId: string | null;
|
|
12
12
|
resources: readonly NativeAdmissionResource[];
|
|
13
13
|
}>): Promise<NativeContextAck>;
|
|
14
|
-
extendContext
|
|
14
|
+
extendContext(installation: string, context: string, resources: readonly NativeAdmissionResource[]): Promise<Readonly<{
|
|
15
15
|
resources: number;
|
|
16
16
|
}>>;
|
|
17
17
|
retireContext(installation: string, context: string): Promise<Readonly<{
|
|
@@ -176,10 +176,7 @@ function createNativeAdmissionWire(native, listen) {
|
|
|
176
176
|
return Object.freeze({ installation: ack.installation });
|
|
177
177
|
},
|
|
178
178
|
registerContext: (id, registration) => safe(() => native.registerContext(id, registration)),
|
|
179
|
-
extendContext: (id, context, resources) => safe(() =>
|
|
180
|
-
if (!native.extendContext) throw unavailable();
|
|
181
|
-
return native.extendContext(id, context, resources);
|
|
182
|
-
}),
|
|
179
|
+
extendContext: (id, context, resources) => safe(() => native.extendContext(id, context, resources)),
|
|
183
180
|
retireContext(id, context) {
|
|
184
181
|
if (id === installation?.id) retireContext(context);
|
|
185
182
|
return safe(() => native.retireContext(id, context));
|
|
@@ -326,6 +323,7 @@ function createReactNativeAdmissionTransport() {
|
|
|
326
323
|
for (const name of [
|
|
327
324
|
"install",
|
|
328
325
|
"registerContext",
|
|
326
|
+
"extendContext",
|
|
329
327
|
"retireContext",
|
|
330
328
|
"completeBatch",
|
|
331
329
|
"remove",
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { e as NativeAdmissionCode, a as NativeAdmissionResource, f as NativeAdmissionBridge, d as NativeRemovalAck } from '../native-admission-contract-
|
|
1
|
+
import { e as NativeAdmissionCode, a as NativeAdmissionResource, f as NativeAdmissionBridge, d as NativeRemovalAck } from '../native-admission-contract-DFLfUP9X.js';
|
|
2
2
|
import { HostedNativeResourcePolicy, createHostedNativeSessionController, HostedNativeSessionFetch, HostedNativeSessionController } from './session.js';
|
|
3
3
|
|
|
4
4
|
type SessionInput = Parameters<typeof createHostedNativeSessionController>[0];
|
|
@@ -69,7 +69,7 @@ declare function createNativeAdmissionOwner(options: {
|
|
|
69
69
|
}>>;
|
|
70
70
|
dispose: () => Promise<NativeRemovalAck>;
|
|
71
71
|
readonly state: Readonly<{
|
|
72
|
-
status: "
|
|
72
|
+
status: "disposed" | "error" | "idle" | "installing" | "ready";
|
|
73
73
|
contexts: number;
|
|
74
74
|
pendingRegistrations: number;
|
|
75
75
|
}>;
|
|
@@ -1459,10 +1459,11 @@ function createNativeAdmissionOwner(options) {
|
|
|
1459
1459
|
if (options.sessionFetch) boundFetch = options.sessionFetch(registered.context);
|
|
1460
1460
|
let retirement;
|
|
1461
1461
|
let retirementNotified = false;
|
|
1462
|
-
const catalog = createNativeAdmissionCatalog(
|
|
1463
|
-
|
|
1464
|
-
|
|
1465
|
-
|
|
1462
|
+
const catalog = createNativeAdmissionCatalog(
|
|
1463
|
+
resources,
|
|
1464
|
+
registered.context,
|
|
1465
|
+
(additions) => bridge.extendContext(ack.installation, registered.context, additions)
|
|
1466
|
+
);
|
|
1466
1467
|
const context = {
|
|
1467
1468
|
id: registered.context,
|
|
1468
1469
|
generation: registered.generation,
|
|
@@ -143,7 +143,9 @@ function snapshotHostedNativeManifestIdentity(source) {
|
|
|
143
143
|
if (sourceUrl !== expected || finalUrl !== expected) throw new Error();
|
|
144
144
|
const manifest = field(source, "manifest");
|
|
145
145
|
const maps = field(manifest, "maps");
|
|
146
|
-
|
|
146
|
+
const manifestVersion = field(manifest, "version");
|
|
147
|
+
if (manifestVersion !== 1 && manifestVersion !== 2 || names(maps, 1)[0] !== name)
|
|
148
|
+
throw new Error();
|
|
147
149
|
const declared = field(maps, name);
|
|
148
150
|
if (field(declared, "mapId") !== mapId || field(declared, "usageMode") !== "session")
|
|
149
151
|
throw new Error();
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { TileflowNativeSourceState } from '@tileflow/core/native';
|
|
2
|
-
import { v as MapSourceState } from '../contract-
|
|
2
|
+
import { v as MapSourceState } from '../contract-Bp-Im7tj.js';
|
|
3
3
|
import '@maplibre/maplibre-react-native';
|
|
4
4
|
import 'react';
|
|
5
5
|
import 'react-native';
|
package/dist/{native-admission-contract-k7LKE1vW.d.ts → native-admission-contract-DFLfUP9X.d.ts}
RENAMED
|
@@ -74,7 +74,7 @@ type NativeAdmissionBridge = Readonly<{
|
|
|
74
74
|
mapId: string | null;
|
|
75
75
|
resources: readonly NativeAdmissionResource[];
|
|
76
76
|
}>): Promise<NativeContextAck>;
|
|
77
|
-
extendContext
|
|
77
|
+
extendContext(installation: string, context: string, resources: readonly NativeAdmissionResource[]): Promise<Readonly<{
|
|
78
78
|
resources: number;
|
|
79
79
|
}>>;
|
|
80
80
|
retireContext(installation: string, context: string): Promise<Readonly<{
|
package/docs/native-admission.md
CHANGED
|
@@ -6,7 +6,7 @@ The mounted owner prepares a **bounded Style/TileJSON resource closure** before
|
|
|
6
6
|
|
|
7
7
|
## Exact native dependencies
|
|
8
8
|
|
|
9
|
-
The source targets React 19.2.0, React Native 0.83.10, MapLibre React Native 11.
|
|
9
|
+
The source targets React 19.2.0, React Native 0.83.10, MapLibre React Native 11.5.0, MapLibre Native Android 13.6.1 and MapLibre Native iOS 6.31.0. Android's HTTP dependency is OkHttp 4.12.0. These pins and the existence of source tests are **not evidence** of a successful build, device run, Hosted service or app-store acceptance; qualify the exact revision in the intended host.
|
|
10
10
|
|
|
11
11
|
Android's library build uses the host's Android Gradle/Kotlin plugins and SDK settings. `react-native.config.cjs` autolinks `TileflowNativeAdmissionPackage`, which registers the private admission, document, configuration and surface modules. The library depends on the autolinked `:maplibre_maplibre-react-native` project and rejects conflicting MapLibre Native versions rather than selecting another version silently.
|
|
12
12
|
|
|
@@ -17,7 +17,7 @@ $MLRN.post_install(installer)
|
|
|
17
17
|
tileflow_native_admission_post_install(installer)
|
|
18
18
|
```
|
|
19
19
|
|
|
20
|
-
The helper requires the MapLibre distribution reference with `exactVersion` 6.
|
|
20
|
+
The helper requires the MapLibre distribution reference with `exactVersion` 6.31.0 and reuses that product for the Tileflow pod/test targets. It does not add another SDK or change the pin.
|
|
21
21
|
|
|
22
22
|
## Installation ownership
|
|
23
23
|
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
def tileflow_native_admission_post_install(installer)
|
|
5
5
|
project = installer.pods_project
|
|
6
6
|
url = 'https://github.com/maplibre/maplibre-gl-native-distribution'
|
|
7
|
-
version = '6.
|
|
7
|
+
version = '6.31.0'
|
|
8
8
|
refs = project.root_object.package_references.select do |reference|
|
|
9
9
|
reference.respond_to?(:repositoryURL) && reference.repositoryURL == url
|
|
10
10
|
end
|
|
@@ -12,7 +12,7 @@ def tileflow_native_admission_post_install(installer)
|
|
|
12
12
|
reference = refs.first
|
|
13
13
|
requirement = reference.requirement.transform_keys(&:to_s)
|
|
14
14
|
unless requirement == { 'kind' => 'exactVersion', 'version' => version }
|
|
15
|
-
raise 'Tileflow native admission requires the exact MapLibre Native 6.
|
|
15
|
+
raise 'Tileflow native admission requires the exact MapLibre Native 6.31.0 SPM product'
|
|
16
16
|
end
|
|
17
17
|
if defined?($MLRN_NATIVE_VERSION) && $MLRN_NATIVE_VERSION.to_s != version
|
|
18
18
|
raise 'Conflicting MapLibre Native version for Tileflow native admission'
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tileflow/react-native",
|
|
3
|
-
"version": "0.1.0-alpha.
|
|
3
|
+
"version": "0.1.0-alpha.4",
|
|
4
4
|
"license": "Apache-2.0",
|
|
5
5
|
"description": "Tileflow maps, camera control and semantic interactions for React Native.",
|
|
6
6
|
"type": "module",
|
|
@@ -36,16 +36,16 @@
|
|
|
36
36
|
}
|
|
37
37
|
},
|
|
38
38
|
"dependencies": {
|
|
39
|
-
"@tileflow/core": ">=0.1.0-alpha.
|
|
40
|
-
"@tileflow/interactions": ">=0.1.0-alpha.
|
|
39
|
+
"@tileflow/core": ">=0.1.0-alpha.35 <0.1.0-beta.0",
|
|
40
|
+
"@tileflow/interactions": ">=0.1.0-alpha.5 <0.1.0-beta.0"
|
|
41
41
|
},
|
|
42
42
|
"peerDependencies": {
|
|
43
|
-
"@maplibre/maplibre-react-native": "11.
|
|
43
|
+
"@maplibre/maplibre-react-native": "11.5.0",
|
|
44
44
|
"react": "19.2.0",
|
|
45
45
|
"react-native": "0.83.10"
|
|
46
46
|
},
|
|
47
47
|
"devDependencies": {
|
|
48
|
-
"@maplibre/maplibre-react-native": "11.
|
|
48
|
+
"@maplibre/maplibre-react-native": "11.5.0",
|
|
49
49
|
"@types/react": "^19.2.17",
|
|
50
50
|
"react": "19.2.0",
|
|
51
51
|
"react-native": "0.83.10"
|