@rural-environmental-registry/map_component 2.0.1 → 2.0.2

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.
@@ -75,7 +75,7 @@ export type LayerData = {
75
75
  name: string;
76
76
  active: boolean;
77
77
  activeDefault: boolean;
78
- role?: 'layer' | 'separator';
78
+ role?: 'layer' | 'separator' | 'subgroup';
79
79
  tooltip?: string;
80
80
  toggle?: {
81
81
  active: string;
@@ -104,6 +104,8 @@ export type LayerData = {
104
104
  infoIcons?: LayerInfoIconConfig[];
105
105
  required?: boolean;
106
106
  editActions?: LayerActionConfig[];
107
+ children?: LayerData[];
108
+ collapsed?: boolean;
107
109
  meta?: Record<string, unknown>;
108
110
  };
109
111
  export type GroupLayerData = {
@@ -5,6 +5,8 @@ export declare const normalizeLayersConfig: (config?: LayersConfig | null) => Se
5
5
  export declare const resolveLayerActions: (layer: LayerData, defaults?: LayerActionDefaults) => LayerActionConfig[];
6
6
  export declare const resolveEditControlAction: (defaults: LayerActionDefaults | undefined, kind: "cancel" | "conclude") => LayerActionConfig;
7
7
  export declare const isMenuSeparator: (layer: LayerData | null | undefined) => boolean;
8
+ export declare const isMenuSubgroup: (layer: LayerData | null | undefined) => boolean;
9
+ export declare const walkMenuLayers: (layers: LayerData[] | undefined, visitor: (layer: LayerData) => void) => void;
8
10
  export declare const shouldApplyMapOverlay: (layer: LayerData) => boolean;
9
11
  export declare const collectLayerMetricsMap: (config?: LayersConfig | null) => LayerMetricsMap;
10
12
  export declare const resolveLayerMetrics: (layer: LayerData | null | undefined) => LayerMetricsConfig[];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rural-environmental-registry/map_component",
3
- "version": "2.0.1",
3
+ "version": "2.0.2",
4
4
  "description": "Map component for Vue.js applications",
5
5
  "main": "dist/index.mjs",
6
6
  "module": "dist/index.mjs",
@@ -49,8 +49,10 @@
49
49
  SectionSelectPayload
50
50
  } from '../../types'
51
51
  import {
52
+ isMenuSubgroup,
52
53
  normalizeLayersConfig,
53
- shouldApplyMapOverlay
54
+ shouldApplyMapOverlay,
55
+ walkMenuLayers
54
56
  } from '../../utils/layersConfigNormalizer'
55
57
  import {
56
58
  resolveGroupCollapsedState,
@@ -152,6 +154,15 @@
152
154
  ? group.collapsed
153
155
  : resolveGroupCollapsedState(group.key, undefined, persist)
154
156
  if (!collapsed) openeds.push(group.key)
157
+
158
+ ;(group.layers || []).forEach((layer) => {
159
+ if (!isMenuSubgroup(layer)) return
160
+ const subCollapsed =
161
+ layer.collapsed !== undefined
162
+ ? layer.collapsed
163
+ : resolveGroupCollapsedState(layer.key, true, persist)
164
+ if (!subCollapsed) openeds.push(layer.key)
165
+ })
155
166
  })
156
167
  })
157
168
 
@@ -279,7 +290,7 @@
279
290
 
