diff --git a/spotlight-client/src/charts/TopologicalMap.tsx b/spotlight-client/src/charts/TopologicalMap.tsx
deleted file mode 100644
index 1c3dbc91..00000000
--- a/spotlight-client/src/charts/TopologicalMap.tsx
+++ /dev/null
@@ -1,218 +0,0 @@
-// Recidiviz - a data platform for criminal justice reform
-// Copyright (C) 2021 Recidiviz, Inc.
-//
-// This program is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with this program. If not, see .
-// =============================================================================
-
-import { geoAlbers, geoCentroid } from "d3-geo";
-import { rem } from "polished";
-import React, { useState } from "react";
-import {
- ComposableMap,
- Geographies,
- Geography,
- Marker,
- GeographyProps,
-} from "react-simple-maps";
-import { Spring } from "react-spring/renderprops.cjs";
-import styled from "styled-components/macro";
-import { mesh } from "topojson";
-import type { Topology } from "topojson-specification";
-import { ValuesType } from "utility-types";
-import { LocalityDataMapping } from "../contentModels/types";
-import MeasureWidth from "../MeasureWidth";
-import { colors } from "../UiLibrary";
-
-const RatioContainerOuter = styled.div`
- position: relative;
- height: 0;
-`;
-
-const RatioContainerInner = styled.div({
- position: "absolute",
- top: 0,
- left: 0,
- right: 0,
- bottom: 0,
-});
-
-/**
- * Implements a version of the Aspect Ratio Box technique described here:
- * https://github.com/zcreativelabs/react-simple-maps/issues/37#issuecomment-349435145
- * but with explicit width (our flex layout prefers it or elements may collapse).
- * This is needed to size the map SVG properly in IE 11 and some mobile devices.
- */
-const RatioContainer: React.FC<{ width: number; aspectRatio: number }> = ({
- aspectRatio,
- children,
- width,
-}) => {
- return (
-
- {children}
-
- );
-};
-
-const Wrapper = styled.div``;
-
-type MapProps = {
- aspectRatio: number;
- localityData: LocalityDataMapping;
- topology: Topology;
-};
-
-/**
- * Given a topojson topology and a mapping of topological object IDs to values,
- * draws a map and labels the topological objects accordingly.
- */
-export default function TopologicalMap({
- aspectRatio,
- localityData,
- topology,
-}: MapProps): React.ReactElement {
- return (
-
- {({ measureRef, width }) => {
- const stateProjection = geoAlbers().fitExtent(
- [
- [0, 0],
- [width, width / aspectRatio],
- ],
- mesh(topology)
- );
-
- return (
-
-
-
-
- {({ geographies }) => {
- return geographies.map((geography) => {
- return (
-
- );
- });
- }}
-
-
-
-
- );
- }}
-
- );
-}
-
-const RegionGroup = styled.g`
- &:focus {
- outline: none;
- }
-`;
-
-const RegionGeography = styled(Geography)`
- &:focus {
- outline: none;
- }
-`;
-
-const RegionMarker = styled(Marker)``;
-
-const RegionLabel = styled.text`
- font-size: ${rem(18)};
- font-weight: 600;
- letter-spacing: -0.015em;
- text-anchor: middle;
-`;
-
-const Region = ({
- data,
- geography,
-}: {
- data: ValuesType;
- geography: GeographyProps["geography"];
-}) => {
- const centroid = geoCentroid(geography);
- const { label, value } = data;
- const [hoverRegion, setHoverRegion] = useState(false);
-
- const setHover = () => {
- setHoverRegion(true);
- };
-
- const clearHover = () => {
- setHoverRegion(false);
- };
-
- return (
-
- {/*
- using spring renderprops instead of hook because react-simple-maps
- components are not compatible with the `animated` wrapper
- */}
-
- {(props) => (
- <>
-
-
- {value}
-
- >
- )}
-
-
- );
-};
diff --git a/spotlight-client/src/charts/TopologicalMap/RatioContainer.tsx b/spotlight-client/src/charts/TopologicalMap/RatioContainer.tsx
new file mode 100644
index 00000000..bd006358
--- /dev/null
+++ b/spotlight-client/src/charts/TopologicalMap/RatioContainer.tsx
@@ -0,0 +1,55 @@
+// Recidiviz - a data platform for criminal justice reform
+// Copyright (C) 2021 Recidiviz, Inc.
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see .
+// =============================================================================
+
+import React from "react";
+import styled from "styled-components/macro";
+
+const RatioContainerOuter = styled.div`
+ position: relative;
+ height: 0;
+`;
+
+const RatioContainerInner = styled.div({
+ position: "absolute",
+ top: 0,
+ left: 0,
+ right: 0,
+ bottom: 0,
+});
+
+/**
+ * Implements a version of the Aspect Ratio Box technique described here:
+ * https://github.com/zcreativelabs/react-simple-maps/issues/37#issuecomment-349435145
+ * but with explicit width (our flex layout prefers it or elements may collapse).
+ * This is needed to size the map SVG properly in IE 11 and some mobile devices.
+ */
+const RatioContainer: React.FC<{ width: number; aspectRatio: number }> = ({
+ aspectRatio,
+ children,
+ width,
+}) => {
+ return (
+
+ {children}
+
+ );
+};
+
+export default RatioContainer;
diff --git a/spotlight-client/src/charts/TopologicalMap/Region.tsx b/spotlight-client/src/charts/TopologicalMap/Region.tsx
new file mode 100644
index 00000000..2aaf7b3c
--- /dev/null
+++ b/spotlight-client/src/charts/TopologicalMap/Region.tsx
@@ -0,0 +1,112 @@
+// Recidiviz - a data platform for criminal justice reform
+// Copyright (C) 2021 Recidiviz, Inc.
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see .
+// =============================================================================
+
+import { geoCentroid } from "d3-geo";
+import { rem } from "polished";
+import React, { useState } from "react";
+import { Geography, Marker, GeographyProps } from "react-simple-maps";
+import { Spring } from "react-spring/renderprops.cjs";
+import styled from "styled-components/macro";
+import { ValuesType } from "utility-types";
+import { LocalityDataMapping } from "../../contentModels/types";
+import { colors } from "../../UiLibrary";
+
+const RegionGroup = styled.g`
+ &:focus {
+ outline: none;
+ }
+`;
+
+const RegionGeography = styled(Geography)`
+ &:focus {
+ outline: none;
+ }
+`;
+
+const RegionMarker = styled(Marker)``;
+
+const RegionLabel = styled.text`
+ font-size: ${rem(18)};
+ font-weight: 600;
+ letter-spacing: -0.015em;
+ text-anchor: middle;
+`;
+
+const Region = ({
+ data,
+ geography,
+}: {
+ data: ValuesType;
+ geography: GeographyProps["geography"];
+}): React.ReactElement => {
+ const centroid = geoCentroid(geography);
+ const { label, value } = data;
+ const [hoverRegion, setHoverRegion] = useState(false);
+
+ const setHover = () => {
+ setHoverRegion(true);
+ };
+
+ const clearHover = () => {
+ setHoverRegion(false);
+ };
+
+ return (
+
+ {/*
+ using spring renderprops instead of hook because react-simple-maps
+ components are not compatible with the `animated` wrapper
+ */}
+
+ {(props) => (
+ <>
+
+
+ {value}
+
+ >
+ )}
+
+
+ );
+};
+
+export default Region;
diff --git a/spotlight-client/src/charts/TopologicalMap/TopologicalMap.tsx b/spotlight-client/src/charts/TopologicalMap/TopologicalMap.tsx
new file mode 100644
index 00000000..9f9bbf6a
--- /dev/null
+++ b/spotlight-client/src/charts/TopologicalMap/TopologicalMap.tsx
@@ -0,0 +1,92 @@
+// Recidiviz - a data platform for criminal justice reform
+// Copyright (C) 2021 Recidiviz, Inc.
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see .
+// =============================================================================
+
+import { geoAlbers } from "d3-geo";
+import React from "react";
+import { ComposableMap, Geographies } from "react-simple-maps";
+import styled from "styled-components/macro";
+import { mesh } from "topojson";
+import type { Topology } from "topojson-specification";
+import { LocalityDataMapping } from "../../contentModels/types";
+import MeasureWidth from "../../MeasureWidth";
+import RatioContainer from "./RatioContainer";
+import Region from "./Region";
+
+const Wrapper = styled.div``;
+
+type MapProps = {
+ aspectRatio: number;
+ localityData: LocalityDataMapping;
+ topology: Topology;
+};
+
+/**
+ * Given a topojson topology and a mapping of topological object IDs to values,
+ * draws a map and labels the topological objects accordingly.
+ */
+export default function TopologicalMap({
+ aspectRatio,
+ localityData,
+ topology,
+}: MapProps): React.ReactElement {
+ return (
+
+ {({ measureRef, width }) => {
+ const stateProjection = geoAlbers().fitExtent(
+ [
+ [0, 0],
+ [width, width / aspectRatio],
+ ],
+ mesh(topology)
+ );
+
+ return (
+
+
+
+
+ {({ geographies }) => {
+ return geographies.map((geography) => {
+ return (
+
+ );
+ });
+ }}
+
+
+
+
+ );
+ }}
+
+ );
+}
diff --git a/spotlight-client/src/charts/TopologicalMap/index.ts b/spotlight-client/src/charts/TopologicalMap/index.ts
new file mode 100644
index 00000000..87520889
--- /dev/null
+++ b/spotlight-client/src/charts/TopologicalMap/index.ts
@@ -0,0 +1,18 @@
+// Recidiviz - a data platform for criminal justice reform
+// Copyright (C) 2021 Recidiviz, Inc.
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see .
+// =============================================================================
+
+export { default } from "./TopologicalMap";