{"version":3,"file":"MapWithLayerSelection-Cd5-GVlm.cjs","names":[],"sources":["../src/Components/Graphs/Maps/GeoHubMaps/MapWithLayerSelection/MapEl.tsx","../src/Components/Graphs/Maps/GeoHubMaps/MapWithLayerSelection/index.tsx"],"sourcesContent":["import * as maplibreGl from 'maplibre-gl';\r\nimport * as pmtiles from 'pmtiles';\r\nimport { useEffect, useRef, useState } from 'react';\r\nimport 'maplibre-gl/dist/maplibre-gl.css';\r\nimport { select } from 'd3-selection';\r\nimport React from 'react';\r\nimport { GraphArea } from '@/Components/Elements/GraphContainer';\r\nimport {\r\n  LegendCollapseButton,\r\n  LegendExpandButton,\r\n} from '@/Components/Elements/LegendExpandControls';\r\nimport { fetchAndParseJSON } from '@/Utils/fetchAndParseData';\r\nimport { string2HTML } from '@/Utils/string2HTML';\r\nimport { filterData } from '@/Utils/transformData/filterData';\r\n\r\ninterface Props {\r\n  mapStyle: string;\r\n  center?: [number, number];\r\n  zoomLevel?: number;\r\n  selectedLayer: string[];\r\n  layerIdList: string[];\r\n  excludeLayers: string[];\r\n  mapLegend?: string | React.ReactNode;\r\n}\r\n\r\nexport function MapEl(props: Props) {\r\n  const { mapStyle, center, zoomLevel, selectedLayer, layerIdList, excludeLayers, mapLegend } =\r\n    props;\r\n\r\n  const [svgWidth, setSvgWidth] = useState(0);\r\n  const [svgHeight, setSvgHeight] = useState(0);\r\n  const [showLegend, setShowLegend] = useState(true);\r\n  // biome-ignore lint/suspicious/noExplicitAny: undefined data type\r\n  const [mapStyleData, setMapStyleData] = useState<any>(undefined);\r\n  const graphDiv = useRef<HTMLDivElement>(null);\r\n  const mapContainer = useRef<HTMLDivElement>(null);\r\n  // biome-ignore lint/suspicious/noExplicitAny: undefined data type\r\n  const mapRef = useRef<any>(null);\r\n  useEffect(() => {\r\n    const resizeObserver = new ResizeObserver((entries) => {\r\n      setSvgWidth(entries[0].target.clientWidth || 620);\r\n      setSvgHeight(entries[0].target.clientHeight || 480);\r\n    });\r\n    if (graphDiv.current) {\r\n      resizeObserver.observe(graphDiv.current);\r\n    }\r\n    return () => resizeObserver.disconnect();\r\n  }, []);\r\n  useEffect(() => {\r\n    if (mapContainer.current && svgWidth && !mapRef.current) {\r\n      fetchAndParseJSON(mapStyle).then((d) => {\r\n        setMapStyleData(d);\r\n        const mapDiv = select(mapContainer.current);\r\n        mapDiv.selectAll('div').remove();\r\n        const protocol = new pmtiles.Protocol();\r\n        maplibreGl.addProtocol('pmtiles', protocol.tile);\r\n        // biome-ignore lint/suspicious/noExplicitAny: undefined data type\r\n        const mapObj: any = {\r\n          // biome-ignore lint/suspicious/noExplicitAny: undefined data type\r\n          container: mapContainer.current as any,\r\n          style: {\r\n            ...d,\r\n            layers: filterData(d.layers, [\r\n              {\r\n                column: 'id',\r\n                excludeValues: [\r\n                  ...excludeLayers,\r\n                  ...layerIdList.filter((el) => selectedLayer.indexOf(el) === -1),\r\n                ],\r\n              },\r\n            ]),\r\n          },\r\n          attributionControl: true,\r\n        };\r\n        if (center) {\r\n          mapObj.center = center;\r\n        }\r\n        if (zoomLevel) {\r\n          mapObj.zoom = zoomLevel;\r\n        }\r\n        mapRef.current = new maplibreGl.Map(mapObj);\r\n        mapRef.current.addControl(\r\n          new maplibreGl.NavigationControl({\r\n            visualizePitch: true,\r\n            showZoom: true,\r\n            showCompass: true,\r\n          }),\r\n          'bottom-right',\r\n        );\r\n        mapRef.current.addControl(new maplibreGl.ScaleControl(), 'bottom-left');\r\n      });\r\n    }\r\n  }, [svgWidth, center, zoomLevel, layerIdList, mapStyle, excludeLayers, selectedLayer]);\r\n  useEffect(() => {\r\n    if (mapRef.current) {\r\n      if (mapStyleData) {\r\n        // biome-ignore lint/suspicious/noExplicitAny: undefined data type\r\n        const mapStyleObj: any = {\r\n          ...mapStyleData,\r\n          layers: filterData(mapStyleData.layers, [\r\n            {\r\n              column: 'id',\r\n              excludeValues: [\r\n                ...excludeLayers,\r\n                ...layerIdList.filter((el) => selectedLayer.indexOf(el) === -1),\r\n              ],\r\n            },\r\n          ]),\r\n        };\r\n        mapRef.current.setStyle(mapStyleObj);\r\n      } else\r\n        fetchAndParseJSON(mapStyle).then((d) => {\r\n          // biome-ignore lint/suspicious/noExplicitAny: undefined data type\r\n          const mapStyleObj: any = {\r\n            ...d,\r\n            layers: filterData(d.layers, [\r\n              {\r\n                column: 'id',\r\n                excludeValues: [\r\n                  ...excludeLayers,\r\n                  ...layerIdList.filter((el) => selectedLayer.indexOf(el) === -1),\r\n                ],\r\n              },\r\n            ]),\r\n          };\r\n          mapRef.current.setStyle(mapStyleObj);\r\n        });\r\n    }\r\n  }, [excludeLayers, layerIdList, mapStyle, mapStyleData, selectedLayer]);\r\n  return (\r\n    <GraphArea ref={graphDiv}>\r\n      {svgWidth && svgHeight ? (\r\n        <div\r\n          style={{\r\n            width: svgWidth,\r\n            height: svgHeight,\r\n          }}\r\n        >\r\n          <div ref={mapContainer} className='map maplibre-show-control w-full h-full' />\r\n          {mapLegend ? (\r\n            <div className='absolute left-5.5 bottom-13'>\r\n              {showLegend ? (\r\n                <>\r\n                  <LegendCollapseButton setExpanded={setShowLegend} />\r\n                  <div\r\n                    className='color-legend-box p-2 bg-surface-sm/70'\r\n                    // biome-ignore lint/security/noDangerouslySetInnerHtmlWithChildren: Allow setInnerHTML here\r\n                    // biome-ignore lint/security/noDangerouslySetInnerHtml: Allow setInnerHTML here\r\n                    dangerouslySetInnerHTML={\r\n                      typeof mapLegend === 'string' ? { __html: string2HTML(mapLegend) } : undefined\r\n                    }\r\n                  >\r\n                    {React.isValidElement(mapLegend) ? mapLegend : null}\r\n                  </div>\r\n                </>\r\n              ) : (\r\n                <LegendExpandButton setExpanded={setShowLegend} />\r\n              )}\r\n            </div>\r\n          ) : null}\r\n        </div>\r\n      ) : null}\r\n    </GraphArea>\r\n  );\r\n}\r\n","import { createFilter, DropdownSelect } from '@undp/design-system-react/DropdownSelect';\r\nimport { Spacer } from '@undp/design-system-react/Spacer';\r\nimport flattenDeep from 'lodash.flattendeep';\r\nimport { useEffect, useMemo, useRef, useState } from 'react';\r\nimport { GraphContainer } from '@/Components/Elements/GraphContainer';\r\nimport { GraphFooter } from '@/Components/Elements/GraphFooter';\r\nimport { GraphHeader } from '@/Components/Elements/GraphHeader';\r\nimport type {\r\n  ClassNameObject,\r\n  Languages,\r\n  MapLegendDataType,\r\n  SourcesDataType,\r\n  StyleObject,\r\n} from '@/Types';\r\nimport { MapEl } from './MapEl';\r\n\r\ninterface Props {\r\n  // Titles, Labels, and Sources\r\n  /** Title of the graph */\r\n  graphTitle?: string | React.ReactNode;\r\n  /** Description of the graph */\r\n  graphDescription?: string | React.ReactNode;\r\n  /** Footnote for the graph */\r\n  footNote?: string | React.ReactNode;\r\n  /** Source data for the graph */\r\n  sources?: SourcesDataType[];\r\n  /** Accessibility label */\r\n  ariaLabel?: string;\r\n\r\n  // Colors and Styling\r\n  /** Background color of the graph */\r\n  backgroundColor?: string | boolean;\r\n  /** Custom styles for the graph. Each object should be a valid React CSS style object. */\r\n  styles?: StyleObject;\r\n  /** Custom class names */\r\n  classNames?: ClassNameObject;\r\n\r\n  // Size and Spacing\r\n  /** Width of the graph */\r\n  width?: number;\r\n  /** Height of the graph */\r\n  height?: number;\r\n  /** Minimum height of the graph */\r\n  minHeight?: number;\r\n  /** Relative height scaling factor. This overwrites the height props */\r\n  relativeHeight?: number;\r\n  /** Padding around the graph. Defaults to 0 if no backgroundColor is mentioned else defaults to 1rem */\r\n  padding?: string;\r\n\r\n  // Graph Parameters\r\n  /** URL for mapStyle JSON  */\r\n  mapStyle: string;\r\n  /** Starting center point of the map */\r\n  center?: [number, number];\r\n  /** Starting zoom level of the map */\r\n  zoomLevel?: number;\r\n  /** List of the layers that the user select and switch between sing a drop down */\r\n  layerSelection: { layerID: string[]; name: string }[];\r\n  /** Defines the legend for the map. mapLegend is of type { mapStyleName: string; legend: string | React.ReactNode }[] where mapStyleName corresponds to the each name in the layerSelection. */\r\n  mapLegend?: MapLegendDataType[];\r\n  /** List of layer IDs to be excluded from the visualization */\r\n  excludeLayers?: string[];\r\n\r\n  // Configuration and Options\r\n  /** Language setting  */\r\n  language?: Languages;\r\n  /** Color theme */\r\n  theme?: 'light' | 'dark';\r\n  /** Theme for the UI elements */\r\n  uiMode?: 'light' | 'normal';\r\n  /** Unique ID for the graph */\r\n  graphID?: string;\r\n}\r\n\r\n/** For using these maps you will have to install [`maplibre`](https://maplibre.org/maplibre-gl-js/docs/#npm) and [pmtiles](https://www.npmjs.com/package/pmtiles) package to your project */\r\nexport function GeoHubMapWithLayerSelection(props: Props) {\r\n  const {\r\n    mapStyle,\r\n    graphTitle,\r\n    height,\r\n    width,\r\n    relativeHeight,\r\n    sources,\r\n    graphDescription,\r\n    footNote,\r\n    padding,\r\n    backgroundColor = false,\r\n    center,\r\n    zoomLevel,\r\n    graphID,\r\n    language = 'en',\r\n    minHeight = 0,\r\n    theme = 'light',\r\n    layerSelection,\r\n    excludeLayers = [],\r\n    ariaLabel,\r\n    uiMode = 'normal',\r\n    styles,\r\n    classNames,\r\n    mapLegend = [],\r\n  } = props;\r\n\r\n  const [selectedLayer, setSelectedLayer] = useState(layerSelection[0].layerID);\r\n  const graphParentDiv = useRef<HTMLDivElement>(null);\r\n\r\n  useEffect(() => {\r\n    setSelectedLayer(layerSelection[0].layerID);\r\n  }, [layerSelection]);\r\n\r\n  const filterConfig = useMemo(\r\n    () => ({\r\n      ignoreCase: true,\r\n      ignoreAccents: true,\r\n      trim: true,\r\n    }),\r\n    [],\r\n  );\r\n  return (\r\n    <GraphContainer\r\n      className={classNames?.graphContainer}\r\n      style={styles?.graphContainer}\r\n      id={graphID}\r\n      ref={graphParentDiv}\r\n      aria-label={ariaLabel}\r\n      backgroundColor={backgroundColor}\r\n      theme={theme}\r\n      language={language}\r\n      minHeight={minHeight}\r\n      width={width}\r\n      height={height}\r\n      relativeHeight={relativeHeight}\r\n      padding={padding}\r\n    >\r\n      {graphTitle || graphDescription ? (\r\n        <GraphHeader\r\n          styles={{\r\n            title: styles?.title,\r\n            description: styles?.description,\r\n          }}\r\n          classNames={{\r\n            title: classNames?.title,\r\n            description: classNames?.description,\r\n          }}\r\n          graphTitle={graphTitle}\r\n          graphDescription={graphDescription}\r\n          width={width}\r\n        />\r\n      ) : null}\r\n      <DropdownSelect\r\n        options={layerSelection.map((d) => ({\r\n          label: d.name,\r\n          value: d.layerID,\r\n        }))}\r\n        size='sm'\r\n        isClearable={false}\r\n        variant={uiMode}\r\n        isRtl={language === 'he' || language === 'ar'}\r\n        isSearchable\r\n        filterOption={createFilter(filterConfig)}\r\n        defaultValue={{\r\n          label: layerSelection[0].name,\r\n          value: layerSelection[0].layerID,\r\n        }}\r\n        controlShouldRenderValue\r\n        // biome-ignore lint/suspicious/noExplicitAny: undefined data type\r\n        onChange={(el: any) => {\r\n          if (el) setSelectedLayer(el.value);\r\n        }}\r\n      />\r\n      <Spacer size='lg' />\r\n      <MapEl\r\n        mapStyle={mapStyle}\r\n        center={center}\r\n        zoomLevel={zoomLevel}\r\n        selectedLayer={selectedLayer}\r\n        layerIdList={flattenDeep(layerSelection.map((d) => d.layerID))}\r\n        excludeLayers={excludeLayers}\r\n        mapLegend={\r\n          (mapLegend as MapLegendDataType[]).find(\r\n            (d) =>\r\n              d.mapStyleName === layerSelection.find((el) => el.layerID === selectedLayer)?.name,\r\n          )?.legend\r\n        }\r\n      />\r\n      {sources || footNote ? (\r\n        <GraphFooter\r\n          styles={{ footnote: styles?.footnote, source: styles?.source }}\r\n          classNames={{\r\n            footnote: classNames?.footnote,\r\n            source: classNames?.source,\r\n          }}\r\n          sources={sources}\r\n          footNote={footNote}\r\n          width={width}\r\n        />\r\n      ) : null}\r\n    </GraphContainer>\r\n  );\r\n}\r\n"],"mappings":"2rBAyBA,SAAA,EAAA,EAAA,s0DA2IA,CCzFA,SAAgB,EAA4B,EAAc,CACxD,GAAM,CACJ,WACA,aACA,SACA,QACA,iBACA,UACA,mBACA,WACA,UACA,kBAAkB,GAClB,SACA,YACA,UACA,WAAW,KACX,YAAY,EACZ,QAAQ,QACR,iBACA,gBAAgB,CAAC,EACjB,YACA,SAAS,SACT,SACA,aACA,YAAY,CAAC,GACX,EAEE,CAAC,EAAe,IAAA,EAAA,EAAA,UAA6B,EAAe,GAAG,OAAO,EACtE,GAAA,EAAA,EAAA,QAAwC,IAAI,GAElD,EAAA,EAAA,eAAgB,CACd,EAAiB,EAAe,GAAG,OAAO,CAC5C,EAAG,CAAC,CAAc,CAAC,EAEnB,IAAM,GAAA,EAAA,EAAA,cACG,CACL,WAAY,GACZ,cAAe,GACf,KAAM,EACR,GACA,CAAC,CACH,EACA,OACE,EAAA,EAAA,MAAC,EAAA,EAAD,CACE,UAAW,GAAY,eACvB,MAAO,GAAQ,eACf,GAAI,EACJ,IAAK,EACL,aAAY,EACK,kBACV,QACG,WACC,YACJ,QACC,SACQ,iBACP,mBAbX,CAeG,GAAc,GACb,EAAA,EAAA,KAAC,EAAA,YAAD,CACE,OAAQ,CACN,MAAO,GAAQ,MACf,YAAa,GAAQ,WACvB,EACA,WAAY,CACV,MAAO,GAAY,MACnB,YAAa,GAAY,WAC3B,EACY,aACM,mBACX,OACR,CAAA,EACC,MACJ,EAAA,EAAA,KAAC,EAAA,eAAD,CACE,QAAS,EAAe,IAAK,IAAO,CAClC,MAAO,EAAE,KACT,MAAO,EAAE,OACX,EAAE,EACF,KAAK,KACL,YAAa,GACb,QAAS,EACT,MAAO,IAAa,MAAQ,IAAa,KACzC,aAAA,GACA,cAAA,EAAA,EAAA,cAA2B,CAAY,EACvC,aAAc,CACZ,MAAO,EAAe,GAAG,KACzB,MAAO,EAAe,GAAG,OAC3B,EACA,yBAAA,GAEA,SAAW,GAAY,CACjB,GAAI,EAAiB,EAAG,KAAK,CACnC,CACD,CAAA,GACD,EAAA,EAAA,KAAC,EAAA,OAAD,CAAQ,KAAK,IAAM,CAAA,GACnB,EAAA,EAAA,KAAC,EAAD,CACY,WACF,SACG,YACI,gBACf,aAAA,EAAA,EAAA,SAAyB,EAAe,IAAK,GAAM,EAAE,OAAO,CAAC,EAC9C,gBACf,UACG,EAAkC,KAChC,GACC,EAAE,eAAiB,EAAe,KAAM,GAAO,EAAG,UAAY,CAAa,GAAG,IAClF,GAAG,MAEN,CAAA,EACA,GAAW,GACV,EAAA,EAAA,KAAC,EAAA,YAAD,CACE,OAAQ,CAAE,SAAU,GAAQ,SAAU,OAAQ,GAAQ,MAAO,EAC7D,WAAY,CACV,SAAU,GAAY,SACtB,OAAQ,GAAY,MACtB,EACS,UACC,WACH,OACR,CAAA,EACC,IACU,GAEpB"}