280
291
  normalizedSections.value.forEach((section) => {
281
292
  section.groups.forEach((group) => {
282
- group.layers?.forEach((layer) => {
293
+ walkMenuLayers(group.layers, (layer) => {
283
294
  if (initializedLayerKeys.has(layer.key)) return
284
295
  if (!shouldApplyMapOverlay(layer)) return
285
296
  if (!shouldInitLayerOnMap(layer, persist)) return
@@ -313,7 +324,7 @@
313
324
  }
314
325
 
315
326
  const onGroupLayerToggle = (parent: GroupLayerData): void => {
316
- parent.layers.forEach((childLayer: LayerData) => {
327
+ walkMenuLayers(parent.layers, (childLayer) => {
317
328
  applyLayerOverlay(childLayer)
318
329
  })
319
330
 
@@ -363,7 +374,8 @@
363
374
 
364
375
  const handleWmsLayer = (layer: LayerData): void => {
365
376
  if (convertedLayers.value[layer.key]) {
366
- if (!layer.active) return removeWmsLayer(layer)
377
+ if (!layer.active) removeWmsLayer(layer)
378
+ return
367
379
  }
368
380
 
369
381
  if (!layer.active) return
@@ -415,7 +427,9 @@
415
427
 
416
428
  const handleGeoJsonLayer = (layer: LayerData): void => {
417
429
  if (convertedGeoJsonLayers.value[layer.key]) {
418
- if (!layer.active) return removeGeoJsonLayer(layer)
430
+ // Já no mapa: só remove se desativada — evita GeoJSON órfão ao reaplicar active=true.
431
+ if (!layer.active) removeGeoJsonLayer(layer)
432
+ return
419
433
  }
420
434
 
421
435
  if (!layer.active) return
@@ -51,8 +51,29 @@
51
51
  v-for="(child, idx) in childrenLayers"
52
52
  :key="child.key"
53
53
  >
54
+ <ElSubMenu
55
+ v-if="isMenuSubgroup(child)"
56
+ :index="child.key"
57
+ class="parent-menu-subgroup-accordion"
58
+ >
59
+ <template #title>
60
+ <div class="parent-menu-subgroup-title">{{ child.name }}</div>
61
+ </template>
62
+ <ChildMenu
63
+ v-for="(nested, nestedIdx) in child.children || []"
64
+ :key="nested.key"
65
+ :actionDefaults="actionDefaults"
66
+ :data="nested"
67
+ :groupKey="groupData.key"
68
+ :persist="props.persist"
69
+ :sectionKey="sectionKey"
70
+ :visibilityMode="visibilityMode"
71
+ @onChildLayerToggle="onNestedChildChange($event, idx, nestedIdx)"
72
+ @onLayerAction="emit('onLayerAction', $event)"
73
+ />
74
+ </ElSubMenu>
54
75
  <ElMenuItem
55
- v-if="isMenuSeparator(child)"
76
+ v-else-if="isMenuSeparator(child)"
56
77
  :index="child.key"
57
78
  class="parent-menu-subgroup-header"
58
79
  disabled
@@ -114,6 +135,7 @@
114
135
  } from '../../types'
115
136
  import {
116
137
  isMenuSeparator,
138
+ isMenuSubgroup,
117
139
  resolveActiveGroupActions
118
140
  } from '../../utils/layersConfigNormalizer'
119
141
  import { resolveLayerActiveState, setHistory } from '../../utils/menuHistory.ts'
@@ -154,16 +176,26 @@
154
176
  onLayerAction: [LayerActionPayload]
155
177
  }>()
156
178
 
179
+ const resolveMenuEntry = (layer: LayerData): LayerData => {
180
+ if (isMenuSubgroup(layer)) {
181
+ return {
182
+ ...layer,
183
+ children: (layer.children || []).map((child) =>
184
+ resolveLayerActiveState(child, props.persist)
185
+ )
186
+ }
187
+ }
188
+ return resolveLayerActiveState(layer, props.persist)
189
+ }
190
+
157
191
  const childrenLayers = ref<LayerData[]>(
158
- (props.groupData.layers ?? []).map((layer) => resolveLayerActiveState(layer, props.persist))
192
+ (props.groupData.layers ?? []).map((layer) => resolveMenuEntry(layer))
159
193
  )
160
194
 
161
195
  watch(
162
196
  () => props.groupData.layers,
163
197
  (layers) => {
164
- childrenLayers.value = (layers ?? []).map((layer) =>
165
- resolveLayerActiveState(layer, props.persist)
166
- )
198
+ childrenLayers.value = (layers ?? []).map((layer) => resolveMenuEntry(layer))
167
199
  },
168
200
  { deep: true }
169
201
  )
@@ -190,9 +222,20 @@
190
222
  'Ocultar'
191
223
  )
192
224
 
193
- const toggleableLayers = computed(() =>
194
- childrenLayers.value.filter((layer: LayerData) => !isMenuSeparator(layer))
195
- )
225
+ const collectToggleableLeaves = (layers: LayerData[]): LayerData[] => {
226
+ const leaves: LayerData[] = []
227
+ for (const layer of layers) {
228
+ if (isMenuSeparator(layer)) continue
229
+ if (isMenuSubgroup(layer)) {
230
+ leaves.push(...collectToggleableLeaves(layer.children || []))
231
+ continue
232
+ }
233
+ leaves.push(layer)
234
+ }
235
+ return leaves
236
+ }
237
+
238
+ const toggleableLayers = computed(() => collectToggleableLeaves(childrenLayers.value))
196
239
 
197
240
  const toggleVisibleAllLayers = (): void => {
198
241
  if (props.persist) {
@@ -210,6 +253,12 @@
210
253
  set: (active: boolean) => {
211
254
  childrenLayers.value = (props.groupData.layers ?? []).map((layer: LayerData) => {
212
255
  if (isMenuSeparator(layer)) return resolveLayerActiveState(layer, props.persist)
256
+ if (isMenuSubgroup(layer)) {
257
+ return {
258
+ ...layer,
259
+ children: (layer.children || []).map((child) => ({ ...child, active }))
260
+ }
261
+ }
213
262
  return { ...layer, active }
214
263
  })
215
264
 
@@ -222,6 +271,19 @@
222
271
  emit('onChildLayerToggle', layer)
223
272
  }
224
273
 
274
+ const onNestedChildChange = (
275
+ layer: LayerData,
276
+ subgroupIdx: number,
277
+ nestedIdx: number
278
+ ): void => {
279
+ const subgroup = childrenLayers.value[subgroupIdx]
280
+ if (!subgroup) return
281
+ const children = [...(subgroup.children || [])]
282
+ children[nestedIdx] = layer
283
+ childrenLayers.value[subgroupIdx] = { ...subgroup, children }
284
+ emit('onChildLayerToggle', layer)
285
+ }
286
+
225
287
  const onGroupActionClick = (action: GroupActionConfig): void => {
226
288
  if (action.disabled) return
227
289
 
@@ -337,7 +399,6 @@
337
399
  margin: 0 !important;
338
400
  }
339
401
 
340
- /* Título de subgrupo: separador visual, sem accordion */
341
402
  .parent-menu .parent-menu-subgroup-header {
342
403
  height: auto !important;
343
404
  line-height: normal !important;
@@ -355,6 +416,21 @@
355
416
  opacity: 1 !important;
356
417
  }
357
418
 
419
+ .parent-menu .parent-menu-subgroup-accordion {
420
+ padding-left: 0 !important;
421
+ }
422
+
423
+ .parent-menu .parent-menu-subgroup-accordion > .el-sub-menu__title {
424
+ height: auto !important;
425
+ line-height: normal !important;
426
+ white-space: normal !important;
427
+ padding: var(--mapa-size-base-10) var(--mapa-size-base-20) var(--mapa-size-base-5) !important;
428
+ }
429
+
430
+ .parent-menu .parent-menu-subgroup-accordion > .el-sub-menu__title:hover {
431
+ background-color: transparent !important;
432
+ }
433
+
358
434
  .parent-menu .parent-menu-subgroup-title {
359
435
  font-size: var(--mapa-fs-12);
360
436
  font-weight: 700;
package/src/index.ts CHANGED
@@ -40,6 +40,8 @@ export {
40
40
  resolveEditControlAction,
41
41
  shouldApplyMapOverlay,
42
42
  isMenuSeparator,
43
+ isMenuSubgroup,
44
+ walkMenuLayers,
43
45
  collectLayerMetricsMap,
44
46
  resolveLayerMetrics,
45
47
  collectLayerInfoIconsMap,
@@ -117,7 +117,7 @@ export type LayerData = {
117
117
  name: string
118
118
  active: boolean
119
119
  activeDefault: boolean
120
- role?: 'layer' | 'separator'
120
+ role?: 'layer' | 'separator' | 'subgroup'
121
121
  tooltip?: string
122
122
  toggle?: {
123
123
  active: string
@@ -147,6 +147,8 @@ export type LayerData = {
147
147
  infoIcons?: LayerInfoIconConfig[]
148
148
  required?: boolean
149
149
  editActions?: LayerActionConfig[]
150
+ children?: LayerData[]
151
+ collapsed?: boolean
150
152
  meta?: Record<string, unknown>
151
153
  }
152
154
 
@@ -166,8 +166,26 @@ export const isMenuSeparator = (layer: LayerData | null | undefined): boolean =>
166
166
  return layer?.role === 'separator' || !!layer?.meta?.isSeparator
167
167
  }
168
168
 
169
+ export const isMenuSubgroup = (layer: LayerData | null | undefined): boolean => {
170
+ return layer?.role === 'subgroup' || !!layer?.meta?.isSubgroup
171
+ }
172
+
173
+ export const walkMenuLayers = (
174
+ layers: LayerData[] | undefined,
175
+ visitor: (layer: LayerData) => void
176
+ ): void => {
177
+ for (const layer of layers || []) {
178
+ if (isMenuSubgroup(layer) && layer.children?.length) {
179
+ walkMenuLayers(layer.children, visitor)
180
+ continue
181
+ }
182
+ if (isMenuSeparator(layer)) continue
183
+ visitor(layer)
184
+ }
185
+ }
186
+
169
187
  export const shouldApplyMapOverlay = (layer: LayerData): boolean => {
170
- if (isMenuSeparator(layer)) return false
188
+ if (isMenuSeparator(layer) || isMenuSubgroup(layer)) return false
171
189
  if (layer.mapSource === 'none' || layer.mapSource === 'consumer') return false
172
190
  if (layer.mapSource === 'wms' || layer.mapSource === 'geojson') return true
173
191
  if (layer.geojson) return true