analytica-frontend-lib 1.4.22 → 1.4.24
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/ChoroplethMap/index.d.ts +1 -1
- package/dist/ChoroplethMap/index.d.ts.map +1 -1
- package/dist/ChoroplethMap/index.js +3 -1
- package/dist/ChoroplethMap/index.js.map +1 -1
- package/dist/ChoroplethMap/index.mjs +3 -1
- package/dist/ChoroplethMap/index.mjs.map +1 -1
- package/dist/index.js +21 -8
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +21 -8
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
|
@@ -27,6 +27,6 @@ import type { ChoroplethMapProps } from './ChoroplethMap.types';
|
|
|
27
27
|
* />
|
|
28
28
|
* ```
|
|
29
29
|
*/
|
|
30
|
-
declare const ChoroplethMap: ({ data, apiKey, title, loading, bounds, onRegionClick, className, }: ChoroplethMapProps) => import("react/jsx-runtime").JSX.Element;
|
|
30
|
+
declare const ChoroplethMap: ({ data, apiKey, title, countLabel, loading, bounds, onRegionClick, className, }: ChoroplethMapProps) => import("react/jsx-runtime").JSX.Element;
|
|
31
31
|
export default ChoroplethMap;
|
|
32
32
|
//# sourceMappingURL=ChoroplethMap.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ChoroplethMap.d.ts","sourceRoot":"","sources":["../../../src/components/ChoroplethMap/ChoroplethMap.tsx"],"names":[],"mappings":"AAQA,OAAO,KAAK,EACV,kBAAkB,EAGnB,MAAM,uBAAuB,CAAC;AA+N/B;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,QAAA,MAAM,aAAa,GAAI,
|
|
1
|
+
{"version":3,"file":"ChoroplethMap.d.ts","sourceRoot":"","sources":["../../../src/components/ChoroplethMap/ChoroplethMap.tsx"],"names":[],"mappings":"AAQA,OAAO,KAAK,EACV,kBAAkB,EAGnB,MAAM,uBAAuB,CAAC;AA+N/B;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,QAAA,MAAM,aAAa,GAAI,iFASpB,kBAAkB,4CA4epB,CAAC;AAEF,eAAe,aAAa,CAAC"}
|
|
@@ -398,6 +398,7 @@ var ChoroplethMap = ({
|
|
|
398
398
|
data,
|
|
399
399
|
apiKey,
|
|
400
400
|
title = "Performance por regi\xE3o",
|
|
401
|
+
countLabel = "Acessos",
|
|
401
402
|
loading = false,
|
|
402
403
|
bounds,
|
|
403
404
|
onRegionClick,
|
|
@@ -758,7 +759,8 @@ var ChoroplethMap = ({
|
|
|
758
759
|
children: [
|
|
759
760
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Text_default, { size: "sm", weight: "semibold", children: hoveredRegion.name }),
|
|
760
761
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(Text_default, { size: "xs", color: "text-text-700", children: [
|
|
761
|
-
|
|
762
|
+
countLabel,
|
|
763
|
+
": ",
|
|
762
764
|
hoveredRegion.accessCount.toLocaleString("pt-BR")
|
|
763
765
|
] })
|
|
764
766
|
]
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/components/ChoroplethMap/ChoroplethMap.tsx","../../src/utils/utils.ts","../../src/hooks/useTheme.ts","../../src/store/themeStore.ts","../../src/components/Text/Text.tsx"],"sourcesContent":["/* global google */\nimport { useCallback, useEffect, useMemo, useRef, useState } from 'react';\nimport { GoogleMap, useJsApiLoader } from '@react-google-maps/api';\nimport union from '@turf/union';\nimport type { Feature, MultiPolygon, Polygon } from 'geojson';\nimport { cn } from '../../utils/utils';\nimport { useTheme } from '../../hooks/useTheme';\nimport Text from '../Text/Text';\nimport type {\n ChoroplethMapProps,\n ColorClass,\n RegionData,\n} from './ChoroplethMap.types';\n\n/**\n * Stable ID for the Google Maps script loader singleton.\n * Must NOT use useId() — the loader rejects re-initialization with different IDs.\n */\nconst GOOGLE_MAPS_LOADER_ID = 'google-maps-script';\n\n/**\n * Fade-in animation duration in milliseconds\n */\nconst FADE_DURATION = 400;\n\n/**\n * Hover animation duration in milliseconds\n */\nconst HOVER_DURATION = 200;\n\n/**\n * Target fill opacity for polygons\n */\nconst TARGET_OPACITY = 0.8;\n\n/**\n * Read a CSS custom property value from the document root\n * @param name - CSS variable name (e.g. '--color-map-highlight')\n * @param fallback - Fallback value when running outside browser\n * @returns Resolved CSS variable value\n */\nconst getCssVar = (name: string, fallback = ''): string => {\n if (typeof document === 'undefined') return fallback;\n return (\n getComputedStyle(document.documentElement).getPropertyValue(name).trim() ||\n fallback\n );\n};\n\n/**\n * Build color classes from CSS variables\n * @returns Color class array for the choropleth map\n */\nconst getColorClasses = (): ColorClass[] => [\n {\n min: 0.75,\n max: 1.01,\n fillColor: getCssVar('--color-map-highlight', '#2c7bb6'),\n strokeColor: getCssVar('--color-map-highlight', '#2c7bb6'),\n label: 'Destaque',\n },\n {\n min: 0.5,\n max: 0.75,\n fillColor: getCssVar('--color-map-above-avg', '#abd9e9'),\n strokeColor: getCssVar('--color-map-above-avg', '#abd9e9'),\n label: 'Acima da média',\n },\n {\n min: 0.25,\n max: 0.5,\n fillColor: getCssVar('--color-map-below-avg', '#fdae61'),\n strokeColor: getCssVar('--color-map-below-avg', '#fdae61'),\n label: 'Abaixo da média',\n },\n {\n min: 0,\n max: 0.25,\n fillColor: getCssVar('--color-map-attention', '#d7191c'),\n strokeColor: getCssVar('--color-map-attention', '#d7191c'),\n label: 'Ponto de atenção',\n },\n];\n\n/**\n * Get color class based on value\n * @param value - Normalized value between 0 and 1\n * @param colorClasses - Array of color class configurations\n * @returns Color class configuration\n */\nconst getColorClass = (\n value: number,\n colorClasses: ColorClass[]\n): ColorClass => {\n for (const colorClass of colorClasses) {\n if (value >= colorClass.min && value < colorClass.max) {\n return colorClass;\n }\n }\n return colorClasses[0];\n};\n\n/**\n * Compute NRE boundary polygons by merging city polygons that share the same regionName\n * @param data - Array of region data with individual city GeoJSON features\n * @returns Array of GeoJSON features representing NRE boundaries\n */\nconst computeNREBoundaries = (\n data: RegionData[]\n): Feature<Polygon | MultiPolygon>[] => {\n const groups = new Map<string, RegionData[]>();\n data.forEach((region) => {\n const existing = groups.get(region.name) ?? [];\n existing.push(region);\n groups.set(region.name, existing);\n });\n\n const boundaries: Feature<Polygon | MultiPolygon>[] = [];\n groups.forEach((regions) => {\n let merged: Feature<Polygon | MultiPolygon> | null = null;\n for (const region of regions) {\n if (region.geoJson.type !== 'Feature') continue;\n const feature: Feature<Polygon | MultiPolygon> = region.geoJson;\n if (merged) {\n const result: Feature<Polygon | MultiPolygon> | null = union({\n type: 'FeatureCollection' as const,\n features: [merged, feature],\n });\n if (result) merged = result;\n } else {\n merged = feature;\n }\n }\n if (merged) boundaries.push(merged);\n });\n\n return boundaries;\n};\n\n/**\n * Create style function for Data Layer features\n * @param opacity - Current fill opacity\n * @param colorClasses - Array of color class configurations\n * @param strokeCityColor - Stroke color for city borders\n * @returns Style function for map.data.setStyle\n */\nconst createStyleFunction = (\n opacity: number,\n colorClasses: ColorClass[],\n strokeCityColor: string\n) => {\n return (feature: google.maps.Data.Feature) => {\n const value = feature.getProperty('regionValue') as number;\n const colorClass = getColorClass(value ?? 0, colorClasses);\n return {\n fillColor: colorClass.fillColor,\n fillOpacity: opacity,\n strokeColor: strokeCityColor,\n strokeWeight: 0.3,\n cursor: 'pointer',\n };\n };\n};\n\n/**\n * Map container style\n * Note: Google Maps requires explicit pixel dimensions to render properly\n */\nconst containerStyle = {\n width: '100%',\n height: '415px',\n borderRadius: '0.5rem',\n};\n\n/**\n * Default map center (Paraná, Brazil)\n */\nconst defaultCenter = {\n lat: -24.7,\n lng: -51.5,\n};\n\n/**\n * Legend Item component for the map\n * @param color - Fill color of the legend circle\n * @param label - Text label for the legend item\n * @param borderColor - Optional border color for the legend circle\n * @param active - Whether the legend class is active (visible on map)\n * @param onClick - Callback when the legend item is clicked\n */\nconst LegendItem = ({\n color,\n label,\n borderColor,\n active = true,\n onClick,\n}: {\n color: string;\n label: string;\n borderColor?: string;\n active?: boolean;\n onClick?: () => void;\n}) => (\n <Text\n as=\"button\"\n type=\"button\"\n aria-pressed={active}\n className=\"flex items-center gap-2 cursor-pointer transition-opacity duration-200\"\n style={{ opacity: active ? 1 : 0.4 }}\n onClick={onClick}\n >\n <div\n className=\"w-3 h-3 rounded-full\"\n style={{\n backgroundColor: color,\n border: borderColor ? `1px solid ${borderColor}` : 'none',\n }}\n />\n <Text as=\"span\" size=\"sm\" weight=\"medium\" color=\"text-text-600\">\n {label}\n </Text>\n </Text>\n);\n\n/**\n * Loading skeleton component\n */\nconst LoadingSkeleton = () => (\n <div className=\"w-full h-full flex items-center justify-center bg-background-50 rounded-lg animate-pulse\">\n <Text size=\"sm\" color=\"text-text-400\">\n Carregando mapa...\n </Text>\n </div>\n);\n\n/**\n * ChoroplethMap component for displaying regional performance data\n *\n * Displays an interactive Google Map with colored regions based on normalized values.\n * Uses 4 color classes to represent different performance levels.\n * Includes fade-in animation, smooth hover transitions, and zoom-to-region on click.\n * NRE boundaries are rendered as a separate overlay with thicker strokes.\n *\n * @param data - Array of region data with GeoJSON and values\n * @param apiKey - Google Maps API key\n * @param title - Optional title for the map section\n * @param loading - Loading state indicator\n * @param bounds - Map bounds for initial view\n * @param onRegionClick - Callback when a region is clicked\n * @param className - Additional CSS classes\n * @returns Choropleth map component\n *\n * @example\n * ```tsx\n * <ChoroplethMap\n * data={regionData}\n * apiKey=\"your-api-key\"\n * title=\"Performance por região\"\n * loading={false}\n * onRegionClick={(region) => console.log(region)}\n * />\n * ```\n */\nconst ChoroplethMap = ({\n data,\n apiKey,\n title = 'Performance por região',\n loading = false,\n bounds,\n onRegionClick,\n className,\n}: ChoroplethMapProps) => {\n const mapId = GOOGLE_MAPS_LOADER_ID;\n const [map, setMap] = useState<google.maps.Map | null>(null);\n const [hoveredRegion, setHoveredRegion] = useState<RegionData | null>(null);\n const [infoPosition, setInfoPosition] = useState<{\n x: number;\n y: number;\n } | null>(null);\n const [activeClasses, setActiveClasses] = useState<Set<number>>(\n new Set([0, 1, 2, 3])\n );\n const fadeAnimationRef = useRef<number | null>(null);\n const hoverAnimationRef = useRef<number | null>(null);\n const nreBoundaryLayerRef = useRef<google.maps.Data | null>(null);\n const onRegionClickRef = useRef(onRegionClick);\n onRegionClickRef.current = onRegionClick;\n\n const { isDark } = useTheme();\n\n const dataSignature = useMemo(\n () =>\n data\n .map((d) => `${d.id}:${d.value}:${d.name}:${d.accessCount}`)\n .join('|'),\n [data]\n );\n const stableData = useMemo(() => data, [dataSignature]);\n\n const colorClasses = useMemo(() => getColorClasses(), [isDark]);\n\n const mapOptions: google.maps.MapOptions = useMemo(() => {\n const bgColor = getCssVar('--color-background-50', '#F6F6F6');\n return {\n disableDefaultUI: true,\n zoomControl: true,\n scrollwheel: true,\n draggable: true,\n backgroundColor: bgColor,\n styles: [\n {\n stylers: [{ color: bgColor }],\n },\n {\n elementType: 'labels',\n stylers: [{ visibility: 'off' }],\n },\n {\n elementType: 'geometry.stroke',\n stylers: [{ visibility: 'off' }],\n },\n ],\n };\n }, [isDark]);\n\n const { isLoaded, loadError } = useJsApiLoader({\n id: mapId,\n googleMapsApiKey: apiKey,\n });\n\n /**\n * Handle map load event\n */\n const onLoad = useCallback(\n (mapInstance: google.maps.Map) => {\n setMap(mapInstance);\n\n // Fit bounds if provided, then bump zoom to fill the container\n if (bounds) {\n const googleBounds = new google.maps.LatLngBounds(\n { lat: bounds.south, lng: bounds.west },\n { lat: bounds.north, lng: bounds.east }\n );\n mapInstance.fitBounds(googleBounds, 0);\n google.maps.event.addListenerOnce(mapInstance, 'idle', () => {\n const currentZoom = mapInstance.getZoom();\n if (currentZoom) {\n mapInstance.setZoom(currentZoom + 0.8);\n }\n });\n }\n },\n [bounds]\n );\n\n /**\n * Handle map unmount\n */\n const onUnmount = useCallback(() => {\n if (nreBoundaryLayerRef.current) {\n nreBoundaryLayerRef.current.setMap(null);\n }\n setMap(null);\n }, []);\n\n const nreBoundaries = useMemo(\n () => computeNREBoundaries(stableData),\n [stableData]\n );\n\n /**\n * Add GeoJSON data to map with animations\n */\n useEffect(() => {\n if (!map || !stableData.length) return;\n\n const strokeCityColor = getCssVar('--color-map-stroke-city', '#9ca3af');\n const strokeNreColor = getCssVar('--color-map-stroke-nre', '#4b5563');\n\n // Clear existing data\n map.data.forEach((feature) => {\n map.data.remove(feature);\n });\n\n // Clear existing NRE boundary layer\n if (nreBoundaryLayerRef.current) {\n nreBoundaryLayerRef.current.setMap(null);\n nreBoundaryLayerRef.current = null;\n }\n\n // Add each region's GeoJSON\n stableData.forEach((region) => {\n try {\n const feature = map.data.addGeoJson(region.geoJson);\n // Store region data in the feature\n if (feature && feature.length > 0) {\n feature.forEach((f) => {\n f.setProperty('regionId', region.id);\n f.setProperty('regionName', region.name);\n f.setProperty('regionValue', region.value);\n f.setProperty('regionAccessCount', region.accessCount);\n });\n }\n } catch (error) {\n console.error(\n `Failed to add GeoJSON for region ${region.name}:`,\n error\n );\n }\n });\n\n // Build NRE feature index for O(1) lookup by region name\n const nreFeatureIndex = new Map<string, google.maps.Data.Feature[]>();\n map.data.forEach((f) => {\n const name = f.getProperty('regionName') as string;\n if (name) {\n const list = nreFeatureIndex.get(name) ?? [];\n list.push(f);\n nreFeatureIndex.set(name, list);\n }\n });\n\n // Start with opacity 0 for fade-in animation\n map.data.setStyle(createStyleFunction(0, colorClasses, strokeCityColor));\n\n // Add NRE boundary overlay\n const nreLayer = new google.maps.Data();\n nreBoundaries.forEach((boundary) => {\n nreLayer.addGeoJson(boundary);\n });\n nreLayer.setStyle({\n fillOpacity: 0,\n strokeColor: strokeNreColor,\n strokeWeight: 1.5,\n clickable: false,\n });\n nreLayer.setMap(map);\n nreBoundaryLayerRef.current = nreLayer;\n\n // Animate fade-in from 0 to TARGET_OPACITY\n const startTime = performance.now();\n const animateFadeIn = (currentTime: number) => {\n const elapsed = currentTime - startTime;\n const progress = Math.min(elapsed / FADE_DURATION, 1);\n const currentOpacity = progress * TARGET_OPACITY;\n\n map.data.setStyle(\n createStyleFunction(currentOpacity, colorClasses, strokeCityColor)\n );\n\n if (progress < 1) {\n fadeAnimationRef.current = requestAnimationFrame(animateFadeIn);\n } else {\n fadeAnimationRef.current = null;\n }\n };\n fadeAnimationRef.current = requestAnimationFrame(animateFadeIn);\n\n /**\n * Apply style overrides to a list of features\n * @param features - Features to style\n * @param opacity - Fill opacity\n * @param weight - Stroke weight\n */\n const applyHoverStyle = (\n features: google.maps.Data.Feature[],\n opacity: number,\n weight: number\n ) => {\n features.forEach((f) => {\n map.data.overrideStyle(f, {\n fillOpacity: opacity,\n strokeColor: strokeCityColor,\n strokeWeight: weight,\n });\n });\n };\n\n /**\n * Animate hover transition for a group of features\n * @param features - Target features to animate\n * @param from - Starting opacity\n * @param to - Target opacity\n * @param fromWeight - Starting stroke weight\n * @param toWeight - Target stroke weight\n */\n const animateHover = (\n features: google.maps.Data.Feature[],\n from: number,\n to: number,\n fromWeight: number,\n toWeight: number\n ) => {\n if (hoverAnimationRef.current) {\n cancelAnimationFrame(hoverAnimationRef.current);\n }\n const start = performance.now();\n const animate = (now: number) => {\n const progress = Math.min((now - start) / HOVER_DURATION, 1);\n const opacity = from + (to - from) * progress;\n const weight = fromWeight + (toWeight - fromWeight) * progress;\n applyHoverStyle(features, opacity, weight);\n if (progress < 1) {\n hoverAnimationRef.current = requestAnimationFrame(animate);\n } else {\n hoverAnimationRef.current = null;\n }\n };\n hoverAnimationRef.current = requestAnimationFrame(animate);\n };\n\n // Handle hover events - highlight all cities in the same NRE\n let currentNRE: string | null = null;\n let revertTimeout: ReturnType<typeof setTimeout> | null = null;\n\n /**\n * Collect all features belonging to a given NRE name (O(1) index lookup)\n * @param nreName - NRE region name to match\n * @returns Array of matching features\n */\n const collectNREFeatures = (\n nreName: string\n ): google.maps.Data.Feature[] => {\n return nreFeatureIndex.get(nreName) ?? [];\n };\n\n const mouseoverListener = map.data.addListener(\n 'mouseover',\n (event: google.maps.Data.MouseEvent) => {\n // Cancel pending revert (when moving between cities in same NRE)\n if (revertTimeout) {\n clearTimeout(revertTimeout);\n revertTimeout = null;\n }\n\n const regionId = event.feature.getProperty('regionId') as string;\n const regionName = event.feature.getProperty('regionName') as string;\n const region = stableData.find((r) => r.id === regionId);\n if (region) {\n setHoveredRegion(region);\n if (event.domEvent) {\n setInfoPosition({\n x: (event.domEvent as MouseEvent).clientX,\n y: (event.domEvent as MouseEvent).clientY,\n });\n }\n }\n\n // Animate highlight for all features in the same NRE group\n if (currentNRE !== regionName) {\n if (currentNRE) {\n const prevFeatures = collectNREFeatures(currentNRE);\n animateHover(prevFeatures, 1, TARGET_OPACITY, 1.5, 0.5);\n }\n currentNRE = regionName;\n const nreFeatures = collectNREFeatures(regionName);\n animateHover(nreFeatures, TARGET_OPACITY, 1, 0.5, 1.5);\n }\n }\n );\n\n const mouseoutListener = map.data.addListener('mouseout', () => {\n // Defer revert to avoid flicker when moving between cities in same NRE\n revertTimeout = setTimeout(() => {\n setHoveredRegion(null);\n setInfoPosition(null);\n if (currentNRE) {\n const prevFeatures = collectNREFeatures(currentNRE);\n animateHover(prevFeatures, 1, TARGET_OPACITY, 1.5, 0.5);\n currentNRE = null;\n }\n }, 50);\n });\n\n const mousemoveListener = map.data.addListener(\n 'mousemove',\n (event: google.maps.Data.MouseEvent) => {\n if (event.domEvent) {\n setInfoPosition({\n x: (event.domEvent as MouseEvent).clientX,\n y: (event.domEvent as MouseEvent).clientY,\n });\n }\n }\n );\n\n /**\n * Compute bounds for all features matching a given NRE name\n * @param nreName - NRE region name to match\n * @returns LatLngBounds encompassing all matching features\n */\n const computeNREBounds = (nreName: string): google.maps.LatLngBounds => {\n const nreBounds = new google.maps.LatLngBounds();\n for (const f of collectNREFeatures(nreName)) {\n f.getGeometry()?.forEachLatLng((latLng) => {\n nreBounds.extend(latLng);\n });\n }\n return nreBounds;\n };\n\n // Handle click events - zoom to NRE region\n const clickListener = map.data.addListener(\n 'click',\n (event: google.maps.Data.MouseEvent) => {\n const regionId = event.feature.getProperty('regionId') as string;\n const regionName = event.feature.getProperty('regionName') as string;\n const region = stableData.find((r) => r.id === regionId);\n if (region) {\n onRegionClickRef.current?.(region);\n }\n\n const nreBounds = computeNREBounds(regionName);\n if (!nreBounds.isEmpty()) {\n map.fitBounds(nreBounds, 20);\n }\n }\n );\n\n return () => {\n if (fadeAnimationRef.current)\n cancelAnimationFrame(fadeAnimationRef.current);\n if (hoverAnimationRef.current)\n cancelAnimationFrame(hoverAnimationRef.current);\n if (revertTimeout) clearTimeout(revertTimeout);\n if (nreBoundaryLayerRef.current) {\n nreBoundaryLayerRef.current.setMap(null);\n nreBoundaryLayerRef.current = null;\n }\n google.maps.event.removeListener(mouseoverListener);\n google.maps.event.removeListener(mouseoutListener);\n google.maps.event.removeListener(mousemoveListener);\n google.maps.event.removeListener(clickListener);\n };\n }, [map, stableData, colorClasses, nreBoundaries]);\n\n /**\n * Apply visibility filter based on active legend classes\n * and adjust map bounds to fit visible features\n */\n useEffect(() => {\n if (!map || !stableData.length) return;\n\n const visibleBounds = new google.maps.LatLngBounds();\n let hasVisibleFeatures = false;\n\n map.data.forEach((feature: google.maps.Data.Feature) => {\n const value = feature.getProperty('regionValue') as number;\n const colorClass = getColorClass(value ?? 0, colorClasses);\n const classIndex = colorClasses.indexOf(colorClass);\n\n if (activeClasses.has(classIndex)) {\n map.data.overrideStyle(feature, { visible: true });\n feature.getGeometry()?.forEachLatLng((latLng) => {\n visibleBounds.extend(latLng);\n });\n hasVisibleFeatures = true;\n } else {\n map.data.overrideStyle(feature, { visible: false });\n }\n });\n\n if (hasVisibleFeatures && !visibleBounds.isEmpty()) {\n map.fitBounds(visibleBounds, 20);\n }\n }, [map, stableData, activeClasses, colorClasses]);\n\n /**\n * Toggle a color class on/off in the legend filter\n * @param index - Index of the color class in colorClasses\n */\n const toggleClass = (index: number) => {\n setActiveClasses((prev) => {\n const next = new Set(prev);\n if (next.has(index)) {\n next.delete(index);\n } else {\n next.add(index);\n }\n return next;\n });\n };\n\n if (loadError) {\n return (\n <div className=\"p-5 bg-background border border-border-50 rounded-xl\">\n <Text color=\"text-error-700\">Erro ao carregar o mapa</Text>\n </div>\n );\n }\n\n return (\n <div\n className={cn(\n 'p-5 bg-background border border-border-50 rounded-xl flex flex-col gap-4',\n className\n )}\n >\n {/* Header */}\n <div className=\"flex flex-col gap-4\">\n <Text\n as=\"h2\"\n size=\"lg\"\n weight=\"bold\"\n className=\"leading-[21px] tracking-[0.2px]\"\n >\n {title}\n </Text>\n\n {/* Legend */}\n <div className=\"flex flex-wrap gap-8\">\n {colorClasses.map((colorClass, index) => (\n <LegendItem\n key={colorClass.label}\n color={colorClass.fillColor}\n borderColor={\n colorClass.fillColor === colorClass.strokeColor\n ? undefined\n : colorClass.strokeColor\n }\n label={colorClass.label}\n active={activeClasses.has(index)}\n onClick={() => toggleClass(index)}\n />\n ))}\n </div>\n </div>\n\n {/* Map Container */}\n <div className=\"bg-background-50 rounded-lg h-[415px] relative overflow-hidden\">\n {loading || !isLoaded ? (\n <LoadingSkeleton />\n ) : (\n <GoogleMap\n mapContainerStyle={containerStyle}\n center={defaultCenter}\n zoom={7}\n onLoad={onLoad}\n onUnmount={onUnmount}\n options={mapOptions}\n />\n )}\n\n {/* Tooltip */}\n {hoveredRegion && infoPosition && (\n <div\n className=\"fixed z-50 bg-background border border-border-50 shadow-lg rounded-lg p-3 pointer-events-none\"\n style={{\n left: Math.min(infoPosition.x + 10, window.innerWidth - 220),\n top: Math.min(infoPosition.y + 10, window.innerHeight - 80),\n }}\n >\n <Text size=\"sm\" weight=\"semibold\">\n {hoveredRegion.name}\n </Text>\n <Text size=\"xs\" color=\"text-text-700\">\n Acessos: {hoveredRegion.accessCount.toLocaleString('pt-BR')}\n </Text>\n </div>\n )}\n </div>\n </div>\n );\n};\n\nexport default ChoroplethMap;\n","import { clsx, type ClassValue } from 'clsx';\nimport { twMerge } from 'tailwind-merge';\n\nexport function cn(...inputs: ClassValue[]) {\n return twMerge(clsx(inputs));\n}\n\nexport { syncDropdownState } from './dropdown';\nexport {\n getSelectedIdsFromCategories,\n toggleArrayItem,\n toggleSingleValue,\n areFiltersEqual,\n} from './activityFilters';\nexport {\n mapQuestionTypeToEnum,\n mapQuestionTypeToEnumRequired,\n} from './questionTypeUtils';\nexport {\n getStatusBadgeConfig,\n formatTimeSpent,\n formatQuestionNumbers,\n formatDateToBrazilian,\n} from './activityDetailsUtils';\n\n/**\n * Format a number as a rounded percentage string\n * @param value - Number to format (0-100)\n * @returns Formatted string with % suffix (e.g., \"72%\")\n */\nexport function formatPercentageRounded(value: number): string {\n return `${Math.round(value)}%`;\n}\n\nexport { formatScore } from './formatScore';\n\n/**\n * Convert hex color to rgba with opacity for background\n * @param hex - Hex color (e.g., \"#4B0082\")\n * @param opacity - Opacity value (0-1)\n * @returns rgba string\n */\nexport function hexToRgba(hex: string, opacity: number): string {\n const result = /^#?([a-f\\d]{2})([a-f\\d]{2})([a-f\\d]{2})$/i.exec(hex);\n if (!result) return `rgba(107, 114, 128, ${opacity})`; // fallback gray\n const r = Number.parseInt(result[1], 16);\n const g = Number.parseInt(result[2], 16);\n const b = Number.parseInt(result[3], 16);\n return `rgba(${r}, ${g}, ${b}, ${opacity})`;\n}\n\n/**\n * Maps Tailwind bg-* class to CSS variable\n * @param bgClass - Tailwind background class (e.g., \"bg-error-600\")\n * @returns CSS variable string (e.g., \"var(--color-error-600)\")\n */\nexport function bgClassToCssVar(bgClass: string): string {\n return `var(--color-${bgClass.replace('bg-', '')})`;\n}\n\n/**\n * Converts polar coordinates to Cartesian for SVG arc path calculations.\n * Angles are in degrees, with 0° at the top (12 o'clock position).\n * @param cx - Center X coordinate\n * @param cy - Center Y coordinate\n * @param r - Radius\n * @param angleDeg - Angle in degrees\n * @returns Cartesian coordinates { x, y }\n */\nexport function polarToCartesian(\n cx: number,\n cy: number,\n r: number,\n angleDeg: number\n): { x: number; y: number } {\n const rad = ((angleDeg - 90) * Math.PI) / 180;\n return { x: cx + r * Math.cos(rad), y: cy + r * Math.sin(rad) };\n}\n\n/**\n * Generates an SVG filled arc (pie slice) path string.\n * @param cx - Center X coordinate\n * @param cy - Center Y coordinate\n * @param r - Radius\n * @param startAngle - Start angle in degrees\n * @param endAngle - End angle in degrees\n * @returns SVG path string for the arc\n */\nexport function describeArc(\n cx: number,\n cy: number,\n r: number,\n startAngle: number,\n endAngle: number\n): string {\n const span = endAngle - startAngle;\n\n // For full circle (or near-full), use two arcs to avoid SVG arc degeneracy\n if (span >= 359.99) {\n const midAngle = startAngle + 180;\n const s = polarToCartesian(cx, cy, r, startAngle);\n const m = polarToCartesian(cx, cy, r, midAngle);\n return `M ${cx} ${cy} L ${s.x} ${s.y} A ${r} ${r} 0 1 1 ${m.x} ${m.y} A ${r} ${r} 0 1 1 ${s.x} ${s.y} Z`;\n }\n\n const s = polarToCartesian(cx, cy, r, endAngle);\n const e = polarToCartesian(cx, cy, r, startAngle);\n const largeArc = span > 180 ? 1 : 0;\n return `M ${cx} ${cy} L ${s.x} ${s.y} A ${r} ${r} 0 ${largeArc} 0 ${e.x} ${e.y} Z`;\n}\n\n/**\n * Retorna a cor hexadecimal com opacidade 0.3 (4d) se não estiver em dark mode.\n * Se estiver em dark mode, retorna a cor original.\n *\n * @param hexColor - Cor hexadecimal (ex: \"#0066b8\" ou \"0066b8\")\n * @param isDark - booleano indicando se está em dark mode\n * @returns string - cor hexadecimal com opacidade se necessário\n */\nexport function getSubjectColorWithOpacity(\n hexColor: string | undefined,\n isDark: boolean\n): string | undefined {\n if (!hexColor) return undefined;\n // Remove o '#' se existir\n let color = hexColor.replace(/^#/, '').toLowerCase();\n\n if (isDark) {\n // Se está em dark mode, sempre remove opacidade se existir\n if (color.length === 8) {\n color = color.slice(0, 6);\n }\n return `#${color}`;\n } else {\n // Se não está em dark mode (light mode)\n let resultColor: string;\n if (color.length === 6) {\n // Adiciona opacidade 0.3 (4D) para cores de 6 dígitos\n resultColor = `#${color}4d`;\n } else if (color.length === 8) {\n // Já tem opacidade, retorna como está\n resultColor = `#${color}`;\n } else {\n // Para outros tamanhos (3, 4, 5 dígitos), retorna como está\n resultColor = `#${color}`;\n }\n return resultColor;\n }\n}\n","import { useEffect, useMemo } from 'react';\nimport { useThemeStore, ThemeMode } from '../store/themeStore';\n\nexport type { ThemeMode };\n\n/**\n * Hook para gerenciar temas e branding institucional\n * Este hook permite alternar entre temas light, dark e automático baseado nas preferências do sistema\n * e fornece acesso aos dados de branding lidos diretamente das meta tags HTML\n * Utiliza Zustand para persistir o estado de tema entre múltiplos arquivos e sessões\n */\nexport const useTheme = () => {\n const {\n themeMode,\n isDark,\n toggleTheme,\n setTheme,\n initializeTheme,\n handleSystemThemeChange,\n } = useThemeStore();\n\n // Read branding data from meta tags\n const branding = useMemo(() => {\n if (typeof document === 'undefined') {\n return {\n theme: null,\n favicon: null,\n icon: null,\n mainLogo: null,\n internalLogo: null,\n loginImage: null,\n };\n }\n\n return {\n theme:\n document.querySelector('meta[name=\"theme\"]')?.getAttribute('content') ??\n null,\n favicon:\n document.querySelector('link[rel=\"icon\"]')?.getAttribute('href') ??\n null,\n icon:\n document\n .querySelector('link[rel=\"apple-touch-icon\"]')\n ?.getAttribute('href') ?? null,\n mainLogo:\n document\n .querySelector('meta[name=\"main-logo\"]')\n ?.getAttribute('content') ?? null,\n internalLogo:\n document\n .querySelector('meta[name=\"internal-logo\"]')\n ?.getAttribute('content') ?? null,\n loginImage:\n document\n .querySelector('meta[name=\"login-image\"]')\n ?.getAttribute('content') ?? null,\n };\n }, []);\n\n useEffect(() => {\n // Initialize theme on first render\n initializeTheme();\n\n // Listener para mudanças nas preferências do sistema (apenas quando mode é 'system')\n const mediaQuery = window.matchMedia('(prefers-color-scheme: dark)');\n\n mediaQuery.addEventListener('change', handleSystemThemeChange);\n\n return () => {\n mediaQuery.removeEventListener('change', handleSystemThemeChange);\n };\n }, [initializeTheme, handleSystemThemeChange]);\n\n return {\n themeMode,\n isDark,\n toggleTheme,\n setTheme,\n branding,\n };\n};\n","import { create } from 'zustand';\nimport { devtools, persist } from 'zustand/middleware';\n\nexport type ThemeMode = 'light' | 'dark' | 'system';\n\n/**\n * Theme store state interface\n */\nexport interface ThemeState {\n /**\n * Current theme mode\n */\n themeMode: ThemeMode;\n /**\n * Whether the current theme is dark\n */\n isDark: boolean;\n}\n\n/**\n * Theme store actions interface\n */\nexport interface ThemeActions {\n /**\n * Apply theme based on the mode selected\n */\n applyTheme: (mode: ThemeMode) => void;\n /**\n * Toggle between themes\n */\n toggleTheme: () => void;\n /**\n * Set a specific theme mode\n */\n setTheme: (mode: ThemeMode) => void;\n /**\n * Set the white-label theme from institution branding\n */\n setWhiteLabelTheme: (theme: string | null) => void;\n /**\n * Clear the white-label theme and revert to default\n */\n clearWhiteLabelTheme: () => void;\n /**\n * Initialize theme on app start\n */\n initializeTheme: () => void;\n /**\n * Handle system theme change\n */\n handleSystemThemeChange: () => void;\n}\n\nexport type ThemeStore = ThemeState & ThemeActions;\n\n/**\n * Mapa de tema light institucional → tema dark correspondente.\n * Adicionar entradas aqui ao introduzir novas instituições.\n */\nconst DARK_THEME_MAP: Record<string, string> = {\n 'base-light': 'base-dark',\n 'enem-parana-light': 'enem-parana-dark',\n 'enem-paraiba-light': 'enem-paraiba-dark',\n 'analytica-light': 'analytica-dark',\n};\n\n/**\n * Resolve o seletor CSS dark concreto com base no tema institucional (light)\n * salvo em `data-original-theme`. Fallback: 'base-dark', que também responde\n * ao seletor legado [data-theme='dark'] preservando compat com apps antigos.\n */\nconst resolveDarkTheme = (originalTheme: string | undefined): string => {\n if (!originalTheme) return 'base-dark';\n return DARK_THEME_MAP[originalTheme] ?? 'base-dark';\n};\n\n/**\n * Apply theme to DOM based on mode\n */\nconst applyThemeToDOM = (mode: ThemeMode): boolean => {\n const htmlElement = document.documentElement;\n const originalTheme = htmlElement.dataset.originalTheme;\n\n if (mode === 'dark') {\n htmlElement.dataset.theme = resolveDarkTheme(originalTheme);\n return true;\n } else if (mode === 'light') {\n if (originalTheme) {\n htmlElement.dataset.theme = originalTheme;\n }\n return false;\n } else if (mode === 'system') {\n const isSystemDark = window.matchMedia(\n '(prefers-color-scheme: dark)'\n ).matches;\n if (isSystemDark) {\n htmlElement.dataset.theme = resolveDarkTheme(originalTheme);\n return true;\n } else if (originalTheme) {\n htmlElement.dataset.theme = originalTheme;\n return false;\n }\n }\n return false;\n};\n\n/**\n * Save original theme from white label (reads from HTML meta tag or data-theme attribute)\n */\nconst saveOriginalTheme = () => {\n const htmlElement = document.documentElement;\n const currentTheme =\n htmlElement.dataset.theme ||\n document.querySelector('meta[name=\"theme\"]')?.getAttribute('content');\n\n if (currentTheme && !htmlElement.dataset.originalTheme) {\n htmlElement.dataset.originalTheme = currentTheme;\n }\n};\n\n/**\n * Theme store using Zustand with persistence\n */\nexport const useThemeStore = create<ThemeStore>()(\n devtools(\n persist(\n (set, get) => ({\n // Initial state\n themeMode: 'system',\n isDark: false,\n\n // Actions\n applyTheme: (mode: ThemeMode) => {\n const isDark = applyThemeToDOM(mode);\n set({ isDark });\n },\n\n toggleTheme: () => {\n const { themeMode, applyTheme } = get();\n let newMode: ThemeMode;\n\n if (themeMode === 'light') {\n newMode = 'dark';\n } else if (themeMode === 'dark') {\n newMode = 'light';\n } else {\n // Se estiver em 'system', vai para 'dark'\n newMode = 'dark';\n }\n\n set({ themeMode: newMode });\n applyTheme(newMode);\n },\n\n setTheme: (mode: ThemeMode) => {\n const { applyTheme } = get();\n set({ themeMode: mode });\n applyTheme(mode);\n },\n\n setWhiteLabelTheme: (theme: string | null) => {\n const htmlElement = document.documentElement;\n\n if (theme) {\n // Set the white-label theme as the original theme\n htmlElement.dataset.originalTheme = theme;\n\n // Apply theme based on current mode\n const { themeMode, applyTheme } = get();\n if (themeMode === 'light' || themeMode === 'system') {\n htmlElement.dataset.theme = theme;\n }\n\n applyTheme(themeMode);\n }\n },\n\n clearWhiteLabelTheme: () => {\n const htmlElement = document.documentElement;\n\n // Remove white-label theme attributes\n delete htmlElement.dataset.originalTheme;\n delete htmlElement.dataset.theme;\n\n // Restore original theme from page metadata\n saveOriginalTheme();\n\n // Re-apply current theme mode to use defaults\n const { themeMode, applyTheme } = get();\n applyTheme(themeMode);\n },\n\n initializeTheme: () => {\n const { themeMode, applyTheme } = get();\n\n // Save original theme from white label\n saveOriginalTheme();\n\n // Apply the current theme mode\n applyTheme(themeMode);\n },\n\n handleSystemThemeChange: () => {\n const { themeMode, applyTheme } = get();\n // Only respond to system changes when in system mode\n if (themeMode === 'system') {\n applyTheme('system');\n }\n },\n }),\n {\n name: 'theme-store', // Nome da chave no localStorage\n partialize: (state) => ({\n themeMode: state.themeMode,\n }), // Só persiste o themeMode, não o isDark\n }\n ),\n {\n name: 'theme-store',\n }\n )\n);\n","import { ComponentPropsWithRef, ElementType, ReactNode } from 'react';\nimport { cn } from '../../utils/utils';\n\n/**\n * Base text component props\n */\ntype BaseTextProps = {\n /** Content to be displayed */\n children?: ReactNode;\n /** Text size variant */\n size?:\n | '2xs'\n | 'xs'\n | 'sm'\n | 'md'\n | 'lg'\n | 'xl'\n | '2xl'\n | '3xl'\n | '4xl'\n | '5xl'\n | '6xl';\n /** Font weight variant */\n weight?:\n | 'hairline'\n | 'light'\n | 'normal'\n | 'medium'\n | 'semibold'\n | 'bold'\n | 'extrabold'\n | 'black';\n /** Color variant - white for light backgrounds, black for dark backgrounds */\n color?: string;\n /** Additional CSS classes to apply */\n className?: string;\n};\n\n/**\n * Polymorphic text component props that ensures type safety based on the 'as' prop\n */\ntype TextProps<T extends ElementType = 'p'> = BaseTextProps & {\n /** HTML tag to render */\n as?: T;\n} & Omit<ComponentPropsWithRef<T>, keyof BaseTextProps>;\n\n/**\n * Text component for Analytica Ensino platforms\n *\n * A flexible polymorphic text component with multiple sizes, weights, and colors.\n * Automatically adapts to dark and light themes with full type safety.\n *\n * @param children - The content to display\n * @param size - The text size variant (2xs, xs, sm, md, lg, xl, 2xl, 3xl, 4xl, 5xl, 6xl)\n * @param weight - The font weight variant (hairline, light, normal, medium, semibold, bold, extrabold, black)\n * @param color - The color variant - adapts to theme\n * @param as - The HTML tag to render - determines allowed attributes via TypeScript\n * @param className - Additional CSS classes\n * @param props - HTML attributes valid for the chosen tag only\n * @returns A styled text element with type-safe attributes\n *\n * @example\n * ```tsx\n * <Text size=\"lg\" weight=\"bold\" color=\"text-info-800\">\n * This is a large, bold text\n * </Text>\n *\n * <Text as=\"a\" href=\"/link\" target=\"_blank\">\n * Link with type-safe anchor attributes\n * </Text>\n *\n * <Text as=\"button\" onClick={handleClick} disabled>\n * Button with type-safe button attributes\n * </Text>\n * ```\n */\nconst Text = <T extends ElementType = 'p'>({\n children,\n size = 'md',\n weight = 'normal',\n color = 'text-text-950',\n as,\n className = '',\n ...props\n}: TextProps<T>) => {\n let sizeClasses: string;\n let weightClasses: string;\n\n // Text size classes mapping\n const sizeClassMap = {\n '2xs': 'text-2xs',\n xs: 'text-xs',\n sm: 'text-sm',\n md: 'text-md',\n lg: 'text-lg',\n xl: 'text-xl',\n '2xl': 'text-2xl',\n '3xl': 'text-3xl',\n '4xl': 'text-4xl',\n '5xl': 'text-5xl',\n '6xl': 'text-6xl',\n } as const;\n\n sizeClasses = sizeClassMap[size] ?? sizeClassMap.md;\n\n // Font weight classes mapping\n const weightClassMap = {\n hairline: 'font-hairline',\n light: 'font-light',\n normal: 'font-normal',\n medium: 'font-medium',\n semibold: 'font-semibold',\n bold: 'font-bold',\n extrabold: 'font-extrabold',\n black: 'font-black',\n } as const;\n\n weightClasses = weightClassMap[weight] ?? weightClassMap.normal;\n\n const baseClasses = 'font-primary';\n const Component = as ?? ('p' as ElementType);\n\n return (\n <Component\n className={cn(baseClasses, sizeClasses, weightClasses, color, className)}\n {...props}\n >\n {children}\n </Component>\n );\n};\n\nexport default Text;\n"],"mappings":"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","names":["import_react","import_jsx_runtime","union"]}
|
|
1
|
+
{"version":3,"sources":["../../src/components/ChoroplethMap/ChoroplethMap.tsx","../../src/utils/utils.ts","../../src/hooks/useTheme.ts","../../src/store/themeStore.ts","../../src/components/Text/Text.tsx"],"sourcesContent":["/* global google */\nimport { useCallback, useEffect, useMemo, useRef, useState } from 'react';\nimport { GoogleMap, useJsApiLoader } from '@react-google-maps/api';\nimport union from '@turf/union';\nimport type { Feature, MultiPolygon, Polygon } from 'geojson';\nimport { cn } from '../../utils/utils';\nimport { useTheme } from '../../hooks/useTheme';\nimport Text from '../Text/Text';\nimport type {\n ChoroplethMapProps,\n ColorClass,\n RegionData,\n} from './ChoroplethMap.types';\n\n/**\n * Stable ID for the Google Maps script loader singleton.\n * Must NOT use useId() — the loader rejects re-initialization with different IDs.\n */\nconst GOOGLE_MAPS_LOADER_ID = 'google-maps-script';\n\n/**\n * Fade-in animation duration in milliseconds\n */\nconst FADE_DURATION = 400;\n\n/**\n * Hover animation duration in milliseconds\n */\nconst HOVER_DURATION = 200;\n\n/**\n * Target fill opacity for polygons\n */\nconst TARGET_OPACITY = 0.8;\n\n/**\n * Read a CSS custom property value from the document root\n * @param name - CSS variable name (e.g. '--color-map-highlight')\n * @param fallback - Fallback value when running outside browser\n * @returns Resolved CSS variable value\n */\nconst getCssVar = (name: string, fallback = ''): string => {\n if (typeof document === 'undefined') return fallback;\n return (\n getComputedStyle(document.documentElement).getPropertyValue(name).trim() ||\n fallback\n );\n};\n\n/**\n * Build color classes from CSS variables\n * @returns Color class array for the choropleth map\n */\nconst getColorClasses = (): ColorClass[] => [\n {\n min: 0.75,\n max: 1.01,\n fillColor: getCssVar('--color-map-highlight', '#2c7bb6'),\n strokeColor: getCssVar('--color-map-highlight', '#2c7bb6'),\n label: 'Destaque',\n },\n {\n min: 0.5,\n max: 0.75,\n fillColor: getCssVar('--color-map-above-avg', '#abd9e9'),\n strokeColor: getCssVar('--color-map-above-avg', '#abd9e9'),\n label: 'Acima da média',\n },\n {\n min: 0.25,\n max: 0.5,\n fillColor: getCssVar('--color-map-below-avg', '#fdae61'),\n strokeColor: getCssVar('--color-map-below-avg', '#fdae61'),\n label: 'Abaixo da média',\n },\n {\n min: 0,\n max: 0.25,\n fillColor: getCssVar('--color-map-attention', '#d7191c'),\n strokeColor: getCssVar('--color-map-attention', '#d7191c'),\n label: 'Ponto de atenção',\n },\n];\n\n/**\n * Get color class based on value\n * @param value - Normalized value between 0 and 1\n * @param colorClasses - Array of color class configurations\n * @returns Color class configuration\n */\nconst getColorClass = (\n value: number,\n colorClasses: ColorClass[]\n): ColorClass => {\n for (const colorClass of colorClasses) {\n if (value >= colorClass.min && value < colorClass.max) {\n return colorClass;\n }\n }\n return colorClasses[0];\n};\n\n/**\n * Compute NRE boundary polygons by merging city polygons that share the same regionName\n * @param data - Array of region data with individual city GeoJSON features\n * @returns Array of GeoJSON features representing NRE boundaries\n */\nconst computeNREBoundaries = (\n data: RegionData[]\n): Feature<Polygon | MultiPolygon>[] => {\n const groups = new Map<string, RegionData[]>();\n data.forEach((region) => {\n const existing = groups.get(region.name) ?? [];\n existing.push(region);\n groups.set(region.name, existing);\n });\n\n const boundaries: Feature<Polygon | MultiPolygon>[] = [];\n groups.forEach((regions) => {\n let merged: Feature<Polygon | MultiPolygon> | null = null;\n for (const region of regions) {\n if (region.geoJson.type !== 'Feature') continue;\n const feature: Feature<Polygon | MultiPolygon> = region.geoJson;\n if (merged) {\n const result: Feature<Polygon | MultiPolygon> | null = union({\n type: 'FeatureCollection' as const,\n features: [merged, feature],\n });\n if (result) merged = result;\n } else {\n merged = feature;\n }\n }\n if (merged) boundaries.push(merged);\n });\n\n return boundaries;\n};\n\n/**\n * Create style function for Data Layer features\n * @param opacity - Current fill opacity\n * @param colorClasses - Array of color class configurations\n * @param strokeCityColor - Stroke color for city borders\n * @returns Style function for map.data.setStyle\n */\nconst createStyleFunction = (\n opacity: number,\n colorClasses: ColorClass[],\n strokeCityColor: string\n) => {\n return (feature: google.maps.Data.Feature) => {\n const value = feature.getProperty('regionValue') as number;\n const colorClass = getColorClass(value ?? 0, colorClasses);\n return {\n fillColor: colorClass.fillColor,\n fillOpacity: opacity,\n strokeColor: strokeCityColor,\n strokeWeight: 0.3,\n cursor: 'pointer',\n };\n };\n};\n\n/**\n * Map container style\n * Note: Google Maps requires explicit pixel dimensions to render properly\n */\nconst containerStyle = {\n width: '100%',\n height: '415px',\n borderRadius: '0.5rem',\n};\n\n/**\n * Default map center (Paraná, Brazil)\n */\nconst defaultCenter = {\n lat: -24.7,\n lng: -51.5,\n};\n\n/**\n * Legend Item component for the map\n * @param color - Fill color of the legend circle\n * @param label - Text label for the legend item\n * @param borderColor - Optional border color for the legend circle\n * @param active - Whether the legend class is active (visible on map)\n * @param onClick - Callback when the legend item is clicked\n */\nconst LegendItem = ({\n color,\n label,\n borderColor,\n active = true,\n onClick,\n}: {\n color: string;\n label: string;\n borderColor?: string;\n active?: boolean;\n onClick?: () => void;\n}) => (\n <Text\n as=\"button\"\n type=\"button\"\n aria-pressed={active}\n className=\"flex items-center gap-2 cursor-pointer transition-opacity duration-200\"\n style={{ opacity: active ? 1 : 0.4 }}\n onClick={onClick}\n >\n <div\n className=\"w-3 h-3 rounded-full\"\n style={{\n backgroundColor: color,\n border: borderColor ? `1px solid ${borderColor}` : 'none',\n }}\n />\n <Text as=\"span\" size=\"sm\" weight=\"medium\" color=\"text-text-600\">\n {label}\n </Text>\n </Text>\n);\n\n/**\n * Loading skeleton component\n */\nconst LoadingSkeleton = () => (\n <div className=\"w-full h-full flex items-center justify-center bg-background-50 rounded-lg animate-pulse\">\n <Text size=\"sm\" color=\"text-text-400\">\n Carregando mapa...\n </Text>\n </div>\n);\n\n/**\n * ChoroplethMap component for displaying regional performance data\n *\n * Displays an interactive Google Map with colored regions based on normalized values.\n * Uses 4 color classes to represent different performance levels.\n * Includes fade-in animation, smooth hover transitions, and zoom-to-region on click.\n * NRE boundaries are rendered as a separate overlay with thicker strokes.\n *\n * @param data - Array of region data with GeoJSON and values\n * @param apiKey - Google Maps API key\n * @param title - Optional title for the map section\n * @param loading - Loading state indicator\n * @param bounds - Map bounds for initial view\n * @param onRegionClick - Callback when a region is clicked\n * @param className - Additional CSS classes\n * @returns Choropleth map component\n *\n * @example\n * ```tsx\n * <ChoroplethMap\n * data={regionData}\n * apiKey=\"your-api-key\"\n * title=\"Performance por região\"\n * loading={false}\n * onRegionClick={(region) => console.log(region)}\n * />\n * ```\n */\nconst ChoroplethMap = ({\n data,\n apiKey,\n title = 'Performance por região',\n countLabel = 'Acessos',\n loading = false,\n bounds,\n onRegionClick,\n className,\n}: ChoroplethMapProps) => {\n const mapId = GOOGLE_MAPS_LOADER_ID;\n const [map, setMap] = useState<google.maps.Map | null>(null);\n const [hoveredRegion, setHoveredRegion] = useState<RegionData | null>(null);\n const [infoPosition, setInfoPosition] = useState<{\n x: number;\n y: number;\n } | null>(null);\n const [activeClasses, setActiveClasses] = useState<Set<number>>(\n new Set([0, 1, 2, 3])\n );\n const fadeAnimationRef = useRef<number | null>(null);\n const hoverAnimationRef = useRef<number | null>(null);\n const nreBoundaryLayerRef = useRef<google.maps.Data | null>(null);\n const onRegionClickRef = useRef(onRegionClick);\n onRegionClickRef.current = onRegionClick;\n\n const { isDark } = useTheme();\n\n const dataSignature = useMemo(\n () =>\n data\n .map((d) => `${d.id}:${d.value}:${d.name}:${d.accessCount}`)\n .join('|'),\n [data]\n );\n const stableData = useMemo(() => data, [dataSignature]);\n\n const colorClasses = useMemo(() => getColorClasses(), [isDark]);\n\n const mapOptions: google.maps.MapOptions = useMemo(() => {\n const bgColor = getCssVar('--color-background-50', '#F6F6F6');\n return {\n disableDefaultUI: true,\n zoomControl: true,\n scrollwheel: true,\n draggable: true,\n backgroundColor: bgColor,\n styles: [\n {\n stylers: [{ color: bgColor }],\n },\n {\n elementType: 'labels',\n stylers: [{ visibility: 'off' }],\n },\n {\n elementType: 'geometry.stroke',\n stylers: [{ visibility: 'off' }],\n },\n ],\n };\n }, [isDark]);\n\n const { isLoaded, loadError } = useJsApiLoader({\n id: mapId,\n googleMapsApiKey: apiKey,\n });\n\n /**\n * Handle map load event\n */\n const onLoad = useCallback(\n (mapInstance: google.maps.Map) => {\n setMap(mapInstance);\n\n // Fit bounds if provided, then bump zoom to fill the container\n if (bounds) {\n const googleBounds = new google.maps.LatLngBounds(\n { lat: bounds.south, lng: bounds.west },\n { lat: bounds.north, lng: bounds.east }\n );\n mapInstance.fitBounds(googleBounds, 0);\n google.maps.event.addListenerOnce(mapInstance, 'idle', () => {\n const currentZoom = mapInstance.getZoom();\n if (currentZoom) {\n mapInstance.setZoom(currentZoom + 0.8);\n }\n });\n }\n },\n [bounds]\n );\n\n /**\n * Handle map unmount\n */\n const onUnmount = useCallback(() => {\n if (nreBoundaryLayerRef.current) {\n nreBoundaryLayerRef.current.setMap(null);\n }\n setMap(null);\n }, []);\n\n const nreBoundaries = useMemo(\n () => computeNREBoundaries(stableData),\n [stableData]\n );\n\n /**\n * Add GeoJSON data to map with animations\n */\n useEffect(() => {\n if (!map || !stableData.length) return;\n\n const strokeCityColor = getCssVar('--color-map-stroke-city', '#9ca3af');\n const strokeNreColor = getCssVar('--color-map-stroke-nre', '#4b5563');\n\n // Clear existing data\n map.data.forEach((feature) => {\n map.data.remove(feature);\n });\n\n // Clear existing NRE boundary layer\n if (nreBoundaryLayerRef.current) {\n nreBoundaryLayerRef.current.setMap(null);\n nreBoundaryLayerRef.current = null;\n }\n\n // Add each region's GeoJSON\n stableData.forEach((region) => {\n try {\n const feature = map.data.addGeoJson(region.geoJson);\n // Store region data in the feature\n if (feature && feature.length > 0) {\n feature.forEach((f) => {\n f.setProperty('regionId', region.id);\n f.setProperty('regionName', region.name);\n f.setProperty('regionValue', region.value);\n f.setProperty('regionAccessCount', region.accessCount);\n });\n }\n } catch (error) {\n console.error(\n `Failed to add GeoJSON for region ${region.name}:`,\n error\n );\n }\n });\n\n // Build NRE feature index for O(1) lookup by region name\n const nreFeatureIndex = new Map<string, google.maps.Data.Feature[]>();\n map.data.forEach((f) => {\n const name = f.getProperty('regionName') as string;\n if (name) {\n const list = nreFeatureIndex.get(name) ?? [];\n list.push(f);\n nreFeatureIndex.set(name, list);\n }\n });\n\n // Start with opacity 0 for fade-in animation\n map.data.setStyle(createStyleFunction(0, colorClasses, strokeCityColor));\n\n // Add NRE boundary overlay\n const nreLayer = new google.maps.Data();\n nreBoundaries.forEach((boundary) => {\n nreLayer.addGeoJson(boundary);\n });\n nreLayer.setStyle({\n fillOpacity: 0,\n strokeColor: strokeNreColor,\n strokeWeight: 1.5,\n clickable: false,\n });\n nreLayer.setMap(map);\n nreBoundaryLayerRef.current = nreLayer;\n\n // Animate fade-in from 0 to TARGET_OPACITY\n const startTime = performance.now();\n const animateFadeIn = (currentTime: number) => {\n const elapsed = currentTime - startTime;\n const progress = Math.min(elapsed / FADE_DURATION, 1);\n const currentOpacity = progress * TARGET_OPACITY;\n\n map.data.setStyle(\n createStyleFunction(currentOpacity, colorClasses, strokeCityColor)\n );\n\n if (progress < 1) {\n fadeAnimationRef.current = requestAnimationFrame(animateFadeIn);\n } else {\n fadeAnimationRef.current = null;\n }\n };\n fadeAnimationRef.current = requestAnimationFrame(animateFadeIn);\n\n /**\n * Apply style overrides to a list of features\n * @param features - Features to style\n * @param opacity - Fill opacity\n * @param weight - Stroke weight\n */\n const applyHoverStyle = (\n features: google.maps.Data.Feature[],\n opacity: number,\n weight: number\n ) => {\n features.forEach((f) => {\n map.data.overrideStyle(f, {\n fillOpacity: opacity,\n strokeColor: strokeCityColor,\n strokeWeight: weight,\n });\n });\n };\n\n /**\n * Animate hover transition for a group of features\n * @param features - Target features to animate\n * @param from - Starting opacity\n * @param to - Target opacity\n * @param fromWeight - Starting stroke weight\n * @param toWeight - Target stroke weight\n */\n const animateHover = (\n features: google.maps.Data.Feature[],\n from: number,\n to: number,\n fromWeight: number,\n toWeight: number\n ) => {\n if (hoverAnimationRef.current) {\n cancelAnimationFrame(hoverAnimationRef.current);\n }\n const start = performance.now();\n const animate = (now: number) => {\n const progress = Math.min((now - start) / HOVER_DURATION, 1);\n const opacity = from + (to - from) * progress;\n const weight = fromWeight + (toWeight - fromWeight) * progress;\n applyHoverStyle(features, opacity, weight);\n if (progress < 1) {\n hoverAnimationRef.current = requestAnimationFrame(animate);\n } else {\n hoverAnimationRef.current = null;\n }\n };\n hoverAnimationRef.current = requestAnimationFrame(animate);\n };\n\n // Handle hover events - highlight all cities in the same NRE\n let currentNRE: string | null = null;\n let revertTimeout: ReturnType<typeof setTimeout> | null = null;\n\n /**\n * Collect all features belonging to a given NRE name (O(1) index lookup)\n * @param nreName - NRE region name to match\n * @returns Array of matching features\n */\n const collectNREFeatures = (\n nreName: string\n ): google.maps.Data.Feature[] => {\n return nreFeatureIndex.get(nreName) ?? [];\n };\n\n const mouseoverListener = map.data.addListener(\n 'mouseover',\n (event: google.maps.Data.MouseEvent) => {\n // Cancel pending revert (when moving between cities in same NRE)\n if (revertTimeout) {\n clearTimeout(revertTimeout);\n revertTimeout = null;\n }\n\n const regionId = event.feature.getProperty('regionId') as string;\n const regionName = event.feature.getProperty('regionName') as string;\n const region = stableData.find((r) => r.id === regionId);\n if (region) {\n setHoveredRegion(region);\n if (event.domEvent) {\n setInfoPosition({\n x: (event.domEvent as MouseEvent).clientX,\n y: (event.domEvent as MouseEvent).clientY,\n });\n }\n }\n\n // Animate highlight for all features in the same NRE group\n if (currentNRE !== regionName) {\n if (currentNRE) {\n const prevFeatures = collectNREFeatures(currentNRE);\n animateHover(prevFeatures, 1, TARGET_OPACITY, 1.5, 0.5);\n }\n currentNRE = regionName;\n const nreFeatures = collectNREFeatures(regionName);\n animateHover(nreFeatures, TARGET_OPACITY, 1, 0.5, 1.5);\n }\n }\n );\n\n const mouseoutListener = map.data.addListener('mouseout', () => {\n // Defer revert to avoid flicker when moving between cities in same NRE\n revertTimeout = setTimeout(() => {\n setHoveredRegion(null);\n setInfoPosition(null);\n if (currentNRE) {\n const prevFeatures = collectNREFeatures(currentNRE);\n animateHover(prevFeatures, 1, TARGET_OPACITY, 1.5, 0.5);\n currentNRE = null;\n }\n }, 50);\n });\n\n const mousemoveListener = map.data.addListener(\n 'mousemove',\n (event: google.maps.Data.MouseEvent) => {\n if (event.domEvent) {\n setInfoPosition({\n x: (event.domEvent as MouseEvent).clientX,\n y: (event.domEvent as MouseEvent).clientY,\n });\n }\n }\n );\n\n /**\n * Compute bounds for all features matching a given NRE name\n * @param nreName - NRE region name to match\n * @returns LatLngBounds encompassing all matching features\n */\n const computeNREBounds = (nreName: string): google.maps.LatLngBounds => {\n const nreBounds = new google.maps.LatLngBounds();\n for (const f of collectNREFeatures(nreName)) {\n f.getGeometry()?.forEachLatLng((latLng) => {\n nreBounds.extend(latLng);\n });\n }\n return nreBounds;\n };\n\n // Handle click events - zoom to NRE region\n const clickListener = map.data.addListener(\n 'click',\n (event: google.maps.Data.MouseEvent) => {\n const regionId = event.feature.getProperty('regionId') as string;\n const regionName = event.feature.getProperty('regionName') as string;\n const region = stableData.find((r) => r.id === regionId);\n if (region) {\n onRegionClickRef.current?.(region);\n }\n\n const nreBounds = computeNREBounds(regionName);\n if (!nreBounds.isEmpty()) {\n map.fitBounds(nreBounds, 20);\n }\n }\n );\n\n return () => {\n if (fadeAnimationRef.current)\n cancelAnimationFrame(fadeAnimationRef.current);\n if (hoverAnimationRef.current)\n cancelAnimationFrame(hoverAnimationRef.current);\n if (revertTimeout) clearTimeout(revertTimeout);\n if (nreBoundaryLayerRef.current) {\n nreBoundaryLayerRef.current.setMap(null);\n nreBoundaryLayerRef.current = null;\n }\n google.maps.event.removeListener(mouseoverListener);\n google.maps.event.removeListener(mouseoutListener);\n google.maps.event.removeListener(mousemoveListener);\n google.maps.event.removeListener(clickListener);\n };\n }, [map, stableData, colorClasses, nreBoundaries]);\n\n /**\n * Apply visibility filter based on active legend classes\n * and adjust map bounds to fit visible features\n */\n useEffect(() => {\n if (!map || !stableData.length) return;\n\n const visibleBounds = new google.maps.LatLngBounds();\n let hasVisibleFeatures = false;\n\n map.data.forEach((feature: google.maps.Data.Feature) => {\n const value = feature.getProperty('regionValue') as number;\n const colorClass = getColorClass(value ?? 0, colorClasses);\n const classIndex = colorClasses.indexOf(colorClass);\n\n if (activeClasses.has(classIndex)) {\n map.data.overrideStyle(feature, { visible: true });\n feature.getGeometry()?.forEachLatLng((latLng) => {\n visibleBounds.extend(latLng);\n });\n hasVisibleFeatures = true;\n } else {\n map.data.overrideStyle(feature, { visible: false });\n }\n });\n\n if (hasVisibleFeatures && !visibleBounds.isEmpty()) {\n map.fitBounds(visibleBounds, 20);\n }\n }, [map, stableData, activeClasses, colorClasses]);\n\n /**\n * Toggle a color class on/off in the legend filter\n * @param index - Index of the color class in colorClasses\n */\n const toggleClass = (index: number) => {\n setActiveClasses((prev) => {\n const next = new Set(prev);\n if (next.has(index)) {\n next.delete(index);\n } else {\n next.add(index);\n }\n return next;\n });\n };\n\n if (loadError) {\n return (\n <div className=\"p-5 bg-background border border-border-50 rounded-xl\">\n <Text color=\"text-error-700\">Erro ao carregar o mapa</Text>\n </div>\n );\n }\n\n return (\n <div\n className={cn(\n 'p-5 bg-background border border-border-50 rounded-xl flex flex-col gap-4',\n className\n )}\n >\n {/* Header */}\n <div className=\"flex flex-col gap-4\">\n <Text\n as=\"h2\"\n size=\"lg\"\n weight=\"bold\"\n className=\"leading-[21px] tracking-[0.2px]\"\n >\n {title}\n </Text>\n\n {/* Legend */}\n <div className=\"flex flex-wrap gap-8\">\n {colorClasses.map((colorClass, index) => (\n <LegendItem\n key={colorClass.label}\n color={colorClass.fillColor}\n borderColor={\n colorClass.fillColor === colorClass.strokeColor\n ? undefined\n : colorClass.strokeColor\n }\n label={colorClass.label}\n active={activeClasses.has(index)}\n onClick={() => toggleClass(index)}\n />\n ))}\n </div>\n </div>\n\n {/* Map Container */}\n <div className=\"bg-background-50 rounded-lg h-[415px] relative overflow-hidden\">\n {loading || !isLoaded ? (\n <LoadingSkeleton />\n ) : (\n <GoogleMap\n mapContainerStyle={containerStyle}\n center={defaultCenter}\n zoom={7}\n onLoad={onLoad}\n onUnmount={onUnmount}\n options={mapOptions}\n />\n )}\n\n {/* Tooltip */}\n {hoveredRegion && infoPosition && (\n <div\n className=\"fixed z-50 bg-background border border-border-50 shadow-lg rounded-lg p-3 pointer-events-none\"\n style={{\n left: Math.min(infoPosition.x + 10, window.innerWidth - 220),\n top: Math.min(infoPosition.y + 10, window.innerHeight - 80),\n }}\n >\n <Text size=\"sm\" weight=\"semibold\">\n {hoveredRegion.name}\n </Text>\n <Text size=\"xs\" color=\"text-text-700\">\n {countLabel}: {hoveredRegion.accessCount.toLocaleString('pt-BR')}\n </Text>\n </div>\n )}\n </div>\n </div>\n );\n};\n\nexport default ChoroplethMap;\n","import { clsx, type ClassValue } from 'clsx';\nimport { twMerge } from 'tailwind-merge';\n\nexport function cn(...inputs: ClassValue[]) {\n return twMerge(clsx(inputs));\n}\n\nexport { syncDropdownState } from './dropdown';\nexport {\n getSelectedIdsFromCategories,\n toggleArrayItem,\n toggleSingleValue,\n areFiltersEqual,\n} from './activityFilters';\nexport {\n mapQuestionTypeToEnum,\n mapQuestionTypeToEnumRequired,\n} from './questionTypeUtils';\nexport {\n getStatusBadgeConfig,\n formatTimeSpent,\n formatQuestionNumbers,\n formatDateToBrazilian,\n} from './activityDetailsUtils';\n\n/**\n * Format a number as a rounded percentage string\n * @param value - Number to format (0-100)\n * @returns Formatted string with % suffix (e.g., \"72%\")\n */\nexport function formatPercentageRounded(value: number): string {\n return `${Math.round(value)}%`;\n}\n\nexport { formatScore } from './formatScore';\n\n/**\n * Convert hex color to rgba with opacity for background\n * @param hex - Hex color (e.g., \"#4B0082\")\n * @param opacity - Opacity value (0-1)\n * @returns rgba string\n */\nexport function hexToRgba(hex: string, opacity: number): string {\n const result = /^#?([a-f\\d]{2})([a-f\\d]{2})([a-f\\d]{2})$/i.exec(hex);\n if (!result) return `rgba(107, 114, 128, ${opacity})`; // fallback gray\n const r = Number.parseInt(result[1], 16);\n const g = Number.parseInt(result[2], 16);\n const b = Number.parseInt(result[3], 16);\n return `rgba(${r}, ${g}, ${b}, ${opacity})`;\n}\n\n/**\n * Maps Tailwind bg-* class to CSS variable\n * @param bgClass - Tailwind background class (e.g., \"bg-error-600\")\n * @returns CSS variable string (e.g., \"var(--color-error-600)\")\n */\nexport function bgClassToCssVar(bgClass: string): string {\n return `var(--color-${bgClass.replace('bg-', '')})`;\n}\n\n/**\n * Converts polar coordinates to Cartesian for SVG arc path calculations.\n * Angles are in degrees, with 0° at the top (12 o'clock position).\n * @param cx - Center X coordinate\n * @param cy - Center Y coordinate\n * @param r - Radius\n * @param angleDeg - Angle in degrees\n * @returns Cartesian coordinates { x, y }\n */\nexport function polarToCartesian(\n cx: number,\n cy: number,\n r: number,\n angleDeg: number\n): { x: number; y: number } {\n const rad = ((angleDeg - 90) * Math.PI) / 180;\n return { x: cx + r * Math.cos(rad), y: cy + r * Math.sin(rad) };\n}\n\n/**\n * Generates an SVG filled arc (pie slice) path string.\n * @param cx - Center X coordinate\n * @param cy - Center Y coordinate\n * @param r - Radius\n * @param startAngle - Start angle in degrees\n * @param endAngle - End angle in degrees\n * @returns SVG path string for the arc\n */\nexport function describeArc(\n cx: number,\n cy: number,\n r: number,\n startAngle: number,\n endAngle: number\n): string {\n const span = endAngle - startAngle;\n\n // For full circle (or near-full), use two arcs to avoid SVG arc degeneracy\n if (span >= 359.99) {\n const midAngle = startAngle + 180;\n const s = polarToCartesian(cx, cy, r, startAngle);\n const m = polarToCartesian(cx, cy, r, midAngle);\n return `M ${cx} ${cy} L ${s.x} ${s.y} A ${r} ${r} 0 1 1 ${m.x} ${m.y} A ${r} ${r} 0 1 1 ${s.x} ${s.y} Z`;\n }\n\n const s = polarToCartesian(cx, cy, r, endAngle);\n const e = polarToCartesian(cx, cy, r, startAngle);\n const largeArc = span > 180 ? 1 : 0;\n return `M ${cx} ${cy} L ${s.x} ${s.y} A ${r} ${r} 0 ${largeArc} 0 ${e.x} ${e.y} Z`;\n}\n\n/**\n * Retorna a cor hexadecimal com opacidade 0.3 (4d) se não estiver em dark mode.\n * Se estiver em dark mode, retorna a cor original.\n *\n * @param hexColor - Cor hexadecimal (ex: \"#0066b8\" ou \"0066b8\")\n * @param isDark - booleano indicando se está em dark mode\n * @returns string - cor hexadecimal com opacidade se necessário\n */\nexport function getSubjectColorWithOpacity(\n hexColor: string | undefined,\n isDark: boolean\n): string | undefined {\n if (!hexColor) return undefined;\n // Remove o '#' se existir\n let color = hexColor.replace(/^#/, '').toLowerCase();\n\n if (isDark) {\n // Se está em dark mode, sempre remove opacidade se existir\n if (color.length === 8) {\n color = color.slice(0, 6);\n }\n return `#${color}`;\n } else {\n // Se não está em dark mode (light mode)\n let resultColor: string;\n if (color.length === 6) {\n // Adiciona opacidade 0.3 (4D) para cores de 6 dígitos\n resultColor = `#${color}4d`;\n } else if (color.length === 8) {\n // Já tem opacidade, retorna como está\n resultColor = `#${color}`;\n } else {\n // Para outros tamanhos (3, 4, 5 dígitos), retorna como está\n resultColor = `#${color}`;\n }\n return resultColor;\n }\n}\n","import { useEffect, useMemo } from 'react';\nimport { useThemeStore, ThemeMode } from '../store/themeStore';\n\nexport type { ThemeMode };\n\n/**\n * Hook para gerenciar temas e branding institucional\n * Este hook permite alternar entre temas light, dark e automático baseado nas preferências do sistema\n * e fornece acesso aos dados de branding lidos diretamente das meta tags HTML\n * Utiliza Zustand para persistir o estado de tema entre múltiplos arquivos e sessões\n */\nexport const useTheme = () => {\n const {\n themeMode,\n isDark,\n toggleTheme,\n setTheme,\n initializeTheme,\n handleSystemThemeChange,\n } = useThemeStore();\n\n // Read branding data from meta tags\n const branding = useMemo(() => {\n if (typeof document === 'undefined') {\n return {\n theme: null,\n favicon: null,\n icon: null,\n mainLogo: null,\n internalLogo: null,\n loginImage: null,\n };\n }\n\n return {\n theme:\n document.querySelector('meta[name=\"theme\"]')?.getAttribute('content') ??\n null,\n favicon:\n document.querySelector('link[rel=\"icon\"]')?.getAttribute('href') ??\n null,\n icon:\n document\n .querySelector('link[rel=\"apple-touch-icon\"]')\n ?.getAttribute('href') ?? null,\n mainLogo:\n document\n .querySelector('meta[name=\"main-logo\"]')\n ?.getAttribute('content') ?? null,\n internalLogo:\n document\n .querySelector('meta[name=\"internal-logo\"]')\n ?.getAttribute('content') ?? null,\n loginImage:\n document\n .querySelector('meta[name=\"login-image\"]')\n ?.getAttribute('content') ?? null,\n };\n }, []);\n\n useEffect(() => {\n // Initialize theme on first render\n initializeTheme();\n\n // Listener para mudanças nas preferências do sistema (apenas quando mode é 'system')\n const mediaQuery = window.matchMedia('(prefers-color-scheme: dark)');\n\n mediaQuery.addEventListener('change', handleSystemThemeChange);\n\n return () => {\n mediaQuery.removeEventListener('change', handleSystemThemeChange);\n };\n }, [initializeTheme, handleSystemThemeChange]);\n\n return {\n themeMode,\n isDark,\n toggleTheme,\n setTheme,\n branding,\n };\n};\n","import { create } from 'zustand';\nimport { devtools, persist } from 'zustand/middleware';\n\nexport type ThemeMode = 'light' | 'dark' | 'system';\n\n/**\n * Theme store state interface\n */\nexport interface ThemeState {\n /**\n * Current theme mode\n */\n themeMode: ThemeMode;\n /**\n * Whether the current theme is dark\n */\n isDark: boolean;\n}\n\n/**\n * Theme store actions interface\n */\nexport interface ThemeActions {\n /**\n * Apply theme based on the mode selected\n */\n applyTheme: (mode: ThemeMode) => void;\n /**\n * Toggle between themes\n */\n toggleTheme: () => void;\n /**\n * Set a specific theme mode\n */\n setTheme: (mode: ThemeMode) => void;\n /**\n * Set the white-label theme from institution branding\n */\n setWhiteLabelTheme: (theme: string | null) => void;\n /**\n * Clear the white-label theme and revert to default\n */\n clearWhiteLabelTheme: () => void;\n /**\n * Initialize theme on app start\n */\n initializeTheme: () => void;\n /**\n * Handle system theme change\n */\n handleSystemThemeChange: () => void;\n}\n\nexport type ThemeStore = ThemeState & ThemeActions;\n\n/**\n * Mapa de tema light institucional → tema dark correspondente.\n * Adicionar entradas aqui ao introduzir novas instituições.\n */\nconst DARK_THEME_MAP: Record<string, string> = {\n 'base-light': 'base-dark',\n 'enem-parana-light': 'enem-parana-dark',\n 'enem-paraiba-light': 'enem-paraiba-dark',\n 'analytica-light': 'analytica-dark',\n};\n\n/**\n * Resolve o seletor CSS dark concreto com base no tema institucional (light)\n * salvo em `data-original-theme`. Fallback: 'base-dark', que também responde\n * ao seletor legado [data-theme='dark'] preservando compat com apps antigos.\n */\nconst resolveDarkTheme = (originalTheme: string | undefined): string => {\n if (!originalTheme) return 'base-dark';\n return DARK_THEME_MAP[originalTheme] ?? 'base-dark';\n};\n\n/**\n * Apply theme to DOM based on mode\n */\nconst applyThemeToDOM = (mode: ThemeMode): boolean => {\n const htmlElement = document.documentElement;\n const originalTheme = htmlElement.dataset.originalTheme;\n\n if (mode === 'dark') {\n htmlElement.dataset.theme = resolveDarkTheme(originalTheme);\n return true;\n } else if (mode === 'light') {\n if (originalTheme) {\n htmlElement.dataset.theme = originalTheme;\n }\n return false;\n } else if (mode === 'system') {\n const isSystemDark = window.matchMedia(\n '(prefers-color-scheme: dark)'\n ).matches;\n if (isSystemDark) {\n htmlElement.dataset.theme = resolveDarkTheme(originalTheme);\n return true;\n } else if (originalTheme) {\n htmlElement.dataset.theme = originalTheme;\n return false;\n }\n }\n return false;\n};\n\n/**\n * Save original theme from white label (reads from HTML meta tag or data-theme attribute)\n */\nconst saveOriginalTheme = () => {\n const htmlElement = document.documentElement;\n const currentTheme =\n htmlElement.dataset.theme ||\n document.querySelector('meta[name=\"theme\"]')?.getAttribute('content');\n\n if (currentTheme && !htmlElement.dataset.originalTheme) {\n htmlElement.dataset.originalTheme = currentTheme;\n }\n};\n\n/**\n * Theme store using Zustand with persistence\n */\nexport const useThemeStore = create<ThemeStore>()(\n devtools(\n persist(\n (set, get) => ({\n // Initial state\n themeMode: 'system',\n isDark: false,\n\n // Actions\n applyTheme: (mode: ThemeMode) => {\n const isDark = applyThemeToDOM(mode);\n set({ isDark });\n },\n\n toggleTheme: () => {\n const { themeMode, applyTheme } = get();\n let newMode: ThemeMode;\n\n if (themeMode === 'light') {\n newMode = 'dark';\n } else if (themeMode === 'dark') {\n newMode = 'light';\n } else {\n // Se estiver em 'system', vai para 'dark'\n newMode = 'dark';\n }\n\n set({ themeMode: newMode });\n applyTheme(newMode);\n },\n\n setTheme: (mode: ThemeMode) => {\n const { applyTheme } = get();\n set({ themeMode: mode });\n applyTheme(mode);\n },\n\n setWhiteLabelTheme: (theme: string | null) => {\n const htmlElement = document.documentElement;\n\n if (theme) {\n // Set the white-label theme as the original theme\n htmlElement.dataset.originalTheme = theme;\n\n // Apply theme based on current mode\n const { themeMode, applyTheme } = get();\n if (themeMode === 'light' || themeMode === 'system') {\n htmlElement.dataset.theme = theme;\n }\n\n applyTheme(themeMode);\n }\n },\n\n clearWhiteLabelTheme: () => {\n const htmlElement = document.documentElement;\n\n // Remove white-label theme attributes\n delete htmlElement.dataset.originalTheme;\n delete htmlElement.dataset.theme;\n\n // Restore original theme from page metadata\n saveOriginalTheme();\n\n // Re-apply current theme mode to use defaults\n const { themeMode, applyTheme } = get();\n applyTheme(themeMode);\n },\n\n initializeTheme: () => {\n const { themeMode, applyTheme } = get();\n\n // Save original theme from white label\n saveOriginalTheme();\n\n // Apply the current theme mode\n applyTheme(themeMode);\n },\n\n handleSystemThemeChange: () => {\n const { themeMode, applyTheme } = get();\n // Only respond to system changes when in system mode\n if (themeMode === 'system') {\n applyTheme('system');\n }\n },\n }),\n {\n name: 'theme-store', // Nome da chave no localStorage\n partialize: (state) => ({\n themeMode: state.themeMode,\n }), // Só persiste o themeMode, não o isDark\n }\n ),\n {\n name: 'theme-store',\n }\n )\n);\n","import { ComponentPropsWithRef, ElementType, ReactNode } from 'react';\nimport { cn } from '../../utils/utils';\n\n/**\n * Base text component props\n */\ntype BaseTextProps = {\n /** Content to be displayed */\n children?: ReactNode;\n /** Text size variant */\n size?:\n | '2xs'\n | 'xs'\n | 'sm'\n | 'md'\n | 'lg'\n | 'xl'\n | '2xl'\n | '3xl'\n | '4xl'\n | '5xl'\n | '6xl';\n /** Font weight variant */\n weight?:\n | 'hairline'\n | 'light'\n | 'normal'\n | 'medium'\n | 'semibold'\n | 'bold'\n | 'extrabold'\n | 'black';\n /** Color variant - white for light backgrounds, black for dark backgrounds */\n color?: string;\n /** Additional CSS classes to apply */\n className?: string;\n};\n\n/**\n * Polymorphic text component props that ensures type safety based on the 'as' prop\n */\ntype TextProps<T extends ElementType = 'p'> = BaseTextProps & {\n /** HTML tag to render */\n as?: T;\n} & Omit<ComponentPropsWithRef<T>, keyof BaseTextProps>;\n\n/**\n * Text component for Analytica Ensino platforms\n *\n * A flexible polymorphic text component with multiple sizes, weights, and colors.\n * Automatically adapts to dark and light themes with full type safety.\n *\n * @param children - The content to display\n * @param size - The text size variant (2xs, xs, sm, md, lg, xl, 2xl, 3xl, 4xl, 5xl, 6xl)\n * @param weight - The font weight variant (hairline, light, normal, medium, semibold, bold, extrabold, black)\n * @param color - The color variant - adapts to theme\n * @param as - The HTML tag to render - determines allowed attributes via TypeScript\n * @param className - Additional CSS classes\n * @param props - HTML attributes valid for the chosen tag only\n * @returns A styled text element with type-safe attributes\n *\n * @example\n * ```tsx\n * <Text size=\"lg\" weight=\"bold\" color=\"text-info-800\">\n * This is a large, bold text\n * </Text>\n *\n * <Text as=\"a\" href=\"/link\" target=\"_blank\">\n * Link with type-safe anchor attributes\n * </Text>\n *\n * <Text as=\"button\" onClick={handleClick} disabled>\n * Button with type-safe button attributes\n * </Text>\n * ```\n */\nconst Text = <T extends ElementType = 'p'>({\n children,\n size = 'md',\n weight = 'normal',\n color = 'text-text-950',\n as,\n className = '',\n ...props\n}: TextProps<T>) => {\n let sizeClasses: string;\n let weightClasses: string;\n\n // Text size classes mapping\n const sizeClassMap = {\n '2xs': 'text-2xs',\n xs: 'text-xs',\n sm: 'text-sm',\n md: 'text-md',\n lg: 'text-lg',\n xl: 'text-xl',\n '2xl': 'text-2xl',\n '3xl': 'text-3xl',\n '4xl': 'text-4xl',\n '5xl': 'text-5xl',\n '6xl': 'text-6xl',\n } as const;\n\n sizeClasses = sizeClassMap[size] ?? sizeClassMap.md;\n\n // Font weight classes mapping\n const weightClassMap = {\n hairline: 'font-hairline',\n light: 'font-light',\n normal: 'font-normal',\n medium: 'font-medium',\n semibold: 'font-semibold',\n bold: 'font-bold',\n extrabold: 'font-extrabold',\n black: 'font-black',\n } as const;\n\n weightClasses = weightClassMap[weight] ?? weightClassMap.normal;\n\n const baseClasses = 'font-primary';\n const Component = as ?? ('p' as ElementType);\n\n return (\n <Component\n className={cn(baseClasses, sizeClasses, weightClasses, color, className)}\n {...props}\n >\n {children}\n </Component>\n );\n};\n\nexport default Text;\n"],"mappings":"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","names":["import_react","import_jsx_runtime","union"]}
|
|
@@ -364,6 +364,7 @@ var ChoroplethMap = ({
|
|
|
364
364
|
data,
|
|
365
365
|
apiKey,
|
|
366
366
|
title = "Performance por regi\xE3o",
|
|
367
|
+
countLabel = "Acessos",
|
|
367
368
|
loading = false,
|
|
368
369
|
bounds,
|
|
369
370
|
onRegionClick,
|
|
@@ -724,7 +725,8 @@ var ChoroplethMap = ({
|
|
|
724
725
|
children: [
|
|
725
726
|
/* @__PURE__ */ jsx2(Text_default, { size: "sm", weight: "semibold", children: hoveredRegion.name }),
|
|
726
727
|
/* @__PURE__ */ jsxs(Text_default, { size: "xs", color: "text-text-700", children: [
|
|
727
|
-
|
|
728
|
+
countLabel,
|
|
729
|
+
": ",
|
|
728
730
|
hoveredRegion.accessCount.toLocaleString("pt-BR")
|
|
729
731
|
] })
|
|
730
732
|
]
|