@tileflow/react 0.1.0-alpha.27 → 0.1.0-alpha.28
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 +79 -9
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -99,6 +99,12 @@ for assets.
|
|
|
99
99
|
explicit light/dark mapping, which Streets supplies. Theme changes preserve the MapLibre instance,
|
|
100
100
|
camera, and interactions, and roll back on failure. `onThemeChange` reports transitions.
|
|
101
101
|
|
|
102
|
+
`themeTransition={{duration: 450}}` cross-fades theme changes over that many milliseconds.
|
|
103
|
+
`themeBlend={{themes: ['night', 'dusk', 'day'], position}}` shows a continuous blend of the map's
|
|
104
|
+
themes instead of `theme`: position 0 is the first theme and 1.5 is halfway from the second to the
|
|
105
|
+
third. Moving the position updates the map at once. See
|
|
106
|
+
[theme transitions and blends](https://github.com/tileflow/tileflow-sdk/blob/main/packages/core/docs/theme-transitions-and-blends.md).
|
|
107
|
+
|
|
102
108
|
`mapOptions` accepts native MapLibre options except `container` and `style`. Direct camera props
|
|
103
109
|
take priority over `mapOptions`, then the manifest view, then shared defaults. `Map` always selects
|
|
104
110
|
a Tileflow map through its manifest; it has no renderer discriminator or direct-style mode.
|
package/dist/index.d.ts
CHANGED
|
@@ -1,13 +1,20 @@
|
|
|
1
1
|
import * as react from 'react';
|
|
2
2
|
import { CSSProperties, ImgHTMLAttributes, ReactNode } from 'react';
|
|
3
3
|
import { MapOptions, Map as Map$1 } from 'maplibre-gl';
|
|
4
|
-
import { TileflowThemeTransition } from '@tileflow/core/browser';
|
|
5
|
-
import { TileflowRuntimeSource, TileflowThemeSelection, TileflowAnalytics } from '@tileflow/core/runtime';
|
|
4
|
+
import { TileflowThemeTransitionOptions, TileflowThemeTransition } from '@tileflow/core/browser';
|
|
5
|
+
import { TileflowRuntimeSource, TileflowThemeSelection, TileflowThemeBlendSelection, TileflowAnalytics } from '@tileflow/core/runtime';
|
|
6
6
|
import { TileflowAnnotation, TileflowInteractionState, TileflowAnnotationViewContext, TileflowInteractionBinding, TileflowInteractionViewContext, TileflowInteractionDiagnostic, TileflowInteractionEvent } from '@tileflow/interactions';
|
|
7
7
|
|
|
8
8
|
type TileflowMapStyleSourceProps = {
|
|
9
9
|
source: TileflowRuntimeSource;
|
|
10
10
|
theme?: TileflowThemeSelection;
|
|
11
|
+
/**
|
|
12
|
+
* Shows a continuous blend of the map's themes instead of `theme`. Moving `position` changes the
|
|
13
|
+
* map at once; changing `themes` prepares a new blend.
|
|
14
|
+
*/
|
|
15
|
+
themeBlend?: TileflowThemeBlendSelection;
|
|
16
|
+
/** Cross-fades theme changes, including entering and leaving a blend. */
|
|
17
|
+
themeTransition?: TileflowThemeTransitionOptions;
|
|
11
18
|
};
|
|
12
19
|
|
|
13
20
|
type TileflowMapSource = TileflowRuntimeSource;
|
package/dist/index.js
CHANGED
|
@@ -31,12 +31,14 @@ import {
|
|
|
31
31
|
defaultTileflowRuntimeView,
|
|
32
32
|
loadTileflowManifest,
|
|
33
33
|
mergeTileflowAnalytics,
|
|
34
|
+
nearestTileflowBlendTheme,
|
|
34
35
|
normalizeTileflowRuntimeCenter,
|
|
35
36
|
normalizeTileflowStaticImageSize,
|
|
36
37
|
resolveTileflowManifestMap,
|
|
37
38
|
resolveTileflowMapMode,
|
|
38
39
|
resolveTileflowRuntimeStyle,
|
|
39
40
|
resolveTileflowRuntimeTheme,
|
|
41
|
+
resolveTileflowRuntimeThemeBlend,
|
|
40
42
|
resolveTileflowRuntimeView,
|
|
41
43
|
resolveTileflowStaticImageUrl
|
|
42
44
|
} from "@tileflow/core/runtime";
|
|
@@ -167,6 +169,7 @@ function prepareTileflowReactInteractionState(interactionState, defaultInteracti
|
|
|
167
169
|
// src/map-style-inputs.ts
|
|
168
170
|
import {
|
|
169
171
|
validateTileflowRuntimeSource,
|
|
172
|
+
validateTileflowThemeBlendSelection,
|
|
170
173
|
validateTileflowThemeSelection
|
|
171
174
|
} from "@tileflow/core/runtime";
|
|
172
175
|
function validateTileflowMapStyleInputs(input) {
|
|
@@ -175,8 +178,25 @@ function validateTileflowMapStyleInputs(input) {
|
|
|
175
178
|
if (input.theme !== void 0 && !validateTileflowThemeSelection(input.theme)) {
|
|
176
179
|
return { error: 'theme must be a concrete portable theme name or "system"', ok: false };
|
|
177
180
|
}
|
|
181
|
+
if (input.themeBlend !== void 0 && !validateTileflowThemeBlendSelection(input.themeBlend)) {
|
|
182
|
+
return {
|
|
183
|
+
error: "themeBlend must name two to eight concrete themes and a position from 0 to themes.length - 1",
|
|
184
|
+
ok: false
|
|
185
|
+
};
|
|
186
|
+
}
|
|
187
|
+
if (input.themeTransition !== void 0 && !isThemeTransition(input.themeTransition)) {
|
|
188
|
+
return {
|
|
189
|
+
error: "themeTransition.duration must be a number of milliseconds from 0 to 5000",
|
|
190
|
+
ok: false
|
|
191
|
+
};
|
|
192
|
+
}
|
|
178
193
|
return { ok: true };
|
|
179
194
|
}
|
|
195
|
+
function isThemeTransition(value) {
|
|
196
|
+
if (!value || typeof value !== "object") return false;
|
|
197
|
+
const { duration } = value;
|
|
198
|
+
return duration === void 0 || typeof duration === "number" && Number.isFinite(duration) && duration >= 0 && duration <= 5e3;
|
|
199
|
+
}
|
|
180
200
|
function assertTileflowMapStyleInputs(input) {
|
|
181
201
|
const validation = validateTileflowMapStyleInputs(input);
|
|
182
202
|
if (!validation.ok) {
|
|
@@ -238,6 +258,8 @@ function Map2(props) {
|
|
|
238
258
|
mapOptions,
|
|
239
259
|
analytics,
|
|
240
260
|
theme,
|
|
261
|
+
themeBlend,
|
|
262
|
+
themeTransition,
|
|
241
263
|
interactionState,
|
|
242
264
|
interactions = defaultInteractions,
|
|
243
265
|
onInteractionDiagnostic,
|
|
@@ -326,19 +348,31 @@ function Map2(props) {
|
|
|
326
348
|
const manifestRequestKey = JSON.stringify([manifestUrl, mapName]);
|
|
327
349
|
const currentManifestResolution = manifestResolution.key === manifestRequestKey ? manifestResolution : { key: manifestRequestKey, map: null, state: "loading" };
|
|
328
350
|
const manifestMap = currentManifestResolution.state === "ready" ? currentManifestResolution.map : null;
|
|
351
|
+
const themeBlendKey = themeBlend ? JSON.stringify(themeBlend.themes) : void 0;
|
|
352
|
+
const themeBlendPosition = themeBlend?.position;
|
|
353
|
+
const blendThemeName = themeBlend ? nearestTileflowBlendTheme(themeBlend) : void 0;
|
|
329
354
|
const themeResolution = useMemo(() => {
|
|
355
|
+
const selection = blendThemeName ?? theme;
|
|
330
356
|
if (!manifestMap) {
|
|
331
|
-
return {
|
|
357
|
+
return {
|
|
358
|
+
error: false,
|
|
359
|
+
name: selection && selection !== "system" ? selection : void 0
|
|
360
|
+
};
|
|
332
361
|
}
|
|
333
362
|
try {
|
|
363
|
+
if (themeBlendKey) {
|
|
364
|
+
for (const name of JSON.parse(themeBlendKey)) {
|
|
365
|
+
resolveTileflowRuntimeTheme(manifestMap, name);
|
|
366
|
+
}
|
|
367
|
+
}
|
|
334
368
|
return {
|
|
335
369
|
error: false,
|
|
336
|
-
name: resolveTileflowRuntimeTheme(manifestMap,
|
|
370
|
+
name: resolveTileflowRuntimeTheme(manifestMap, selection, systemColorScheme).name
|
|
337
371
|
};
|
|
338
372
|
} catch {
|
|
339
373
|
return { error: true, name: void 0 };
|
|
340
374
|
}
|
|
341
|
-
}, [manifestMap, systemColorScheme, theme]);
|
|
375
|
+
}, [blendThemeName, manifestMap, systemColorScheme, theme, themeBlendKey]);
|
|
342
376
|
const resolvedThemeName = themeResolution.name;
|
|
343
377
|
const manifestView = resolveTileflowRuntimeView({ manifestMap });
|
|
344
378
|
const manifestCenter = useStableMapOptionValue(
|
|
@@ -477,6 +511,22 @@ function Map2(props) {
|
|
|
477
511
|
});
|
|
478
512
|
}, [isImageMode, manifestMap, runtimeSource, systemColorScheme, themeResolution]);
|
|
479
513
|
runtimeStyleRef.current = runtimeStyle;
|
|
514
|
+
const blendStyles = useMemo(() => {
|
|
515
|
+
if (isImageMode || !manifestMap || !themeBlendKey) return null;
|
|
516
|
+
try {
|
|
517
|
+
return resolveTileflowRuntimeThemeBlend({
|
|
518
|
+
blend: { position: 0, themes: JSON.parse(themeBlendKey) },
|
|
519
|
+
manifestMap,
|
|
520
|
+
source: runtimeSource
|
|
521
|
+
});
|
|
522
|
+
} catch {
|
|
523
|
+
return null;
|
|
524
|
+
}
|
|
525
|
+
}, [isImageMode, manifestMap, runtimeSource, themeBlendKey]);
|
|
526
|
+
const blendRequestRef = useRef(null);
|
|
527
|
+
blendRequestRef.current = blendStyles && themeBlendPosition !== void 0 ? { position: themeBlendPosition, themes: blendStyles } : null;
|
|
528
|
+
const themeTransitionRef = useRef(themeTransition);
|
|
529
|
+
themeTransitionRef.current = themeTransition;
|
|
480
530
|
const runtimeMapIdentity = `${manifestUrl}\0${runtimeSource.map}`;
|
|
481
531
|
const runtimeStyleReady = runtimeStyle !== null || themeResolution.error && mapRef.current !== null;
|
|
482
532
|
const resolvedAnalytics = useMemo(
|
|
@@ -919,9 +969,15 @@ function Map2(props) {
|
|
|
919
969
|
});
|
|
920
970
|
registerCleanup(() => lifecycle.dispose());
|
|
921
971
|
const latestRuntimeStyle = runtimeStyleRef.current;
|
|
922
|
-
|
|
972
|
+
const latestBlend = blendRequestRef.current;
|
|
973
|
+
if (themeController && latestBlend) {
|
|
974
|
+
if (latestRuntimeStyle) setActiveRuntimeResource(latestRuntimeStyle);
|
|
975
|
+
void themeController.setBlend(latestBlend, { transition: themeTransitionRef.current });
|
|
976
|
+
} else if (themeController && latestRuntimeStyle && latestRuntimeStyle !== initialRuntimeStyle) {
|
|
923
977
|
setActiveRuntimeResource(latestRuntimeStyle);
|
|
924
|
-
void themeController.setTheme(latestRuntimeStyle
|
|
978
|
+
void themeController.setTheme(latestRuntimeStyle, {
|
|
979
|
+
transition: themeTransitionRef.current
|
|
980
|
+
});
|
|
925
981
|
}
|
|
926
982
|
}).catch((error) => {
|
|
927
983
|
try {
|
|
@@ -942,19 +998,33 @@ function Map2(props) {
|
|
|
942
998
|
}, [resolvedInteractive, runtimeMapIdentity, runtimeStyleReady, stableMapOptions]);
|
|
943
999
|
useEffect(() => {
|
|
944
1000
|
const controller = themeControllerRef.current;
|
|
945
|
-
if (!controller) return;
|
|
1001
|
+
if (!controller || themeBlendKey) return;
|
|
946
1002
|
if (themeResolution.error) {
|
|
947
1003
|
void controller.setTheme(controller.getCurrent());
|
|
948
1004
|
return;
|
|
949
1005
|
}
|
|
950
|
-
if (!runtimeStyle || controller.getCurrent() === runtimeStyle)
|
|
1006
|
+
if (!runtimeStyle || controller.getCurrent() === runtimeStyle && !controller.getBlend())
|
|
1007
|
+
return;
|
|
951
1008
|
setActiveRuntimeResource(runtimeStyle);
|
|
952
|
-
void controller.setTheme(runtimeStyle).then((result) => {
|
|
1009
|
+
void controller.setTheme(runtimeStyle, { transition: themeTransitionRef.current }).then((result) => {
|
|
953
1010
|
if (result.status === "failed") {
|
|
954
1011
|
console.error("Failed to change the Tileflow map theme", result.error);
|
|
955
1012
|
}
|
|
956
1013
|
});
|
|
957
|
-
}, [runtimeStyle, themeResolution.error]);
|
|
1014
|
+
}, [runtimeStyle, themeBlendKey, themeResolution.error]);
|
|
1015
|
+
useEffect(() => {
|
|
1016
|
+
const controller = themeControllerRef.current;
|
|
1017
|
+
if (!controller || !blendStyles || themeBlendPosition === void 0) return;
|
|
1018
|
+
if (runtimeStyle) setActiveRuntimeResource(runtimeStyle);
|
|
1019
|
+
void controller.setBlend(
|
|
1020
|
+
{ position: themeBlendPosition, themes: blendStyles },
|
|
1021
|
+
{ transition: themeTransitionRef.current }
|
|
1022
|
+
).then((result) => {
|
|
1023
|
+
if (result.status === "failed") {
|
|
1024
|
+
console.error("Failed to blend the Tileflow map themes", result.error);
|
|
1025
|
+
}
|
|
1026
|
+
});
|
|
1027
|
+
}, [blendStyles, runtimeStyle, themeBlendPosition]);
|
|
958
1028
|
useLayoutEffect(() => {
|
|
959
1029
|
if (!isImageMode) return;
|
|
960
1030
|
readinessRunRef.current += 1;
|
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.28",
|
|
4
4
|
"license": "Apache-2.0",
|
|
5
5
|
"description": "React components for rendering Tileflow maps with MapLibre.",
|
|
6
6
|
"type": "module",
|
|
@@ -43,7 +43,7 @@
|
|
|
43
43
|
"access": "public"
|
|
44
44
|
},
|
|
45
45
|
"dependencies": {
|
|
46
|
-
"@tileflow/core": ">=0.1.0-alpha.
|
|
46
|
+
"@tileflow/core": ">=0.1.0-alpha.30 <0.1.0-beta.0",
|
|
47
47
|
"@tileflow/interactions": ">=0.1.0-alpha.4 <0.1.0-beta.0",
|
|
48
48
|
"@tileflow/static": ">=0.1.0-alpha.27 <0.1.0-beta.0"
|
|
49
49
|
},
|