@defra/interactive-map 0.0.30-alpha → 0.0.31-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.
Files changed (192) hide show
  1. package/dist/css/index.css +1 -1
  2. package/dist/esm/im-core.js +1 -1
  3. package/dist/esm/im-shell.js +1 -1
  4. package/dist/umd/im-core.js +1 -1
  5. package/dist/umd/index.js +1 -1
  6. package/docs/api/context.md +4 -4
  7. package/docs/api.md +111 -37
  8. package/docs/assets/css/docusaurus.scss +20 -4
  9. package/docs/assets/images/basic-map.jpg +0 -0
  10. package/docs/assets/images/button-first.jpg +0 -0
  11. package/docs/assets/images/deuteranopia-ozs-map-thumb.jpg +0 -0
  12. package/docs/assets/images/draw.jpg +0 -0
  13. package/docs/assets/images/marker-panel.jpg +0 -0
  14. package/docs/assets/images/night-ozs-map-thumb.jpg +0 -0
  15. package/docs/assets/images/outdoor-ozs-map-thumb.jpg +0 -0
  16. package/docs/assets/images/search.jpg +0 -0
  17. package/docs/assets/images/select-feature.jpg +0 -0
  18. package/docs/assets/images/style-switcher.jpg +0 -0
  19. package/docs/assets/images/toggle-marker-label.jpg +0 -0
  20. package/docs/assets/images/tritanopia-ozs-map-thumb.jpg +0 -0
  21. package/docs/examples/add-marker-with-panel.mdx +2 -2
  22. package/docs/examples/basic-map.mdx +2 -2
  23. package/docs/examples/draw.mdx +271 -0
  24. package/docs/examples/index.mdx +58 -10
  25. package/docs/examples/search-control.mdx +71 -0
  26. package/docs/examples/select-feature.mdx +146 -0
  27. package/docs/examples/style-switcher.mdx +135 -0
  28. package/docs/examples/toggle-marker-label.mdx +3 -3
  29. package/docs/plugins/datasets.md +15 -28
  30. package/docusaurus.config.cjs +5 -1
  31. package/package.json +1 -1
  32. package/plugins/beta/datasets/dist/css/index.css +4 -0
  33. package/plugins/beta/datasets/dist/esm/im-datasets-ml-adapter.js +1 -0
  34. package/plugins/beta/datasets/dist/esm/im-datasets-plugin.js +1 -1
  35. package/plugins/beta/datasets/dist/esm/index.js +1 -1
  36. package/plugins/beta/datasets/dist/umd/im-datasets-ml-adapter.js +2 -0
  37. package/plugins/beta/datasets/dist/umd/im-datasets-plugin.js +2 -0
  38. package/plugins/beta/datasets/dist/umd/index.js +2 -0
  39. package/plugins/beta/datasets/src/adapters/loadLayerAdapter.js +33 -0
  40. package/plugins/beta/datasets/src/adapters/maplibre/layerBuilders.js +44 -120
  41. package/plugins/beta/datasets/src/adapters/maplibre/maplibreLayerAdapter.js +145 -245
  42. package/plugins/beta/datasets/src/adapters/maplibre/maplibreLayerAdapter.test.js +516 -0
  43. package/plugins/beta/datasets/src/adapters/maplibre/registry/mapLibreDataset.js +191 -0
  44. package/plugins/beta/datasets/src/adapters/maplibre/registry/mapLibreDataset.test.js +441 -0
  45. package/plugins/beta/datasets/src/api/addDataset.js +2 -5
  46. package/plugins/beta/datasets/src/api/addDataset.test.js +16 -0
  47. package/plugins/beta/datasets/src/api/getOpacity.js +14 -14
  48. package/plugins/beta/datasets/src/api/getOpacity.test.js +72 -0
  49. package/plugins/beta/datasets/src/api/getStyle.js +8 -9
  50. package/plugins/beta/datasets/src/api/getStyle.test.js +42 -0
  51. package/plugins/beta/datasets/src/api/removeDataset.js +7 -7
  52. package/plugins/beta/datasets/src/api/removeDataset.test.js +45 -0
  53. package/plugins/beta/datasets/src/api/setData.js +9 -3
  54. package/plugins/beta/datasets/src/api/setData.test.js +62 -0
  55. package/plugins/beta/datasets/src/api/setDatasetVisibility.js +5 -30
  56. package/plugins/beta/datasets/src/api/setDatasetVisibility.test.js +31 -0
  57. package/plugins/beta/datasets/src/api/setFeatureVisibility.js +3 -21
  58. package/plugins/beta/datasets/src/api/setFeatureVisibility.test.js +32 -0
  59. package/plugins/beta/datasets/src/api/setGlobals.js +20 -0
  60. package/plugins/beta/datasets/src/api/setGlobals.test.js +63 -0
  61. package/plugins/beta/datasets/src/api/setOpacity.js +8 -27
  62. package/plugins/beta/datasets/src/api/setOpacity.test.js +31 -0
  63. package/plugins/beta/datasets/src/api/setStyle.js +5 -21
  64. package/plugins/beta/datasets/src/api/setStyle.test.js +53 -0
  65. package/plugins/beta/datasets/src/components/Key/Key.jsx +51 -0
  66. package/plugins/beta/datasets/src/components/Key/KeyGroupItem.jsx +18 -0
  67. package/plugins/beta/datasets/src/components/Key/KeyItem.jsx +20 -0
  68. package/plugins/beta/datasets/src/components/Key/KeySvg.jsx +22 -0
  69. package/plugins/beta/datasets/src/components/Key/KeySvg.test.jsx +87 -0
  70. package/plugins/beta/datasets/src/components/Key/KeySvgLine.jsx +19 -0
  71. package/plugins/beta/datasets/src/components/Key/KeySvgLine.test.jsx +71 -0
  72. package/plugins/beta/datasets/src/components/{KeySvgPattern.jsx → Key/KeySvgPattern.jsx} +3 -4
  73. package/plugins/beta/datasets/src/components/Key/KeySvgPattern.test.jsx +55 -0
  74. package/plugins/beta/datasets/src/components/Key/KeySvgRect.jsx +22 -0
  75. package/plugins/beta/datasets/src/components/Key/KeySvgRect.test.jsx +85 -0
  76. package/plugins/beta/datasets/src/components/{KeySvgSymbol.jsx → Key/KeySvgSymbol.jsx} +5 -5
  77. package/plugins/beta/datasets/src/components/Key/KeySvgSymbol.test.jsx +80 -0
  78. package/plugins/beta/datasets/src/components/Key/svgProperties.test.js +61 -0
  79. package/plugins/beta/datasets/src/{panels → components/LayersMenu}/Layers.module.scss +4 -0
  80. package/plugins/beta/datasets/src/components/LayersMenu/LayersMenu.jsx +33 -0
  81. package/plugins/beta/datasets/src/components/LayersMenu/LayersMenuCheckbox.jsx +31 -0
  82. package/plugins/beta/datasets/src/components/LayersMenu/LayersMenuGroupWrapper.jsx +19 -0
  83. package/plugins/beta/datasets/src/datasets.scss +2 -2
  84. package/plugins/beta/datasets/src/fetch/createDynamicSource.js +8 -8
  85. package/plugins/beta/datasets/src/{DatasetsInit.jsx → initialise/DatasetsInit.jsx} +19 -21
  86. package/plugins/beta/datasets/src/{defaults.js → initialise/defaults.js} +17 -2
  87. package/plugins/beta/datasets/src/initialise/defaults.test.js +127 -0
  88. package/plugins/beta/datasets/src/{datasets.js → initialise/initialiseDatasets.js} +30 -26
  89. package/plugins/beta/datasets/src/initialise/initialiseDatasets.test.js +273 -0
  90. package/plugins/beta/datasets/src/manifest.js +8 -6
  91. package/plugins/beta/datasets/src/reducers/__data__/demoDatasets.js +253 -0
  92. package/plugins/beta/datasets/src/reducers/datasetsToMenu.js +78 -0
  93. package/plugins/beta/datasets/src/reducers/datasetsToMenu.test.js +35 -0
  94. package/plugins/beta/datasets/src/reducers/mappedDatasetsReducer.js +34 -0
  95. package/plugins/beta/datasets/src/reducers/mappedDatasetsReducer.test.js +117 -0
  96. package/plugins/beta/datasets/src/reducers/pluginState.js +206 -0
  97. package/plugins/beta/datasets/src/reducers/pluginState.test.js +386 -0
  98. package/plugins/beta/datasets/src/registry/__mocks__/datasetRegistry.js +29 -0
  99. package/plugins/beta/datasets/src/registry/createDataset.js +5 -0
  100. package/plugins/beta/datasets/src/registry/dataset.js +172 -0
  101. package/plugins/beta/datasets/src/registry/dataset.test.js +483 -0
  102. package/plugins/beta/datasets/src/registry/datasetDefinitionCache.js +35 -0
  103. package/plugins/beta/datasets/src/registry/datasetRegistry.js +116 -0
  104. package/plugins/beta/datasets/src/registry/datasetRegistry.test.js +335 -0
  105. package/plugins/beta/datasets/src/registry/dynamicGeoJson.js +17 -0
  106. package/plugins/beta/datasets/src/registry/globalDataset.js +36 -0
  107. package/plugins/beta/draw-ml/dist/esm/im-draw-ml-plugin.js +1 -1
  108. package/plugins/beta/draw-ml/dist/umd/im-draw-ml-plugin.js +1 -1
  109. package/plugins/beta/draw-ml/src/events.js +13 -1
  110. package/plugins/beta/draw-ml/src/index.js +1 -1
  111. package/plugins/beta/draw-ml/src/manifest.js +3 -0
  112. package/plugins/interact/dist/esm/im-interact-plugin.js +1 -1
  113. package/plugins/interact/dist/umd/im-interact-plugin.js +1 -1
  114. package/plugins/interact/src/InteractInit.jsx +2 -2
  115. package/plugins/interact/src/InteractInit.test.js +1 -1
  116. package/plugins/interact/src/events.js +2 -29
  117. package/plugins/interact/src/events.test.js +4 -102
  118. package/plugins/interact/src/hooks/useAttachEvents.js +3 -4
  119. package/plugins/interact/src/hooks/useAttachEvents.test.js +1 -3
  120. package/plugins/interact/src/hooks/useInteractionHandlers.js +10 -1
  121. package/plugins/interact/src/hooks/useInteractionHandlers.test.js +23 -4
  122. package/plugins/interact/src/manifest.js +0 -35
  123. package/plugins/interact/src/manifest.test.js +3 -43
  124. package/providers/beta/esri/dist/esm/im-esri-provider.js +1 -1
  125. package/providers/beta/esri/src/esriProvider.js +4 -0
  126. package/providers/beta/openlayers/dist/esm/im-openlayers-provider.js +1 -1
  127. package/providers/beta/openlayers/dist/umd/im-openlayers-provider.js +1 -1
  128. package/providers/beta/openlayers/src/openlayersProvider.js +4 -0
  129. package/providers/beta/openlayers/src/openlayersProvider.test.js +5 -0
  130. package/providers/maplibre/dist/esm/im-maplibre-provider.js +1 -1
  131. package/providers/maplibre/dist/umd/im-maplibre-provider.js +1 -1
  132. package/providers/maplibre/src/maplibreProvider.js +6 -4
  133. package/providers/maplibre/src/maplibreProvider.test.js +5 -0
  134. package/providers/maplibre/src/utils/highlightFeatures.js +74 -25
  135. package/providers/maplibre/src/utils/highlightFeatures.test.js +132 -0
  136. package/providers/maplibre/src/utils/patternImages.js +2 -4
  137. package/providers/maplibre/src/utils/symbolImages.js +1 -4
  138. package/rollup.esm.mjs +2 -8
  139. package/src/App/components/MapButton/MapButton.jsx +16 -1
  140. package/src/App/components/MapButton/MapButton.module.scss +12 -1
  141. package/src/App/components/MapButton/MapButton.test.jsx +40 -1
  142. package/src/App/hooks/useContinueEnabledEvaluator.js +31 -0
  143. package/src/App/hooks/useContinueEnabledEvaluator.test.js +118 -0
  144. package/src/App/hooks/useEvaluateProp.js +15 -15
  145. package/src/App/hooks/useEvaluateProp.test.js +80 -76
  146. package/src/App/hooks/useLayoutMeasurements.js +1 -3
  147. package/src/App/hooks/useResizeObserver.js +12 -1
  148. package/src/App/hooks/useResizeObserver.test.js +1 -0
  149. package/src/App/renderer/PluginInits.jsx +2 -0
  150. package/src/App/renderer/mapButtons.js +21 -1
  151. package/src/App/renderer/mapButtons.test.js +46 -1
  152. package/src/App/store/appReducer.js +1 -1
  153. package/src/App/store/appReducer.test.js +37 -0
  154. package/src/InteractiveMap/InteractiveMap.js +10 -0
  155. package/src/InteractiveMap/InteractiveMap.test.js +8 -0
  156. package/src/config/appConfig.js +25 -0
  157. package/src/config/appConfig.test.js +50 -0
  158. package/src/config/defaults.js +1 -0
  159. package/src/scss/settings/_dimensions.scss +1 -0
  160. package/src/services/patternRegistry.js +8 -4
  161. package/src/types.js +7 -0
  162. package/src/utils/patternUtils.js +1 -2
  163. package/src/utils/patternUtils.test.js +9 -0
  164. package/webpack.dev.mjs +10 -0
  165. package/webpack.umd.mjs +1 -1
  166. package/plugins/beta/datasets/dist/adapters/maplibre/esm/im-datasets-ml-adapter.js +0 -1
  167. package/plugins/beta/datasets/dist/adapters/maplibre/esm/index.js +0 -1
  168. package/plugins/beta/datasets/dist/umd/maplibre/im-datasets-maplibre-adapter.js +0 -2
  169. package/plugins/beta/datasets/dist/umd/maplibre/im-datasets-plugin.js +0 -2
  170. package/plugins/beta/datasets/dist/umd/maplibre/index.js +0 -2
  171. package/plugins/beta/datasets/src/adapters/maplibre/index.js +0 -18
  172. package/plugins/beta/datasets/src/adapters/maplibre/layerIds.js +0 -75
  173. package/plugins/beta/datasets/src/adapters/maplibre/patternImages.js +0 -27
  174. package/plugins/beta/datasets/src/adapters/maplibre/symbolImages.js +0 -31
  175. package/plugins/beta/datasets/src/components/KeySvg.jsx +0 -24
  176. package/plugins/beta/datasets/src/components/KeySvgLine.jsx +0 -19
  177. package/plugins/beta/datasets/src/components/KeySvgRect.jsx +0 -22
  178. package/plugins/beta/datasets/src/index.maplibre.umd.js +0 -23
  179. package/plugins/beta/datasets/src/panels/Key.jsx +0 -62
  180. package/plugins/beta/datasets/src/panels/Layers.jsx +0 -141
  181. package/plugins/beta/datasets/src/reducer.js +0 -219
  182. package/plugins/beta/datasets/src/reducers/keyReducer.js +0 -34
  183. package/plugins/beta/datasets/src/utils/filters.js +0 -34
  184. package/plugins/beta/datasets/src/utils/mergeSublayer.js +0 -86
  185. package/plugins/beta/draw-ml/dist/css/index.css +0 -21
  186. /package/plugins/beta/datasets/dist/umd/{maplibre/im-datasets-maplibre-adapter.js.LICENSE.txt → im-datasets-ml-adapter.js.LICENSE.txt} +0 -0
  187. /package/plugins/beta/datasets/dist/umd/{maplibre/im-datasets-plugin.js.LICENSE.txt → im-datasets-plugin.js.LICENSE.txt} +0 -0
  188. /package/plugins/beta/datasets/dist/umd/{maplibre/index.js.LICENSE.txt → index.js.LICENSE.txt} +0 -0
  189. /package/plugins/beta/datasets/src/components/{EmptyKey.jsx → Key/EmptyKey.jsx} +0 -0
  190. /package/plugins/beta/datasets/src/components/{EmptyKey.test.jsx → Key/EmptyKey.test.jsx} +0 -0
  191. /package/plugins/beta/datasets/src/{panels → components/Key}/Key.module.scss +0 -0
  192. /package/plugins/beta/datasets/src/components/{svgProperties.js → Key/svgProperties.js} +0 -0
