@defra/interactive-map 0.0.22-alpha → 0.0.23-alpha
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/dist/css/index.css +1 -1
- package/dist/esm/im-core.js +1 -1
- package/dist/esm/im-shell.js +1 -1
- package/dist/umd/im-core.js +1 -1
- package/dist/umd/index.js +1 -1
- package/docs/api/button-definition.md +39 -0
- package/docs/api/context.md +4 -4
- package/docs/api/map-style-config.md +11 -2
- package/docs/api/marker-config.md +38 -7
- package/docs/api/panel-definition.md +7 -3
- package/docs/api/symbol-config.md +10 -26
- package/docs/api/symbol-registry.md +28 -13
- package/docs/api.md +24 -2
- package/docs/assets/css/{docusaurus.css → docusaurus.scss} +18 -12
- package/docs/assets/images/toggle-marker-label.jpg +0 -0
- package/docs/examples/index.mdx +12 -0
- package/docs/examples/toggle-marker-label.mdx +89 -0
- package/docs/plugins/interact.md +4 -11
- package/docusaurus.config.cjs +2 -1
- package/package.json +8 -8
- package/plugins/beta/datasets/dist/adapters/maplibre/esm/im-datasets-ml-adapter.js +1 -1
- package/plugins/beta/datasets/dist/css/index.css +2 -2
- package/plugins/beta/datasets/dist/esm/im-datasets-plugin.js +1 -1
- package/plugins/beta/datasets/dist/umd/maplibre/im-datasets-maplibre-adapter.js +1 -1
- package/plugins/beta/datasets/dist/umd/maplibre/im-datasets-plugin.js +1 -1
- package/plugins/beta/datasets/dist/umd/maplibre/index.js +1 -1
- package/plugins/beta/datasets/src/adapters/maplibre/layerBuilders.js +5 -5
- package/plugins/beta/datasets/src/adapters/maplibre/maplibreLayerAdapter.js +24 -29
- package/plugins/beta/datasets/src/adapters/maplibre/patternImages.js +2 -2
- package/plugins/beta/datasets/src/adapters/maplibre/symbolImages.js +3 -3
- package/plugins/beta/datasets/src/components/KeySvg.jsx +2 -2
- package/plugins/beta/datasets/src/components/KeySvgPattern.jsx +1 -2
- package/plugins/beta/datasets/src/components/svgProperties.js +2 -2
- package/plugins/beta/datasets/src/panels/Key.module.scss +2 -2
- package/plugins/beta/draw-es/dist/esm/im-draw-es-plugin.js +1 -1
- package/plugins/beta/draw-ml/dist/esm/im-draw-ml-plugin.js +1 -1
- package/plugins/beta/draw-ml/dist/umd/im-draw-ml-plugin.js +1 -1
- package/plugins/beta/map-styles/dist/esm/im-map-styles-plugin.js +1 -1
- package/plugins/beta/map-styles/dist/umd/im-map-styles-plugin.js +1 -1
- package/plugins/beta/map-styles/dist/umd/index.js +1 -1
- package/plugins/beta/use-location/dist/esm/im-use-location-plugin.js +1 -1
- package/plugins/beta/use-location/dist/umd/im-use-location-plugin.js +1 -1
- package/plugins/beta/use-location/src/manifest.js +1 -0
- package/plugins/interact/dist/esm/im-interact-plugin.js +1 -1
- package/plugins/interact/dist/umd/im-interact-plugin.js +1 -1
- package/plugins/interact/dist/umd/index.js +1 -1
- package/plugins/interact/src/InteractInit.jsx +23 -55
- package/plugins/interact/src/InteractInit.test.js +58 -80
- package/plugins/interact/src/defaults.js +1 -3
- package/plugins/interact/src/hooks/useAttachEvents.js +46 -0
- package/plugins/interact/src/hooks/useAttachEvents.test.js +65 -0
- package/plugins/interact/src/hooks/useCrossHairVisibility.js +47 -0
- package/plugins/interact/src/hooks/useCrossHairVisibility.test.js +54 -0
- package/plugins/interact/src/hooks/useHighlightSync.js +30 -8
- package/plugins/interact/src/hooks/useHighlightSync.test.js +127 -80
- package/plugins/interact/src/hooks/useInteractionHandlers.js +18 -17
- package/plugins/interact/src/hooks/useInteractionHandlers.test.js +22 -61
- package/plugins/interact/src/hooks/useMapItemList.js +187 -0
- package/plugins/interact/src/hooks/useMapItemList.test.js +584 -0
- package/plugins/interact/src/index.js +0 -2
- package/plugins/interact/src/index.test.js +0 -2
- package/plugins/interact/src/manifest.js +37 -6
- package/plugins/interact/src/reducer.js +8 -4
- package/plugins/interact/src/reducer.test.js +18 -3
- package/plugins/interact/src/utils/buildStylesMap.js +21 -10
- package/plugins/interact/src/utils/buildStylesMap.test.js +29 -29
- package/plugins/interact/src/utils/spatial.js +0 -15
- package/plugins/interact/src/utils/spatial.test.js +1 -13
- package/plugins/search/dist/css/index.css +1 -1
- package/plugins/search/dist/esm/im-search-plugin.js +1 -1
- package/plugins/search/dist/umd/im-search-plugin.js +1 -1
- package/plugins/search/src/components/CloseButton/CloseButton.module.scss +2 -0
- package/plugins/search/src/components/OpenButton/OpenButton.jsx +1 -1
- package/plugins/search/src/components/OpenButton/OpenButton.module.scss +3 -0
- package/plugins/search/src/search.scss +1 -0
- package/providers/beta/esri/dist/esm/im-esri-provider.js +1 -1
- package/providers/beta/esri/src/esriProvider.js +4 -0
- package/providers/maplibre/dist/esm/im-maplibre-provider.js +1 -1
- package/providers/maplibre/dist/esm/index.js +1 -1
- package/providers/maplibre/dist/umd/im-maplibre-provider.js +1 -1
- package/providers/maplibre/dist/umd/index.js +1 -1
- package/providers/maplibre/src/index.js +1 -1
- package/providers/maplibre/src/index.test.js +9 -14
- package/providers/maplibre/src/mapEvents.js +11 -5
- package/providers/maplibre/src/mapEvents.test.js +14 -3
- package/providers/maplibre/src/maplibreProvider.js +18 -11
- package/providers/maplibre/src/maplibreProvider.test.js +43 -36
- package/providers/maplibre/src/utils/highlightFeatures.js +102 -57
- package/providers/maplibre/src/utils/highlightFeatures.test.js +162 -51
- package/providers/maplibre/src/utils/maplibreFixes.js +10 -0
- package/providers/maplibre/src/utils/maplibreFixes.test.js +31 -0
- package/providers/maplibre/src/utils/patternImages.js +10 -12
- package/providers/maplibre/src/utils/patternImages.test.js +145 -167
- package/providers/maplibre/src/utils/rasteriseToImageData.js +1 -4
- package/providers/maplibre/src/utils/rasteriseToImageData.test.js +23 -24
- package/providers/maplibre/src/utils/symbolImages.js +23 -86
- package/providers/maplibre/src/utils/symbolImages.test.js +60 -105
- package/src/App/components/Actions/Actions.module.scss +1 -0
- package/src/App/components/Actions/Actions.test.jsx +17 -4
- package/src/App/components/Hints/Hints.jsx +52 -0
- package/src/App/components/Hints/Hints.module.scss +37 -0
- package/src/App/components/Hints/Hints.test.jsx +104 -0
- package/src/App/components/KeyboardHelp/KeyboardHelp.jsx +57 -19
- package/src/App/components/KeyboardHelp/KeyboardHelp.module.scss +10 -0
- package/src/App/components/KeyboardHelp/KeyboardHelp.test.jsx +140 -31
- package/src/App/components/Markers/LabelMarker.jsx +14 -0
- package/src/App/components/Markers/LabelMarker.test.jsx +36 -0
- package/src/App/components/Markers/Markers.jsx +44 -75
- package/src/App/components/Markers/Markers.module.scss +58 -0
- package/src/App/components/Markers/Markers.test.jsx +90 -113
- package/src/App/components/Markers/SymbolLabelMarker.jsx +43 -0
- package/src/App/components/Markers/SymbolLabelMarker.test.jsx +56 -0
- package/src/App/components/Markers/SymbolMarker.jsx +31 -0
- package/src/App/components/Markers/SymbolMarker.test.jsx +72 -0
- package/src/App/components/Panel/Panel.jsx +1 -1
- package/src/App/components/Panel/Panel.module.scss +1 -0
- package/src/App/components/PopupMenu/PopupMenu.test.jsx +117 -1
- package/src/App/components/PopupMenu/usePopupMenu.js +132 -85
- package/src/App/components/Tabs/Tabs.jsx +68 -0
- package/src/App/components/Tabs/Tabs.module.scss +57 -0
- package/src/App/components/Tabs/Tabs.test.jsx +121 -0
- package/src/App/components/Tooltip/Tooltip.module.scss +1 -1
- package/src/App/components/Viewport/Features.jsx +35 -0
- package/src/App/components/Viewport/Features.module.scss +31 -0
- package/src/App/components/Viewport/Features.test.jsx +124 -0
- package/src/App/components/Viewport/MapStatus.jsx +0 -4
- package/src/App/components/Viewport/Viewport.jsx +35 -29
- package/src/App/components/Viewport/Viewport.module.scss +7 -21
- package/src/App/components/Viewport/Viewport.test.jsx +108 -65
- package/src/App/controls/keyboardActions.js +9 -3
- package/src/App/controls/keyboardActions.test.js +122 -87
- package/src/App/controls/keyboardShortcuts.js +1 -14
- package/src/App/hooks/useFeatureFocus.js +199 -0
- package/src/App/hooks/useFeatureFocus.test.js +635 -0
- package/src/App/hooks/useFeatureItems.js +30 -0
- package/src/App/hooks/useFeatureItems.test.js +97 -0
- package/src/App/hooks/useFocusVisible.js +4 -7
- package/src/App/hooks/useFocusVisible.test.js +6 -6
- package/src/App/hooks/useKeyboardHint.js +9 -34
- package/src/App/hooks/useKeyboardHint.test.js +34 -84
- package/src/App/hooks/useKeyboardShortcuts.js +8 -5
- package/src/App/hooks/useKeyboardShortcuts.test.js +16 -12
- package/src/App/hooks/useLayoutMeasurements.js +10 -4
- package/src/App/hooks/useLayoutMeasurements.test.js +30 -0
- package/src/App/hooks/useMarkerCursor.js +33 -0
- package/src/App/hooks/useMarkerCursor.test.js +87 -0
- package/src/App/hooks/useMarkersAPI.js +32 -9
- package/src/App/hooks/useMarkersAPI.test.js +162 -94
- package/src/App/layout/Layout.jsx +2 -0
- package/src/App/layout/Layout.test.jsx +3 -0
- package/src/App/registry/keyboardShortcutRegistry.js +3 -2
- package/src/App/registry/keyboardShortcutRegistry.test.js +6 -8
- package/src/App/renderer/mapButtons.js +5 -1
- package/src/App/renderer/mapButtons.test.js +37 -1
- package/src/App/store/ServiceProvider.jsx +4 -1
- package/src/App/store/ServiceProvider.test.jsx +11 -0
- package/src/App/store/appActionsMap.js +5 -1
- package/src/App/store/appActionsMap.test.js +13 -0
- package/src/App/store/appReducer.js +1 -0
- package/src/App/store/mapActionsMap.js +2 -1
- package/src/InteractiveMap/InteractiveMap.js +12 -0
- package/src/InteractiveMap/InteractiveMap.test.js +2 -0
- package/src/config/appConfig.js +3 -1
- package/src/config/appConfig.test.js +4 -0
- package/src/config/defaults.js +1 -1
- package/src/config/events.js +8 -0
- package/src/config/mapTheme.js +8 -4
- package/src/config/symbolConfig.js +23 -16
- package/src/scss/main.scss +3 -0
- package/src/scss/tools/_border-focus.scss +0 -1
- package/src/services/eventBus.js +15 -0
- package/src/services/eventBus.test.js +11 -0
- package/src/services/hints.js +47 -0
- package/src/services/hints.test.js +110 -0
- package/src/services/patternRegistry.js +69 -1
- package/src/services/patternRegistry.test.js +112 -1
- package/src/services/reverseGeocode.js +4 -0
- package/src/services/reverseGeocode.test.js +11 -1
- package/src/services/symbolRegistry.js +152 -17
- package/src/services/symbolRegistry.test.js +141 -31
- package/src/types.js +71 -14
- package/src/utils/constrainKeyboardFocus.js +5 -5
- package/src/utils/detectInterfaceType.js +27 -5
- package/src/utils/detectInterfaceType.test.js +29 -3
- package/src/utils/patternUtils.js +4 -67
- package/src/utils/patternUtils.test.js +1 -123
- package/src/utils/symbolUtils.js +11 -13
- package/src/utils/symbolUtils.test.js +18 -26
- package/plugins/interact/dist/css/index.css +0 -1
- package/plugins/interact/src/interact.scss +0 -24
|
@@ -1,7 +1,9 @@
|
|
|
1
|
-
import { getValueForStyle } from '../utils/getValueForStyle.js'
|
|
2
|
-
|
|
3
1
|
// Border path rendered behind the pattern content in Key panel symbols (20×20 coordinate space).
|
|
4
2
|
export const KEY_BORDER_PATH = '<path d="M19 2.862v14.275c0 1.028-.835 1.862-1.862 1.862H2.863c-1.028 0-1.862-.835-1.862-1.862V2.862C1.001 1.834 1.836 1 2.863 1h14.275C18.166 1 19 1.835 19 2.862z" fill="{{backgroundColor}}" stroke="{{foregroundColor}}" stroke-width="2"/>'
|
|
3
|
+
// Minimum oversampling — keeps 16×16 physical pixels as the floor so patterns remain crisp.
|
|
4
|
+
const PATTERN_MIN_PIXEL_RATIO = 2
|
|
5
|
+
|
|
6
|
+
export const getEffectivePixelRatio = (pixelRatio) => Math.max(PATTERN_MIN_PIXEL_RATIO, pixelRatio * 2)
|
|
5
7
|
|
|
6
8
|
export const hashString = (str) => {
|
|
7
9
|
let hash = 0
|
|
@@ -32,68 +34,3 @@ export const injectColors = (content, foregroundColor, backgroundColor) =>
|
|
|
32
34
|
* @returns {boolean}
|
|
33
35
|
*/
|
|
34
36
|
export const hasPattern = (dataset) => !!(dataset.fillPattern || dataset.fillPatternSvgContent)
|
|
35
|
-
|
|
36
|
-
/**
|
|
37
|
-
* Returns the raw (un-coloured) inner SVG content for a dataset's pattern.
|
|
38
|
-
* Precedence: inline fillPatternSvgContent → named fillPattern from registry.
|
|
39
|
-
*
|
|
40
|
-
* @param {Object} dataset
|
|
41
|
-
* @param {Object} patternRegistry
|
|
42
|
-
* @returns {string|null}
|
|
43
|
-
*/
|
|
44
|
-
export const getPatternInnerContent = (dataset, patternRegistry) => {
|
|
45
|
-
if (dataset.fillPatternSvgContent) {
|
|
46
|
-
return dataset.fillPatternSvgContent
|
|
47
|
-
}
|
|
48
|
-
if (dataset.fillPattern) {
|
|
49
|
-
return patternRegistry?.get(dataset.fillPattern)?.svgContent ?? null
|
|
50
|
-
}
|
|
51
|
-
return null
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
/**
|
|
55
|
-
* Returns a deterministic image ID for a pattern + resolved colour + pixel ratio combination.
|
|
56
|
-
*
|
|
57
|
-
* @param {Object} dataset
|
|
58
|
-
* @param {string} mapStyleId
|
|
59
|
-
* @param {Object} patternRegistry
|
|
60
|
-
* @param {number} [pixelRatio=1]
|
|
61
|
-
* @returns {string|null}
|
|
62
|
-
*/
|
|
63
|
-
// Minimum oversampling — keeps 16×16 physical pixels as the floor so patterns remain crisp.
|
|
64
|
-
export const PATTERN_MIN_PIXEL_RATIO = 2
|
|
65
|
-
|
|
66
|
-
export const getPatternImageId = (dataset, mapStyleId, patternRegistry, pixelRatio = 1) => {
|
|
67
|
-
const innerContent = getPatternInnerContent(dataset, patternRegistry)
|
|
68
|
-
if (!innerContent) {
|
|
69
|
-
return null
|
|
70
|
-
}
|
|
71
|
-
const fg = getValueForStyle(dataset.fillPatternForegroundColor, mapStyleId) || 'black'
|
|
72
|
-
const bg = getValueForStyle(dataset.fillPatternBackgroundColor, mapStyleId) || 'transparent'
|
|
73
|
-
const effectiveRatio = Math.max(PATTERN_MIN_PIXEL_RATIO, pixelRatio)
|
|
74
|
-
return `pattern-${hashString(innerContent + fg + bg)}-${effectiveRatio}x`
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
/**
|
|
78
|
-
* Returns colour-injected SVG path content for use in Key panel pattern symbols.
|
|
79
|
-
* Returns { border, content } where border is the rounded-rect outline and content
|
|
80
|
-
* is the pattern fill. Returns null if the dataset has no pattern.
|
|
81
|
-
*
|
|
82
|
-
* @param {Object} dataset
|
|
83
|
-
* @param {string} mapStyleId
|
|
84
|
-
* @param {Object} patternRegistry
|
|
85
|
-
* @returns {{ border: string, content: string }|null}
|
|
86
|
-
*/
|
|
87
|
-
export const getKeyPatternPaths = (dataset, mapStyleId, patternRegistry) => {
|
|
88
|
-
const innerContent = getPatternInnerContent(dataset, patternRegistry)
|
|
89
|
-
if (!innerContent) {
|
|
90
|
-
return null
|
|
91
|
-
}
|
|
92
|
-
const fg = getValueForStyle(dataset.fillPatternForegroundColor, mapStyleId) || 'black'
|
|
93
|
-
const bg = getValueForStyle(dataset.fillPatternBackgroundColor, mapStyleId) || 'transparent'
|
|
94
|
-
const borderStroke = getValueForStyle(dataset.stroke, mapStyleId) || fg
|
|
95
|
-
return {
|
|
96
|
-
border: injectColors(KEY_BORDER_PATH, borderStroke, bg),
|
|
97
|
-
content: injectColors(innerContent, fg, bg)
|
|
98
|
-
}
|
|
99
|
-
}
|
|
@@ -1,17 +1,9 @@
|
|
|
1
1
|
import {
|
|
2
2
|
hashString,
|
|
3
3
|
injectColors,
|
|
4
|
-
hasPattern
|
|
5
|
-
getPatternInnerContent,
|
|
6
|
-
getPatternImageId,
|
|
7
|
-
getKeyPatternPaths,
|
|
8
|
-
KEY_BORDER_PATH
|
|
4
|
+
hasPattern
|
|
9
5
|
} from './patternUtils.js'
|
|
10
6
|
|
|
11
|
-
const mockRegistry = {
|
|
12
|
-
get: (id) => id === 'dot' ? { id: 'dot', svgContent: '<path d="M4 4" fill="{{foregroundColor}}"/>' } : undefined
|
|
13
|
-
}
|
|
14
|
-
|
|
15
7
|
describe('hashString', () => {
|
|
16
8
|
test('returns a non-empty string', () => {
|
|
17
9
|
expect(typeof hashString('hello')).toBe('string')
|
|
@@ -61,117 +53,3 @@ describe('hasPattern', () => {
|
|
|
61
53
|
expect(hasPattern({ fill: 'red' })).toBe(false)
|
|
62
54
|
})
|
|
63
55
|
})
|
|
64
|
-
|
|
65
|
-
describe('getPatternInnerContent', () => {
|
|
66
|
-
test('returns fillPatternSvgContent when set (inline SVG takes precedence)', () => {
|
|
67
|
-
const dataset = { fillPatternSvgContent: '<path d="custom"/>', fillPattern: 'dot' }
|
|
68
|
-
expect(getPatternInnerContent(dataset, mockRegistry)).toBe('<path d="custom"/>')
|
|
69
|
-
})
|
|
70
|
-
|
|
71
|
-
test('returns svgContent from registry for a named fillPattern', () => {
|
|
72
|
-
const dataset = { fillPattern: 'dot' }
|
|
73
|
-
expect(getPatternInnerContent(dataset, mockRegistry)).toBe('<path d="M4 4" fill="{{foregroundColor}}"/>')
|
|
74
|
-
})
|
|
75
|
-
|
|
76
|
-
test('returns null for an unregistered fillPattern name', () => {
|
|
77
|
-
const dataset = { fillPattern: 'unknown-pattern' }
|
|
78
|
-
expect(getPatternInnerContent(dataset, mockRegistry)).toBeNull()
|
|
79
|
-
})
|
|
80
|
-
|
|
81
|
-
test('returns null when no pattern is configured', () => {
|
|
82
|
-
expect(getPatternInnerContent({}, mockRegistry)).toBeNull()
|
|
83
|
-
})
|
|
84
|
-
})
|
|
85
|
-
|
|
86
|
-
describe('getPatternImageId', () => {
|
|
87
|
-
test('returns a deterministic string id', () => {
|
|
88
|
-
const dataset = { fillPattern: 'dot', fillPatternForegroundColor: 'red', fillPatternBackgroundColor: 'blue' }
|
|
89
|
-
const id = getPatternImageId(dataset, 'style-a', mockRegistry)
|
|
90
|
-
expect(typeof id).toBe('string')
|
|
91
|
-
expect(id).toMatch(/^pattern-/)
|
|
92
|
-
expect(id).toBe(getPatternImageId(dataset, 'style-a', mockRegistry))
|
|
93
|
-
})
|
|
94
|
-
|
|
95
|
-
test('returns null when no pattern content is found', () => {
|
|
96
|
-
expect(getPatternImageId({ fillPattern: 'unknown' }, 'style-a', mockRegistry)).toBeNull()
|
|
97
|
-
})
|
|
98
|
-
|
|
99
|
-
test('produces different ids for different colours', () => {
|
|
100
|
-
const base = { fillPattern: 'dot' }
|
|
101
|
-
const idA = getPatternImageId({ ...base, fillPatternForegroundColor: 'red' }, 'style-a', mockRegistry)
|
|
102
|
-
const idB = getPatternImageId({ ...base, fillPatternForegroundColor: 'blue' }, 'style-a', mockRegistry)
|
|
103
|
-
expect(idA).not.toBe(idB)
|
|
104
|
-
})
|
|
105
|
-
|
|
106
|
-
test('floors effective ratio at PATTERN_MIN_PIXEL_RATIO so low-DPI ids match 2x', () => {
|
|
107
|
-
const dataset = { fillPattern: 'dot' }
|
|
108
|
-
const id1x = getPatternImageId(dataset, 'style-a', mockRegistry, 1)
|
|
109
|
-
const id2x = getPatternImageId(dataset, 'style-a', mockRegistry, 2)
|
|
110
|
-
expect(id1x).toBe(id2x)
|
|
111
|
-
expect(id1x).toMatch(/-2x$/)
|
|
112
|
-
})
|
|
113
|
-
|
|
114
|
-
test('produces different ids for pixelRatios above the floor', () => {
|
|
115
|
-
const dataset = { fillPattern: 'dot' }
|
|
116
|
-
const id2x = getPatternImageId(dataset, 'style-a', mockRegistry, 2)
|
|
117
|
-
const id3x = getPatternImageId(dataset, 'style-a', mockRegistry, 3)
|
|
118
|
-
expect(id2x).not.toBe(id3x)
|
|
119
|
-
expect(id2x).toMatch(/-2x$/)
|
|
120
|
-
expect(id3x).toMatch(/-3x$/)
|
|
121
|
-
})
|
|
122
|
-
|
|
123
|
-
test('falls back to "black" foreground and "transparent" background when colours are absent', () => {
|
|
124
|
-
const id = getPatternImageId({ fillPattern: 'dot' }, 'style-a', mockRegistry)
|
|
125
|
-
const idExplicit = getPatternImageId(
|
|
126
|
-
{ fillPattern: 'dot', fillPatternForegroundColor: 'black', fillPatternBackgroundColor: 'transparent' },
|
|
127
|
-
'style-a',
|
|
128
|
-
mockRegistry
|
|
129
|
-
)
|
|
130
|
-
expect(id).toBe(idExplicit)
|
|
131
|
-
})
|
|
132
|
-
})
|
|
133
|
-
|
|
134
|
-
describe('getKeyPatternPaths', () => {
|
|
135
|
-
test('returns border and content strings with colours injected', () => {
|
|
136
|
-
const dataset = {
|
|
137
|
-
fillPattern: 'dot',
|
|
138
|
-
fillPatternForegroundColor: 'red',
|
|
139
|
-
fillPatternBackgroundColor: 'white',
|
|
140
|
-
stroke: 'black'
|
|
141
|
-
}
|
|
142
|
-
const result = getKeyPatternPaths(dataset, 'style-a', mockRegistry)
|
|
143
|
-
expect(result).not.toBeNull()
|
|
144
|
-
expect(result.border).toContain('black') // stroke colour
|
|
145
|
-
expect(result.border).toContain('white') // background colour
|
|
146
|
-
expect(result.content).toContain('red') // foreground colour
|
|
147
|
-
expect(result.border).not.toContain('{{foregroundColor}}')
|
|
148
|
-
expect(result.content).not.toContain('{{foregroundColor}}')
|
|
149
|
-
})
|
|
150
|
-
|
|
151
|
-
test('returns null when no pattern content is found', () => {
|
|
152
|
-
expect(getKeyPatternPaths({ fillPattern: 'unknown' }, 'style-a', mockRegistry)).toBeNull()
|
|
153
|
-
})
|
|
154
|
-
|
|
155
|
-
test('falls back to "black" fg and "transparent" bg when colour properties are absent', () => {
|
|
156
|
-
const result = getKeyPatternPaths({ fillPattern: 'dot' }, 'style-a', mockRegistry)
|
|
157
|
-
expect(result).not.toBeNull()
|
|
158
|
-
expect(result.content).toContain('black')
|
|
159
|
-
expect(result.border).toContain('transparent')
|
|
160
|
-
})
|
|
161
|
-
|
|
162
|
-
test('border stroke falls back to foreground colour when stroke is absent', () => {
|
|
163
|
-
const result = getKeyPatternPaths(
|
|
164
|
-
{ fillPattern: 'dot', fillPatternForegroundColor: 'green' },
|
|
165
|
-
'style-a',
|
|
166
|
-
mockRegistry
|
|
167
|
-
)
|
|
168
|
-
expect(result).not.toBeNull()
|
|
169
|
-
// borderStroke falls back to fg ('green'), so the border uses green for both stroke and background
|
|
170
|
-
expect(result.border).toContain('green')
|
|
171
|
-
})
|
|
172
|
-
|
|
173
|
-
test('KEY_BORDER_PATH contains foregroundColor and backgroundColor tokens', () => {
|
|
174
|
-
expect(KEY_BORDER_PATH).toContain('{{foregroundColor}}')
|
|
175
|
-
expect(KEY_BORDER_PATH).toContain('{{backgroundColor}}')
|
|
176
|
-
})
|
|
177
|
-
})
|
package/src/utils/symbolUtils.js
CHANGED
|
@@ -14,23 +14,21 @@ const SYMBOL_STYLE_PROPS = new Set([
|
|
|
14
14
|
export const hasSymbol = (dataset) => !!(dataset.symbol || dataset.symbolSvgContent)
|
|
15
15
|
|
|
16
16
|
/**
|
|
17
|
-
*
|
|
17
|
+
* Returns true if a marker item should render as a standalone label with no symbol.
|
|
18
|
+
* Requires label content and at least one of symbol/symbolSvgContent to be explicitly null.
|
|
19
|
+
* Undefined values fall through to render-time default symbol resolution.
|
|
18
20
|
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
* @param {Object} dataset
|
|
23
|
-
* @param {Object} symbolRegistry
|
|
24
|
-
* @returns {Object|undefined}
|
|
21
|
+
* @param {Object} marker
|
|
22
|
+
* @returns {boolean}
|
|
25
23
|
*/
|
|
26
|
-
export const
|
|
27
|
-
if (
|
|
28
|
-
return
|
|
24
|
+
export const isStandaloneLabel = (marker) => {
|
|
25
|
+
if (!marker.label) {
|
|
26
|
+
return false
|
|
29
27
|
}
|
|
30
|
-
if (
|
|
31
|
-
return
|
|
28
|
+
if (marker.symbol || marker.symbolSvgContent) {
|
|
29
|
+
return false
|
|
32
30
|
}
|
|
33
|
-
return
|
|
31
|
+
return marker.symbol === null || marker.symbolSvgContent === null
|
|
34
32
|
}
|
|
35
33
|
|
|
36
34
|
/**
|
|
@@ -1,15 +1,11 @@
|
|
|
1
1
|
import {
|
|
2
2
|
hasSymbol,
|
|
3
|
-
|
|
3
|
+
isStandaloneLabel,
|
|
4
4
|
getSymbolStyleColors,
|
|
5
5
|
getSymbolViewBox,
|
|
6
6
|
getSymbolAnchor
|
|
7
7
|
} from './symbolUtils.js'
|
|
8
8
|
|
|
9
|
-
const mockRegistry = (defs = {}) => ({
|
|
10
|
-
get: jest.fn((id) => defs[id])
|
|
11
|
-
})
|
|
12
|
-
|
|
13
9
|
// ─── hasSymbol ────────────────────────────────────────────────────────────────
|
|
14
10
|
|
|
15
11
|
describe('hasSymbol', () => {
|
|
@@ -30,34 +26,32 @@ describe('hasSymbol', () => {
|
|
|
30
26
|
})
|
|
31
27
|
})
|
|
32
28
|
|
|
33
|
-
// ───
|
|
29
|
+
// ─── isStandaloneLabel ────────────────────────────────────────────────────────
|
|
30
|
+
|
|
31
|
+
describe('isStandaloneLabel', () => {
|
|
32
|
+
it('returns false when marker has no label', () => {
|
|
33
|
+
expect(isStandaloneLabel({})).toBe(false)
|
|
34
|
+
expect(isStandaloneLabel({ symbol: null })).toBe(false)
|
|
35
|
+
})
|
|
34
36
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
expect(getSymbolDef({}, mockRegistry())).toBeUndefined()
|
|
37
|
+
it('returns false when marker has a truthy symbol string (line 28)', () => {
|
|
38
|
+
expect(isStandaloneLabel({ label: 'My label', symbol: 'pin' })).toBe(false)
|
|
38
39
|
})
|
|
39
40
|
|
|
40
|
-
it('
|
|
41
|
-
|
|
42
|
-
const registry = mockRegistry({ pin: pinDef })
|
|
43
|
-
expect(getSymbolDef({ symbol: 'pin' }, registry)).toBe(pinDef)
|
|
41
|
+
it('returns false when marker has symbolSvgContent (line 28)', () => {
|
|
42
|
+
expect(isStandaloneLabel({ label: 'My label', symbolSvgContent: '<circle/>' })).toBe(false)
|
|
44
43
|
})
|
|
45
44
|
|
|
46
|
-
it('returns
|
|
47
|
-
expect(
|
|
45
|
+
it('returns false when label is present but both symbol and symbolSvgContent are undefined (line 31)', () => {
|
|
46
|
+
expect(isStandaloneLabel({ label: 'My label' })).toBe(false)
|
|
48
47
|
})
|
|
49
48
|
|
|
50
|
-
it('returns
|
|
51
|
-
|
|
52
|
-
const result = getSymbolDef(dataset, mockRegistry())
|
|
53
|
-
expect(result.svg).toBe('<circle/>')
|
|
49
|
+
it('returns true when label is present and symbol is explicitly null (line 31)', () => {
|
|
50
|
+
expect(isStandaloneLabel({ label: 'My label', symbol: null })).toBe(true)
|
|
54
51
|
})
|
|
55
52
|
|
|
56
|
-
it('symbolSvgContent
|
|
57
|
-
|
|
58
|
-
const registry = mockRegistry({ pin: pinDef })
|
|
59
|
-
const result = getSymbolDef({ symbol: 'pin', symbolSvgContent: '<circle/>' }, registry)
|
|
60
|
-
expect(result.svg).toBe('<circle/>')
|
|
53
|
+
it('returns true when label is present and symbolSvgContent is explicitly null (line 31)', () => {
|
|
54
|
+
expect(isStandaloneLabel({ label: 'My label', symbolSvgContent: null })).toBe(true)
|
|
61
55
|
})
|
|
62
56
|
})
|
|
63
57
|
|
|
@@ -77,13 +71,11 @@ describe('getSymbolStyleColors', () => {
|
|
|
77
71
|
symbol: 'pin',
|
|
78
72
|
symbolBackgroundColor: '#ff0000',
|
|
79
73
|
symbolForegroundColor: '#ffffff',
|
|
80
|
-
symbolHaloWidth: '2',
|
|
81
74
|
symbolGraphic: 'cross'
|
|
82
75
|
}
|
|
83
76
|
expect(getSymbolStyleColors(dataset)).toEqual({
|
|
84
77
|
backgroundColor: '#ff0000',
|
|
85
78
|
foregroundColor: '#ffffff',
|
|
86
|
-
haloWidth: '2',
|
|
87
79
|
graphic: 'cross'
|
|
88
80
|
})
|
|
89
81
|
})
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
.im-c-mark-location{display:flex;justify-content:center;gap:var(--divider-gap)}.im-o-app--mobile .im-c-mark-location .im-c-button-wrapper,.im-o-app--mobile .im-c-mark-location .im-c-map-button{flex:1 1 auto;min-width:fit-content}.im-o-app--mouse.im-o-app--tablet .im-c-mark-location .im-c-map-button,.im-o-app--mouse.im-o-app--desktop .im-c-mark-location .im-c-map-button{min-width:150px}.im-o-app--mobile .im-c-mark-location .im-c-map-button{flex:1 1 auto;min-width:fit-content}
|
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
.im-c-mark-location {
|
|
2
|
-
display: flex;
|
|
3
|
-
justify-content: center;
|
|
4
|
-
gap: var(--divider-gap);
|
|
5
|
-
}
|
|
6
|
-
|
|
7
|
-
.im-o-app--mobile .im-c-mark-location {
|
|
8
|
-
.im-c-button-wrapper, .im-c-map-button {
|
|
9
|
-
flex: 1 1 auto;
|
|
10
|
-
min-width: fit-content;
|
|
11
|
-
}
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
.im-o-app--mouse.im-o-app--tablet,
|
|
15
|
-
.im-o-app--mouse.im-o-app--desktop {
|
|
16
|
-
.im-c-mark-location .im-c-map-button {
|
|
17
|
-
min-width: 150px;
|
|
18
|
-
}
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
.im-o-app--mobile .im-c-mark-location .im-c-map-button {
|
|
22
|
-
flex: 1 1 auto;
|
|
23
|
-
min-width: fit-content;
|
|
24
|
-
}
|