@tileflow/svelte 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 +132 -147
  2. package/package.json +3 -3
package/README.md CHANGED
@@ -1,211 +1,196 @@
1
1
  # @tileflow/svelte
2
2
 
3
- Svelte component for rendering Tileflow maps with MapLibre.
3
+ Svelte components for interactive Tileflow maps, annotations, and existing-image display.
4
+ The component consumes prepared assets; it does not compile executable map configuration 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).
6
8
 
7
- ```svelte
8
- <script lang="ts">
9
- import {TileflowMap} from '@tileflow/svelte';
10
- import 'maplibre-gl/dist/maplibre-gl.css';
11
- </script>
9
+ ## Install
12
10
 
13
- <TileflowMap
14
- source={{kind: 'tileflow', map: 'madrid'}}
15
- theme="system"
16
- center={[-3.7038, 40.4168]}
17
- zoom={12}
18
- mapOptions={{
19
- cooperativeGestures: true,
20
- maxZoom: 18,
21
- }}
22
- />
11
+ Use an existing Svelte 5 application. Supported peers are Svelte `>=5 <6` 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/svelte@alpha @tileflow/core@alpha @tileflow/maps@alpha "maplibre-gl@^6.4.1"
16
+ npm install --save-dev --save-exact tileflow@alpha
23
17
  ```
24
18
 
25
- ## MapLibre 6 worker
19
+ ## Prepare a map
26
20
 
27
- With MapLibre GL JS 6, configure the application-owned worker once before mounting an interactive
28
- map. The worker URL must come from the same `maplibre-gl` package installed by the application.
21
+ Create `tileflow.config.ts` at the application root:
22
+
23
+ <!-- docs:check -->
29
24
 
30
25
  ```ts
31
- // main.ts
32
- import workerUrl from 'maplibre-gl/dist/maplibre-gl-worker.mjs?worker&url';
33
- import {configureTileflowMapLibre} from '@tileflow/svelte';
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
+ ```
34
36
 
35
- configureTileflowMapLibre({workerUrl});
37
+ For a Vite application serving `public/` at the URL root:
38
+
39
+ ```sh
40
+ npx tileflow build --out public/tileflow
36
41
  ```
37
42
 
