bento-charts 2.3.0 → 2.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (65) hide show
  1. package/.github/workflows/release.yml +1 -1
  2. package/README.md +94 -23
  3. package/dist/ChartConfigProvider.d.ts +2 -2
  4. package/dist/ChartConfigProvider.js.map +1 -1
  5. package/dist/Components/Charts/BentoBarChart.js.map +1 -1
  6. package/dist/Components/Charts/BentoPie.js +33 -31
  7. package/dist/Components/Charts/BentoPie.js.map +1 -1
  8. package/dist/Components/Maps/BentoChoroplethMap.d.ts +3 -0
  9. package/dist/Components/Maps/BentoChoroplethMap.js +91 -0
  10. package/dist/Components/Maps/BentoChoroplethMap.js.map +1 -0
  11. package/dist/Components/Maps/BentoMapContainer.d.ts +7 -0
  12. package/dist/Components/Maps/BentoMapContainer.js +33 -0
  13. package/dist/Components/Maps/BentoMapContainer.js.map +1 -0
  14. package/dist/Components/Maps/BentoOSMTileLayer.d.ts +2 -0
  15. package/dist/Components/Maps/BentoOSMTileLayer.js +6 -0
  16. package/dist/Components/Maps/BentoOSMTileLayer.js.map +1 -0
  17. package/dist/Components/Maps/BentoPointMap.d.ts +3 -0
  18. package/dist/Components/Maps/BentoPointMap.js +28 -0
  19. package/dist/Components/Maps/BentoPointMap.js.map +1 -0
  20. package/dist/Components/Maps/controls/MapLegendContinuous.d.ts +10 -0
  21. package/dist/Components/Maps/controls/MapLegendContinuous.js +19 -0
  22. package/dist/Components/Maps/controls/MapLegendContinuous.js.map +1 -0
  23. package/dist/Components/Maps/controls/MapLegendDiscrete.d.ts +8 -0
  24. package/dist/Components/Maps/controls/MapLegendDiscrete.js +22 -0
  25. package/dist/Components/Maps/controls/MapLegendDiscrete.js.map +1 -0
  26. package/dist/Components/Maps/controls/utils.d.ts +4 -0
  27. package/dist/Components/Maps/controls/utils.js +7 -0
  28. package/dist/Components/Maps/controls/utils.js.map +1 -0
  29. package/dist/constants/mapConstants.d.ts +2 -0
  30. package/dist/constants/mapConstants.js +3 -0
  31. package/dist/constants/mapConstants.js.map +1 -0
  32. package/dist/index.js +5 -0
  33. package/dist/index.js.map +1 -1
  34. package/dist/maps.d.ts +3 -0
  35. package/dist/maps.js +5 -0
  36. package/dist/maps.js.map +1 -0
  37. package/dist/styles.css +48 -0
  38. package/dist/types/chartTypes.d.ts +11 -9
  39. package/dist/types/geoJSONTypes.d.ts +18 -0
  40. package/dist/types/geoJSONTypes.js +2 -0
  41. package/dist/types/geoJSONTypes.js.map +1 -0
  42. package/dist/types/mapTypes.d.ts +43 -0
  43. package/dist/types/mapTypes.js +2 -0
  44. package/dist/types/mapTypes.js.map +1 -0
  45. package/package.json +32 -5
  46. package/src/ChartConfigProvider.tsx +9 -2
  47. package/src/Components/Charts/BentoBarChart.tsx +2 -2
  48. package/src/Components/Charts/BentoPie.tsx +55 -53
  49. package/src/Components/Maps/BentoChoroplethMap.tsx +138 -0
  50. package/src/Components/Maps/BentoMapContainer.tsx +35 -0
  51. package/src/Components/Maps/BentoOSMTileLayer.tsx +7 -0
  52. package/src/Components/Maps/BentoPointMap.tsx +33 -0
  53. package/src/Components/Maps/controls/MapLegendContinuous.tsx +32 -0
  54. package/src/Components/Maps/controls/MapLegendDiscrete.tsx +31 -0
  55. package/src/Components/Maps/controls/utils.ts +8 -0
  56. package/src/constants/mapConstants.ts +4 -0
  57. package/src/index.ts +7 -0
  58. package/src/maps.ts +4 -0
  59. package/src/react-app-env.d.ts +1 -0
  60. package/src/styles.css +48 -0
  61. package/src/types/chartTypes.ts +12 -9
  62. package/src/types/geoJSONTypes.ts +21 -0
  63. package/src/types/mapTypes.ts +52 -0
  64. package/tsconfig.json +1 -1
  65. package/webpack.config.js +60 -0
