@trackunit/react-map-adapter-shared 0.0.12 → 0.0.17
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/index.cjs.js +3 -162
- package/index.esm.js +2 -155
- package/package.json +4 -3
- package/src/LayerPort.d.ts +8 -0
- package/src/index.d.ts +0 -1
- package/src/shapeStyleDefaults.d.ts +26 -18
- package/src/colorUtils.d.ts +0 -39
package/index.cjs.js
CHANGED
|
@@ -4,6 +4,7 @@ var geoJsonUtils = require('@trackunit/geo-json-utils');
|
|
|
4
4
|
var uiDesignTokens = require('@trackunit/ui-design-tokens');
|
|
5
5
|
var esToolkit = require('es-toolkit');
|
|
6
6
|
var zod = require('zod');
|
|
7
|
+
var reactMapColorUtils = require('@trackunit/react-map-color-utils');
|
|
7
8
|
|
|
8
9
|
/**
|
|
9
10
|
* Helper to define an adapter factory with proper type inference.
|
|
@@ -556,140 +557,6 @@ const mergeAntimeridianFeatures = (features) => {
|
|
|
556
557
|
};
|
|
557
558
|
};
|
|
558
559
|
|
|
559
|
-
// TODO (next PR): colorUtils is a generic CSS utility with no adapter-specific knowledge.
|
|
560
|
-
// Extract to a standalone utility package so it isn't coupled to the adapter layer.
|
|
561
|
-
/**
|
|
562
|
-
* Browser-backed color mixing via CSS `color-mix()`.
|
|
563
|
-
*
|
|
564
|
-
* Uses a hidden DOM element + `getComputedStyle` to resolve expressions,
|
|
565
|
-
* cached so each unique expression is computed at most once.
|
|
566
|
-
*/
|
|
567
|
-
const colorCache = new Map();
|
|
568
|
-
/**
|
|
569
|
-
* Modern browsers return CSS Color Level 4 `color(srgb r g b)` from
|
|
570
|
-
* `getComputedStyle`, but Mapbox GL JS only accepts classic formats
|
|
571
|
-
* (hex, rgb, rgba, hsl, hsla). Convert to `rgb()`/`rgba()`.
|
|
572
|
-
*/
|
|
573
|
-
const normalizeComputedColor = (color) => {
|
|
574
|
-
const m = color.match(/^color\(srgb\s+([\d.e+-]+)\s+([\d.e+-]+)\s+([\d.e+-]+)(?:\s*\/\s*([\d.e+-]+))?\)$/);
|
|
575
|
-
if (!m)
|
|
576
|
-
return color;
|
|
577
|
-
const r = Math.round(parseFloat(m[1] ?? "0") * 255);
|
|
578
|
-
const g = Math.round(parseFloat(m[2] ?? "0") * 255);
|
|
579
|
-
const b = Math.round(parseFloat(m[3] ?? "0") * 255);
|
|
580
|
-
if (m[4] !== undefined) {
|
|
581
|
-
return `rgba(${r}, ${g}, ${b}, ${parseFloat(m[4])})`;
|
|
582
|
-
}
|
|
583
|
-
return `rgb(${r}, ${g}, ${b})`;
|
|
584
|
-
};
|
|
585
|
-
let probeElement = null;
|
|
586
|
-
const getProbeElement = () => {
|
|
587
|
-
if (probeElement) {
|
|
588
|
-
return probeElement;
|
|
589
|
-
}
|
|
590
|
-
if (typeof document === "undefined") {
|
|
591
|
-
return null;
|
|
592
|
-
}
|
|
593
|
-
const el = document.createElement("span");
|
|
594
|
-
el.style.display = "none";
|
|
595
|
-
document.body.appendChild(el);
|
|
596
|
-
probeElement = el;
|
|
597
|
-
return el;
|
|
598
|
-
};
|
|
599
|
-
const resolveColorMix = (expression, fallback) => {
|
|
600
|
-
const cached = colorCache.get(expression);
|
|
601
|
-
if (cached !== undefined) {
|
|
602
|
-
return cached;
|
|
603
|
-
}
|
|
604
|
-
const el = getProbeElement();
|
|
605
|
-
if (!el) {
|
|
606
|
-
return fallback;
|
|
607
|
-
}
|
|
608
|
-
el.style.color = "";
|
|
609
|
-
el.style.color = expression;
|
|
610
|
-
if (!el.style.color) {
|
|
611
|
-
return fallback;
|
|
612
|
-
}
|
|
613
|
-
const computed = getComputedStyle(el).color;
|
|
614
|
-
if (!computed) {
|
|
615
|
-
return fallback;
|
|
616
|
-
}
|
|
617
|
-
const normalized = normalizeComputedColor(computed);
|
|
618
|
-
colorCache.set(expression, normalized);
|
|
619
|
-
return normalized;
|
|
620
|
-
};
|
|
621
|
-
/**
|
|
622
|
-
* Mix two CSS colors using the browser's `color-mix(in srgb)` function.
|
|
623
|
-
*
|
|
624
|
-
* @param color1 - First color (any valid CSS color string)
|
|
625
|
-
* @param color2 - Second color (any valid CSS color string)
|
|
626
|
-
* @param percentage - Percentage of `color1` in the mix (0–100)
|
|
627
|
-
* @returns Resolved color as an `rgb()` string, or `color1` if resolution fails
|
|
628
|
-
*/
|
|
629
|
-
const mixColor = (color1, color2, percentage) => {
|
|
630
|
-
const expression = `color-mix(in srgb, ${color1} ${percentage}%, ${color2})`;
|
|
631
|
-
return resolveColorMix(expression, color1);
|
|
632
|
-
};
|
|
633
|
-
/**
|
|
634
|
-
* Darken a CSS color by mixing it with black.
|
|
635
|
-
*
|
|
636
|
-
* @param color - Any valid CSS color string
|
|
637
|
-
* @param amount - Darkening intensity from 0 (no change) to 100 (pure black)
|
|
638
|
-
*/
|
|
639
|
-
const darkenColor = (color, amount) => mixColor(color, "black", 100 - amount);
|
|
640
|
-
/**
|
|
641
|
-
* Lighten a CSS color by mixing it with white.
|
|
642
|
-
*
|
|
643
|
-
* @param color - Any valid CSS color string
|
|
644
|
-
* @param amount - Lightening intensity from 0 (no change) to 100 (pure white)
|
|
645
|
-
*/
|
|
646
|
-
const lightenColor = (color, amount) => mixColor(color, "white", 100 - amount);
|
|
647
|
-
/**
|
|
648
|
-
* Resolve a CSS color and apply an opacity multiplier to its alpha channel.
|
|
649
|
-
*
|
|
650
|
-
* Unlike setting `element.style.opacity`, this only affects the individual
|
|
651
|
-
* color value — useful when fill and stroke need independent opacity.
|
|
652
|
-
*
|
|
653
|
-
* @param color - Any valid CSS color string
|
|
654
|
-
* @param opacity - Opacity multiplier from 0 to 1 (multiplied with existing alpha)
|
|
655
|
-
* @returns `rgba()` string with the combined alpha, or the original color if resolution fails
|
|
656
|
-
*/
|
|
657
|
-
const colorWithOpacity = (color, opacity) => {
|
|
658
|
-
if (opacity >= 1)
|
|
659
|
-
return color;
|
|
660
|
-
const cacheKey = `${color}@${opacity}`;
|
|
661
|
-
const cached = colorCache.get(cacheKey);
|
|
662
|
-
if (cached !== undefined)
|
|
663
|
-
return cached;
|
|
664
|
-
const el = getProbeElement();
|
|
665
|
-
if (!el)
|
|
666
|
-
return color;
|
|
667
|
-
el.style.color = "";
|
|
668
|
-
el.style.color = color;
|
|
669
|
-
const computed = getComputedStyle(el).color;
|
|
670
|
-
if (!computed)
|
|
671
|
-
return color;
|
|
672
|
-
const normalized = normalizeComputedColor(computed);
|
|
673
|
-
const rgbaMatch = normalized.match(/^rgba?\((\d+),\s*(\d+),\s*(\d+)(?:,\s*([\d.]+))?\)$/);
|
|
674
|
-
if (!rgbaMatch)
|
|
675
|
-
return color;
|
|
676
|
-
const existingAlpha = rgbaMatch[4] !== undefined ? parseFloat(rgbaMatch[4]) : 1;
|
|
677
|
-
const result = `rgba(${rgbaMatch[1]}, ${rgbaMatch[2]}, ${rgbaMatch[3]}, ${existingAlpha * opacity})`;
|
|
678
|
-
colorCache.set(cacheKey, result);
|
|
679
|
-
return result;
|
|
680
|
-
};
|
|
681
|
-
/**
|
|
682
|
-
* Clear the resolved-color cache and detach the probe element.
|
|
683
|
-
* Exposed for test teardown only — not part of the public API.
|
|
684
|
-
*/
|
|
685
|
-
const resetColorUtilsForTesting = () => {
|
|
686
|
-
colorCache.clear();
|
|
687
|
-
if (probeElement) {
|
|
688
|
-
probeElement.remove();
|
|
689
|
-
probeElement = null;
|
|
690
|
-
}
|
|
691
|
-
};
|
|
692
|
-
|
|
693
560
|
/**
|
|
694
561
|
* Web Mercator max latitude in degrees: atan(sinh(π)).
|
|
695
562
|
* This is where Mercator tiles are cut off to form a square map (EPSG:3857).
|
|
@@ -2522,26 +2389,6 @@ const attachSafeAreaHoverListeners = (el, onEnter, onLeave, state) => {
|
|
|
2522
2389
|
});
|
|
2523
2390
|
};
|
|
2524
2391
|
|
|
2525
|
-
// TODO (next PR): shapeStyleDefaults computes visual defaults for shapes — a map consumer
|
|
2526
|
-
// concern, not an adapter concern. Make these injectable from react-map's createMapComponent
|
|
2527
|
-
// so adapters don't need to know about default visual styles.
|
|
2528
|
-
const SHAPE_STYLE_DEFAULTS = {
|
|
2529
|
-
polygon: {
|
|
2530
|
-
fillOpacity: 0.05,
|
|
2531
|
-
strokeWidth: 1,
|
|
2532
|
-
strokeOpacity: 1,
|
|
2533
|
-
},
|
|
2534
|
-
line: {
|
|
2535
|
-
strokeWidth: 1,
|
|
2536
|
-
strokeOpacity: 1,
|
|
2537
|
-
},
|
|
2538
|
-
point: {
|
|
2539
|
-
fillOpacity: 0.2,
|
|
2540
|
-
strokeWidth: 1,
|
|
2541
|
-
strokeOpacity: 1,
|
|
2542
|
-
pointRadius: 5,
|
|
2543
|
-
},
|
|
2544
|
-
};
|
|
2545
2392
|
// ============================================================================
|
|
2546
2393
|
// Interaction style constants
|
|
2547
2394
|
// ============================================================================
|
|
@@ -2559,7 +2406,7 @@ const SELECTED_COLOR_SHIFT = 25;
|
|
|
2559
2406
|
const resolveHoveredStyle = (base, _shapeType, theme) => {
|
|
2560
2407
|
const userOverrides = base.hovered;
|
|
2561
2408
|
const baseStroke = base.stroke ?? "#000000";
|
|
2562
|
-
const autoStroke = theme === "dark" ? lightenColor(baseStroke, HOVER_COLOR_SHIFT) : darkenColor(baseStroke, HOVER_COLOR_SHIFT);
|
|
2409
|
+
const autoStroke = theme === "dark" ? reactMapColorUtils.lightenColor(baseStroke, HOVER_COLOR_SHIFT) : reactMapColorUtils.darkenColor(baseStroke, HOVER_COLOR_SHIFT);
|
|
2563
2410
|
return {
|
|
2564
2411
|
fill: userOverrides?.fill ?? base.fill,
|
|
2565
2412
|
fillOpacity: userOverrides?.fillOpacity ?? base.fillOpacity,
|
|
@@ -2578,7 +2425,7 @@ const resolveHoveredStyle = (base, _shapeType, theme) => {
|
|
|
2578
2425
|
const resolveSelectedStyle = (base, _shapeType, theme) => {
|
|
2579
2426
|
const userOverrides = base.selected;
|
|
2580
2427
|
const baseStroke = base.stroke ?? "#000000";
|
|
2581
|
-
const autoStroke = theme === "dark" ? lightenColor(baseStroke, SELECTED_COLOR_SHIFT) : darkenColor(baseStroke, SELECTED_COLOR_SHIFT);
|
|
2428
|
+
const autoStroke = theme === "dark" ? reactMapColorUtils.lightenColor(baseStroke, SELECTED_COLOR_SHIFT) : reactMapColorUtils.darkenColor(baseStroke, SELECTED_COLOR_SHIFT);
|
|
2582
2429
|
return {
|
|
2583
2430
|
fill: userOverrides?.fill ?? base.fill,
|
|
2584
2431
|
fillOpacity: userOverrides?.fillOpacity ?? base.fillOpacity,
|
|
@@ -2623,7 +2470,6 @@ exports.MAP_CURSORS = MAP_CURSORS;
|
|
|
2623
2470
|
exports.MAX_ZOOM = MAX_ZOOM;
|
|
2624
2471
|
exports.MIN_ZOOM = MIN_ZOOM;
|
|
2625
2472
|
exports.SAFE_AREA_DEFAULT_BUFFER_PX = SAFE_AREA_DEFAULT_BUFFER_PX;
|
|
2626
|
-
exports.SHAPE_STYLE_DEFAULTS = SHAPE_STYLE_DEFAULTS;
|
|
2627
2473
|
exports.WORLD_BBOX = WORLD_BBOX;
|
|
2628
2474
|
exports.allocSafeAreaDebugId = allocSafeAreaDebugId;
|
|
2629
2475
|
exports.anchorFromBottomCenter = anchorFromBottomCenter;
|
|
@@ -2640,14 +2486,12 @@ exports.canPatchAdaptiveViewport = canPatchAdaptiveViewport;
|
|
|
2640
2486
|
exports.canPatchMarkerInPlace = canPatchMarkerInPlace;
|
|
2641
2487
|
exports.clearSafeArea = clearSafeArea;
|
|
2642
2488
|
exports.collectFeatureIdSet = collectFeatureIdSet;
|
|
2643
|
-
exports.colorWithOpacity = colorWithOpacity;
|
|
2644
2489
|
exports.computeInitialState = computeInitialState;
|
|
2645
2490
|
exports.computeMarkerDomPortalZIndex = computeMarkerDomPortalZIndex;
|
|
2646
2491
|
exports.convexHull = convexHull;
|
|
2647
2492
|
exports.createClusterPinElement = createClusterPinElement;
|
|
2648
2493
|
exports.createDefaultClusterElement = createDefaultClusterElement;
|
|
2649
2494
|
exports.createSymbolDotElement = createSymbolDotElement;
|
|
2650
|
-
exports.darkenColor = darkenColor;
|
|
2651
2495
|
exports.defineAdapter = defineAdapter;
|
|
2652
2496
|
exports.densifyGeodesicFeatures = densifyGeodesicFeatures;
|
|
2653
2497
|
exports.disableSafeAreaDebug = disableSafeAreaDebug;
|
|
@@ -2670,19 +2514,16 @@ exports.intermediatePoint = intermediatePoint;
|
|
|
2670
2514
|
exports.isCanvasMarkerMode = isCanvasMarkerMode;
|
|
2671
2515
|
exports.isEventOfType = isEventOfType;
|
|
2672
2516
|
exports.isSafeAreaDebugEnabled = isSafeAreaDebugEnabled;
|
|
2673
|
-
exports.lightenColor = lightenColor;
|
|
2674
2517
|
exports.mapAppearanceSchema = mapAppearanceSchema;
|
|
2675
2518
|
exports.mapStateEquals = mapStateEquals;
|
|
2676
2519
|
exports.mapThemeSchema = mapThemeSchema;
|
|
2677
2520
|
exports.mapTypeSchema = mapTypeSchema;
|
|
2678
2521
|
exports.mercatorCenterFromBounds = mercatorCenterFromBounds;
|
|
2679
2522
|
exports.mergeAntimeridianFeatures = mergeAntimeridianFeatures;
|
|
2680
|
-
exports.mixColor = mixColor;
|
|
2681
2523
|
exports.patchPortalDescriptors = patchPortalDescriptors;
|
|
2682
2524
|
exports.pointInPolygon = pointInPolygon;
|
|
2683
2525
|
exports.removeGoneIndexedMarkers = removeGoneIndexedMarkers;
|
|
2684
2526
|
exports.renderSafeArea = renderSafeArea;
|
|
2685
|
-
exports.resetColorUtilsForTesting = resetColorUtilsForTesting;
|
|
2686
2527
|
exports.resolveCircleSymbolDefaults = resolveCircleSymbolDefaults;
|
|
2687
2528
|
exports.resolveHoveredStyle = resolveHoveredStyle;
|
|
2688
2529
|
exports.resolveSelectedStyle = resolveSelectedStyle;
|
package/index.esm.js
CHANGED
|
@@ -2,6 +2,7 @@ import { validatePosition, validateBbox, geoJsonBboxSchema } from '@trackunit/ge
|
|
|
2
2
|
import { color } from '@trackunit/ui-design-tokens';
|
|
3
3
|
import { isEqual } from 'es-toolkit';
|
|
4
4
|
import { z } from 'zod';
|
|
5
|
+
import { lightenColor, darkenColor } from '@trackunit/react-map-color-utils';
|
|
5
6
|
|
|
6
7
|
/**
|
|
7
8
|
* Helper to define an adapter factory with proper type inference.
|
|
@@ -554,140 +555,6 @@ const mergeAntimeridianFeatures = (features) => {
|
|
|
554
555
|
};
|
|
555
556
|
};
|
|
556
557
|
|
|
557
|
-
// TODO (next PR): colorUtils is a generic CSS utility with no adapter-specific knowledge.
|
|
558
|
-
// Extract to a standalone utility package so it isn't coupled to the adapter layer.
|
|
559
|
-
/**
|
|
560
|
-
* Browser-backed color mixing via CSS `color-mix()`.
|
|
561
|
-
*
|
|
562
|
-
* Uses a hidden DOM element + `getComputedStyle` to resolve expressions,
|
|
563
|
-
* cached so each unique expression is computed at most once.
|
|
564
|
-
*/
|
|
565
|
-
const colorCache = new Map();
|
|
566
|
-
/**
|
|
567
|
-
* Modern browsers return CSS Color Level 4 `color(srgb r g b)` from
|
|
568
|
-
* `getComputedStyle`, but Mapbox GL JS only accepts classic formats
|
|
569
|
-
* (hex, rgb, rgba, hsl, hsla). Convert to `rgb()`/`rgba()`.
|
|
570
|
-
*/
|
|
571
|
-
const normalizeComputedColor = (color) => {
|
|
572
|
-
const m = color.match(/^color\(srgb\s+([\d.e+-]+)\s+([\d.e+-]+)\s+([\d.e+-]+)(?:\s*\/\s*([\d.e+-]+))?\)$/);
|
|
573
|
-
if (!m)
|
|
574
|
-
return color;
|
|
575
|
-
const r = Math.round(parseFloat(m[1] ?? "0") * 255);
|
|
576
|
-
const g = Math.round(parseFloat(m[2] ?? "0") * 255);
|
|
577
|
-
const b = Math.round(parseFloat(m[3] ?? "0") * 255);
|
|
578
|
-
if (m[4] !== undefined) {
|
|
579
|
-
return `rgba(${r}, ${g}, ${b}, ${parseFloat(m[4])})`;
|
|
580
|
-
}
|
|
581
|
-
return `rgb(${r}, ${g}, ${b})`;
|
|
582
|
-
};
|
|
583
|
-
let probeElement = null;
|
|
584
|
-
const getProbeElement = () => {
|
|
585
|
-
if (probeElement) {
|
|
586
|
-
return probeElement;
|
|
587
|
-
}
|
|
588
|
-
if (typeof document === "undefined") {
|
|
589
|
-
return null;
|
|
590
|
-
}
|
|
591
|
-
const el = document.createElement("span");
|
|
592
|
-
el.style.display = "none";
|
|
593
|
-
document.body.appendChild(el);
|
|
594
|
-
probeElement = el;
|
|
595
|
-
return el;
|
|
596
|
-
};
|
|
597
|
-
const resolveColorMix = (expression, fallback) => {
|
|
598
|
-
const cached = colorCache.get(expression);
|
|
599
|
-
if (cached !== undefined) {
|
|
600
|
-
return cached;
|
|
601
|
-
}
|
|
602
|
-
const el = getProbeElement();
|
|
603
|
-
if (!el) {
|
|
604
|
-
return fallback;
|
|
605
|
-
}
|
|
606
|
-
el.style.color = "";
|
|
607
|
-
el.style.color = expression;
|
|
608
|
-
if (!el.style.color) {
|
|
609
|
-
return fallback;
|
|
610
|
-
}
|
|
611
|
-
const computed = getComputedStyle(el).color;
|
|
612
|
-
if (!computed) {
|
|
613
|
-
return fallback;
|
|
614
|
-
}
|
|
615
|
-
const normalized = normalizeComputedColor(computed);
|
|
616
|
-
colorCache.set(expression, normalized);
|
|
617
|
-
return normalized;
|
|
618
|
-
};
|
|
619
|
-
/**
|
|
620
|
-
* Mix two CSS colors using the browser's `color-mix(in srgb)` function.
|
|
621
|
-
*
|
|
622
|
-
* @param color1 - First color (any valid CSS color string)
|
|
623
|
-
* @param color2 - Second color (any valid CSS color string)
|
|
624
|
-
* @param percentage - Percentage of `color1` in the mix (0–100)
|
|
625
|
-
* @returns Resolved color as an `rgb()` string, or `color1` if resolution fails
|
|
626
|
-
*/
|
|
627
|
-
const mixColor = (color1, color2, percentage) => {
|
|
628
|
-
const expression = `color-mix(in srgb, ${color1} ${percentage}%, ${color2})`;
|
|
629
|
-
return resolveColorMix(expression, color1);
|
|
630
|
-
};
|
|
631
|
-
/**
|
|
632
|
-
* Darken a CSS color by mixing it with black.
|
|
633
|
-
*
|
|
634
|
-
* @param color - Any valid CSS color string
|
|
635
|
-
* @param amount - Darkening intensity from 0 (no change) to 100 (pure black)
|
|
636
|
-
*/
|
|
637
|
-
const darkenColor = (color, amount) => mixColor(color, "black", 100 - amount);
|
|
638
|
-
/**
|
|
639
|
-
* Lighten a CSS color by mixing it with white.
|
|
640
|
-
*
|
|
641
|
-
* @param color - Any valid CSS color string
|
|
642
|
-
* @param amount - Lightening intensity from 0 (no change) to 100 (pure white)
|
|
643
|
-
*/
|
|
644
|
-
const lightenColor = (color, amount) => mixColor(color, "white", 100 - amount);
|
|
645
|
-
/**
|
|
646
|
-
* Resolve a CSS color and apply an opacity multiplier to its alpha channel.
|
|
647
|
-
*
|
|
648
|
-
* Unlike setting `element.style.opacity`, this only affects the individual
|
|
649
|
-
* color value — useful when fill and stroke need independent opacity.
|
|
650
|
-
*
|
|
651
|
-
* @param color - Any valid CSS color string
|
|
652
|
-
* @param opacity - Opacity multiplier from 0 to 1 (multiplied with existing alpha)
|
|
653
|
-
* @returns `rgba()` string with the combined alpha, or the original color if resolution fails
|
|
654
|
-
*/
|
|
655
|
-
const colorWithOpacity = (color, opacity) => {
|
|
656
|
-
if (opacity >= 1)
|
|
657
|
-
return color;
|
|
658
|
-
const cacheKey = `${color}@${opacity}`;
|
|
659
|
-
const cached = colorCache.get(cacheKey);
|
|
660
|
-
if (cached !== undefined)
|
|
661
|
-
return cached;
|
|
662
|
-
const el = getProbeElement();
|
|
663
|
-
if (!el)
|
|
664
|
-
return color;
|
|
665
|
-
el.style.color = "";
|
|
666
|
-
el.style.color = color;
|
|
667
|
-
const computed = getComputedStyle(el).color;
|
|
668
|
-
if (!computed)
|
|
669
|
-
return color;
|
|
670
|
-
const normalized = normalizeComputedColor(computed);
|
|
671
|
-
const rgbaMatch = normalized.match(/^rgba?\((\d+),\s*(\d+),\s*(\d+)(?:,\s*([\d.]+))?\)$/);
|
|
672
|
-
if (!rgbaMatch)
|
|
673
|
-
return color;
|
|
674
|
-
const existingAlpha = rgbaMatch[4] !== undefined ? parseFloat(rgbaMatch[4]) : 1;
|
|
675
|
-
const result = `rgba(${rgbaMatch[1]}, ${rgbaMatch[2]}, ${rgbaMatch[3]}, ${existingAlpha * opacity})`;
|
|
676
|
-
colorCache.set(cacheKey, result);
|
|
677
|
-
return result;
|
|
678
|
-
};
|
|
679
|
-
/**
|
|
680
|
-
* Clear the resolved-color cache and detach the probe element.
|
|
681
|
-
* Exposed for test teardown only — not part of the public API.
|
|
682
|
-
*/
|
|
683
|
-
const resetColorUtilsForTesting = () => {
|
|
684
|
-
colorCache.clear();
|
|
685
|
-
if (probeElement) {
|
|
686
|
-
probeElement.remove();
|
|
687
|
-
probeElement = null;
|
|
688
|
-
}
|
|
689
|
-
};
|
|
690
|
-
|
|
691
558
|
/**
|
|
692
559
|
* Web Mercator max latitude in degrees: atan(sinh(π)).
|
|
693
560
|
* This is where Mercator tiles are cut off to form a square map (EPSG:3857).
|
|
@@ -2520,26 +2387,6 @@ const attachSafeAreaHoverListeners = (el, onEnter, onLeave, state) => {
|
|
|
2520
2387
|
});
|
|
2521
2388
|
};
|
|
2522
2389
|
|
|
2523
|
-
// TODO (next PR): shapeStyleDefaults computes visual defaults for shapes — a map consumer
|
|
2524
|
-
// concern, not an adapter concern. Make these injectable from react-map's createMapComponent
|
|
2525
|
-
// so adapters don't need to know about default visual styles.
|
|
2526
|
-
const SHAPE_STYLE_DEFAULTS = {
|
|
2527
|
-
polygon: {
|
|
2528
|
-
fillOpacity: 0.05,
|
|
2529
|
-
strokeWidth: 1,
|
|
2530
|
-
strokeOpacity: 1,
|
|
2531
|
-
},
|
|
2532
|
-
line: {
|
|
2533
|
-
strokeWidth: 1,
|
|
2534
|
-
strokeOpacity: 1,
|
|
2535
|
-
},
|
|
2536
|
-
point: {
|
|
2537
|
-
fillOpacity: 0.2,
|
|
2538
|
-
strokeWidth: 1,
|
|
2539
|
-
strokeOpacity: 1,
|
|
2540
|
-
pointRadius: 5,
|
|
2541
|
-
},
|
|
2542
|
-
};
|
|
2543
2390
|
// ============================================================================
|
|
2544
2391
|
// Interaction style constants
|
|
2545
2392
|
// ============================================================================
|
|
@@ -2602,4 +2449,4 @@ const resolveStrokeColors = (style, shapeType, theme) => {
|
|
|
2602
2449
|
};
|
|
2603
2450
|
};
|
|
2604
2451
|
|
|
2605
|
-
export { ANCHOR_SELECTOR, CIRCLE_SYMBOL_DEFAULT_DIAMETER_PX, CIRCLE_SYMBOL_DEFAULT_OPACITY, DEFAULT_CENTER, DEFAULT_MAP_APPEARANCE, DEFAULT_ZOOM, GEODESIC_MAX_SEGMENT_KM, HIT_SURFACE_SELECTOR, INITIAL_CAMERA_STATE, INITIAL_INTERACTION_STATE, INITIAL_MAP_STATE, INITIAL_MAP_STATUS, KEYBOARD_PAN_AMOUNT, KEYBOARD_ZOOM_AMOUNT, LAYER_FADE_DURATION_MS, MAP_CURSORS, MAX_ZOOM, MIN_ZOOM, SAFE_AREA_DEFAULT_BUFFER_PX,
|
|
2452
|
+
export { ANCHOR_SELECTOR, CIRCLE_SYMBOL_DEFAULT_DIAMETER_PX, CIRCLE_SYMBOL_DEFAULT_OPACITY, DEFAULT_CENTER, DEFAULT_MAP_APPEARANCE, DEFAULT_ZOOM, GEODESIC_MAX_SEGMENT_KM, HIT_SURFACE_SELECTOR, INITIAL_CAMERA_STATE, INITIAL_INTERACTION_STATE, INITIAL_MAP_STATE, INITIAL_MAP_STATUS, KEYBOARD_PAN_AMOUNT, KEYBOARD_ZOOM_AMOUNT, LAYER_FADE_DURATION_MS, MAP_CURSORS, MAX_ZOOM, MIN_ZOOM, SAFE_AREA_DEFAULT_BUFFER_PX, WORLD_BBOX, allocSafeAreaDebugId, anchorFromBottomCenter, angularDistance, attachSafeAreaHoverListeners, bboxEquals, bufferRectCorners, buildAdaptiveDomEntries, buildAdaptiveDomRenderFn, buildAdaptiveSymbolStyleFn, cameraStateEquals, canPatchAdaptiveMarker, canPatchAdaptiveViewport, canPatchMarkerInPlace, clearSafeArea, collectFeatureIdSet, computeInitialState, computeMarkerDomPortalZIndex, convexHull, createClusterPinElement, createDefaultClusterElement, createSymbolDotElement, defineAdapter, densifyGeodesicFeatures, disableSafeAreaDebug, discriminateRenderResult, enableSafeAreaDebug, estimateZoomFromBounds, extractLineCoordinates, extractPointCoordinates, extractPolygonPaths, extractSourceData, fadeInElement, filterRectsByCursorDirection, geometryTypeToShapeType, getAdaptiveDomFeatureIds, getAnchorRect, getEffectiveRestrictBounds, getHitSurfaceRect, hasSameFeatureIds, intermediatePoint, isCanvasMarkerMode, isEventOfType, isSafeAreaDebugEnabled, mapAppearanceSchema, mapStateEquals, mapThemeSchema, mapTypeSchema, mercatorCenterFromBounds, mergeAntimeridianFeatures, patchPortalDescriptors, pointInPolygon, removeGoneIndexedMarkers, renderSafeArea, resolveCircleSymbolDefaults, resolveHoveredStyle, resolveSelectedStyle, resolveStrokeColors, resolveSymbolDescriptor, safePolygon, toDeg, toRad, validateInitialViewport, watchSafeAreaLeave };
|
package/package.json
CHANGED
|
@@ -1,14 +1,15 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@trackunit/react-map-adapter-shared",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.17",
|
|
4
4
|
"repository": "https://github.com/Trackunit/manager",
|
|
5
5
|
"license": "SEE LICENSE IN LICENSE.txt",
|
|
6
6
|
"engines": {
|
|
7
7
|
"node": ">=24.x"
|
|
8
8
|
},
|
|
9
9
|
"dependencies": {
|
|
10
|
-
"@trackunit/
|
|
11
|
-
"@trackunit/
|
|
10
|
+
"@trackunit/react-map-color-utils": "0.0.2",
|
|
11
|
+
"@trackunit/geo-json-utils": "1.14.36",
|
|
12
|
+
"@trackunit/ui-design-tokens": "1.13.33",
|
|
12
13
|
"es-toolkit": "^1.39.10",
|
|
13
14
|
"zod": "^3.25.76"
|
|
14
15
|
},
|
package/src/LayerPort.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { GeoJsonBbox } from "@trackunit/geo-json-utils";
|
|
2
2
|
import type { Entity } from "./interactionTypes";
|
|
3
|
+
import type { ShapeStyleDefaults } from "./shapeStyleDefaults";
|
|
3
4
|
import type { AdaptiveMarkerResolution, ClusterConfig, ClusterRenderConfig, ClusterRenderState, DomRenderState, GeoJsonFeatureCollection, GeoJsonGeometry, RenderConfig, RouteStyle, ShapeInteractiveMode, ShapeStyle } from "./layerApiTypes";
|
|
4
5
|
type ReactNode = import("react").ReactNode;
|
|
5
6
|
/**
|
|
@@ -231,6 +232,13 @@ export type LayerPort = Readonly<{
|
|
|
231
232
|
* @returns Unsubscribe function.
|
|
232
233
|
*/
|
|
233
234
|
onSourceReady: (configId: string, callback: () => void) => () => void;
|
|
235
|
+
/**
|
|
236
|
+
* Injects the per-shape-type visual defaults from the map consumer.
|
|
237
|
+
*
|
|
238
|
+
* Called by `createMapComponent` before any snapshot is sent, so adapters
|
|
239
|
+
* always receive the consumer-owned defaults rather than hard-coding them.
|
|
240
|
+
*/
|
|
241
|
+
setShapeStyleDefaults: (defaults: ShapeStyleDefaults) => void;
|
|
234
242
|
/**
|
|
235
243
|
* Subscription for DOM-rendered individual markers (including adaptive DOM
|
|
236
244
|
* features). `<Layers>` routes these descriptors to `markerRender`.
|
package/src/index.d.ts
CHANGED
|
@@ -1,23 +1,31 @@
|
|
|
1
|
-
import type { MapTheme } from "./primitiveMapTypes";
|
|
2
1
|
import type { ShapeType } from "./interactionTypes";
|
|
3
2
|
import type { ShapeStyle, ShapeStyleOverrides } from "./layerApiTypes";
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
3
|
+
import type { MapTheme } from "./primitiveMapTypes";
|
|
4
|
+
/**
|
|
5
|
+
* Per-shape-type visual defaults injected by the map consumer via `createMapComponent`.
|
|
6
|
+
* Adapters receive these via `LayerPort.setShapeStyleDefaults` rather than importing
|
|
7
|
+
* hardcoded values directly.
|
|
8
|
+
*
|
|
9
|
+
* Each shape type exposes the required numeric fields adapters use as fallbacks so
|
|
10
|
+
* TypeScript can infer non-nullable numbers without extra guards.
|
|
11
|
+
*/
|
|
12
|
+
export type ShapeStyleDefaults = Readonly<{
|
|
13
|
+
polygon: Readonly<{
|
|
14
|
+
fillOpacity: number;
|
|
15
|
+
strokeWidth: number;
|
|
16
|
+
strokeOpacity: number;
|
|
17
|
+
}>;
|
|
18
|
+
line: Readonly<{
|
|
19
|
+
strokeWidth: number;
|
|
20
|
+
strokeOpacity: number;
|
|
21
|
+
}>;
|
|
22
|
+
point: Readonly<{
|
|
23
|
+
fillOpacity: number;
|
|
24
|
+
strokeWidth: number;
|
|
25
|
+
strokeOpacity: number;
|
|
26
|
+
pointRadius: number;
|
|
27
|
+
}>;
|
|
28
|
+
}>;
|
|
21
29
|
/**
|
|
22
30
|
* Resolve the visual style for a hovered shape.
|
|
23
31
|
*
|
package/src/colorUtils.d.ts
DELETED
|
@@ -1,39 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Mix two CSS colors using the browser's `color-mix(in srgb)` function.
|
|
3
|
-
*
|
|
4
|
-
* @param color1 - First color (any valid CSS color string)
|
|
5
|
-
* @param color2 - Second color (any valid CSS color string)
|
|
6
|
-
* @param percentage - Percentage of `color1` in the mix (0–100)
|
|
7
|
-
* @returns Resolved color as an `rgb()` string, or `color1` if resolution fails
|
|
8
|
-
*/
|
|
9
|
-
export declare const mixColor: (color1: string, color2: string, percentage: number) => string;
|
|
10
|
-
/**
|
|
11
|
-
* Darken a CSS color by mixing it with black.
|
|
12
|
-
*
|
|
13
|
-
* @param color - Any valid CSS color string
|
|
14
|
-
* @param amount - Darkening intensity from 0 (no change) to 100 (pure black)
|
|
15
|
-
*/
|
|
16
|
-
export declare const darkenColor: (color: string, amount: number) => string;
|
|
17
|
-
/**
|
|
18
|
-
* Lighten a CSS color by mixing it with white.
|
|
19
|
-
*
|
|
20
|
-
* @param color - Any valid CSS color string
|
|
21
|
-
* @param amount - Lightening intensity from 0 (no change) to 100 (pure white)
|
|
22
|
-
*/
|
|
23
|
-
export declare const lightenColor: (color: string, amount: number) => string;
|
|
24
|
-
/**
|
|
25
|
-
* Resolve a CSS color and apply an opacity multiplier to its alpha channel.
|
|
26
|
-
*
|
|
27
|
-
* Unlike setting `element.style.opacity`, this only affects the individual
|
|
28
|
-
* color value — useful when fill and stroke need independent opacity.
|
|
29
|
-
*
|
|
30
|
-
* @param color - Any valid CSS color string
|
|
31
|
-
* @param opacity - Opacity multiplier from 0 to 1 (multiplied with existing alpha)
|
|
32
|
-
* @returns `rgba()` string with the combined alpha, or the original color if resolution fails
|
|
33
|
-
*/
|
|
34
|
-
export declare const colorWithOpacity: (color: string, opacity: number) => string;
|
|
35
|
-
/**
|
|
36
|
-
* Clear the resolved-color cache and detach the probe element.
|
|
37
|
-
* Exposed for test teardown only — not part of the public API.
|
|
38
|
-
*/
|
|
39
|
-
export declare const resetColorUtilsForTesting: () => void;
|