38
- This is the Vite setup. Run it before `mount(...)`; `mode="image"` remains MapLibre-free. MapLibre
39
- GL JS 6.4.1-6.x is supported. Use the `@tileflow/next` or `@tileflow/webpack` README for their
40
- worker-delivery recipes.
43
+ SvelteKit serves static files from `static/` by default; for that setup, build to `static/tileflow`
44
+ instead. Set the component's manifest URL to the final public URL when a base path changes it.
45
+ Rebuild after config/asset changes or use the
46
+ [Vite integration](https://github.com/tileflow/tileflow-sdk/blob/main/packages/vite/README.md)
47
+ for watched development and production output. Local preparation needs no API key; rendering can
48
+ still fetch configured remote resources.
49
+
50
+ ## Configure the worker
41
51
 
42
- `mapOptions` accepts native MapLibre options except `container` and `style`, which
43
- Tileflow resolves from `source`. Direct
44
- Tileflow props such as `center`, `zoom`, and `interactive` take priority when
45
- provided. Camera resolution is the same in interactive and image modes: direct props, then
46
- `mapOptions`, then the published manifest view, then Tileflow's shared runtime defaults.
52
+ In a Vite client entry, add the following before mounting the application:
53
+
54
+ ```ts
55
+ import workerUrl from 'maplibre-gl/dist/maplibre-gl-worker.mjs?worker&url';
56
+ import {configureTileflowMapLibre} from '@tileflow/svelte';
47
57
 
48
- Every map has exactly one discriminated `source`. Use `kind: 'tileflow'` with `map` and an optional
49
- `manifestUrl` for published delivery. `kind: 'maplibre'` is an unmanaged escape hatch for one direct
50
- style object or URL; it has no Tileflow theme identity, `system` selection, switching, or manifest
51
- traceability. Browser components do not compile `tileflow.config.ts`.
58
+ configureTileflowMapLibre({workerUrl});
59
+ ```
52
60
 
53
- Without `manifestUrl`, the exact default is `/tileflow/manifest.json`. If a bundler, framework base
54
- path, reverse proxy, or Tileflow plugin publishes it elsewhere, set the final public URL explicitly;
55
- the component does not guess it. Manifest 404s, unknown map IDs, unresolved styles, and unresolved
56
- image URLs enter `data-tileflow-state="error"`.
61
+ Configure once before an interactive map mounts. In SvelteKit, place client-only setup in the
62
+ application's client initialization path rather than running browser setup in a server load
63
+ function. The `?worker&url` syntax is Vite-specific. Webpack users need the
64
+ [Webpack worker recipe](https://github.com/tileflow/tileflow-sdk/blob/main/packages/webpack/README.md).
65
+ The worker and shared module must match the application's installed MapLibre version.
57
66
 
58
- `theme` selects a published theme name. Omission uses `defaultTheme`; `"system"` requires the map's
59
- explicit light/dark mapping. Switching preserves the MapLibre instance, camera, and interactions,
60
- and rolls back a failed style. `onThemeChange` receives transition state.
67
+ ## Render a map
61
68
 
62
69
  ```svelte
63
- <TileflowMap
64
- source={{
65
- kind: 'tileflow',
66
- map: 'madrid',
67
- manifestUrl: 'https://cdn.example.com/tileflow/manifest.json',
68
- }}
69
- />
70
+ <script lang="ts">
71
+ import 'maplibre-gl/dist/maplibre-gl.css';
72
+ import {TileflowMap} from '@tileflow/svelte';
73
+ </script>
70
74
 
71
75
  <TileflowMap
72
- source={{
73
- kind: 'maplibre',
74
- style: 'https://cdn.example.com/tileflow/styles/madrid/dark.json',
75
- }}
76
+ source={{kind: 'tileflow', map: 'madrid'}}
77
+ theme="system"
78
+ center={[-3.7038, 40.4168]}
79
+ zoom={12}
80
+ mapOptions={{cooperativeGestures: true, maxZoom: 18}}
76
81
  />
77
82
  ```
78
83
 
79
- `mode="image"` resolves an explicit or published image URL and renders an `<img>` without loading
80
- or evaluating MapLibre. All environments follow the same published manifest contract.
84
+ Coordinates are `[longitude, latitude]`. `source.map` matches the config's portable ID, not a hosted
85
+ `map_...` identifier. The default manifest URL is exactly `/tileflow/manifest.json`. Set
86
+ `source.manifestUrl` for a subpath or external host; the browser does not infer bundler configuration.
87
+
88
+ Omitting `theme` uses `defaultTheme`. `system` needs an explicit light/dark mapping, which Streets
89
+ supplies. Theme changes keep the MapLibre instance, camera, and interactions, and roll back on
90
+ failure. `onThemeChange` reports transitions.
81
91
 
82
- Hosted maps automatically preflight a short-lived commercial session grant before eligible
83
- resources. Setting `analytics={{enabled: false}}` disables the optional beacon only; it does not
84
- remove hosted authorization or override a user `mapOptions.transformRequest` callback.
85
- Use `analytics={{surfaceId: 'store-locator'}}` when the same Map is embedded in several stable
86
- product locations. Missing or invalid Surface IDs become `default`; do not use URLs, branches,
87
- random instance IDs, or user IDs.
88
- Direct Tileflow World maps keep early `GRACE` silent, show a compact accessible owner-action pill
89
- when late `GRACE` is activated, and show a stronger banner in `MANAGED_REQUIRED`. Missing tiles and
90
- MapLibre failures do not remove that recovery path.
92
+ `mapOptions` accepts native MapLibre options except `container` and `style`. Direct props win over
93
+ those options, then the manifest view, then shared defaults. An unmanaged source with
94
+ `{kind: 'maplibre', style: styleUrl}` loads one style without Tileflow themes or manifest identity;
95
+ do not pass a Tileflow theme with it.
91
96
 
92
- ## Annotations and overlays
97
+ ## Add annotations and native popup UI
93
98
 
94
- Use `annotations` for keyed markers with optional tooltips and popups. Tileflow supplies accessible,
95
- text-only defaults; Svelte snippets can replace any surface and are mounted into the DOM containers
96
- owned by the shared MapLibre interaction runtime.
99
+ Install the contract types used below:
100
+
101
+ ```sh
102
+ npm install @tileflow/interactions@alpha
103
+ ```
104
+
105
+ This Svelte 5 component uses the worker and CSS setup above:
97
106
 
98
107
  ```svelte
99
108
  <script lang="ts">
100
- import {TileflowMap} from '@tileflow/svelte';
101
109
  import type {
102
110
  TileflowAnnotation,
103
- TileflowInteractionBinding,
104
111
  TileflowInteractionState,
112
+ TileflowInteractionViewContext,
105
113
  } from '@tileflow/interactions';
114
+ import {TileflowMap} from '@tileflow/svelte';
106
115
 
107
- const annotations: TileflowAnnotation[] = [
116
+ const annotations = [
108
117
  {
109
- ariaLabel: 'Madrid',
110
- coordinate: [-3.7038, 40.4168],
111
118
  id: 'madrid',
112
119
  kind: 'marker',
113
- marker: {content: {kind: 'text', text: 'Madrid'}},
120
+ coordinate: [-3.7038, 40.4168],
121
+ ariaLabel: 'Madrid',
122
+ tooltip: {content: {kind: 'text', text: 'View Madrid'}},
114
123
  popup: {content: {kind: 'view', name: 'city-card'}},
115
- tooltip: {content: {kind: 'text', text: 'Open Madrid'}},
116
124
  },
117
- ];
125
+ ] satisfies readonly TileflowAnnotation[];
118
126
 
119
- const interactions: TileflowInteractionBinding[] = [
120
- {
121
- id: 'poi-details',
122
- popup: {content: {kind: 'view', name: 'poi-card'}},
123
- target: {categories: ['food-drink'], domain: 'poi', kind: 'semantic-feature'},
124
- tooltip: {content: {field: 'name', fallback: 'Restaurant', kind: 'field'}},
125
- },
126
- ];
127
-
128
- let interactionState: TileflowInteractionState = {popup: null};
127
+ let state = $state<TileflowInteractionState>({popup: null});
129
128
  </script>
130
129
 
131
- {#snippet marker(context)}
132
- <span>{context.annotation.ariaLabel}</span>
133
- {/snippet}
134
-
135
- {#snippet tooltip(context)}
130
+ {#snippet popup(context: TileflowInteractionViewContext)}
136
131
  {#if context.target.kind === 'annotation'}
137
- <span>{context.target.annotation.ariaLabel}</span>
138
- {:else}
139
- <span>Point of interest</span>
140
- {/if}
141
- {/snippet}
142
-
143
- {#snippet popup(context)}
144
- <article>
145
- {#if context.target.kind === 'annotation'}
132
+ <article>
146
133
  <h2>{context.target.annotation.ariaLabel}</h2>
147
- {:else if context.target.kind === 'semantic-feature'}
148
- <h2>POI details</h2>
149
- {/if}
150
- <button type="button" onclick={context.close}>Close</button>
151
- </article>
134
+ <button type="button" onclick={context.close}>Close</button>
135
+ </article>
136
+ {/if}
152
137
  {/snippet}
153
138
 
154
139
  <TileflowMap
155
140
  source={{kind: 'tileflow', map: 'madrid'}}
156
141
  {annotations}
157
- {interactions}
158
- {interactionState}
159
- onInteractionStateChange={(next) => (interactionState = next)}
160
- onInteractionEvent={(event) => console.log(event.type)}
161
- onInteractionDiagnostic={(diagnostic) => console.error(diagnostic)}
162
- {marker}
163
- {tooltip}
142
+ interactionState={state}
143
+ onInteractionStateChange={(next) => (state = next)}
144
+ onInteractionDiagnostic={(diagnostic) => console.error(diagnostic.code)}
164
145
  {popup}
165
146
  />
166
147
  ```
167
148
 
168
- `annotations` is the only application-owned marker input. Controlled `interactionState` and
169
- uncontrolled `defaultInteractionState` are mutually exclusive. `interactions` binds tooltips and
170
- popups to semantic POIs exposed by the compiled style metadata; applications select the stable
171
- `poi` domain and optional categories rather than physical style-layer IDs.
149
+ Annotations need a stable `id`, singular `coordinate`, and non-empty `ariaLabel`; optional data must
150
+ be JSON-safe. `marker` receives annotation-only context. `tooltip` and `popup` receive the shared
151
+ interaction context; narrow `target.kind` before reading annotation or semantic feature data.
172
152
 
173
- Snippet callbacks are read at the time an interaction occurs, and adding or removing a snippet
174
- switches between custom and default rendering without recreating the map or its keyed markers.
175
- `marker` receives the annotation-only context. `tooltip` and `popup` receive the general interaction
176
- context and therefore handle both annotation and semantic-feature targets. Each context includes
177
- resolved content, the target, optional view name, and `close()`.
153
+ Use `interactions` with `target: {kind: 'semantic-feature', domain: 'poi'}` for POIs already rendered
154
+ by the style. Optional categories use Tileflow's taxonomy, such as `food-drink` or `retail`, not raw
155
+ source classes. Semantic bindings require compatible style metadata and avoid one DOM marker per
156
+ feature. Annotation and semantic overlays share one popup state.
178
157
 
179
- Both runtimes are controlled by one interaction-state coordinator. Replacing an annotation popup
180
- with a POI popup (or the reverse) closes the previous owner before opening the next one, so event
181
- order remains `popup:close` followed by `popup:open`.
158
+ Controlled `interactionState` and uncontrolled `defaultInteractionState` are mutually exclusive.
159
+ Do not change ownership during the component's lifetime. Updating annotations, bindings, state, or
160
+ snippets reconciles existing runtimes rather than recreating MapLibre.
182
161
 
183
- Annotations and semantic interactions are interactive-only. The TypeScript API excludes
184
- annotations, interactions, interaction state, snippets, and interaction callbacks from the
185
- `mode="image"` branch. Untyped JavaScript that supplies them still receives an
186
- `UNSUPPORTED_MODE` diagnostic and capture readiness `error`, rather than pretending the static image
187
- contains live overlays.
162
+ Text/field descriptors render as text. A `view` names an application snippet; it is not serialized
163
+ HTML. Keep tooltips non-interactive and put buttons, links, and forms in popups.
188
164
 
189
- ## Headless capture readiness
165
+ ## Display an existing image
190
166
 
191
- Use `captureId` to disambiguate repeated named maps:
167
+ `mode="image"` displays an explicit `imageUrl` or a published manifest image without loading
168
+ MapLibre. A local style build does not generate that image. This mode does not submit or poll a
169
+ Static Maps operation; use the server-side
170
+ [Static Maps client](https://github.com/tileflow/tileflow-sdk/blob/main/packages/static/README.md)
171
+ for new renders, keeping privileged credentials off the browser.
192
172
 
193
- ```svelte
194
- <TileflowMap source={{kind: 'tileflow', map: 'madrid'}} captureId="checkout-map" />
195
- ```
173
+ Annotations, semantic bindings, interaction state, and interaction snippets are interactive-only.
174
+ Untyped callers that pass them to image mode receive `UNSUPPORTED_MODE` and capture readiness
175
+ `error`, not simulated live overlays.
176
+
177
+ ## Capture, authorization, and troubleshooting
196
178
 
197
- The root exposes `data-tileflow-map`, optional `data-tileflow-capture-id`, and
198
- `data-tileflow-state="loading|idle|error"`. It becomes idle only after MapLibre idle plus two
199
- animation frames and, for custom interaction snippets, the Svelte DOM commit plus two current
200
- animation frames. It returns to loading when either surface changes and marks map or interaction
201
- errors. In image mode, readiness follows image decode/load when no interaction configuration is
202
- present. Application capture selects exactly one ready target.
179
+ Use `captureId` to disambiguate repeated maps. The root exposes `data-tileflow-map`, resolved
180
+ `data-tileflow-theme`, optional `data-tileflow-capture-id`, and
181
+ `data-tileflow-state="loading|idle|error"`. Readiness includes MapLibre/image loading and committed
182
+ Svelte interaction views. Application capture needs exactly one ready target and the application's
183
+ normal loopback server.
203
184
 
204
- ## Compatibility
185
+ For an error or blank map, check the manifest URL, map/theme IDs, imported CSS, and matching
186
+ worker/shared assets. The component does not guess a new manifest location after a 404.
205
187
 
206
- The supported peer window is Svelte 5.x and MapLibre GL JS 6.4.1-6.x. Compatibility smoke tests
207
- install Svelte 5.0.0 with the exact lower bound and selected current release from packed Tileflow
208
- tarballs, typecheck the public declarations, and compile real Svelte consumers. Future Svelte majors
209
- stay outside the peer range until that matrix passes.
188
+ Hosted maps acquire a short-lived session grant before eligible resource requests.
189
+ `analytics={{enabled: false}}` disables the optional beacon, not authorization. Use a stable product
190
+ `surfaceId`, not a URL or user identifier. Direct World maps can show owner-action notices when
191
+ managed delivery is required. Imports and the image path remain SSR-safe; interactive rendering
192
+ requires a browser with WebGL.
210
193
 
211
- Docs: https://tileflow.dev/docs
194
+ See the [interaction guide](https://github.com/tileflow/tileflow-sdk/blob/main/packages/interactions/README.md)
195
+ and [browser runtime contract](https://github.com/tileflow/tileflow-sdk/blob/main/docs/contracts/framework-browser-runtime.md).
196
+ Use the installed declarations and README for release-specific behavior; `main` may be newer than npm.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tileflow/svelte",
3
- "version": "0.1.0-alpha.23",
3
+ "version": "0.1.0-alpha.24",
4
4
  "license": "Apache-2.0",
5
5
  "description": "Svelte component for rendering Tileflow maps with MapLibre.",
6
6
  "type": "module",
@@ -44,8 +44,8 @@
44
44
  "access": "public"
45
45
  },
46
46
  "dependencies": {
47
- "@tileflow/core": ">=0.1.0-alpha.24 <0.1.0-beta.0",
48
- "@tileflow/interactions": ">=0.1.0-alpha.3 <0.1.0-beta.0"
47
+ "@tileflow/core": ">=0.1.0-alpha.25 <0.1.0-beta.0",
48
+ "@tileflow/interactions": ">=0.1.0-alpha.4 <0.1.0-beta.0"
49
49
  },
50
50
  "peerDependencies": {
51
51
  "maplibre-gl": ">=6.4.1 <7",