@@ -0,0 +1,138 @@
1
+ import React, { Ref, useCallback, useEffect, useMemo, useRef, useState } from 'react';
2
+ import { GeoJSON, Popup } from 'react-leaflet';
3
+ import { interpolateRgb } from 'd3-interpolate';
4
+ import type { Feature as GeoJSONFeatureType } from 'geojson';
5
+ import type {
6
+ ControlPosition,
7
+ GeoJSON as LeafletGeoJSON,
8
+ LeafletMouseEvent,
9
+ LeafletEventHandlerFnMap,
10
+ PathOptions,
11
+ } from 'leaflet';
12
+
13
+ import type { ChoroplethMapProps } from '../../types/mapTypes';
14
+
15
+ import BentoMapContainer from './BentoMapContainer';
16
+ import MapLegendContinuous from './controls/MapLegendContinuous';
17
+ import MapLegendDiscrete from './controls/MapLegendDiscrete';
18
+
19
+ const DEFAULT_CATEGORY = '';
20
+ const POS_BOTTOM_RIGHT: ControlPosition = 'bottomright';
21
+
22
+ const BentoChoroplethMap = ({
23
+ height,
24
+ data: originalData,
25
+ preFilter,
26
+ dataMap,
27
+ postFilter,
28
+ center,
29
+ zoom,
30
+ tileLayer,
31
+ colorMode,
32
+ features,
33
+ categoryProp,
34
+ onClick,
35
+ renderPopupBody,
36
+ }: ChoroplethMapProps) => {
37
+ const data = useMemo(() => {
38
+ let data = [...originalData];
39
+ if (preFilter) data = data.filter(preFilter);
40
+ if (dataMap) data = data.map(dataMap);
41
+ if (postFilter) data = data.filter(postFilter);
42
+ return data;
43
+ }, [originalData]);
44
+
45
+ const dataByFeatureCat = useMemo(() => Object.fromEntries(data.map((d) => [d.x, d.y])), [data]);
46
+
47
+ const minYVal = useMemo(() => Math.min(...data.map((d) => d.y)), [data]);
48
+ const maxYVal = useMemo(() => Math.max(...data.map((d) => d.y)), [data]);
49
+
50
+ const calculateColor = useCallback(
51
+ (v: number | undefined): string =>
52
+ colorMode.mode === 'continuous'
53
+ ? interpolateRgb(colorMode.minColor, colorMode.maxColor)(((v ?? minYVal) - minYVal) / (maxYVal - minYVal))
54
+ : colorMode.colorFunction(v),
55
+ [colorMode, minYVal, maxYVal]
56
+ );
57
+
58
+ const shapeStyle = useCallback(
59
+ (f: GeoJSONFeatureType): PathOptions => {
60
+ const fProps = f.properties ?? {};
61
+ if (!Object.keys(fProps).includes(categoryProp)) {
62
+ console.warn(`Feature is missing category prop ${categoryProp}`, f);
63
+ }
64
+ const cat: string = fProps[categoryProp] ?? DEFAULT_CATEGORY;
65
+ return {
66
+ color: 'white',
67
+ weight: 2,
68
+ fillColor: calculateColor(dataByFeatureCat[cat]),
69
+ fillOpacity: 1, // actual opacity set by fillColor
70
+ };
71
+ },
72
+ [data, features]
73
+ );
74
+
75
+ const [popupContents, setPopupContents] = useState<React.ReactNode | null>(null);
76
+
77
+ const eventHandlers = useMemo(
78
+ () =>
79
+ ({
80
+ click: (e: LeafletMouseEvent) => {
81
+ const feature = e.sourceTarget.feature as GeoJSONFeatureType;
82
+ const fProps = feature.properties ?? {};
83
+ const title = fProps.title ? `${fProps.title} (${fProps[categoryProp]})` : fProps[categoryProp];
84
+ setPopupContents(
85
+ <div>
86
+ <h4 style={{ marginBottom: renderPopupBody ? 6 : 0 }}>
87
+ {onClick ? (
88
+ <a
89
+ href="#"
90
+ onClick={(e) => {
91
+ if (onClick) onClick(feature);
92
+ e.preventDefault();
93
+ }}
94
+ >
95
+ {title}
96
+ </a>
97
+ ) : (
98
+ <span>{title}</span>
99
+ )}
100
+ </h4>
101
+ {renderPopupBody ? renderPopupBody(feature, dataByFeatureCat[fProps[categoryProp]]) : null}
102
+ </div>
103
+ );
104
+ },
105
+ } as LeafletEventHandlerFnMap),
106
+ [onClick, categoryProp, renderPopupBody]
107
+ );
108
+
109
+ const geoJsonLayer: Ref<LeafletGeoJSON> = useRef(null);
110
+ useEffect(() => {
111
+ // Bizarre workaround needed for react-leaflet when handling `features` change:
112
+ // See https://github.com/PaulLeCam/react-leaflet/issues/332#issuecomment-731379795
113
+ if (geoJsonLayer.current) {
114
+ geoJsonLayer.current.clearLayers().addData(features);
115
+ }
116
+ }, [features]);
117
+
118
+ return (
119
+ <BentoMapContainer height={height} center={center} zoom={zoom} tileLayer={tileLayer}>
120
+ <GeoJSON ref={geoJsonLayer} data={features} style={shapeStyle} eventHandlers={eventHandlers}>
121
+ <Popup>{popupContents}</Popup>
122
+ </GeoJSON>
123
+ {colorMode.mode === 'continuous' ? (
124
+ <MapLegendContinuous
125
+ position={POS_BOTTOM_RIGHT}
126
+ minColor={colorMode.minColor}
127
+ minValue={minYVal}
128
+ maxColor={colorMode.maxColor}
129
+ maxValue={maxYVal}
130
+ />
131
+ ) : (
132
+ <MapLegendDiscrete position={POS_BOTTOM_RIGHT} legendItems={colorMode.legendItems} />
133
+ )}
134
+ </BentoMapContainer>
135
+ );
136
+ };
137
+
138
+ export default BentoChoroplethMap;
@@ -0,0 +1,35 @@
1
+ import React from 'react';
2
+ import type { ReactNode } from 'react';
3
+ import { MapContainer } from 'react-leaflet';
4
+ import L, { Point } from 'leaflet';
5
+
6
+ import BentoOSMTileLayer from './BentoOSMTileLayer';
7
+ import type { BaseMapProps } from '../../types/mapTypes';
8
+
9
+ import iconPng from 'leaflet/dist/images/marker-icon.png';
10
+ import icon2XPng from 'leaflet/dist/images/marker-icon-2x.png';
11
+ import iconShadowPng from 'leaflet/dist/images/marker-shadow.png';
12
+
13
+ const defaultIcon = L.icon({
14
+ iconUrl: iconPng,
15
+ iconRetinaUrl: icon2XPng,
16
+ iconSize: new Point(25, 41),
17
+ iconAnchor: new Point(12, 41),
18
+ popupAnchor: new Point(1, -41),
19
+ shadowUrl: iconShadowPng,
20
+ });
21
+
22
+ L.Marker.prototype.options.icon = defaultIcon;
23
+
24
+ interface MapContainerProps extends BaseMapProps {
25
+ children: ReactNode;
26
+ }
27
+
28
+ const BentoMapContainer = ({ height, center, zoom, children, tileLayer }: MapContainerProps) => (
29
+ <MapContainer style={{ height }} center={center} zoom={zoom}>
30
+ {tileLayer ?? <BentoOSMTileLayer />}
31
+ {children}
32
+ </MapContainer>
33
+ );
34
+
35
+ export default BentoMapContainer;
@@ -0,0 +1,7 @@
1
+ import React from 'react';
2
+ import { TileLayer } from 'react-leaflet';
3
+ import { OSM_TILE_LAYER_ATTRIBUTION, OSM_TILE_LAYER_TEMPLATE } from '../../constants/mapConstants';
4
+
5
+ const BentoOSMTileLayer = () => <TileLayer attribution={OSM_TILE_LAYER_ATTRIBUTION} url={OSM_TILE_LAYER_TEMPLATE} />;
6
+
7
+ export default BentoOSMTileLayer;
@@ -0,0 +1,33 @@
1
+ import React from 'react';
2
+ import { Marker, Popup } from 'react-leaflet';
3
+ import BentoMapContainer from './BentoMapContainer';
4
+ import type { PointMapProps } from '../../types/mapTypes';
5
+
6
+ const BentoPointMap = ({ height, center, zoom, tileLayer, data, onClick, renderPopupBody }: PointMapProps) => {
7
+ return (
8
+ <BentoMapContainer height={height} center={center} zoom={zoom} tileLayer={tileLayer}>
9
+ {data.map((point, i) => {
10
+ const { coordinates, title } = point;
11
+
12
+ // We expect points in [long, lat] order (consistent with GeoJSON), but Leaflet wants them in [lat, long].
13
+ const coordinatesLatLongOrder: [number, number] = [coordinates[1], coordinates[0]];
14
+
15
+ return (
16
+ <Marker key={i} position={coordinatesLatLongOrder}>
17
+ <Popup>
18
+ <h4 style={{ marginBottom: renderPopupBody ? 6 : 0 }}>
19
+ {onClick ? <a href="#" onClick={(e) => {
20
+ onClick(point);
21
+ e.preventDefault();
22
+ }}>{title}</a> : <>{title}</>}
23
+ </h4>
24
+ {renderPopupBody ? renderPopupBody(point) : null}
25
+ </Popup>
26
+ </Marker>
27
+ );
28
+ })}
29
+ </BentoMapContainer>
30
+ );
31
+ };
32
+
33
+ export default BentoPointMap;
@@ -0,0 +1,32 @@
1
+ import React from 'react';
2
+ import type { ControlPosition } from 'leaflet';
3
+ import { controlPositionClasses } from './utils';
4
+
5
+ export interface MapLegendDiscreteProps {
6
+ position: ControlPosition;
7
+ minValue: number;
8
+ minColor: string;
9
+ maxValue: number;
10
+ maxColor: string;
11
+ }
12
+
13
+ const MapLegendContinuous = ({ position, minValue, minColor, maxValue, maxColor }: MapLegendDiscreteProps) => {
14
+ return (
15
+ <div className={controlPositionClasses[position]}>
16
+ <div className="leaflet-control bento-charts--map--legend">
17
+ <div className="bento-charts--map--legend--scale">
18
+ <div
19
+ className="bento-charts--continuous-scale"
20
+ style={{ background: `linear-gradient(0deg, ${minColor} 0%, ${maxColor} 100%)` }}
21
+ />
22
+ <div className="bento-charts--map--legend--values">
23
+ <span>{maxValue}</span>
24
+ <span>{minValue}</span>
25
+ </div>
26
+ </div>
27
+ </div>
28
+ </div>
29
+ );
30
+ };
31
+
32
+ export default MapLegendContinuous;
@@ -0,0 +1,31 @@
1
+ import React from 'react';
2
+ import type { ControlPosition } from 'leaflet';
3
+ import type { MapDiscreteLegendItem } from '../../../types/mapTypes';
4
+ import { controlPositionClasses } from './utils';
5
+
6
+ export interface MapLegendDiscreteProps {
7
+ position: ControlPosition;
8
+ legendItems: MapDiscreteLegendItem[];
9
+ }
10
+
11
+ const MapLegendDiscrete = ({ position, legendItems }: MapLegendDiscreteProps) => {
12
+ return (
13
+ <div className={controlPositionClasses[position]}>
14
+ <div className="leaflet-control bento-charts--map--legend">
15
+ <ul>
16
+ {legendItems.map(({ label, color }, i) => (
17
+ <li key={i}>
18
+ <span
19
+ className="bento-charts--map--legend--patch"
20
+ style={{ backgroundColor: color ?? `rgba(255, 255, 255, 0)` }}
21
+ />
22
+ {label}
23
+ </li>
24
+ ))}
25
+ </ul>
26
+ </div>
27
+ </div>
28
+ );
29
+ };
30
+
31
+ export default MapLegendDiscrete;
@@ -0,0 +1,8 @@
1
+ import type { ControlPosition } from 'leaflet';
2
+
3
+ export const controlPositionClasses: { [x in ControlPosition]: string } = {
4
+ bottomleft: 'leaflet-bottom leaflet-left',
5
+ bottomright: 'leaflet-bottom leaflet-right',
6
+ topleft: 'leaflet-top leaflet-left',
7
+ topright: 'leaflet-bottom leaflet-right',
8
+ };
@@ -0,0 +1,4 @@
1
+ export const OSM_TILE_LAYER_ATTRIBUTION = `
2
+ &copy; <a href='https://www.openstreetmap.org/copyright'>OpenStreetMap</a> contributors
3
+ `;
4
+ export const OSM_TILE_LAYER_TEMPLATE = 'https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png';
package/src/index.ts CHANGED
@@ -1,5 +1,12 @@
1
+ // Disable unused item linting in WebStorm:
2
+ // noinspection JSUnusedGlobalSymbols
3
+
4
+ // Categorical charts
1
5
  export { default as BarChart } from './Components/Charts/BentoBarChart';