@@ -1,62 +0,0 @@
1
- import React from 'react'
2
- import { getValueForStyle } from '../../../../../src/utils/getValueForStyle'
3
- import { mergeSublayer } from '../utils/mergeSublayer.js'
4
- import { EmptyKey } from '../components/EmptyKey.jsx'
5
- import { KeySvg } from '../components/KeySvg.jsx'
6
-
7
- export const Key = ({ pluginConfig, mapState, pluginState, services }) => {
8
- if (!pluginState?.key?.items?.length) {
9
- return (<EmptyKey text={pluginConfig.noKeyItemText} />)
10
- }
11
- const { mapStyle } = mapState
12
- const { symbolRegistry, patternRegistry } = services
13
-
14
- const renderEntry = (key, config) => (
15
- <dl key={key} className='im-c-datasets-key__item'>
16
- <dt className='im-c-datasets-key__item-symbol'>
17
- <KeySvg {...config} symbolRegistry={symbolRegistry} patternRegistry={patternRegistry} mapStyle={mapStyle} />
18
- </dt>
19
- <dd className='im-c-datasets-key__item-label'>
20
- {config.label}
21
- {config.symbolDescription && (
22
- <span className='govuk-visually-hidden'>
23
- ({getValueForStyle(config.symbolDescription, mapStyle.id)})
24
- </span>
25
- )}
26
- </dd>
27
- </dl>
28
- )
29
-
30
- const { items: keyGroups, hasGroups } = pluginState.key
31
- const containerClass = `im-c-datasets-key${hasGroups ? ' im-c-datasets-key--has-groups' : ''}`
32
-
33
- return (
34
- <div className={containerClass}>
35
- {keyGroups.map(item => {
36
- if (item.type === 'sublayers') {
37
- const headingId = `key-heading-${item.dataset.id}`
38
- return (
39
- <section key={item.dataset.id} className='im-c-datasets-key__group' aria-labelledby={headingId}>
40
- <h3 id={headingId} className='im-c-datasets-key__group-heading'>{item.dataset.label}</h3>
41
- {item.dataset.sublayers
42
- .filter(sublayer => item.dataset.sublayerVisibility?.[sublayer.id] !== 'hidden')
43
- .map(sublayer => renderEntry(`${item.dataset.id}-${sublayer.id}`, mergeSublayer(item.dataset, sublayer)))}
44
- </section>
45
- )
46
- }
47
-
48
- if (item.type === 'group') {
49
- const headingId = `key-heading-${item.groupLabel.toLowerCase().replaceAll(/\s+/g, '-')}`
50
- return (
51
- <section key={item.groupLabel} className='im-c-datasets-key__group' aria-labelledby={headingId}>
52
- <h3 id={headingId} className='im-c-datasets-key__group-heading'>{item.groupLabel}</h3>
53
- {item.datasets.map(dataset => renderEntry(dataset.id, dataset))}
54
- </section>
55
- )
56
- }
57
-
58
- return renderEntry(item.dataset.id, item.dataset)
59
- })}
60
- </div>
61
- )
62
- }
@@ -1,141 +0,0 @@
1
- import React from 'react'
2
- import { setDatasetVisibility } from '../api/setDatasetVisibility'
3
-
4
- const CHECKBOX_LABEL_CLASS = 'im-c-datasets-layers__item-label govuk-label govuk-checkboxes__label'
5
-
6
- const hasToggleableSublayers = (dataset) => dataset.sublayers?.some(sublayer => sublayer.showInMenu)
7
-
8
- /**
9
- * Collapse the filtered dataset list into ordered render items:
10
- * { type: 'sublayers', dataset } — dataset with sublayers (takes precedence)
11
- * { type: 'group', groupLabel, datasets } — datasets sharing a groupLabel
12
- * { type: 'flat', dataset } — standalone dataset
13
- */
14
- const buildRenderItems = (datasets) => {
15
- const seenGroups = new Set()
16
- const items = []
17
- datasets.forEach(dataset => {
18
- if (hasToggleableSublayers(dataset)) {
19
- items.push({ type: 'sublayers', dataset })
20
- return
21
- }
22
- if (dataset.groupLabel) {
23
- if (seenGroups.has(dataset.groupLabel)) {
24
- return
25
- }
26
- seenGroups.add(dataset.groupLabel)
27
- items.push({
28
- type: 'group',
29
- groupLabel: dataset.groupLabel,
30
- datasets: datasets.filter(d => !hasToggleableSublayers(d) && d.groupLabel === dataset.groupLabel)
31
- })
32
- return
33
- }
34
- items.push({ type: 'flat', dataset })
35
- })
36
- return items
37
- }
38
-
39
- export const Layers = ({ pluginState }) => {
40
- const handleDatasetChange = (e) => {
41
- const { value, checked } = e.target
42
- setDatasetVisibility({ pluginState }, checked, { datasetId: value })
43
- }
44
-
45
- const handleSublayerChange = (e) => {
46
- const { checked } = e.target
47
- const datasetId = e.target.dataset.datasetId
48
- const sublayerId = e.target.dataset.sublayerId
49
- setDatasetVisibility({ pluginState }, checked, { datasetId, sublayerId })
50
- }
51
-
52
- const renderDatasetItem = (dataset) => {
53
- const itemClass = `im-c-datasets-layers__item govuk-checkboxes govuk-checkboxes--small${dataset.visibility === 'hidden' ? '' : ' im-c-datasets-layers__item--checked'}`
54
- return (
55
- <div key={dataset.id} className={itemClass} data-module='govuk-checkboxes'>
56
- <div className='govuk-checkboxes__item'>
57
- <input
58
- className='govuk-checkboxes__input'
59
- id={dataset.id}
60
- name='layers'
61
- type='checkbox'
62
- value={dataset.id}
63
- checked={dataset.visibility !== 'hidden'}
64
- onChange={handleDatasetChange}
65
- />
66
- <label className={CHECKBOX_LABEL_CLASS} htmlFor={dataset.id}>
67
- {dataset.label}
68
- </label>
69
- </div>
70
- </div>
71
- )
72
- }
73
-
74
- const visibleDatasets = (pluginState.datasets || [])
75
- .filter(dataset => dataset.showInMenu || hasToggleableSublayers(dataset))
76
-
77
- const renderItems = buildRenderItems(visibleDatasets)
78
- const hasGroups = renderItems.some(item => item.type === 'sublayers' || item.type === 'group')
79
- const containerClass = `im-c-datasets-layers${hasGroups ? ' im-c-datasets-layers--has-groups' : ''}`
80
-
81
- return (
82
- <div className={containerClass}>
83
- {renderItems.map(item => {
84
- if (item.type === 'sublayers') {
85
- const { dataset } = item
86
- const anySublayerChecked = dataset.sublayers
87
- .filter(sublayer => sublayer.showInMenu)
88
- .some(sublayer => dataset.sublayerVisibility?.[sublayer.id] !== 'hidden')
89
- const wrapperClass = `govuk-form-group im-c-datasets-layers-group${anySublayerChecked ? ' im-c-datasets-layers-group--items-checked' : ''}`
90
- return (
91
- <div key={dataset.id} className={wrapperClass}>
92
- <fieldset className='im-c-datasets-layers-group__fieldset'>
93
- <legend className='im-c-datasets-layers-group__legend'>{dataset.label}</legend>
94
- {dataset.sublayers
95
- .filter(sublayer => sublayer.showInMenu)
96
- .map(sublayer => {
97
- const sublayerVisible = dataset.sublayerVisibility?.[sublayer.id] !== 'hidden'
98
- const inputId = `${dataset.id}-${sublayer.id}`
99
- const itemClass = `im-c-datasets-layers__item govuk-checkboxes govuk-checkboxes--small${sublayerVisible ? ' im-c-datasets-layers__item--checked' : ''}`
100
- return (
101
- <div key={sublayer.id} className={itemClass} data-module='govuk-checkboxes'>
102
- <div className='govuk-checkboxes__item'>
103
- <input
104
- className='govuk-checkboxes__input'
105
- id={inputId}
106
- type='checkbox'
107
- checked={sublayerVisible}
108
- data-dataset-id={dataset.id}
109
- data-sublayer-id={sublayer.id}
110
- onChange={handleSublayerChange}
111
- />
112
- <label className={CHECKBOX_LABEL_CLASS} htmlFor={inputId}>
113
- {sublayer.label}
114
- </label>
115
- </div>
116
- </div>
117
- )
118
- })}
119
- </fieldset>
120
- </div>
121
- )
122
- }
123
-
124
- if (item.type === 'group') {
125
- const anyDatasetChecked = item.datasets.some(d => d.visibility !== 'hidden')
126
- const wrapperClass = `govuk-form-group im-c-datasets-layers-group${anyDatasetChecked ? ' im-c-datasets-layers-group--items-checked' : ''}`
127
- return (
128
- <div key={item.groupLabel} className={wrapperClass}>
129
- <fieldset className='im-c-datasets-layers-group__fieldset'>
130
- <legend className='im-c-datasets-layers-group__legend'>{item.groupLabel}</legend>
131
- {item.datasets.map(dataset => renderDatasetItem(dataset))}
132
- </fieldset>
133
- </div>
134
- )
135
- }
136
-
137
- return renderDatasetItem(item.dataset)
138
- })}
139
- </div>
140
- )
141
- }
@@ -1,219 +0,0 @@
1
- import { applyDatasetDefaults } from './defaults.js'
2
- import { keyReducer } from './reducers/keyReducer.js'
3
-
4
- const initialState = {
5
- datasets: null,
6
- key: {
7
- items: [],
8
- hasGroups: false
9
- },
10
- hiddenFeatures: {}, // { [layerId]: { idProperty: string, ids: string[] } }
11
- layerAdapter: null
12
- }
13
-
14
- const initSublayerVisibility = (dataset) => {
15
- if (!dataset.sublayers?.length) {
16
- return dataset
17
- }
18
- const sublayerVisibility = {}
19
- dataset.sublayers.forEach(sublayer => {
20
- sublayerVisibility[sublayer.id] = 'visible'
21
- })
22
- return { ...dataset, sublayerVisibility }
23
- }
24
-
25
- const setDatasets = (state, payload) => {
26
- const { datasets, datasetDefaults } = payload
27
- return {
28
- ...state,
29
- datasets: datasets.map(dataset => initSublayerVisibility(applyDatasetDefaults(dataset, datasetDefaults)))
30
- }
31
- }
32
-
33
- const addDataset = (state, payload) => {
34
- const { dataset, datasetDefaults } = payload
35
- return {
36
- ...state,
37
- datasets: [
38
- ...(state.datasets || []),
39
- initSublayerVisibility(applyDatasetDefaults(dataset, datasetDefaults))
40
- ]
41
- }
42
- }
43
-
44
- const removeDataset = (state, payload) => {
45
- const { id } = payload
46
- return {
47
- ...state,
48
- datasets: state.datasets?.filter(dataset => dataset.id !== id) || []
49
- }
50
- }
51
-
52
- const setDatasetVisibility = (state, payload) => {
53
- const { id, visibility } = payload
54
- return {
55
- ...state,
56
- datasets: state.datasets?.map(dataset =>
57
- dataset.id === id ? { ...dataset, visibility } : dataset
58
- )
59
- }
60
- }
61
-
62
- const setGlobalVisibility = (state, payload) => {
63
- const { visibility } = payload
64
- return {
65
- ...state,
66
- datasets: state.datasets?.map(dataset => ({ ...dataset, visibility }))
67
- }
68
- }
69
-
70
- const hideFeatures = (state, payload) => {
71
- const { layerId, idProperty, featureIds } = payload
72
- const existing = state.hiddenFeatures[layerId]
73
- const existingIds = existing?.ids || []
74
- const newIds = [...new Set([...existingIds, ...featureIds])]
75
-
76
- return {
77
- ...state,
78
- hiddenFeatures: {
79
- ...state.hiddenFeatures,
80
- [layerId]: { idProperty, ids: newIds }
81
- }
82
- }
83
- }
84
-
85
- const showFeatures = (state, payload) => {
86
- const { layerId, featureIds } = payload
87
- const existing = state.hiddenFeatures[layerId]
88
- if (!existing) {
89
- return state
90
- }
91
-
92
- const newIds = existing.ids.filter(id => !featureIds.includes(id))
93
-
94
- if (newIds.length === 0) {
95
- const rest = { ...state.hiddenFeatures }
96
- delete rest[layerId]
97
- return { ...state, hiddenFeatures: rest }
98
- }
99
-
100
- return {
101
- ...state,
102
- hiddenFeatures: {
103
- ...state.hiddenFeatures,
104
- [layerId]: { ...existing, ids: newIds }
105
- }
106
- }
107
- }
108
-
109
- const setSublayerVisibility = (state, payload) => {
110
- const { datasetId, sublayerId, visibility } = payload
111
- return {
112
- ...state,
113
- datasets: state.datasets?.map(dataset => {
114
- if (dataset.id !== datasetId) {
115
- return dataset
116
- }
117
- return {
118
- ...dataset,
119
- sublayerVisibility: {
120
- ...dataset.sublayerVisibility,
121
- [sublayerId]: visibility
122
- }
123
- }
124
- })
125
- }
126
- }
127
-
128
- const setDatasetStyle = (state, payload) => {
129
- const { datasetId, styleChanges } = payload
130
- return {
131
- ...state,
132
- datasets: state.datasets?.map(dataset =>
133
- dataset.id === datasetId ? { ...dataset, ...styleChanges } : dataset
134
- )
135
- }
136
- }
137
-
138
- const setSublayerStyle = (state, payload) => {
139
- const { datasetId, sublayerId, styleChanges } = payload
140
- return {
141
- ...state,
142
- datasets: state.datasets?.map(dataset => {
143
- if (dataset.id !== datasetId) {
144
- return dataset
145
- }
146
- return {
147
- ...dataset,
148
- sublayers: dataset.sublayers?.map(sublayer =>
149
- sublayer.id === sublayerId
150
- ? { ...sublayer, style: { ...sublayer.style, ...styleChanges } }
151
- : sublayer
152
- )
153
- }
154
- })
155
- }
156
- }
157
-
158
- const setOpacity = (state, payload) => {
159
- const { datasetId, opacity } = payload
160
- return {
161
- ...state,
162
- datasets: state.datasets?.map(dataset =>
163
- dataset.id === datasetId ? { ...dataset, opacity } : dataset
164
- )
165
- }
166
- }
167
-
168
- const setGlobalOpacity = (state, payload) => {
169
- const { opacity } = payload
170
- return {
171
- ...state,
172
- datasets: state.datasets?.map(dataset => ({ ...dataset, opacity }))
173
- }
174
- }
175
-
176
- const setSublayerOpacity = (state, payload) => {
177
- const { datasetId, sublayerId, opacity } = payload
178
- return {
179
- ...state,
180
- datasets: state.datasets?.map(dataset => {
181
- if (dataset.id !== datasetId) {
182
- return dataset
183
- }
184
- return {
185
- ...dataset,
186
- sublayers: dataset.sublayers?.map(sublayer =>
187
- sublayer.id === sublayerId
188
- ? { ...sublayer, style: { ...sublayer.style, opacity } }
189
- : sublayer
190
- )
191
- }
192
- })
193
- }
194
- }
195
-
196
- const setLayerAdapter = (state, payload) => ({ ...state, layerAdapter: payload })
197
-
198
- const actions = {
199
- BUILD_KEY_GROUPS: keyReducer,
200
- SET_DATASETS: setDatasets,
201
- ADD_DATASET: addDataset,
202
- REMOVE_DATASET: removeDataset,
203
- SET_DATASET_VISIBILITY: setDatasetVisibility,
204
- SET_GLOBAL_VISIBILITY: setGlobalVisibility,
205
- SET_SUBLAYER_VISIBILITY: setSublayerVisibility,
206
- SET_DATASET_STYLE: setDatasetStyle,
207
- SET_SUBLAYER_STYLE: setSublayerStyle,
208
- SET_OPACITY: setOpacity,
209
- SET_GLOBAL_OPACITY: setGlobalOpacity,
210
- SET_SUBLAYER_OPACITY: setSublayerOpacity,
211
- HIDE_FEATURES: hideFeatures,
212
- SHOW_FEATURES: showFeatures,
213
- SET_LAYER_ADAPTER: setLayerAdapter
214
- }
215
-
216
- export {
217
- initialState,
218
- actions
219
- }
@@ -1,34 +0,0 @@
1
- export const keyReducer = (state) => {
2
- const datasets = state.datasets || []
3
- const seenGroups = new Set()
4
- const items = []
5
- let hasGroups = false
6
- datasets.forEach(dataset => {
7
- if (!dataset.showInKey || dataset.visibility === 'hidden') {
8
- return
9
- }
10
- if (dataset.sublayers?.length) {
11
- const { sublayerVisibility = [] } = dataset
12
- if (Object.values(sublayerVisibility).some((value) => value !== 'hidden')) {
13
- hasGroups = true
14
- items.push({ type: 'sublayers', dataset })
15
- }
16
- return
17
- }
18
- if (dataset.groupLabel) {
19
- if (seenGroups.has(dataset.groupLabel)) {
20
- return
21
- }
22
- seenGroups.add(dataset.groupLabel)
23
- hasGroups = true
24
- items.push({
25
- type: 'group',
26
- groupLabel: dataset.groupLabel,
27
- datasets: datasets.filter(d => !d.sublayers?.length && d.groupLabel === dataset.groupLabel)
28
- })
29
- return
30
- }
31
- items.push({ type: 'flat', dataset })
32
- })
33
- return { ...state, key: { items, hasGroups } }
34
- }
@@ -1,34 +0,0 @@
1
- /**
2
- * Build a filter that excludes specific features by ID property
3
- * Coerces values to strings for comparison to handle mixed number/string types
4
- */
5
- export const buildExclusionFilter = (originalFilter, idProperty, excludeIds) => {
6
- if (!excludeIds || excludeIds.length === 0) {
7
- return originalFilter
8
- }
9
-
10
- // Coerce both sides to strings to handle number/string type mismatches
11
- // When no idProperty, use feature-level id via ['id'] (GeoJSON feature.id)
12
- const idExpr = idProperty ? ['to-string', ['get', idProperty]] : ['to-string', ['id']]
13
- // Convert all IDs to strings; map passes each element as the first argument to String
14
- const stringIds = excludeIds.map(String)
15
- const exclusionFilter = ['!', ['in', idExpr, ['literal', stringIds]]]
16
-
17
- if (!originalFilter) {
18
- return exclusionFilter
19
- }
20
-
21
- return ['all', originalFilter, exclusionFilter]
22
- }
23
-
24
- /**
25
- * Apply exclusion filter to a map layer
26
- */
27
- export const applyExclusionFilter = (map, layerId, originalFilter, idProperty, excludeIds) => {
28
- if (!map.getLayer(layerId)) {
29
- return
30
- }
31
-
32
- const filter = buildExclusionFilter(originalFilter, idProperty, excludeIds)
33
- map.setFilter(layerId, filter)
34
- }
@@ -1,86 +0,0 @@
1
- import { hasCustomVisualStyle } from '../defaults.js'
2
-
3
- const getFillProps = (dataset, sublayerStyle) => {
4
- if (sublayerStyle.fillPattern || sublayerStyle.fillPatternSvgContent) {
5
- return {
6
- fillPattern: sublayerStyle.fillPattern,
7
- fillPatternSvgContent: sublayerStyle.fillPatternSvgContent,
8
- fillPatternForegroundColor: sublayerStyle.fillPatternForegroundColor ?? dataset.fillPatternForegroundColor,
9
- fillPatternBackgroundColor: sublayerStyle.fillPatternBackgroundColor ?? dataset.fillPatternBackgroundColor
10
- }
11
- }
12
- if ('fill' in sublayerStyle) {
13
- // Sublayer explicitly sets a plain fill — do not inherit any parent pattern
14
- return { fill: sublayerStyle.fill }
15
- }
16
- return {
17
- fill: dataset.fill,
18
- fillPattern: dataset.fillPattern,
19
- fillPatternSvgContent: dataset.fillPatternSvgContent,
20
- fillPatternForegroundColor: dataset.fillPatternForegroundColor,
21
- fillPatternBackgroundColor: dataset.fillPatternBackgroundColor
22
- }
23
- }
24
-
25
- const getCombinedFilter = (datasetFilter, sublayerFilter) => {
26
- if (datasetFilter && sublayerFilter) {
27
- return ['all', datasetFilter, sublayerFilter]
28
- }
29
- return sublayerFilter || datasetFilter || null
30
- }
31
-
32
- const getSymbolDescription = (dataset, sublayerStyle) => {
33
- if ('symbolDescription' in sublayerStyle) {
34
- return sublayerStyle.symbolDescription
35
- }
36
- if (hasCustomVisualStyle(sublayerStyle)) {
37
- return undefined
38
- }
39
- return dataset.symbolDescription
40
- }
41
-
42
- /**
43
- * Merge a sublayer with its parent dataset, producing a flat style
44
- * object suitable for layer creation and key symbol rendering.
45
- *
46
- * The sublayer's nested `style` object is flattened before merging.
47
- *
48
- * Fill precedence (highest to lowest):
49
- * 1. Sublayer's own fillPattern
50
- * 2. Sublayer's own fill (explicit, even if transparent — clears any parent pattern)
51
- * 3. Parent's fillPattern
52
- * 4. Parent's fill
53
- *
54
- * symbolDescription is only inherited from the parent when the sublayer has no
55
- * custom visual styles of its own. If the sublayer overrides stroke/fill/pattern
56
- * without setting symbolDescription explicitly, no description is shown.
57
- */
58
- export const mergeSublayer = (dataset, sublayer) => {
59
- const sublayerStyle = sublayer.style || {}
60
- const combinedFilter = getCombinedFilter(dataset.filter, sublayer.filter)
61
-
62
- return {
63
- id: sublayer.id,
64
- label: sublayer.label,
65
- stroke: sublayerStyle.stroke ?? dataset.stroke,
66
- strokeWidth: sublayerStyle.strokeWidth ?? dataset.strokeWidth,
67
- strokeDashArray: sublayerStyle.strokeDashArray ?? dataset.strokeDashArray,
68
- opacity: sublayerStyle.opacity ?? dataset.opacity,
69
- keySymbolShape: sublayerStyle.keySymbolShape ?? dataset.keySymbolShape,
70
- symbolDescription: getSymbolDescription(dataset, sublayerStyle),
71
- showInKey: sublayer.showInKey ?? dataset.showInKey,
72
- showInMenu: sublayer.showInMenu ?? false,
73
- filter: combinedFilter,
74
- minZoom: dataset.minZoom,
75
- maxZoom: dataset.maxZoom,
76
- symbol: sublayerStyle.symbol ?? dataset.symbol,
77
- symbolSvgContent: sublayerStyle.symbolSvgContent ?? dataset.symbolSvgContent,
78
- symbolViewBox: sublayerStyle.symbolViewBox ?? dataset.symbolViewBox,
79
- symbolAnchor: sublayerStyle.symbolAnchor ?? dataset.symbolAnchor,
80
- symbolBackgroundColor: sublayerStyle.symbolBackgroundColor ?? dataset.symbolBackgroundColor,
81
- symbolForegroundColor: sublayerStyle.symbolForegroundColor ?? dataset.symbolForegroundColor,
82
- symbolHaloWidth: sublayerStyle.symbolHaloWidth ?? dataset.symbolHaloWidth,
83
- symbolGraphic: sublayerStyle.symbolGraphic ?? dataset.symbolGraphic,
84
- ...getFillProps(dataset, sublayerStyle)
85
- }
86
- }
@@ -1,21 +0,0 @@
1
- .touch-vertex-target circle {
2
- fill: var(--map-overlay-foreground-color);
3
- }
4
- .touch-vertex-target path {
5
- fill: var(--map-overlay-halo-color);
6
- }
7
-
8
- .im-c-actions .im-c-button-wrapper--draw-done,
9
- .im-c-actions .im-c-button-wrapper--draw-menu,
10
- .im-c-actions .im-c-button-wrapper--draw-cancel {
11
- width: 33.33%;
12
- }
13
-
14
- .im-o-app--tablet .im-c-actions .im-c-button-wrapper--draw-done,
15
- .im-o-app--tablet .im-c-actions .im-c-button-wrapper--draw-menu,
16
- .im-o-app--tablet .im-c-actions .im-c-button-wrapper--draw-cancel,
17
- .im-o-app--desktop .im-c-actions .im-c-button-wrapper--draw-done,
18
- .im-o-app--desktop .im-c-actions .im-c-button-wrapper--draw-menu,
19
- .im-o-app--desktop .im-c-actions .im-c-button-wrapper--draw-cancel {
20
- width: 100px;
21
- }