@tileflow/interactions 0.1.0-alpha.3 → 0.1.0-alpha.5
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 +28 -4
- package/dist/maplibre-entry.js +17 -11
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
#
|
|
1
|
+
# @tileflow/interactions
|
|
2
2
|
|
|
3
3
|
Portable annotations, tooltips, popups, state, and interaction bindings for Tileflow maps.
|
|
4
4
|
|
|
@@ -10,10 +10,26 @@ The package has two boundaries:
|
|
|
10
10
|
Framework applications normally use `@tileflow/react`, `@tileflow/vue`, or `@tileflow/svelte`
|
|
11
11
|
instead of calling the MapLibre controller directly.
|
|
12
12
|
|
|
13
|
+
> Related packages and guides: [documentation index](https://raw.githubusercontent.com/tileflow/tileflow-sdk/main/llms.txt).
|
|
14
|
+
|
|
15
|
+
## Install
|
|
16
|
+
|
|
17
|
+
```sh
|
|
18
|
+
npm install @tileflow/interactions@alpha
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
The root entry needs no MapLibre installation or browser. For live UI, install one framework adapter
|
|
22
|
+
and follow its worker, CSS, and asset-preparation guide:
|
|
23
|
+
[React](https://github.com/tileflow/tileflow-sdk/blob/main/packages/react/README.md),
|
|
24
|
+
[Vue](https://github.com/tileflow/tileflow-sdk/blob/main/packages/vue/README.md), or
|
|
25
|
+
[Svelte](https://github.com/tileflow/tileflow-sdk/blob/main/packages/svelte/README.md).
|
|
26
|
+
|
|
13
27
|
## Annotation model
|
|
14
28
|
|
|
29
|
+
<!-- docs:check -->
|
|
30
|
+
|
|
15
31
|
```ts
|
|
16
|
-
import type
|
|
32
|
+
import {type TileflowAnnotation, validateTileflowAnnotations} from '@tileflow/interactions';
|
|
17
33
|
|
|
18
34
|
const properties = [
|
|
19
35
|
{
|
|
@@ -27,6 +43,10 @@ const properties = [
|
|
|
27
43
|
popup: {content: {kind: 'view', name: 'property-card'}},
|
|
28
44
|
},
|
|
29
45
|
] satisfies TileflowAnnotation[];
|
|
46
|
+
|
|
47
|
+
const result = validateTileflowAnnotations(properties);
|
|
48
|
+
if (!result.ok) throw new Error(JSON.stringify(result.diagnostics));
|
|
49
|
+
console.log(result.annotations);
|
|
30
50
|
```
|
|
31
51
|
|
|
32
52
|
`text` and scalar `field` content are inserted as text. `view` is a small dispatch name for a
|
|
@@ -35,11 +55,13 @@ Custom tooltip views must remain brief and non-focusable; put buttons, links, fo
|
|
|
35
55
|
interactive content in a popup.
|
|
36
56
|
|
|
37
57
|
Every new annotation needs a stable `id`, singular `coordinate`, and non-empty `ariaLabel`.
|
|
38
|
-
Optional `data` must be recursively JSON-safe. Call `validateTileflowAnnotations` at an untrusted
|
|
58
|
+
Coordinates use `[longitude, latitude]`. Optional `data` must be recursively JSON-safe. Call `validateTileflowAnnotations` at an untrusted
|
|
39
59
|
boundary to receive atomic validation and structured JSON-Pointer diagnostics.
|
|
40
60
|
|
|
41
61
|
## Popup state
|
|
42
62
|
|
|
63
|
+
<!-- docs:check -->
|
|
64
|
+
|
|
43
65
|
```ts
|
|
44
66
|
import {
|
|
45
67
|
initialTileflowInteractionState,
|
|
@@ -59,6 +81,8 @@ adapters expose controlled and uncontrolled ownership without changing this seri
|
|
|
59
81
|
|
|
60
82
|
The first semantic runtime target is `domain: 'poi'`:
|
|
61
83
|
|
|
84
|
+
<!-- docs:check -->
|
|
85
|
+
|
|
62
86
|
```ts
|
|
63
87
|
import type {TileflowInteractionBinding} from '@tileflow/interactions';
|
|
64
88
|
|
|
@@ -91,5 +115,5 @@ objects and schedulers are injected at attach time, so both subpath imports rema
|
|
|
91
115
|
`createTileflowMapLibreInteractionCoordinator` joins them around one controlled or uncontrolled
|
|
92
116
|
popup state and commits the closing runtime before the opening runtime.
|
|
93
117
|
|
|
94
|
-
See [`docs/contracts/map-interactions.md`](
|
|
118
|
+
See [`docs/contracts/map-interactions.md`](https://github.com/tileflow/tileflow-sdk/blob/main/docs/contracts/map-interactions.md) for lifecycle,
|
|
95
119
|
accessibility, security, capture, and framework parity requirements.
|
package/dist/maplibre-entry.js
CHANGED
|
@@ -1662,7 +1662,7 @@ var tileflowInteractionActionSchema = z.discriminatedUnion("type", [
|
|
|
1662
1662
|
|
|
1663
1663
|
// src/maplibre-poi.ts
|
|
1664
1664
|
var interactionManifestMetadataKey = "tileflow:interaction-manifest";
|
|
1665
|
-
var interactionManifestVersion =
|
|
1665
|
+
var interactionManifestVersion = 3;
|
|
1666
1666
|
var missingSourceLayerNamespace = "tileflow-no-source-layer";
|
|
1667
1667
|
function createTileflowMapLibrePoiController(options) {
|
|
1668
1668
|
let bindings = semanticPoiBindings(options.bindings ?? [], options.onDiagnostic);
|
|
@@ -1726,9 +1726,20 @@ function createTileflowMapLibrePoiController(options) {
|
|
|
1726
1726
|
);
|
|
1727
1727
|
continue;
|
|
1728
1728
|
}
|
|
1729
|
+
const properties = normalizePoiProperties(feature.properties, manifest.fields);
|
|
1730
|
+
const category = properties.category;
|
|
1731
|
+
if (category === void 0) {
|
|
1732
|
+
manifestMismatch = true;
|
|
1733
|
+
diagnostic(
|
|
1734
|
+
options.onDiagnostic,
|
|
1735
|
+
"SEMANTIC_MANIFEST_MISMATCH",
|
|
1736
|
+
"A rendered POI feature has no supported category."
|
|
1737
|
+
);
|
|
1738
|
+
continue;
|
|
1739
|
+
}
|
|
1729
1740
|
const binding = bindings.find((candidate) => {
|
|
1730
1741
|
const target = candidate.target;
|
|
1731
|
-
return target.kind === "semantic-feature" && target.domain === "poi" && (!target.categories || target.categories.includes(
|
|
1742
|
+
return target.kind === "semantic-feature" && target.domain === "poi" && (!target.categories || target.categories.includes(category));
|
|
1732
1743
|
});
|
|
1733
1744
|
if (!binding) continue;
|
|
1734
1745
|
const featureId = normalizeFeatureId(feature.id);
|
|
@@ -1742,9 +1753,9 @@ function createTileflowMapLibrePoiController(options) {
|
|
|
1742
1753
|
coordinate: [event.lngLat.lng, event.lngLat.lat],
|
|
1743
1754
|
domain: "poi",
|
|
1744
1755
|
feature: {
|
|
1745
|
-
category
|
|
1756
|
+
category,
|
|
1746
1757
|
...featureId === void 0 ? {} : { id: featureId },
|
|
1747
|
-
properties
|
|
1758
|
+
properties
|
|
1748
1759
|
},
|
|
1749
1760
|
kind: "semantic-feature"
|
|
1750
1761
|
}
|
|
@@ -1974,7 +1985,7 @@ function parsePoiManifest(styleInput, onDiagnostic) {
|
|
|
1974
1985
|
for (const input of layerInputs) {
|
|
1975
1986
|
const layer = asRecord(input);
|
|
1976
1987
|
const sourceLayer = layer?.sourceLayer;
|
|
1977
|
-
if (!layer || !
|
|
1988
|
+
if (!layer || !isSafeManifestName(layer.layerId) || !isSafeManifestName(layer.source) || sourceLayer !== void 0 && !isSafeManifestName(sourceLayer) || layer.anchor !== "pointer-coordinate" || !isPoiRepresentation(layer.representation) || !Number.isSafeInteger(layer.priority) || layer.priority < 0 || layer.priority > 1e5 || ids.has(layer.layerId)) {
|
|
1978
1989
|
diagnostic(onDiagnostic, "SEMANTIC_MANIFEST_MISMATCH", "Invalid semantic POI layer lookup.");
|
|
1979
1990
|
return null;
|
|
1980
1991
|
}
|
|
@@ -2002,7 +2013,6 @@ function parsePoiManifest(styleInput, onDiagnostic) {
|
|
|
2002
2013
|
identityNamespace = namespace;
|
|
2003
2014
|
ids.add(layer.layerId);
|
|
2004
2015
|
layers.push({
|
|
2005
|
-
category: layer.category,
|
|
2006
2016
|
layerId: layer.layerId,
|
|
2007
2017
|
priority: layer.priority,
|
|
2008
2018
|
representation: layer.representation,
|
|
@@ -2072,11 +2082,7 @@ function sourceLayerNamespace(sourceLayer) {
|
|
|
2072
2082
|
return sourceLayer ?? missingSourceLayerNamespace;
|
|
2073
2083
|
}
|
|
2074
2084
|
function relevantLayerIds(manifest, bindings) {
|
|
2075
|
-
return manifest.layers.
|
|
2076
|
-
(layer) => bindings.some(
|
|
2077
|
-
(binding) => binding.target.kind === "semantic-feature" && (!binding.target.categories || binding.target.categories.includes(layer.category))
|
|
2078
|
-
)
|
|
2079
|
-
).map((layer) => layer.layerId);
|
|
2085
|
+
return bindings.some((binding) => binding.target.kind === "semantic-feature") ? manifest.layers.map((layer) => layer.layerId) : [];
|
|
2080
2086
|
}
|
|
2081
2087
|
function normalizePoiProperties(properties, fields) {
|
|
2082
2088
|
const source = properties ?? {};
|