2
6
  export { default as PieChart } from './Components/Charts/BentoPie';
3
7
 
8
+ // Maps are not included in index.ts - instead, they need to be included from `bento-charts/maps`.
9
+ // This way, we can have optional peer dependencies.
10
+
4
11
  export { default as ChartConfigProvider } from './ChartConfigProvider';
5
12
  export * from './types/chartTypes';
package/src/maps.ts ADDED
@@ -0,0 +1,4 @@
1
+ // Maps
2
+ export { default as PointMap } from './Components/Maps/BentoPointMap';
3
+ export { default as ChoroplethMap } from './Components/Maps/BentoChoroplethMap';
4
+ export * from './types/mapTypes';
@@ -0,0 +1 @@
1
+ declare module '*.png';
package/src/styles.css ADDED
@@ -0,0 +1,48 @@
1
+ .bento-charts--map--legend {
2
+ background-color: white;
3
+ padding: 12px;
4
+ border-radius: 12px;
5
+ border: 1px solid rgba(0, 0, 0, 0.2);
6
+ box-shadow: 0 1px 3px rgba(0, 0, 0, 0.07);
7
+ }
8
+ .leaflet-bottom .bento-charts--map--legend {
9
+ margin-bottom: 28px;
10
+ }
11
+
12
+ .bento-charts--map--legend ul {
13
+ list-style: none;
14
+ margin: 0;
15
+ padding: 0;
16
+ display: flex;
17
+ flex-direction: column;
18
+ gap: 6px;
19
+ }
20
+
21
+ .bento-charts--map--legend--patch {
22
+ display: inline-block;
23
+ width: 1rem;
24
+ height: 1rem;
25
+ border: 1px solid white;
26
+ vertical-align: top;
27
+ margin-right: 12px;
28
+ border-radius: 3px;
29
+ }
30
+
31
+ .bento-charts--map--legend--scale {
32
+ height: 100px;
33
+ display: flex;
34
+ gap: 12px;
35
+ }
36
+
37
+ .bento-charts--continuous-scale {
38
+ width: 1rem;
39
+ height: 100%;
40
+ }
41
+
42
+ .bento-charts--map--legend--values {
43
+ display: flex;
44
+ flex-direction: column;
45
+ }
46
+ .bento-charts--map--legend--values > span:first-of-type {
47
+ flex: 1;
48
+ }
@@ -1,8 +1,8 @@
1
- import { PieProps, BarProps } from 'recharts';
1
+ import type { PieProps, BarProps } from 'recharts';
2
2
 
