@tileflow/svelte 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 +136 -148
- package/package.json +3 -3
- package/src/TileflowMap.svelte +9 -39
- package/src/style-source.js +0 -6
package/README.md
CHANGED
|
@@ -1,211 +1,199 @@
|
|
|
1
1
|
# @tileflow/svelte
|
|
2
2
|
|
|
3
|
-
Svelte
|
|
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
|
-
|
|
7
|
+
> Related packages and guides: [documentation index](https://raw.githubusercontent.com/tileflow/tileflow-sdk/main/llms.txt).
|
|
6
8
|
|
|
7
|
-
|
|
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
|
-
<
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
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
|
-
##
|
|
19
|
+
## Prepare a map
|
|
26
20
|
|
|
27
|
-
|
|
28
|
-
|
|
21
|
+
Create `tileflow.config.ts` at the application root:
|
|
22
|
+
|
|
23
|
+
<!-- docs:check -->
|
|
29
24
|
|
|
30
25
|
```ts
|
|
31
|
-
|
|
32
|
-
import
|
|
33
|
-
|
|
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
|
-
|
|
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
|
-
|
|
39
|
-
|
|
40
|
-
|
|
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
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
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
|
-
|
|
49
|
-
|
|
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
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
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
|
-
|
|
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
|
-
<
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
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
|
-
|
|
74
|
-
|
|
75
|
-
}
|
|
76
|
+
source={{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
|
-
|
|
80
|
-
|
|
84
|
+
Coordinates are `[longitude, latitude]`. `source` is one object, `{map, manifestUrl?}`.
|
|
85
|
+
`source.map` matches the config's portable ID, not a hosted `map_...` identifier. The default
|
|
86
|
+
manifest URL is exactly `/tileflow/manifest.json`. Set `source.manifestUrl` for a subpath or external
|
|
87
|
+
host; the browser does not infer bundler configuration.
|
|
88
|
+
|
|
89
|
+
Omitting `theme` uses `defaultTheme`. `system` needs an explicit light/dark mapping, which Streets
|
|
90
|
+
supplies. Theme changes keep the MapLibre instance, camera, and interactions, and roll back on
|
|
91
|
+
failure. `onThemeChange` reports transitions.
|
|
92
|
+
|
|
93
|
+
`mapOptions` accepts native MapLibre options except `container` and `style`. Direct props win over
|
|
94
|
+
those options, then the manifest view, then shared defaults. `TileflowMap` always selects a Tileflow
|
|
95
|
+
map through its manifest; it has no renderer discriminator or direct-style mode. The obsolete
|
|
96
|
+
source fields `kind` and `style` are rejected. For a completely unmanaged map, use `maplibre-gl`
|
|
97
|
+
directly rather than a Tileflow component.
|
|
81
98
|
|
|
82
|
-
|
|
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.
|
|
99
|
+
## Add annotations and native popup UI
|
|
91
100
|
|
|
92
|
-
|
|
101
|
+
Install the contract types used below:
|
|
93
102
|
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
103
|
+
```sh
|
|
104
|
+
npm install @tileflow/interactions@alpha
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
This Svelte 5 component uses the worker and CSS setup above:
|
|
97
108
|
|
|
98
109
|
```svelte
|
|
99
110
|
<script lang="ts">
|
|
100
|
-
import {TileflowMap} from '@tileflow/svelte';
|
|
101
111
|
import type {
|
|
102
112
|
TileflowAnnotation,
|
|
103
|
-
TileflowInteractionBinding,
|
|
104
113
|
TileflowInteractionState,
|
|
114
|
+
TileflowInteractionViewContext,
|
|
105
115
|
} from '@tileflow/interactions';
|
|
116
|
+
import {TileflowMap} from '@tileflow/svelte';
|
|
106
117
|
|
|
107
|
-
const annotations
|
|
118
|
+
const annotations = [
|
|
108
119
|
{
|
|
109
|
-
ariaLabel: 'Madrid',
|
|
110
|
-
coordinate: [-3.7038, 40.4168],
|
|
111
120
|
id: 'madrid',
|
|
112
121
|
kind: 'marker',
|
|
113
|
-
|
|
122
|
+
coordinate: [-3.7038, 40.4168],
|
|
123
|
+
ariaLabel: 'Madrid',
|
|
124
|
+
tooltip: {content: {kind: 'text', text: 'View Madrid'}},
|
|
114
125
|
popup: {content: {kind: 'view', name: 'city-card'}},
|
|
115
|
-
tooltip: {content: {kind: 'text', text: 'Open Madrid'}},
|
|
116
|
-
},
|
|
117
|
-
];
|
|
118
|
-
|
|
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
|
},
|
|
126
|
-
];
|
|
127
|
+
] satisfies readonly TileflowAnnotation[];
|
|
127
128
|
|
|
128
|
-
let
|
|
129
|
+
let state = $state<TileflowInteractionState>({popup: null});
|
|
129
130
|
</script>
|
|
130
131
|
|
|
131
|
-
{#snippet
|
|
132
|
-
<span>{context.annotation.ariaLabel}</span>
|
|
133
|
-
{/snippet}
|
|
134
|
-
|
|
135
|
-
{#snippet tooltip(context)}
|
|
132
|
+
{#snippet popup(context: TileflowInteractionViewContext)}
|
|
136
133
|
{#if context.target.kind === 'annotation'}
|
|
137
|
-
<
|
|
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'}
|
|
134
|
+
<article>
|
|
146
135
|
<h2>{context.target.annotation.ariaLabel}</h2>
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
<button type="button" onclick={context.close}>Close</button>
|
|
151
|
-
</article>
|
|
136
|
+
<button type="button" onclick={context.close}>Close</button>
|
|
137
|
+
</article>
|
|
138
|
+
{/if}
|
|
152
139
|
{/snippet}
|
|
153
140
|
|
|
154
141
|
<TileflowMap
|
|
155
|
-
source={{
|
|
142
|
+
source={{map: 'madrid'}}
|
|
156
143
|
{annotations}
|
|
157
|
-
{
|
|
158
|
-
{
|
|
159
|
-
|
|
160
|
-
onInteractionEvent={(event) => console.log(event.type)}
|
|
161
|
-
onInteractionDiagnostic={(diagnostic) => console.error(diagnostic)}
|
|
162
|
-
{marker}
|
|
163
|
-
{tooltip}
|
|
144
|
+
interactionState={state}
|
|
145
|
+
onInteractionStateChange={(next) => (state = next)}
|
|
146
|
+
onInteractionDiagnostic={(diagnostic) => console.error(diagnostic.code)}
|
|
164
147
|
{popup}
|
|
165
148
|
/>
|
|
166
149
|
```
|
|
167
150
|
|
|
168
|
-
`
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
`poi` domain and optional categories rather than physical style-layer IDs.
|
|
151
|
+
Annotations need a stable `id`, singular `coordinate`, and non-empty `ariaLabel`; optional data must
|
|
152
|
+
be JSON-safe. `marker` receives annotation-only context. `tooltip` and `popup` receive the shared
|
|
153
|
+
interaction context; narrow `target.kind` before reading annotation or semantic feature data.
|
|
172
154
|
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
resolved content, the target, optional view name, and `close()`.
|
|
155
|
+
Use `interactions` with `target: {kind: 'semantic-feature', domain: 'poi'}` for POIs already rendered
|
|
156
|
+
by the style. Optional categories use Tileflow's taxonomy, such as `food-drink` or `retail`, not raw
|
|
157
|
+
source classes. Semantic bindings require compatible style metadata and avoid one DOM marker per
|
|
158
|
+
feature. Annotation and semantic overlays share one popup state.
|
|
178
159
|
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
160
|
+
Controlled `interactionState` and uncontrolled `defaultInteractionState` are mutually exclusive.
|
|
161
|
+
Do not change ownership during the component's lifetime. Updating annotations, bindings, state, or
|
|
162
|
+
snippets reconciles existing runtimes rather than recreating MapLibre.
|
|
182
163
|
|
|
183
|
-
|
|
184
|
-
|
|
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.
|
|
164
|
+
Text/field descriptors render as text. A `view` names an application snippet; it is not serialized
|
|
165
|
+
HTML. Keep tooltips non-interactive and put buttons, links, and forms in popups.
|
|
188
166
|
|
|
189
|
-
##
|
|
167
|
+
## Display an existing image
|
|
190
168
|
|
|
191
|
-
|
|
169
|
+
`mode="image"` displays an explicit `imageUrl` or derives an image URL from the selected manifest
|
|
170
|
+
map's `mapId`, `apiUrl`, concrete theme and view, without loading MapLibre. It still requires a valid
|
|
171
|
+
Tileflow source. A local style build does not generate that image. This mode does not submit or poll
|
|
172
|
+
a Static Maps operation; use the server-side
|
|
173
|
+
[Static Maps client](https://github.com/tileflow/tileflow-sdk/blob/main/packages/static/README.md)
|
|
174
|
+
for new renders, keeping privileged credentials off the browser.
|
|
192
175
|
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
176
|
+
Annotations, semantic bindings, interaction state, and interaction snippets are interactive-only.
|
|
177
|
+
Untyped callers that pass them to image mode receive `UNSUPPORTED_MODE` and capture readiness
|
|
178
|
+
`error`, not simulated live overlays.
|
|
179
|
+
|
|
180
|
+
## Capture, authorization, and troubleshooting
|
|
196
181
|
|
|
197
|
-
The root exposes `data-tileflow-map`,
|
|
198
|
-
`data-tileflow-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
present. Application capture selects exactly one ready target.
|
|
182
|
+
Use `captureId` to disambiguate repeated maps. The root exposes `data-tileflow-map`, resolved
|
|
183
|
+
`data-tileflow-theme`, optional `data-tileflow-capture-id`, and
|
|
184
|
+
`data-tileflow-state="loading|idle|error"`. Readiness includes MapLibre/image loading and committed
|
|
185
|
+
Svelte interaction views. Application capture needs exactly one ready target and the application's
|
|
186
|
+
normal loopback server.
|
|
203
187
|
|
|
204
|
-
|
|
188
|
+
For an error or blank map, check the manifest URL, map/theme IDs, imported CSS, and matching
|
|
189
|
+
worker/shared assets. The component does not guess a new manifest location after a 404.
|
|
205
190
|
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
191
|
+
Hosted maps acquire a short-lived session grant before eligible resource requests.
|
|
192
|
+
`analytics={{enabled: false}}` disables the optional beacon, not authorization. Use a stable product
|
|
193
|
+
`surfaceId`, not a URL or user identifier. Direct World maps can show owner-action notices when
|
|
194
|
+
managed delivery is required. Imports and the image path remain SSR-safe; interactive rendering
|
|
195
|
+
requires a browser with WebGL.
|
|
210
196
|
|
|
211
|
-
|
|
197
|
+
See the [interaction guide](https://github.com/tileflow/tileflow-sdk/blob/main/packages/interactions/README.md)
|
|
198
|
+
and [browser runtime contract](https://github.com/tileflow/tileflow-sdk/blob/main/docs/contracts/framework-browser-runtime.md).
|
|
199
|
+
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.
|
|
3
|
+
"version": "0.1.0-alpha.25",
|
|
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.
|
|
48
|
-
"@tileflow/interactions": ">=0.1.0-alpha.
|
|
47
|
+
"@tileflow/core": ">=0.1.0-alpha.27 <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",
|
package/src/TileflowMap.svelte
CHANGED
|
@@ -23,7 +23,6 @@
|
|
|
23
23
|
resolveTileflowRuntimeTheme,
|
|
24
24
|
resolveTileflowRuntimeView,
|
|
25
25
|
resolveTileflowStaticImageUrl,
|
|
26
|
-
shouldLoadTileflowManifest,
|
|
27
26
|
type TileflowRuntimeManifestMap,
|
|
28
27
|
} from '@tileflow/core/runtime';
|
|
29
28
|
import {
|
|
@@ -144,7 +143,7 @@
|
|
|
144
143
|
let manifestMap: TileflowRuntimeManifestMap | null = null;
|
|
145
144
|
let manifestLoadId = 0;
|
|
146
145
|
let manifestResolutionKey = '';
|
|
147
|
-
let manifestResolutionState: 'error' | 'loading' | '
|
|
146
|
+
let manifestResolutionState: 'error' | 'loading' | 'ready' = 'loading';
|
|
148
147
|
let mapLoadId = 0;
|
|
149
148
|
let mounted = false;
|
|
150
149
|
let refreshRunId = 0;
|
|
@@ -170,23 +169,11 @@
|
|
|
170
169
|
$: assertTileflowMapStyleInputs({source, theme});
|
|
171
170
|
$: resolvedCaptureId = normalizeTileflowCaptureId(captureId);
|
|
172
171
|
$: isImageMode = resolvedMode === 'image';
|
|
173
|
-
$: mapName = source
|
|
174
|
-
$: manifestUrl =
|
|
175
|
-
|
|
176
|
-
? (source.manifestUrl ?? defaultTileflowManifestUrl)
|
|
177
|
-
: defaultTileflowManifestUrl;
|
|
178
|
-
$: shouldLoadManifest = shouldLoadTileflowManifest({
|
|
179
|
-
source,
|
|
180
|
-
});
|
|
181
|
-
$: manifestRequestKey = shouldLoadManifest
|
|
182
|
-
? JSON.stringify([manifestUrl, mapName])
|
|
183
|
-
: 'not-needed';
|
|
172
|
+
$: mapName = source.map;
|
|
173
|
+
$: manifestUrl = source.manifestUrl ?? defaultTileflowManifestUrl;
|
|
174
|
+
$: manifestRequestKey = JSON.stringify([manifestUrl, mapName]);
|
|
184
175
|
$: currentManifestResolutionState =
|
|
185
|
-
manifestResolutionKey === manifestRequestKey
|
|
186
|
-
? manifestResolutionState
|
|
187
|
-
: shouldLoadManifest
|
|
188
|
-
? 'loading'
|
|
189
|
-
: 'not-needed';
|
|
176
|
+
manifestResolutionKey === manifestRequestKey ? manifestResolutionState : 'loading';
|
|
190
177
|
$: manifestMap =
|
|
191
178
|
manifestResolutionKey === manifestRequestKey && manifestResolutionState === 'ready'
|
|
192
179
|
? loadedManifestMap
|
|
@@ -194,7 +181,6 @@
|
|
|
194
181
|
$: themeResolution = resolveThemeSelection({
|
|
195
182
|
colorScheme: systemColorScheme,
|
|
196
183
|
manifestMap,
|
|
197
|
-
source,
|
|
198
184
|
theme,
|
|
199
185
|
});
|
|
200
186
|
$: resolvedThemeName = themeResolution.name;
|
|
@@ -237,7 +223,6 @@
|
|
|
237
223
|
isImageMode,
|
|
238
224
|
runtimeImageUrl,
|
|
239
225
|
runtimeStyle,
|
|
240
|
-
shouldLoadManifest,
|
|
241
226
|
themeResolutionError: themeResolution.error,
|
|
242
227
|
});
|
|
243
228
|
$: currentMapCaptureState =
|
|
@@ -384,17 +369,7 @@
|
|
|
384
369
|
}
|
|
385
370
|
|
|
386
371
|
async function refreshManifest() {
|
|
387
|
-
const shouldLoad = shouldLoadManifest;
|
|
388
372
|
const requestKey = manifestRequestKey;
|
|
389
|
-
|
|
390
|
-
if (!shouldLoad) {
|
|
391
|
-
manifestLoadId += 1;
|
|
392
|
-
loadedManifestMap = null;
|
|
393
|
-
manifestResolutionKey = requestKey;
|
|
394
|
-
manifestResolutionState = 'not-needed';
|
|
395
|
-
return;
|
|
396
|
-
}
|
|
397
|
-
|
|
398
373
|
const loadId = ++manifestLoadId;
|
|
399
374
|
loadedManifestMap = null;
|
|
400
375
|
manifestResolutionKey = requestKey;
|
|
@@ -1228,16 +1203,12 @@
|
|
|
1228
1203
|
function resolveThemeSelection(input: {
|
|
1229
1204
|
colorScheme: 'dark' | 'light';
|
|
1230
1205
|
manifestMap: TileflowRuntimeManifestMap | null;
|
|
1231
|
-
source: TileflowMapProps['source'];
|
|
1232
1206
|
theme: TileflowMapProps['theme'];
|
|
1233
1207
|
}): Readonly<{error: boolean; name: string | undefined}> {
|
|
1234
|
-
if (!input.manifestMap
|
|
1208
|
+
if (!input.manifestMap) {
|
|
1235
1209
|
return {
|
|
1236
1210
|
error: false,
|
|
1237
|
-
name:
|
|
1238
|
-
input.source.kind === 'tileflow' && input.theme && input.theme !== 'system'
|
|
1239
|
-
? input.theme
|
|
1240
|
-
: undefined,
|
|
1211
|
+
name: input.theme && input.theme !== 'system' ? input.theme : undefined,
|
|
1241
1212
|
};
|
|
1242
1213
|
}
|
|
1243
1214
|
|
|
@@ -1252,16 +1223,15 @@
|
|
|
1252
1223
|
}
|
|
1253
1224
|
|
|
1254
1225
|
function resolveRuntimeResolutionState(input: {
|
|
1255
|
-
currentManifestResolutionState: 'error' | 'loading' | '
|
|
1226
|
+
currentManifestResolutionState: 'error' | 'loading' | 'ready';
|
|
1256
1227
|
imageSize: {height: number; width: number} | null;
|
|
1257
1228
|
imageUrl: string | undefined;
|
|
1258
1229
|
isImageMode: boolean;
|
|
1259
1230
|
runtimeImageUrl: string | undefined;
|
|
1260
1231
|
runtimeStyle: ReturnType<typeof resolveTileflowRuntimeStyle>;
|
|
1261
|
-
shouldLoadManifest: boolean;
|
|
1262
1232
|
themeResolutionError: boolean;
|
|
1263
1233
|
}): 'error' | 'idle' | 'loading' {
|
|
1264
|
-
if (input.
|
|
1234
|
+
if (input.currentManifestResolutionState !== 'ready') {
|
|
1265
1235
|
return input.currentManifestResolutionState === 'error' ? 'error' : 'loading';
|
|
1266
1236
|
}
|
|
1267
1237
|
if (input.themeResolutionError) return 'error';
|
package/src/style-source.js
CHANGED
|
@@ -16,12 +16,6 @@ export function validateTileflowMapStyleInputs(input) {
|
|
|
16
16
|
if (input.theme !== undefined && !validateTileflowThemeSelection(input.theme)) {
|
|
17
17
|
return {error: 'theme must be a concrete portable theme name or "system"', ok: false};
|
|
18
18
|
}
|
|
19
|
-
if (
|
|
20
|
-
input.theme !== undefined &&
|
|
21
|
-
/** @type {{kind?: unknown}} */ (input.source).kind !== 'tileflow'
|
|
22
|
-
) {
|
|
23
|
-
return {error: 'theme is only valid with a tileflow source', ok: false};
|
|
24
|
-
}
|
|
25
19
|
return {ok: true};
|
|
26
20
|
}
|
|
27
21
|
|