@tileflow/vue 0.1.0-alpha.26 → 0.1.0-alpha.27
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 +6 -0
- package/dist/index.d.ts +9 -2
- package/dist/index.js +76 -7
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -88,6 +88,12 @@ Omitting `theme` uses `defaultTheme`. `system` needs the map's explicit light/da
|
|
|
88
88
|
Streets supplies. Switching themes preserves the map, camera, and interactions, with rollback on
|
|
89
89
|
failure. Listen to `themeChange` for transitions.
|
|
90
90
|
|
|
91
|
+
`:theme-transition="{duration: 450}"` cross-fades theme changes over that many milliseconds.
|
|
92
|
+
`:theme-blend="{themes: ['night', 'dusk', 'day'], position}"` shows a continuous blend of the
|
|
93
|
+
map's themes instead of `theme`: position 0 is the first theme and 1.5 is halfway from the second to
|
|
94
|
+
the third. Moving the position updates the map at once. See
|
|
95
|
+
[theme transitions and blends](https://github.com/tileflow/tileflow-sdk/blob/main/packages/core/docs/theme-transitions-and-blends.md).
|
|
96
|
+
|
|
91
97
|
`mapOptions` accepts native MapLibre options except `container` and `style`. Direct props take
|
|
92
98
|
priority over those options, then the published view, then shared defaults. `TileflowMap` always
|
|
93
99
|
selects a Tileflow map through its manifest; it has no renderer discriminator or direct-style mode.
|
package/dist/index.d.ts
CHANGED
|
@@ -1,12 +1,19 @@
|
|
|
1
1
|
import { MapOptions, Map } from 'maplibre-gl';
|
|
2
2
|
import { DefineComponent, VNodeChild } from 'vue';
|
|
3
|
-
import { TileflowThemeTransition } from '@tileflow/core/browser';
|
|
4
|
-
import { TileflowRuntimeSource, TileflowThemeSelection, TileflowAnalytics } from '@tileflow/core/runtime';
|
|
3
|
+
import { TileflowThemeTransitionOptions, TileflowThemeTransition } from '@tileflow/core/browser';
|
|
4
|
+
import { TileflowRuntimeSource, TileflowThemeSelection, TileflowThemeBlendSelection, TileflowAnalytics } from '@tileflow/core/runtime';
|
|
5
5
|
import { TileflowAnnotation, TileflowInteractionJsonValue, TileflowInteractionState, TileflowInteractionBinding, TileflowInteractionDiagnostic, TileflowInteractionEvent, TileflowAnnotationViewContext, TileflowInteractionViewContext } from '@tileflow/interactions';
|
|
6
6
|
|
|
7
7
|
type TileflowMapStyleSourceProps = {
|
|
8
8
|
source: TileflowRuntimeSource;
|
|
9
9
|
theme?: TileflowThemeSelection;
|
|
10
|
+
/**
|
|
11
|
+
* Shows a continuous blend of the map's themes instead of `theme`. Moving `position` changes the
|
|
12
|
+
* map at once; changing `themes` prepares a new blend.
|
|
13
|
+
*/
|
|
14
|
+
themeBlend?: TileflowThemeBlendSelection;
|
|
15
|
+
/** Cross-fades theme changes, including entering and leaving a blend. */
|
|
16
|
+
themeTransition?: TileflowThemeTransitionOptions;
|
|
10
17
|
};
|
|
11
18
|
|
|
12
19
|
type TileflowMapLibreConfiguration = Readonly<{
|
package/dist/index.js
CHANGED
|
@@ -34,12 +34,14 @@ import {
|
|
|
34
34
|
defaultTileflowRuntimeView,
|
|
35
35
|
loadTileflowManifest,
|
|
36
36
|
mergeTileflowAnalytics,
|
|
37
|
+
nearestTileflowBlendTheme,
|
|
37
38
|
normalizeTileflowRuntimeCenter,
|
|
38
39
|
normalizeTileflowStaticImageSize,
|
|
39
40
|
resolveTileflowManifestMap,
|
|
40
41
|
resolveTileflowMapMode,
|
|
41
42
|
resolveTileflowRuntimeStyle,
|
|
42
43
|
resolveTileflowRuntimeTheme,
|
|
44
|
+
resolveTileflowRuntimeThemeBlend,
|
|
43
45
|
resolveTileflowRuntimeView,
|
|
44
46
|
resolveTileflowStaticImageUrl
|
|
45
47
|
} from "@tileflow/core/runtime";
|
|
@@ -159,6 +161,7 @@ function configureTileflowMapLibreModule(maplibregl) {
|
|
|
159
161
|
// src/style-source.ts
|
|
160
162
|
import {
|
|
161
163
|
validateTileflowRuntimeSource,
|
|
164
|
+
validateTileflowThemeBlendSelection,
|
|
162
165
|
validateTileflowThemeSelection
|
|
163
166
|
} from "@tileflow/core/runtime";
|
|
164
167
|
function validateTileflowMapStyleInputs(input) {
|
|
@@ -167,8 +170,25 @@ function validateTileflowMapStyleInputs(input) {
|
|
|
167
170
|
if (input.theme !== void 0 && !validateTileflowThemeSelection(input.theme)) {
|
|
168
171
|
return { error: 'theme must be a concrete portable theme name or "system"', ok: false };
|
|
169
172
|
}
|
|
173
|
+
if (input.themeBlend !== void 0 && !validateTileflowThemeBlendSelection(input.themeBlend)) {
|
|
174
|
+
return {
|
|
175
|
+
error: "themeBlend must name two to eight concrete themes and a position from 0 to themes.length - 1",
|
|
176
|
+
ok: false
|
|
177
|
+
};
|
|
178
|
+
}
|
|
179
|
+
if (input.themeTransition !== void 0 && !isThemeTransition(input.themeTransition)) {
|
|
180
|
+
return {
|
|
181
|
+
error: "themeTransition.duration must be a number of milliseconds from 0 to 5000",
|
|
182
|
+
ok: false
|
|
183
|
+
};
|
|
184
|
+
}
|
|
170
185
|
return { ok: true };
|
|
171
186
|
}
|
|
187
|
+
function isThemeTransition(value) {
|
|
188
|
+
if (!value || typeof value !== "object") return false;
|
|
189
|
+
const { duration } = value;
|
|
190
|
+
return duration === void 0 || typeof duration === "number" && Number.isFinite(duration) && duration >= 0 && duration <= 5e3;
|
|
191
|
+
}
|
|
172
192
|
function assertTileflowMapStyleInputs(input) {
|
|
173
193
|
const validation = validateTileflowMapStyleInputs(input);
|
|
174
194
|
if (!validation.ok) {
|
|
@@ -217,6 +237,8 @@ var TileflowMap = defineComponent({
|
|
|
217
237
|
type: Object
|
|
218
238
|
},
|
|
219
239
|
theme: String,
|
|
240
|
+
themeBlend: Object,
|
|
241
|
+
themeTransition: Object,
|
|
220
242
|
zoom: Number
|
|
221
243
|
},
|
|
222
244
|
emits: {
|
|
@@ -336,17 +358,24 @@ var TileflowMap = defineComponent({
|
|
|
336
358
|
const manifestMap = computed(
|
|
337
359
|
() => manifestResolutionKey.value === manifestRequestKey.value && manifestResolutionState.value === "ready" ? loadedManifestMap.value : null
|
|
338
360
|
);
|
|
361
|
+
const themeBlendKey = computed(
|
|
362
|
+
() => props.themeBlend ? JSON.stringify(props.themeBlend.themes) : void 0
|
|
363
|
+
);
|
|
339
364
|
const themeResolution = computed(() => {
|
|
365
|
+
const selection = props.themeBlend ? nearestTileflowBlendTheme(props.themeBlend) : props.theme;
|
|
340
366
|
if (!manifestMap.value) {
|
|
341
367
|
return {
|
|
342
368
|
error: false,
|
|
343
|
-
name:
|
|
369
|
+
name: selection && selection !== "system" ? selection : void 0
|
|
344
370
|
};
|
|
345
371
|
}
|
|
346
372
|
try {
|
|
373
|
+
for (const name of props.themeBlend?.themes ?? []) {
|
|
374
|
+
resolveTileflowRuntimeTheme(manifestMap.value, name);
|
|
375
|
+
}
|
|
347
376
|
return {
|
|
348
377
|
error: false,
|
|
349
|
-
name: resolveTileflowRuntimeTheme(manifestMap.value,
|
|
378
|
+
name: resolveTileflowRuntimeTheme(manifestMap.value, selection, systemColorScheme.value).name
|
|
350
379
|
};
|
|
351
380
|
} catch {
|
|
352
381
|
return { error: true, name: void 0 };
|
|
@@ -387,6 +416,19 @@ var TileflowMap = defineComponent({
|
|
|
387
416
|
theme: themeResolution.value.name
|
|
388
417
|
})
|
|
389
418
|
);
|
|
419
|
+
const blendStyles = computed(() => {
|
|
420
|
+
const key = themeBlendKey.value;
|
|
421
|
+
if (isImageMode.value || !manifestMap.value || !key) return null;
|
|
422
|
+
try {
|
|
423
|
+
return resolveTileflowRuntimeThemeBlend({
|
|
424
|
+
blend: { position: 0, themes: JSON.parse(key) },
|
|
425
|
+
manifestMap: manifestMap.value,
|
|
426
|
+
source: props.source
|
|
427
|
+
});
|
|
428
|
+
} catch {
|
|
429
|
+
return null;
|
|
430
|
+
}
|
|
431
|
+
});
|
|
390
432
|
const resolvedAnalytics = computed(
|
|
391
433
|
() => mergeTileflowAnalytics(props.analytics, runtimeStyle.value?.analytics)
|
|
392
434
|
);
|
|
@@ -512,7 +554,12 @@ var TileflowMap = defineComponent({
|
|
|
512
554
|
]);
|
|
513
555
|
};
|
|
514
556
|
watchEffect(() => {
|
|
515
|
-
assertTileflowMapStyleInputs({
|
|
557
|
+
assertTileflowMapStyleInputs({
|
|
558
|
+
source: props.source,
|
|
559
|
+
theme: props.theme,
|
|
560
|
+
themeBlend: props.themeBlend,
|
|
561
|
+
themeTransition: props.themeTransition
|
|
562
|
+
});
|
|
516
563
|
});
|
|
517
564
|
watchEffect(() => {
|
|
518
565
|
const diagnostics = interactionInputDiagnostics.value;
|
|
@@ -879,13 +926,30 @@ var TileflowMap = defineComponent({
|
|
|
879
926
|
return () => subscription.unsubscribe();
|
|
880
927
|
}
|
|
881
928
|
});
|
|
882
|
-
if (themeController &&
|
|
929
|
+
if (themeController && blendStyles.value && props.themeBlend) {
|
|
930
|
+
switchBlend();
|
|
931
|
+
} else if (themeController && runtimeStyle.value && runtimeStyle.value !== runtime) {
|
|
883
932
|
activeRuntimeResource.value = runtimeStyle.value;
|
|
884
|
-
void themeController.setTheme(runtimeStyle.value);
|
|
933
|
+
void themeController.setTheme(runtimeStyle.value, { transition: props.themeTransition });
|
|
885
934
|
}
|
|
886
935
|
};
|
|
936
|
+
const switchBlend = () => {
|
|
937
|
+
const themes = blendStyles.value;
|
|
938
|
+
const position = props.themeBlend?.position;
|
|
939
|
+
if (!themeController || !themes || position === void 0) return;
|
|
940
|
+
if (runtimeStyle.value) activeRuntimeResource.value = runtimeStyle.value;
|
|
941
|
+
void themeController.setBlend({ position, themes }, { transition: props.themeTransition }).then((result) => {
|
|
942
|
+
if (result.status === "failed") {
|
|
943
|
+
console.error("Failed to blend the Tileflow map themes", result.error);
|
|
944
|
+
}
|
|
945
|
+
});
|
|
946
|
+
};
|
|
887
947
|
const switchTheme = () => {
|
|
888
948
|
if (!themeController) return;
|
|
949
|
+
if (props.themeBlend) {
|
|
950
|
+
if (runtimeStyle.value) activeRuntimeResource.value = runtimeStyle.value;
|
|
951
|
+
return;
|
|
952
|
+
}
|
|
889
953
|
if (themeResolution.value.error) {
|
|
890
954
|
void themeController.setTheme(themeController.getCurrent());
|
|
891
955
|
return;
|
|
@@ -893,7 +957,7 @@ var TileflowMap = defineComponent({
|
|
|
893
957
|
const next = runtimeStyle.value;
|
|
894
958
|
if (!next) return;
|
|
895
959
|
activeRuntimeResource.value = next;
|
|
896
|
-
void themeController.setTheme(next).then((result) => {
|
|
960
|
+
void themeController.setTheme(next, { transition: props.themeTransition }).then((result) => {
|
|
897
961
|
if (result.status === "failed") {
|
|
898
962
|
console.error("Failed to change the Tileflow map theme", result.error);
|
|
899
963
|
}
|
|
@@ -976,10 +1040,15 @@ var TileflowMap = defineComponent({
|
|
|
976
1040
|
() => syncSystemColorSchemeSubscription()
|
|
977
1041
|
);
|
|
978
1042
|
watch(
|
|
979
|
-
() => runtimeStyle.value,
|
|
1043
|
+
() => [runtimeStyle.value, themeBlendKey.value],
|
|
980
1044
|
() => switchTheme(),
|
|
981
1045
|
{ flush: "post" }
|
|
982
1046
|
);
|
|
1047
|
+
watch(
|
|
1048
|
+
() => [blendStyles.value, props.themeBlend?.position],
|
|
1049
|
+
() => switchBlend(),
|
|
1050
|
+
{ flush: "post" }
|
|
1051
|
+
);
|
|
983
1052
|
watch(
|
|
984
1053
|
() => [hasInteractionConfiguration.value, isImageMode.value, runtimeImageUrl.value],
|
|
985
1054
|
() => {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tileflow/vue",
|
|
3
|
-
"version": "0.1.0-alpha.
|
|
3
|
+
"version": "0.1.0-alpha.27",
|
|
4
4
|
"license": "Apache-2.0",
|
|
5
5
|
"description": "Vue component for rendering Tileflow maps with MapLibre.",
|
|
6
6
|
"type": "module",
|
|
@@ -38,7 +38,7 @@
|
|
|
38
38
|
"access": "public"
|
|
39
39
|
},
|
|
40
40
|
"dependencies": {
|
|
41
|
-
"@tileflow/core": ">=0.1.0-alpha.
|
|
41
|
+
"@tileflow/core": ">=0.1.0-alpha.30 <0.1.0-beta.0",
|
|
42
42
|
"@tileflow/interactions": ">=0.1.0-alpha.4 <0.1.0-beta.0"
|
|
43
43
|
},
|
|
44
44
|
"peerDependencies": {
|