3
- export type ChartDataType = ChartDataItem[];
3
+ export type CategoricalChartDataType = CategoricalChartDataItem[];
4
4
 
5
- export interface ChartDataItem {
5
+ export interface CategoricalChartDataItem {
6
6
  x: string;
7
7
  y: number;
8
8
  }
@@ -36,7 +36,7 @@ export type FilterCallback<T> = (value: T, index: number, array: T[]) => boolean
36
36
  export type UnitaryMapCallback<T> = (value: T, index: number, array: T[]) => T;
37
37
  // export type BinaryMapCallback<T, U> = (value: T, index: number, array: T[]) => U;
38
38
 
39
- export type ChartFilterCallback = FilterCallback<ChartDataItem>;
39
+ export type ChartFilterCallback = FilterCallback<CategoricalChartDataItem>;
40
40
 
41
41
  export type SupportedLng = 'en' | 'fr';
42
42
 
@@ -51,16 +51,19 @@ export type TranslationObject = {
51
51
  };
52
52
 
53
53
  // ################### COMPONENT PROPS #####################
54
- interface BaseChartProps {
55
- data: ChartDataType;
54
+ export interface BaseChartComponentProps {
56
55
  height: number;
57
56
  preFilter?: ChartFilterCallback;
58
- dataMap?: UnitaryMapCallback<ChartDataItem>;
57
+ dataMap?: UnitaryMapCallback<CategoricalChartDataItem>;
59
58
  postFilter?: ChartFilterCallback;
59
+ }
60
+
61
+ interface BaseCategoricalChartProps extends BaseChartComponentProps {
62
+ data: CategoricalChartDataType;
60
63
  removeEmpty?: boolean;
61
64
  }
62
65
 
63
- export interface PieChartProps extends BaseChartProps {
66
+ export interface PieChartProps extends BaseCategoricalChartProps {
64
67
  colorTheme?: keyof ChartTheme['pie'];
65
68
  sort?: boolean;
66
69
  onClick?: PieProps['onClick'];
@@ -68,7 +71,7 @@ export interface PieChartProps extends BaseChartProps {
68
71
  maxLabelChars?: number;
69
72
  }
70
73
 
71
- export interface BarChartProps extends BaseChartProps {
74
+ export interface BarChartProps extends BaseCategoricalChartProps {
72
75
  colorTheme?: keyof ChartTheme['bar'];
73
76
  title?: string;
74
77
  units: string;
@@ -0,0 +1,21 @@
1
+ export interface GeoJSONGeomPolygon {
2
+ type: 'Polygon';
3
+ coordinates: number[][][];
4
+ }
5
+
6
+ export interface BentoGeoJSONProperties {
7
+ title: string;
8
+ [x: string]: unknown;
9
+ }
10
+
11
+ export interface GeoJSONPolygonFeature {
12
+ type: 'Feature';
13
+ geometry: GeoJSONGeomPolygon;
14
+ properties: BentoGeoJSONProperties;
15
+ }
16
+
17
+ export interface GeoJSONPolygonOnlyFeatureCollection {
18
+ type: 'FeatureCollection';
19
+ features: GeoJSONPolygonFeature[];
20
+ [x: string]: unknown;
21
+ }
@@ -0,0 +1,52 @@
1
+ import { ReactElement, ReactNode } from 'react';
2
+ import type { Feature as GeoJSONFeatureType } from 'geojson';
3
+
4
+ import { BaseChartComponentProps, CategoricalChartDataType } from './chartTypes';
5
+ import type { GeoJSONPolygonOnlyFeatureCollection } from './geoJSONTypes';
6
+
7
+ export interface GeoPointDataItem {
8
+ coordinates: [number, number];
9
+ title: string;
10
+ }
11
+
12
+ type PointMapOnClick = (point: GeoPointDataItem) => void;
13
+
14
+ type GeoJSONShapeOnClick = (shape: GeoJSONFeatureType) => void;
15
+
16
+ export interface BaseMapProps extends BaseChartComponentProps {
17
+ center: [number, number];
18
+ zoom: number;
19
+ tileLayer?: ReactElement;
20
+ }
21
+
22
+ export interface PointMapProps extends BaseMapProps {
23
+ data: GeoPointDataItem[];
24
+ onClick?: PointMapOnClick;
25
+ renderPopupBody?: (p: GeoPointDataItem) => ReactNode;
26
+ }
27
+
28
+ export interface MapDiscreteLegendItem {
29
+ color: string | undefined;
30
+ label: string;
31
+ }
32
+
33
+ export interface ChoroplethMapColorModeContinuous {
34
+ mode: 'continuous';
35
+ minColor: string;
36
+ maxColor: string;
37
+ }
38
+
39
+ export interface ChoroplethMapColorModeDiscrete {
40
+ mode: 'discrete';
41
+ colorFunction: (x: number | undefined) => string;
42
+ legendItems: MapDiscreteLegendItem[];
43
+ }
44
+
45
+ export interface ChoroplethMapProps extends BaseMapProps {
46
+ data: CategoricalChartDataType; // heatmaps are 'categorical' + geographical
47
+ features: GeoJSONPolygonOnlyFeatureCollection;
48
+ colorMode: ChoroplethMapColorModeContinuous | ChoroplethMapColorModeDiscrete;
49
+ categoryProp: string;
50
+ onClick?: GeoJSONShapeOnClick;
51
+ renderPopupBody?: (f: GeoJSONFeatureType, d: number | undefined) => ReactNode;
52
+ }
package/tsconfig.json CHANGED
@@ -23,4 +23,4 @@
23
23
  "exclude": [
24
24
  "node_modules"
25
25
  ],
26
- }
26
+ }
@@ -0,0 +1,60 @@
1
+ const path = require('path');
2
+
3
+ const HtmlWebpackPlugin = require('html-webpack-plugin');
4
+
5
+ const config = {
6
+ mode: 'development',
7
+ entry: './test/js/index.tsx',
8
+ output: {
9
+ path: __dirname + '/test/dist',
10
+ publicPath: '',
11
+ filename: 'js/[name][chunkhash].js',
12
+ },
13
+ module: {
14
+ rules: [
15
+ { test: /\.[tj](sx|s)?$/, use: { loader: 'ts-loader' }, exclude: /node_modules/ },
16
+ {
17
+ test: /\.html$/i,
18
+ loader: 'html-loader',
19
+ },
20
+ {
21
+ test: /\.css$/i,
22
+ use: ['style-loader', 'css-loader'],
23
+ },
24
+ {
25
+ test: /\.(png|jpe?g|gif)$/i,
26
+ loader: 'file-loader',
27
+ },
28
+ ],
29
+ },
30
+ watchOptions: {
31
+ poll: 1000,
32
+ },
33
+ plugins: [
34
+ new HtmlWebpackPlugin({
35
+ title: 'Development',
36
+ inject: false,
37
+ template: 'test/index.ejs',
38
+ }),
39
+ ],
40
+ optimization: {
41
+ runtimeChunk: 'single',
42
+ },
43
+ devtool: 'source-map',
44
+ devServer: {
45
+ static: './test/dist',
46
+ },
47
+ resolve: {
48
+ alias: {
49
+ '@': path.resolve(__dirname, 'src'),
50
+ },
51
+ extensions: ['.tsx', '.ts', '.js'],
52
+ },
53
+ };
54
+
55
+ module.exports = (_env, argv) => {
56
+ if (argv.mode === 'development') {
57
+ config.devtool = 'inline-source-map';
58
+ }
59
+ return config;
60
+ };