@tileflow/react 0.1.0-alpha.23 → 0.1.0-alpha.25
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 +192 -212
- package/dist/index.d.ts +7 -1
- package/dist/index.js +23 -3
- package/package.json +6 -6
package/README.md
CHANGED
|
@@ -1,12 +1,80 @@
|
|
|
1
1
|
# @tileflow/react
|
|
2
2
|
|
|
3
|
-
React components for
|
|
3
|
+
React components for interactive Tileflow maps, annotations, and static-image display.
|
|
4
|
+
Interactive maps use MapLibre GL JS; browser components read prepared assets rather than compiling
|
|
5
|
+
`tileflow.config.ts`.
|
|
4
6
|
|
|
5
|
-
|
|
7
|
+
> Related packages and guides: [documentation index](https://raw.githubusercontent.com/tileflow/tileflow-sdk/main/llms.txt).
|
|
8
|
+
|
|
9
|
+
## Install
|
|
10
|
+
|
|
11
|
+
Use an existing React 18 or 19 application with matching `react-dom`. The following local build
|
|
12
|
+
workflow needs Node.js 22 or newer:
|
|
13
|
+
|
|
14
|
+
```sh
|
|
15
|
+
npm install @tileflow/react@alpha @tileflow/core@alpha @tileflow/maps@alpha "maplibre-gl@^6.4.1"
|
|
16
|
+
npm install --save-dev --save-exact tileflow@alpha
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
The supported peer ranges are React/React DOM 18–19 and MapLibre GL JS `>=6.4.1 <7`. The worker
|
|
20
|
+
must come from the same MapLibre installation as the main module.
|
|
21
|
+
|
|
22
|
+
## Prepare a map
|
|
23
|
+
|
|
24
|
+
Create `tileflow.config.ts` at the application root:
|
|
25
|
+
|
|
26
|
+
<!-- docs:check -->
|
|
27
|
+
|
|
28
|
+
```ts
|
|
29
|
+
import {defineMap} from '@tileflow/core';
|
|
30
|
+
import {streets} from '@tileflow/maps';
|
|
31
|
+
|
|
32
|
+
export default defineMap({
|
|
33
|
+
id: 'madrid',
|
|
34
|
+
version: 1,
|
|
35
|
+
extends: streets,
|
|
36
|
+
view: {center: [-3.7038, 40.4168], zoom: 12},
|
|
37
|
+
});
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
Build the assets into the application's public directory:
|
|
41
|
+
|
|
42
|
+
```sh
|
|
43
|
+
npx tileflow build --out public/tileflow
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
This assumes the application serves `public/` at its URL root. Rebuild after config or asset
|
|
47
|
+
changes, or use the [Vite](https://github.com/tileflow/tileflow-sdk/blob/main/packages/vite/README.md),
|
|
48
|
+
[Next.js](https://github.com/tileflow/tileflow-sdk/blob/main/packages/next/README.md), or
|
|
49
|
+
[Webpack](https://github.com/tileflow/tileflow-sdk/blob/main/packages/webpack/README.md) integration
|
|
50
|
+
for watched development and production builds. Do not use both workflows to overwrite the same
|
|
51
|
+
hosted manifest.
|
|
52
|
+
|
|
53
|
+
## Configure the worker
|
|
54
|
+
|
|
55
|
+
In a Vite application's client entry, add this before mounting React:
|
|
56
|
+
|
|
57
|
+
```ts
|
|
58
|
+
import workerUrl from 'maplibre-gl/dist/maplibre-gl-worker.mjs?worker&url';
|
|
59
|
+
import {configureTileflowMapLibre} from '@tileflow/react';
|
|
60
|
+
|
|
61
|
+
configureTileflowMapLibre({workerUrl});
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
This import syntax is specific to Vite. Use the Next.js or Webpack guide linked above for that
|
|
65
|
+
bundler's worker-delivery recipe. Configure the worker once, outside component rendering. Do not
|
|
66
|
+
use a CDN worker from another MapLibre version. Next.js interactive components belong behind a
|
|
67
|
+
`'use client'` boundary.
|
|
68
|
+
|
|
69
|
+
## Render a map
|
|
70
|
+
|
|
71
|
+
Import MapLibre's CSS once in the application. After the worker and assets are ready, render:
|
|
72
|
+
|
|
73
|
+
<!-- docs:check -->
|
|
6
74
|
|
|
7
75
|
```tsx
|
|
8
|
-
import {Map} from '@tileflow/react';
|
|
9
76
|
import 'maplibre-gl/dist/maplibre-gl.css';
|
|
77
|
+
import {Map} from '@tileflow/react';
|
|
10
78
|
|
|
11
79
|
export function App() {
|
|
12
80
|
return (
|
|
@@ -15,56 +83,69 @@ export function App() {
|
|
|
15
83
|
theme="system"
|
|
16
84
|
center={[-3.7038, 40.4168]}
|
|
17
85
|
zoom={12}
|
|
18
|
-
mapOptions={{
|
|
19
|
-
cooperativeGestures: true,
|
|
20
|
-
maxZoom: 18,
|
|
21
|
-
}}
|
|
86
|
+
mapOptions={{cooperativeGestures: true, maxZoom: 18}}
|
|
22
87
|
/>
|
|
23
88
|
);
|
|
24
89
|
}
|
|
25
90
|
```
|
|
26
91
|
|
|
27
|
-
|
|
92
|
+
Coordinates are `[longitude, latitude]`. `source.map` must match the config's portable map ID,
|
|
93
|
+
not a hosted `map_...` identifier. The default manifest URL is exactly `/tileflow/manifest.json`.
|
|
94
|
+
For a subpath or external host, provide `manifestUrl` in the source; the component does not infer
|
|
95
|
+
bundler configuration or search for assets.
|
|
96
|
+
|
|
97
|
+
`theme` selects a published concrete theme. Omission uses `defaultTheme`; `system` requires an
|
|
98
|
+
explicit light/dark mapping, which Streets supplies. Theme changes preserve the MapLibre instance,
|
|
99
|
+
camera, and interactions, and roll back on failure. `onThemeChange` reports transitions.
|
|
100
|
+
|
|
101
|
+
`mapOptions` accepts native MapLibre options except `container` and `style`. Direct camera props
|
|
102
|
+
take priority over `mapOptions`, then the manifest view, then shared defaults. To load one unmanaged
|
|
103
|
+
style, use `source={{kind: 'maplibre', style: styleUrl}}`; that source has no Tileflow theme switching
|
|
104
|
+
or manifest identity. Do not supply a Tileflow theme with an unmanaged source.
|
|
105
|
+
|
|
106
|
+
## Add annotations and popups
|
|
107
|
+
|
|
108
|
+
Install the contract package when importing its types directly:
|
|
109
|
+
|
|
110
|
+
```sh
|
|
111
|
+
npm install @tileflow/interactions@alpha
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
Annotations are small, application-owned marker sets. Every annotation has a stable `id`, singular
|
|
115
|
+
`coordinate`, and non-empty `ariaLabel`. Data must be JSON-safe. Native React renderers use portals
|
|
116
|
+
into hosts managed by the interaction runtime:
|
|
28
117
|
|
|
29
|
-
|
|
30
|
-
`renderMarker`, `renderTooltip`, and `renderPopup` render native React UI through portals into the
|
|
31
|
-
MapLibre-owned marker and overlay hosts.
|
|
118
|
+
<!-- docs:check -->
|
|
32
119
|
|
|
33
120
|
```tsx
|
|
34
|
-
import {Map} from '@tileflow/react';
|
|
35
121
|
import {useState} from 'react';
|
|
36
122
|
import type {TileflowAnnotation, TileflowInteractionState} from '@tileflow/interactions';
|
|
123
|
+
import {Map} from '@tileflow/react';
|
|
37
124
|
|
|
38
|
-
type Property = {
|
|
39
|
-
price: number;
|
|
40
|
-
title: string;
|
|
41
|
-
};
|
|
125
|
+
type Property = {price: number; title: string};
|
|
42
126
|
|
|
43
127
|
const annotations = [
|
|
44
128
|
{
|
|
45
|
-
ariaLabel: 'Apartment in Madrid',
|
|
46
|
-
coordinate: [-3.7038, 40.4168],
|
|
47
|
-
data: {price: 320_000, title: 'Apartment in Madrid'},
|
|
48
129
|
id: 'property-42',
|
|
49
130
|
kind: 'marker',
|
|
50
|
-
|
|
131
|
+
coordinate: [-3.7038, 40.4168],
|
|
132
|
+
ariaLabel: 'Apartment in Madrid',
|
|
133
|
+
data: {price: 320_000, title: 'Apartment in Madrid'},
|
|
51
134
|
tooltip: {content: {kind: 'field', field: 'title'}},
|
|
52
135
|
popup: {content: {kind: 'view', name: 'property-card'}},
|
|
53
136
|
},
|
|
54
137
|
] satisfies readonly TileflowAnnotation<Property>[];
|
|
55
138
|
|
|
56
139
|
export function PropertyMap() {
|
|
57
|
-
const [
|
|
140
|
+
const [state, setState] = useState<TileflowInteractionState>({popup: null});
|
|
58
141
|
|
|
59
142
|
return (
|
|
60
143
|
<Map
|
|
61
144
|
source={{kind: 'tileflow', map: 'madrid'}}
|
|
62
145
|
annotations={annotations}
|
|
63
|
-
interactionState={
|
|
64
|
-
onInteractionStateChange={
|
|
65
|
-
onInteractionDiagnostic={(diagnostic) => console.error(diagnostic)}
|
|
66
|
-
onInteractionEvent={(event) => console.log(event.type, event.target)}
|
|
67
|
-
renderMarker={({annotation}) => <strong>EUR {annotation.data.price.toLocaleString()}</strong>}
|
|
146
|
+
interactionState={state}
|
|
147
|
+
onInteractionStateChange={setState}
|
|
148
|
+
onInteractionDiagnostic={(diagnostic) => console.error(diagnostic.code)}
|
|
68
149
|
renderPopup={({annotation, close}) => (
|
|
69
150
|
<article>
|
|
70
151
|
<h2>{annotation.data.title}</h2>
|
|
@@ -79,208 +160,107 @@ export function PropertyMap() {
|
|
|
79
160
|
}
|
|
80
161
|
```
|
|
81
162
|
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
host.
|
|
163
|
+
This uses the worker/CSS setup from the preceding sections. Omit controlled `interactionState` and
|
|
164
|
+
use `defaultInteractionState` for uncontrolled state; never supply both or switch ownership during
|
|
165
|
+
the component's lifetime. Updating annotations, renderers, callbacks, or state does not recreate
|
|
166
|
+
the map. Reusing an annotation ID preserves a compatible marker host.
|
|
86
167
|
|
|
87
|
-
`
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
168
|
+
Use `interactions` with `target: {kind: 'semantic-feature', domain: 'poi'}` for POIs already in the
|
|
169
|
+
compiled map instead of creating a DOM marker for every feature. Optional categories use Tileflow's
|
|
170
|
+
semantic taxonomy, such as `food-drink` or `retail`, not raw source classes. The style must contain
|
|
171
|
+
compatible interaction metadata. With semantic bindings, narrow `context.target.kind` in
|
|
172
|
+
`renderTooltip` or `renderPopup` before accessing annotation or feature data. `renderMarker` remains
|
|
173
|
+
annotation-only. See the
|
|
174
|
+
[interaction guide](https://github.com/tileflow/tileflow-sdk/blob/main/packages/interactions/README.md).
|
|
91
175
|
|
|
92
|
-
|
|
176
|
+
Text/field content uses safe text defaults. A `view` is an application renderer name, not HTML.
|
|
177
|
+
Keep tooltips non-interactive; put buttons, links, and forms in popups.
|
|
93
178
|
|
|
94
|
-
|
|
95
|
-
Tileflow style. Application code names the `poi` domain, never compiler-generated MapLibre layer
|
|
96
|
-
IDs. The runtime queries only manifest-declared layers and mounts DOM only for the active overlay.
|
|
179
|
+
## Display an image or create a render
|
|
97
180
|
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
181
|
+
`<Map mode="image">` displays an existing explicit `imageUrl` or an image URL in the published
|
|
182
|
+
manifest. It does not create a static render, poll an operation, or load MapLibre. A local style
|
|
183
|
+
build alone does not create that image. Annotations, semantic bindings, and interaction state are
|
|
184
|
+
not supported in image mode.
|
|
101
185
|
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
id: 'poi-details',
|
|
105
|
-
target: {kind: 'semantic-feature', domain: 'poi', categories: ['food-drink', 'retail']},
|
|
106
|
-
tooltip: {content: {kind: 'field', field: 'name', fallback: 'Point of interest'}},
|
|
107
|
-
popup: {content: {kind: 'view', name: 'poi-card'}},
|
|
108
|
-
},
|
|
109
|
-
] satisfies readonly TileflowInteractionBinding[];
|
|
186
|
+
To request a new static render, use `StaticMap` from `@tileflow/react/static`. First install the
|
|
187
|
+
shared client/types used by this example:
|
|
110
188
|
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
<Map
|
|
114
|
-
source={{kind: 'tileflow', map: 'madrid'}}
|
|
115
|
-
interactions={interactions}
|
|
116
|
-
renderPopup={(context) =>
|
|
117
|
-
context.target.kind === 'semantic-feature' ? (
|
|
118
|
-
<article>
|
|
119
|
-
<h2>{String(context.target.feature.properties.name ?? 'Point of interest')}</h2>
|
|
120
|
-
<button type="button" onClick={context.close}>
|
|
121
|
-
Close
|
|
122
|
-
</button>
|
|
123
|
-
</article>
|
|
124
|
-
) : null
|
|
125
|
-
}
|
|
126
|
-
/>
|
|
127
|
-
);
|
|
128
|
-
}
|
|
189
|
+
```sh
|
|
190
|
+
npm install @tileflow/static@alpha
|
|
129
191
|
```
|
|
130
192
|
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
state, so replacing either target closes the previous popup before opening the next.
|
|
135
|
-
|
|
136
|
-
`MapProps` rejects controlled and default interaction state together. Its `mode="image"` branch
|
|
137
|
-
excludes annotations, semantic bindings, interaction state, renderers, and interaction callbacks.
|
|
138
|
-
JavaScript callers and widened inputs still receive the corresponding runtime diagnostics.
|
|
139
|
-
|
|
140
|
-
`onInteractionDiagnostic` receives each newly reported structured runtime diagnostic. Changing any
|
|
141
|
-
callback identity does not resubscribe the runtime or recreate MapLibre.
|
|
142
|
-
|
|
143
|
-
Custom portal targets move capture readiness to `loading` until React commits the target and two
|
|
144
|
-
current animation frames complete. Removing or replacing a target invalidates pending frames.
|
|
145
|
-
|
|
146
|
-
When no render prop is present, text and safe field descriptors use the shared unbranded DOM
|
|
147
|
-
defaults. A `view` descriptor is a dispatch name for an application renderer; it is not HTML or a
|
|
148
|
-
serialized component tree. Tooltip content remains non-interactive, while popup content may contain
|
|
149
|
-
normal React controls.
|
|
193
|
+
The application must implement an authorized `/api/static-maps` endpoint that forwards the normalized
|
|
194
|
+
scene and idempotency key to the hosted service and returns its result contract. Keep privileged
|
|
195
|
+
Tileflow credentials on that server, not in React props or a browser bundle.
|
|
150
196
|
|
|
151
|
-
|
|
152
|
-
`ariaLabel`, and optional `marker` descriptor feed the keyed runtime directly. `mode="image"`
|
|
153
|
-
cannot render interaction configuration and shows an explicit `UNSUPPORTED_MODE` diagnostic
|
|
154
|
-
without loading MapLibre.
|
|
155
|
-
|
|
156
|
-
`mapOptions` accepts native MapLibre options except `container` and `style`, which
|
|
157
|
-
Tileflow resolves from `source`. Direct
|
|
158
|
-
Tileflow props such as `center`, `zoom`, and `interactive` take priority when
|
|
159
|
-
provided. Camera resolution is the same in interactive and image modes: direct props, then
|
|
160
|
-
`mapOptions`, then the published manifest view, then Tileflow's shared runtime defaults.
|
|
161
|
-
|
|
162
|
-
Every map has exactly one discriminated `source`. Use `kind: 'tileflow'` for a map published in a
|
|
163
|
-
Tileflow manifest. `kind: 'maplibre'` is the unmanaged MapLibre escape hatch for one direct style
|
|
164
|
-
object or URL: it deliberately has no Tileflow theme identity, `system` selection, switching, or
|
|
165
|
-
manifest traceability. Browser components do not compile `tileflow.config.ts`.
|
|
166
|
-
|
|
167
|
-
Without `manifestUrl`, the exact default is `/tileflow/manifest.json`. If Vite, Webpack, Next, a
|
|
168
|
-
reverse proxy, or the Tileflow plugin publishes it anywhere else, set the final public URL
|
|
169
|
-
explicitly; the component does not attempt runtime base-path discovery. Manifest 404s, unknown map
|
|
170
|
-
IDs, unresolved styles, and unresolved image URLs enter `data-tileflow-state="error"`.
|
|
171
|
-
|
|
172
|
-
`theme` selects a published theme name. Omitting it uses the map's `defaultTheme`; `"system"` is
|
|
173
|
-
available only when the map declares explicit light and dark mappings. Changes preload fonts, diff
|
|
174
|
-
the style on the existing MapLibre instance, preserve camera and interactions, and roll back if the
|
|
175
|
-
new style fails. `onThemeChange` reports preloading, applying, ready, and error transitions.
|
|
176
|
-
|
|
177
|
-
To reuse one published map across multiple repos, point every app at the same
|
|
178
|
-
manifest:
|
|
197
|
+
<!-- docs:check -->
|
|
179
198
|
|
|
180
199
|
```tsx
|
|
181
|
-
<Map
|
|
182
|
-
source={{
|
|
183
|
-
kind: 'tileflow',
|
|
184
|
-
map: 'madrid',
|
|
185
|
-
manifestUrl: 'https://cdn.example.com/tileflow/manifest.json',
|
|
186
|
-
}}
|
|
187
|
-
/>
|
|
188
|
-
```
|
|
189
|
-
|
|
190
|
-
Or deliberately leave the Tileflow theme contract and load one concrete Style JSON directly:
|
|
191
|
-
|
|
192
|
-
```tsx
|
|
193
|
-
<Map
|
|
194
|
-
source={{
|
|
195
|
-
kind: 'maplibre',
|
|
196
|
-
style: 'https://cdn.example.com/tileflow/styles/madrid/dark.json',
|
|
197
|
-
}}
|
|
198
|
-
/>
|
|
199
|
-
```
|
|
200
|
-
|
|
201
|
-
For a lightweight display of an already hosted static image, use image mode:
|
|
202
|
-
|
|
203
|
-
```tsx
|
|
204
|
-
<Map
|
|
205
|
-
source={{kind: 'tileflow', map: 'madrid'}}
|
|
206
|
-
mode="image"
|
|
207
|
-
center={[-3.7038, 40.4168]}
|
|
208
|
-
zoom={12}
|
|
209
|
-
/>
|
|
210
|
-
```
|
|
211
|
-
|
|
212
|
-
`Map mode="image"` only resolves an existing image URL (explicitly or from the published map
|
|
213
|
-
manifest) and renders an `<img>`; it does not submit a render scene, create an operation, poll, or
|
|
214
|
-
apply `StaticMap` overlays. This path does not load or evaluate MapLibre. Without an explicit
|
|
215
|
-
`imageUrl`, all environments use the image URL published for the Tileflow source.
|
|
216
|
-
|
|
217
|
-
For a new, fully specified render with exact size, center/bounds camera, overlays, idempotency, and
|
|
218
|
-
asynchronous create/poll behavior, use `StaticMap` from `@tileflow/react/static` or helpers from
|
|
219
|
-
`@tileflow/static`.
|
|
220
|
-
|
|
221
|
-
```tsx
|
|
222
|
-
import {StaticMap} from '@tileflow/react/static';
|
|
223
200
|
import {useState} from 'react';
|
|
224
|
-
import {
|
|
201
|
+
import {StaticMap} from '@tileflow/react/static';
|
|
202
|
+
import type {StaticMapAttributionEntry} from '@tileflow/static';
|
|
225
203
|
|
|
226
|
-
export function
|
|
227
|
-
const [
|
|
204
|
+
export function StaticPreview({idempotencyKey}: {idempotencyKey: string}) {
|
|
205
|
+
const [entries, setEntries] = useState<readonly StaticMapAttributionEntry[]>([]);
|
|
228
206
|
|
|
229
207
|
return (
|
|
230
|
-
<
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
208
|
+
<figure>
|
|
209
|
+
<StaticMap
|
|
210
|
+
map="madrid"
|
|
211
|
+
theme="dark"
|
|
212
|
+
alt="Map of central Madrid"
|
|
213
|
+
camera={{type: 'center', center: [-3.7038, 40.4168], zoom: 12}}
|
|
214
|
+
size={{width: 1200, height: 800}}
|
|
215
|
+
attribution={{mode: 'external'}}
|
|
216
|
+
createUrl="/api/static-maps"
|
|
217
|
+
idempotencyKey={idempotencyKey}
|
|
218
|
+
onReady={(result) => {
|
|
219
|
+
if ('attribution' in result) setEntries(result.attribution.entries);
|
|
220
|
+
}}
|
|
221
|
+
/>
|
|
222
|
+
<figcaption>
|
|
223
|
+
{entries.map((entry, index) => (
|
|
224
|
+
<p key={index}>
|
|
225
|
+
{entry.text}{' '}
|
|
226
|
+
{entry.links.map((link) => (
|
|
227
|
+
<a key={link.url} href={link.url}>
|
|
228
|
+
{link.label}
|
|
229
|
+
</a>
|
|
230
|
+
))}
|
|
231
|
+
</p>
|
|
232
|
+
))}
|
|
233
|
+
</figcaption>
|
|
234
|
+
</figure>
|
|
241
235
|
);
|
|
242
236
|
}
|
|
243
237
|
```
|
|
244
238
|
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
The root element exposes `data-tileflow-map`, optional `data-tileflow-capture-id`, and
|
|
274
|
-
`data-tileflow-state="loading|idle|error"`. Interactive mode becomes idle after MapLibre is idle
|
|
275
|
-
and two animation frames; style/data work returns it to loading. Image mode waits for decode or a
|
|
276
|
-
successful load fallback, including cached hydration. `tileflow capture` uses these markers for
|
|
277
|
-
application scenes and requires exactly one target.
|
|
278
|
-
|
|
279
|
-
## Compatibility
|
|
280
|
-
|
|
281
|
-
The supported peer window is React 18-19 and MapLibre GL JS 5-6. Compatibility smoke tests install
|
|
282
|
-
the exact lower bound and the first release of every accepted major from packed Tileflow tarballs,
|
|
283
|
-
typecheck a consumer, and render the image/SSR path while rejecting any MapLibre import. Future
|
|
284
|
-
majors stay outside the peer range until that matrix passes.
|
|
285
|
-
|
|
286
|
-
Docs: https://tileflow.dev/docs
|
|
239
|
+
Create the key with `createStaticMapIdempotencyKey()` once per intentional render action and retain
|
|
240
|
+
it in the owning application state across retries and remounts. Pass it into this component; do not
|
|
241
|
+
regenerate it on every render. A new scene is a new action and needs a new key.
|
|
242
|
+
|
|
243
|
+
Hosted results have `resultVersion: 1` and attribution. `onReady` also supports existing-image
|
|
244
|
+
results, which have no attribution field; narrow the union before reading it. External attribution
|
|
245
|
+
must remain visible beside the image. Omitted attribution uses embedded automatic placement.
|
|
246
|
+
See the [Static Maps guide](https://github.com/tileflow/tileflow-sdk/blob/main/packages/static/README.md)
|
|
247
|
+
for server transport, errors, overlays, and limits.
|
|
248
|
+
|
|
249
|
+
## Capture, authorization, and errors
|
|
250
|
+
|
|
251
|
+
`captureId` disambiguates repeated maps on a page. The root exposes `data-tileflow-map`, the resolved
|
|
252
|
+
`data-tileflow-theme`, optional `data-tileflow-capture-id`, and `data-tileflow-state="loading|idle|error"`.
|
|
253
|
+
Capture waits for MapLibre/image readiness and committed custom interaction views. Manifest 404s,
|
|
254
|
+
unknown maps/themes, and missing styles or images enter the error state rather than silently using
|
|
255
|
+
another map.
|
|
256
|
+
|
|
257
|
+
Hosted interactive maps acquire a short-lived session grant before eligible resource requests.
|
|
258
|
+
`analytics={{enabled: false}}` disables the optional beacon, not hosted authorization. A stable
|
|
259
|
+
`surfaceId`, such as `store-locator`, identifies a product location; do not use user IDs or URLs.
|
|
260
|
+
Existing request transforms remain application-owned, and direct World use can display an
|
|
261
|
+
owner-action notice when managed delivery is required.
|
|
262
|
+
|
|
263
|
+
The image/SSR path does not load MapLibre. Interactive rendering needs a browser with WebGL and the
|
|
264
|
+
matching worker assets. For release-specific APIs, use the installed declarations and README;
|
|
265
|
+
source `main` may be ahead of npm. Report defects in the
|
|
266
|
+
[issue tracker](https://github.com/tileflow/tileflow-sdk/issues).
|
package/dist/index.d.ts
CHANGED
|
@@ -69,4 +69,10 @@ type MapImageProps = MapSharedProps & {
|
|
|
69
69
|
type MapProps<TAnnotation extends TileflowAnnotation = TileflowAnnotation> = (MapInteractiveProps<TAnnotation> | MapImageProps) & TileflowMapStyleSourceProps;
|
|
70
70
|
declare function Map<TAnnotation extends TileflowAnnotation = TileflowAnnotation>(props: MapProps<TAnnotation>): react.JSX.Element;
|
|
71
71
|
|
|
72
|
-
|
|
72
|
+
type TileflowMapLibreConfiguration = Readonly<{
|
|
73
|
+
workerUrl: string;
|
|
74
|
+
}>;
|
|
75
|
+
/** Configure the application-owned worker before mounting an interactive Tileflow map. */
|
|
76
|
+
declare function configureTileflowMapLibre(configuration: TileflowMapLibreConfiguration): void;
|
|
77
|
+
|
|
78
|
+
export { Map, type MapProps, type TileflowAnnotationRenderer, type TileflowInteractionRenderer, type TileflowMapLibreConfiguration, type TileflowMapOptions, type TileflowMapSource, configureTileflowMapLibre };
|
package/dist/index.js
CHANGED
|
@@ -189,8 +189,21 @@ function assertTileflowMapStyleInputs(input) {
|
|
|
189
189
|
|
|
190
190
|
// src/maplibre.ts
|
|
191
191
|
var mapLibrePromise;
|
|
192
|
+
var mapLibre;
|
|
193
|
+
var workerUrl;
|
|
194
|
+
function configureTileflowMapLibre(configuration) {
|
|
195
|
+
const nextWorkerUrl = configuration.workerUrl;
|
|
196
|
+
if (typeof nextWorkerUrl !== "string" || nextWorkerUrl.trim().length === 0) {
|
|
197
|
+
throw new TypeError("Tileflow MapLibre workerUrl must be a non-empty string.");
|
|
198
|
+
}
|
|
199
|
+
if (workerUrl !== void 0 && workerUrl !== nextWorkerUrl) {
|
|
200
|
+
throw new Error("Tileflow MapLibre workerUrl is already configured.");
|
|
201
|
+
}
|
|
202
|
+
workerUrl = nextWorkerUrl;
|
|
203
|
+
mapLibre?.setWorkerUrl(nextWorkerUrl);
|
|
204
|
+
}
|
|
192
205
|
function loadTileflowMapLibre() {
|
|
193
|
-
mapLibrePromise ??= import("maplibre-gl").then(resolveMapLibreModule).catch((error) => {
|
|
206
|
+
mapLibrePromise ??= import("maplibre-gl").then(resolveMapLibreModule).then(configureTileflowMapLibreModule).catch((error) => {
|
|
194
207
|
mapLibrePromise = void 0;
|
|
195
208
|
throw error;
|
|
196
209
|
});
|
|
@@ -200,6 +213,11 @@ function resolveMapLibreModule(module) {
|
|
|
200
213
|
const defaultExport = module.default;
|
|
201
214
|
return defaultExport ?? module;
|
|
202
215
|
}
|
|
216
|
+
function configureTileflowMapLibreModule(maplibregl) {
|
|
217
|
+
if (workerUrl !== void 0) maplibregl.setWorkerUrl(workerUrl);
|
|
218
|
+
mapLibre = maplibregl;
|
|
219
|
+
return maplibregl;
|
|
220
|
+
}
|
|
203
221
|
|
|
204
222
|
// src/map.tsx
|
|
205
223
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
@@ -1218,10 +1236,11 @@ function wrapMapLibrePositioned(positioned) {
|
|
|
1218
1236
|
};
|
|
1219
1237
|
}
|
|
1220
1238
|
function createTileflowMapLibrePoiMap(map) {
|
|
1239
|
+
const poiMap = map;
|
|
1221
1240
|
return {
|
|
1222
1241
|
getStyle: () => map.getStyle(),
|
|
1223
1242
|
on(event, listener) {
|
|
1224
|
-
return
|
|
1243
|
+
return poiMap.on(event, listener);
|
|
1225
1244
|
},
|
|
1226
1245
|
queryRenderedFeatures(point, options) {
|
|
1227
1246
|
return map.queryRenderedFeatures(point, {
|
|
@@ -1298,5 +1317,6 @@ function isPlainObject(value) {
|
|
|
1298
1317
|
return prototype === Object.prototype || prototype === null;
|
|
1299
1318
|
}
|
|
1300
1319
|
export {
|
|
1301
|
-
Map2 as Map
|
|
1320
|
+
Map2 as Map,
|
|
1321
|
+
configureTileflowMapLibre
|
|
1302
1322
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tileflow/react",
|
|
3
|
-
"version": "0.1.0-alpha.
|
|
3
|
+
"version": "0.1.0-alpha.25",
|
|
4
4
|
"license": "Apache-2.0",
|
|
5
5
|
"description": "React components for rendering Tileflow maps with MapLibre.",
|
|
6
6
|
"type": "module",
|
|
@@ -43,19 +43,19 @@
|
|
|
43
43
|
"access": "public"
|
|
44
44
|
},
|
|
45
45
|
"dependencies": {
|
|
46
|
-
"@tileflow/core": ">=0.1.0-alpha.
|
|
47
|
-
"@tileflow/interactions": ">=0.1.0-alpha.
|
|
48
|
-
"@tileflow/static": ">=0.1.0-alpha.
|
|
46
|
+
"@tileflow/core": ">=0.1.0-alpha.25 <0.1.0-beta.0",
|
|
47
|
+
"@tileflow/interactions": ">=0.1.0-alpha.4 <0.1.0-beta.0",
|
|
48
|
+
"@tileflow/static": ">=0.1.0-alpha.26 <0.1.0-beta.0"
|
|
49
49
|
},
|
|
50
50
|
"peerDependencies": {
|
|
51
|
-
"maplibre-gl": ">=
|
|
51
|
+
"maplibre-gl": ">=6.4.1 <7",
|
|
52
52
|
"react": ">=18 <20",
|
|
53
53
|
"react-dom": ">=18 <20"
|
|
54
54
|
},
|
|
55
55
|
"devDependencies": {
|
|
56
56
|
"@types/react": "^19.2.17",
|
|
57
57
|
"@types/react-dom": "^19.2.3",
|
|
58
|
-
"maplibre-gl": "
|
|
58
|
+
"maplibre-gl": "6.9.0",
|
|
59
59
|
"react": "^19.2.7",
|
|
60
60
|
"react-dom": "^19.2.7"
|
|
61
61
|
},
|