@tileflow/vue 0.1.0-alpha.23 → 0.1.0-alpha.24

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.
Files changed (2) hide show
  1. package/README.md +127 -155
  2. package/package.json +3 -3
package/README.md CHANGED
@@ -1,8 +1,65 @@
1
1
  # @tileflow/vue
2
2
 
3
- Vue component for rendering Tileflow maps with MapLibre.
3
+ Vue components for interactive Tileflow maps, annotations, and existing-image display.
4
+ The component reads prepared manifests and styles; it does not compile `tileflow.config.ts` in the
5
+ browser.
4
6
 
5
- Install `maplibre-gl` alongside the package and import its CSS once in your app.
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 Vue 3 application. Supported peers are Vue `>=3.3 <4` and MapLibre GL JS
12
+ `>=6.4.1 <7`. The local build workflow below requires Node.js 22 or newer.
13
+
14
+ ```sh
15
+ npm install @tileflow/vue@alpha @tileflow/core@alpha @tileflow/maps@alpha "maplibre-gl@^6.4.1"
16
+ npm install --save-dev --save-exact tileflow@alpha
17
+ ```
18
+
19
+ ## Prepare a map
20
+
21
+ Create `tileflow.config.ts` at the application root:
22
+
23
+ <!-- docs:check -->
24
+
25
+ ```ts
26
+ import {defineMap} from '@tileflow/core';
27
+ import {streets} from '@tileflow/maps';
28
+
29
+ export default defineMap({
30
+ id: 'madrid',
31
+ version: 1,
32
+ extends: streets,
33
+ view: {center: [-3.7038, 40.4168], zoom: 12},
34
+ });
35
+ ```
36
+
37
+ ```sh
38
+ npx tileflow build --out public/tileflow
39
+ ```
40
+
41
+ Serve `public/` at the application's URL root. Rebuild after map or asset changes, or use the
42
+ [Vite integration](https://github.com/tileflow/tileflow-sdk/blob/main/packages/vite/README.md)
43
+ for watched development and production output. Local build and validation need no API key;
44
+ rendering may still request configured remote tiles and fonts.
45
+
46
+ ## Configure the worker
47
+
48
+ For Vite, add the following to the existing client entry before `createApp(...).mount(...)`:
49
+
50
+ ```ts
51
+ import workerUrl from 'maplibre-gl/dist/maplibre-gl-worker.mjs?worker&url';
52
+ import {configureTileflowMapLibre} from '@tileflow/vue';
53
+
54
+ configureTileflowMapLibre({workerUrl});
55
+ ```
56
+
57
+ Configure this once before mounting an interactive map. The worker must come from the same installed
58
+ MapLibre package as the main module. The `?worker&url` import is Vite-specific; use the
59
+ [Webpack recipe](https://github.com/tileflow/tileflow-sdk/blob/main/packages/webpack/README.md)
60
+ for Webpack. Keep MapLibre's CSS in the client application as well.
61
+
62
+ ## Render a map
6
63
 
7
64
  ```vue
8
65
  <script setup lang="ts">
@@ -16,142 +73,66 @@ import {TileflowMap} from '@tileflow/vue';
16
73
  theme="system"
17
74
  :center="[-3.7038, 40.4168]"
18
75
  :zoom="12"
19
- :map-options="{
20
- cooperativeGestures: true,
21
- maxZoom: 18,
22
- }"
76
+ :height="420"
77
+ :map-options="{cooperativeGestures: true, maxZoom: 18}"
23
78
  />
24
79
  </template>
25
80
  ```
26
81
 
27
- ## MapLibre 6 worker
82
+ Coordinates are `[longitude, latitude]`. `source.map` is the config's portable ID, not a hosted
83
+ `map_...` identifier. The default manifest URL is exactly `/tileflow/manifest.json`; provide
84
+ `source.manifestUrl` explicitly for a subpath, reverse proxy, or external host. The component does
85
+ not infer build-tool configuration.
28
86
 
29
- With MapLibre GL JS 6, configure the application-owned worker once before mounting an interactive
30
- map. The worker URL must come from the same `maplibre-gl` package installed by the application.
87
+ Omitting `theme` uses `defaultTheme`. `system` needs the map's explicit light/dark mapping, which
88
+ Streets supplies. Switching themes preserves the map, camera, and interactions, with rollback on
89
+ failure. Listen to `themeChange` for transitions.
31
90
 
32
- ```ts
33
- // main.ts
34
- import workerUrl from 'maplibre-gl/dist/maplibre-gl-worker.mjs?worker&url';
35
- import {configureTileflowMapLibre} from '@tileflow/vue';
91
+ `mapOptions` accepts native MapLibre options except `container` and `style`. Direct props take
92
+ priority over those options, then the published view, then shared defaults. An unmanaged
93
+ `source: {kind: 'maplibre', style: styleUrl}` loads a single style without Tileflow theme selection
94
+ or manifest traceability; do not combine it with a Tileflow theme.
36
95
 
37
- configureTileflowMapLibre({workerUrl});
38
- ```
39
-
40
- This is the Vite setup. Run it before `createApp(...).mount(...)`; `mode="image"` remains
41
- MapLibre-free. MapLibre GL JS 6.4.1-6.x is supported. Use the `@tileflow/next` or
42
- `@tileflow/webpack` README for their worker-delivery recipes.
43
-
44
- `mapOptions` accepts native MapLibre options except `container` and `style`, which
45
- Tileflow resolves from `source`. Direct
46
- Tileflow props such as `center`, `zoom`, and `interactive` take priority when
47
- provided. Camera resolution is the same in interactive and image modes: direct props, then
48
- `mapOptions`, then the published manifest view, then Tileflow's shared runtime defaults.
49
-
50
- Every map has exactly one discriminated `source`. Use `kind: 'tileflow'` with `map` and an optional
51
- `manifestUrl` for published delivery. `kind: 'maplibre'` is an unmanaged escape hatch for one direct
52
- style object or URL; it has no Tileflow theme identity, `system` selection, switching, or manifest
53
- traceability. Browser components do not compile `tileflow.config.ts`.
96
+ ## Add annotations and native popup UI
54
97
 
55
- Without `manifestUrl`, the exact default is `/tileflow/manifest.json`. If a bundler, framework base
56
- path, reverse proxy, or Tileflow plugin publishes it elsewhere, set the final public URL explicitly;
57
- the component does not guess it. Manifest 404s, unknown map IDs, unresolved styles, and unresolved
58
- image URLs enter `data-tileflow-state="error"`.
98
+ Install the contracts when importing them directly:
59
99
 
60
- `theme` selects a published theme name; omission uses `defaultTheme`, while `"system"` requires the
61
- map's explicit light/dark mapping. Switching themes preserves the MapLibre instance, camera, and
62
- interaction state, with rollback on failure. Listen to `themeChange` for transition state.
63
-
64
- ```vue
65
- <TileflowMap
66
- :source="{
67
- kind: 'tileflow',
68
- map: 'madrid',
69
- manifestUrl: 'https://cdn.example.com/tileflow/manifest.json',
70
- }"
71
- />
72
-
73
- <TileflowMap
74
- :source="{
75
- kind: 'maplibre',
76
- style: 'https://cdn.example.com/tileflow/styles/madrid/dark.json',
77
- }"
78
- />
100
+ ```sh
101
+ npm install @tileflow/interactions@alpha
79
102
  ```
80
103
 
81
- `mode="image"` resolves an explicit or published image URL and renders an `<img>` without loading
82
- or evaluating MapLibre. All environments follow the same published manifest contract.
83
-
84
- ## Annotations, semantic POIs, and native Vue views
85
-
86
- Use `annotations` for small, application-owned DOM markers. The portable annotation data and
87
- interaction state remain JSON-safe. Use `interactions` to bind tooltip or popup behavior to
88
- manifest-declared semantic POIs already rendered by the map style; this avoids creating one DOM
89
- marker per feature. Scoped slots render native Vue UI into hosts owned by the shared interaction
90
- runtime.
104
+ This component uses the worker and CSS setup above:
91
105
 
92
106
  ```vue
93
107
  <script setup lang="ts">
94
108
  import {ref} from 'vue';
95
- import type {
96
- TileflowAnnotation,
97
- TileflowInteractionBinding,
98
- TileflowInteractionState,
99
- } from '@tileflow/interactions';
109
+ import type {TileflowAnnotation, TileflowInteractionState} from '@tileflow/interactions';
100
110
  import {TileflowMap} from '@tileflow/vue';
101
111
 
102
- type Property = {address: string; price: number};
103
-
104
112
  const annotations = [
105
113
  {
106
- kind: 'marker',
107
114
  id: 'property-42',
108
- coordinate: [-3.7, 40.4],
115
+ kind: 'marker',
116
+ coordinate: [-3.7038, 40.4168],
109
117
  ariaLabel: 'Apartment in Madrid',
110
- data: {address: 'Calle Mayor', price: 320_000},
111
- tooltip: {content: {kind: 'field', field: 'address'}},
118
+ tooltip: {content: {kind: 'text', text: 'View apartment'}},
112
119
  popup: {content: {kind: 'view', name: 'property-card'}},
113
120
  },
114
- ] satisfies readonly TileflowAnnotation<Property>[];
115
-
116
- const interactions = [
117
- {
118
- id: 'restaurant-details',
119
- target: {kind: 'semantic-feature', domain: 'poi', categories: ['food-drink']},
120
- tooltip: {content: {kind: 'field', field: 'name', fallback: 'Restaurant'}},
121
- popup: {content: {kind: 'view', name: 'poi-card'}},
122
- },
123
- ] satisfies readonly TileflowInteractionBinding[];
121
+ ] satisfies readonly TileflowAnnotation[];
124
122
 
125
- const interactionState = ref<TileflowInteractionState>({popup: null});
123
+ const state = ref<TileflowInteractionState>({popup: null});
126
124
  </script>
127
125
 
128
126
  <template>
129
127
  <TileflowMap
130
- v-model:interaction-state="interactionState"
128
+ v-model:interaction-state="state"
131
129
  :source="{kind: 'tileflow', map: 'madrid'}"
132
130
  :annotations="annotations"
133
- :interactions="interactions"
134
- @interaction-event="(event) => console.log(event.type, event.target)"
135
- @interaction-diagnostic="(diagnostic) => console.warn(diagnostic.code)"
131
+ @interaction-diagnostic="(diagnostic) => console.error(diagnostic.code)"
136
132
  >
137
- <template #marker="{annotation}">
138
- <span class="price-marker">{{ annotation.data.price.toLocaleString() }}</span>
139
- </template>
140
-
141
- <template #tooltip="{target}">
142
- <span v-if="target.kind === 'annotation'">{{ target.annotation.data.address }}</span>
143
- <span v-else-if="target.kind === 'semantic-feature'">
144
- {{ target.feature.properties.name }}
145
- </span>
146
- </template>
147
-
148
133
  <template #popup="{target, close}">
149
134
  <article v-if="target.kind === 'annotation'">
150
- <strong>{{ target.annotation.data.address }}</strong>
151
- <button type="button" @click="close">Close</button>
152
- </article>
153
- <article v-else-if="target.kind === 'semantic-feature'">
154
- <strong>{{ target.feature.properties.name }}</strong>
135
+ <h2>{{ target.annotation.ariaLabel }}</h2>
155
136
  <button type="button" @click="close">Close</button>
156
137
  </article>
157
138
  </template>
@@ -159,58 +140,49 @@ const interactionState = ref<TileflowInteractionState>({popup: null});
159
140
  </template>
160
141
  ```
161
142
 
162
- Omit `interactionState` and use `default-interaction-state` for uncontrolled state. Do not provide
163
- both or switch ownership modes during a component instance's lifetime. `annotations` is the only
164
- application-owned marker input and uses singular `coordinate` plus required `ariaLabel`.
165
-
166
- The `marker` slot is annotation-only and preserves the annotation's generic `data` type.
167
- `tooltip` and `popup` receive the general `TileflowInteractionViewContext`; narrow
168
- `target.kind` to access either `target.annotation` or the resolved semantic feature. Semantic POI
169
- bindings require a compatible `tileflow:interaction-manifest` in the active style. Bindings are
170
- validated before reaching MapLibre, POI hit tests are coalesced with `requestAnimationFrame`, and
171
- annotation plus semantic runtimes share one controlled or uncontrolled popup state.
172
- Values in `target.categories` use Tileflow's semantic taxonomy (for example `food` or `coffee`),
173
- not raw OpenMapTiles classes.
174
-
175
- Text content is inserted as text, `field` is a bounded declarative lookup, and `view` is only a
176
- dispatch name for the corresponding application-owned scoped slot. No interaction path evaluates
177
- HTML. Passing annotations, semantic interactions, or interaction state to `mode="image"` emits an `UNSUPPORTED_MODE`
178
- diagnostic, marks capture readiness as `error`, and still does not load or evaluate MapLibre.
179
-
180
- Changing annotations, semantic bindings, slots, state listeners, or diagnostic listeners
181
- reconciles the existing runtimes; it does not recreate the map. The semantic runtime is initialized
182
- lazily, and the component and its interaction imports remain SSR-safe.
183
-
184
- Hosted maps automatically preflight a short-lived commercial session grant before eligible
185
- resources. Setting `analytics` with `enabled: false` disables the optional beacon only; it does not
186
- remove hosted authorization or override a user `mapOptions.transformRequest` callback.
187
- Use `:analytics="{surfaceId: 'store-locator'}"` when the same Map is embedded in several stable
188
- product locations. Missing or invalid Surface IDs become `default`; do not use URLs, branches,
189
- random instance IDs, or user IDs.
190
- Direct Tileflow World maps keep early `GRACE` silent, show a compact accessible owner-action pill
191
- when late `GRACE` is activated, and show a stronger banner in `MANAGED_REQUIRED`. Missing tiles and
192
- MapLibre failures do not remove that recovery path.
193
-
194
- ## Headless capture readiness
195
-
196
- Pass `capture-id` when a page contains multiple copies of the same named map:
143
+ Annotations require a stable `id`, singular `coordinate`, and non-empty `ariaLabel`; optional data
144
+ must be JSON-safe. `marker` receives annotation-only context. `tooltip` and `popup` receive the
145
+ shared interaction context; narrow `target.kind` before reading annotation or semantic feature data.
197
146
 
198
- ```vue
199
- <TileflowMap :source="{kind: 'tileflow', map: 'madrid'}" capture-id="checkout-map" />
200
- ```
147
+ Use `interactions` with `target: {kind: 'semantic-feature', domain: 'poi'}` for POIs already rendered
148
+ by the style. Categories use Tileflow's taxonomy, such as `food-drink` or `retail`, not raw source
149
+ classes. Semantic bindings require compatible metadata in the active style and avoid creating one
150
+ DOM marker per feature.
151
+
152
+ Omit controlled state and use `default-interaction-state` for uncontrolled ownership. Do not supply
153
+ both or change ownership during a component's lifetime. Annotations, bindings, slots, and callbacks
154
+ reconcile without recreating MapLibre. Text/field descriptors render as text; `view` dispatches to
155
+ an application slot and never evaluates HTML. Tooltips must remain non-interactive; use a popup for
156
+ links, buttons, or forms.
157
+
158
+ ## Display an existing image
159
+
160
+ `mode="image"` renders an explicit `imageUrl` or a published manifest image without loading MapLibre.
161
+ A local style build does not generate an image. This mode does not create or poll a static render;
162
+ use the server-side [Static Maps client](https://github.com/tileflow/tileflow-sdk/blob/main/packages/static/README.md)
163
+ for that operation and keep privileged keys on the server.
164
+
165
+ Do not pass annotations, semantic bindings, state, or interaction slots to image mode. Unsupported
166
+ interaction input reports `UNSUPPORTED_MODE` and capture readiness `error`; it does not silently
167
+ pretend the image contains live overlays.
168
+
169
+ ## Capture, authorization, and troubleshooting
201
170
 
202
- The root exposes `data-tileflow-map`, optional `data-tileflow-capture-id`, and
203
- `data-tileflow-state="loading|idle|error"`. It becomes idle only after MapLibre idle plus two
204
- animation frames (or image decode/load in image mode). A change to custom tooltip/popup/marker
205
- render-target keys independently returns interaction readiness to loading until Vue commits the
206
- Teleports and two current animation frames pass. Map and interaction errors are combined;
207
- application capture selects exactly one ready target.
171
+ Pass `capture-id` when multiple components show the same map. The root exposes `data-tileflow-map`,
172
+ resolved `data-tileflow-theme`, optional `data-tileflow-capture-id`, and
173
+ `data-tileflow-state="loading|idle|error"`. Readiness includes MapLibre or image loading plus committed
174
+ Vue interaction views. Application capture needs exactly one ready target and the application's
175
+ normal loopback server.
208
176
 
209
- ## Compatibility
177
+ For a blank/error map, check that the manifest URL returns JSON, the map and theme exist, MapLibre
178
+ CSS is imported, and the matching worker/shared assets are served. Manifest 404s and unresolved
179
+ styles/images are errors; the component does not guess another URL.
210
180
 
211
- The supported peer window is Vue 3.3-3.x and MapLibre GL JS 6.4.1-6.x. Compatibility smoke tests
212
- install Vue 3.3.0 with the exact lower bound and selected current release from packed Tileflow
213
- tarballs, typecheck a consumer, and render the image/SSR path while rejecting any MapLibre import.
214
- Vue 4 stays outside the peer range until that matrix passes.
181
+ Hosted maps preflight a short-lived session grant. `:analytics="{enabled: false}"` disables only the
182
+ optional beacon, not authorization. Use a stable product `surfaceId` rather than a user ID or URL.
183
+ Direct World maps can show owner-action notices when managed delivery is required. Imports and the
184
+ image path remain SSR-safe; interactive rendering needs a browser with WebGL.
215
185
 
216
- Docs: https://tileflow.dev/docs
186
+ See the [interaction guide](https://github.com/tileflow/tileflow-sdk/blob/main/packages/interactions/README.md)
187
+ and [browser runtime contract](https://github.com/tileflow/tileflow-sdk/blob/main/docs/contracts/framework-browser-runtime.md).
188
+ Use the installed package's declarations and README for a release; `main` can include newer changes.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tileflow/vue",
3
- "version": "0.1.0-alpha.23",
3
+ "version": "0.1.0-alpha.24",
4
4
  "license": "Apache-2.0",
5
5
  "description": "Vue component for rendering Tileflow maps with MapLibre.",
6
6
  "type": "module",
@@ -38,8 +38,8 @@
38
38
  "access": "public"
39
39
  },
40
40
  "dependencies": {
41
- "@tileflow/core": ">=0.1.0-alpha.24 <0.1.0-beta.0",
42
- "@tileflow/interactions": ">=0.1.0-alpha.3 <0.1.0-beta.0"
41
+ "@tileflow/core": ">=0.1.0-alpha.25 <0.1.0-beta.0",
42
+ "@tileflow/interactions": ">=0.1.0-alpha.4 <0.1.0-beta.0"
43
43
  },
44
44
  "peerDependencies": {
45
45
  "maplibre-gl": ">=6.4.1 <7",