ethio-map-kit 0.1.1 → 0.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/README.md +67 -337
  2. package/package.json +1 -1
package/README.md CHANGED
@@ -1,8 +1,8 @@
1
1
  # Ethio Map Kit
2
2
 
3
- Type-safe React components for an interactive Ethiopia regional SVG map.
3
+ React components for building interactive Ethiopia map visualizations.
4
4
 
5
- Ethio Map Kit ships a polished Ethiopia map surface, region legend, selected-region card, service-stat card, and location list. It includes default demo data, a bundled Ethiopia regions SVG, a lightweight transparent terrain WebP, and CSS for light/dark dashboard-style layouts.
5
+ Ethio Map Kit includes a regional Ethiopia map, smooth region selection, light/dark themes, terrain and heat layers, marker support, service stats, and TypeScript types.
6
6
 
7
7
  ## Install
8
8
 
@@ -10,13 +10,7 @@ Ethio Map Kit ships a polished Ethiopia map surface, region legend, selected-reg
10
10
  npm install ethio-map-kit
11
11
  ```
12
12
 
13
- React and React DOM are peer dependencies:
14
-
15
- ```bash
16
- npm install react react-dom
17
- ```
18
-
19
- Import the stylesheet once in your app:
13
+ Import the stylesheet once:
20
14
 
21
15
  ```tsx
22
16
  import "ethio-map-kit/styles.css";
@@ -40,95 +34,68 @@ export function App() {
40
34
  serviceStats={defaultRegionServiceStats}
41
35
  locations={defaultLocations}
42
36
  theme="light"
43
- layer="terrain"
37
+ layer="regions"
44
38
  showLabels
45
- showMarkers
46
- onRegionSelect={(selection) => {
47
- console.log(selection.regionId, selection.region);
39
+ onRegionSelect={({ regionId, region }) => {
40
+ console.log(regionId, region);
48
41
  }}
49
42
  />
50
43
  );
51
44
  }
52
45
  ```
53
46
 
54
- You can also import from the React subpath:
47
+ ## Terrain Layer
55
48
 
56
49
  ```tsx
57
- import { EthiopiaMap } from "ethio-map-kit/react";
50
+ <EthiopiaMap
51
+ data={defaultRegionData}
52
+ layer="terrain"
53
+ theme="dark"
54
+ />
58
55
  ```
59
56
 
60
- ## Exports
57
+ The bundled terrain image is a transparent WebP, so it works in both light and dark mode.
61
58
 
62
- Components:
59
+ ## Custom Data
63
60
 
64
- - `EthiopiaMap`
65
- - `EthiopiaMapSurface`
66
- - `EthiopiaMapProvider`
67
- - `EthiopiaMapRoot`
68
- - `EthiopiaMapLegend`
69
- - `EthiopiaSelectedRegionCard`
70
- - `EthiopiaRegionServicesCard`
71
- - `EthiopiaLocationsPanel`
72
-
73
- Hooks:
74
-
75
- - `useEthiopiaMap`
76
- - `useSelectedRegionId`
77
-
78
- Default data and map metadata:
79
-
80
- - `defaultRegionData`
81
- - `defaultRegionServiceStats`
82
- - `defaultLocations`
83
- - `regionPathMap`
84
- - `ETHIOPIA_REGION_IDS`
85
- - `ETHIOPIA_AUTO_TOUR_SEQUENCE`
86
-
87
- ## Main Component
61
+ ```tsx
62
+ import type { RegionRecord, RegionDatum } from "ethio-map-kit";
88
63
 
89
- `EthiopiaMap` is the fastest way to render a complete standalone map. It wraps `EthiopiaMapProvider` and `EthiopiaMapSurface` for you.
64
+ const data: RegionRecord<RegionDatum> = {
65
+ ...defaultRegionData,
66
+ amhara: {
67
+ name: "Amhara",
68
+ value: 78,
69
+ trend: "+12%",
70
+ copy: "High regional index with several sample cities.",
71
+ },
72
+ };
90
73
 
91
- ```tsx
92
- <EthiopiaMap
93
- data={regionData}
94
- serviceStats={serviceStats}
95
- locations={locations}
96
- theme="dark"
97
- layer="heat"
98
- selectedRegionId={selectedRegionId}
99
- onRegionSelect={setSelection}
100
- />
74
+ <EthiopiaMap data={data} />;
101
75
  ```
102
76
 
103
- ### `EthiopiaMap` Props
77
+ ## Common Props
104
78
 
105
- | Prop | Type | Default | Description |
106
- | --- | --- | --- | --- |
107
- | `data` | `RegionRecord<RegionDatum>` | Required | Region data keyed by Ethiopia region ID. |
108
- | `serviceStats` | `RegionServiceStats` | `{}` | Per-region service statistics shown in the in-map panel and service card. |
109
- | `locations` | `readonly LatLngLocation[]` | `[]` | Lat/lng points for marker and location-list UI. |
110
- | `theme` | `"light" \| "dark"` | `"light"` | Visual theme. |
111
- | `layer` | `"regions" \| "heat" \| "terrain"` | `"regions"` | Main visual layer. |
112
- | `viewMode` | `"map" \| "bars"` | `"map"` | Standard map view or bar morph view. |
113
- | `selectionAnimation` | `"pulse" \| "static" \| "none" \| "outline"` | `"pulse"` | Selected-region visual treatment. |
114
- | `showLabels` | `boolean` | `true` | Show or hide SVG labels. |
115
- | `showMarkers` | `boolean` | `false` | Show or hide location markers. |
116
- | `showInMapStats` | `boolean` | `true` | Show selected-region stats inside the map surface. |
117
- | `autoTour` | `boolean` | `false` | Automatically cycle through regions. |
118
- | `autoTourSequence` | `readonly (EthiopiaRegionId \| null)[]` | `ETHIOPIA_AUTO_TOUR_SEQUENCE` | Custom tour route. Use `null` for reset steps. |
119
- | `autoTourIntervalMs` | `number` | `3200` | Delay between auto-tour steps. |
120
- | `regionColors` | `PartialRegionRecord<string>` | `{}` | Override choropleth color for one or more regions. |
121
- | `selectedRegionId` | `EthiopiaRegionId \| null` | Uncontrolled | Controlled selected region. |
122
- | `defaultSelectedRegionId` | `EthiopiaRegionId \| null` | `null` | Initial selected region for uncontrolled usage. |
123
- | `onRegionSelect` | `(selection: EthiopiaMapSelection) => void` | `undefined` | Called when the user selects or clears a region. |
124
- | `className` | `string` | `undefined` | Extra class for the map surface. |
125
- | `svgText` | `string` | Bundled SVG | Raw SVG text override. |
126
- | `svgUrl` | `string` | `undefined` | Fetch an SVG from a URL instead of using the bundled SVG. |
127
- | `terrainImageUrl` | `string` | Bundled WebP | Custom terrain image URL. |
79
+ | Prop | Type | Description |
80
+ | --- | --- | --- |
81
+ | `data` | `RegionRecord<RegionDatum>` | Region values and copy keyed by region ID. |
82
+ | `serviceStats` | `RegionServiceStats` | Optional service indicators for each region. |
83
+ | `locations` | `LatLngLocation[]` | Optional marker/location data. |
84
+ | `theme` | `"light" \| "dark"` | Map theme. |
85
+ | `layer` | `"regions" \| "heat" \| "terrain"` | Active visual layer. |
86
+ | `viewMode` | `"map" \| "bars"` | Map view or bar view. |
87
+ | `selectionAnimation` | `"pulse" \| "static" \| "none" \| "outline"` | Selected-region animation style. |
88
+ | `showLabels` | `boolean` | Show or hide region labels. |
89
+ | `showMarkers` | `boolean` | Show or hide location markers. |
90
+ | `regionColors` | `PartialRegionRecord<string>` | Override region colors. |
91
+ | `selectedRegionId` | `EthiopiaRegionId \| null` | Controlled selected region. |
92
+ | `defaultSelectedRegionId` | `EthiopiaRegionId \| null` | Initial selected region. |
93
+ | `onRegionSelect` | `(selection) => void` | Called when a region is selected or cleared. |
94
+ | `terrainImageUrl` | `string` | Custom terrain image URL. |
128
95
 
129
- ## Composable Layout
96
+ ## Composable Components
130
97
 
131
- Use the provider when you want to arrange the map and panels yourself.
98
+ For custom layouts, wrap components with `EthiopiaMapProvider`.
132
99
 
133
100
  ```tsx
134
101
  import {
@@ -143,112 +110,35 @@ import {
143
110
 
144
111
  export function Dashboard() {
145
112
  return (
146
- <EthiopiaMapProvider data={defaultRegionData} theme="light" layer="regions">
147
- <div className="dashboard-grid">
148
- <EthiopiaMapSurface />
149
- <aside>
150
- <EthiopiaMapLegend maxItems={8} />
151
- <EthiopiaSelectedRegionCard />
152
- <EthiopiaRegionServicesCard />
153
- <EthiopiaLocationsPanel />
154
- </aside>
155
- </div>
113
+ <EthiopiaMapProvider data={defaultRegionData}>
114
+ <EthiopiaMapSurface />
115
+ <EthiopiaMapLegend />
116
+ <EthiopiaSelectedRegionCard />
117
+ <EthiopiaRegionServicesCard />
118
+ <EthiopiaLocationsPanel />
156
119
  </EthiopiaMapProvider>
157
120
  );
158
121
  }
159
122
  ```
160
123
 
161
- ### `EthiopiaMapProvider` Props
162
-
163
- `EthiopiaMapProvider` accepts the same data, selection, theme, layer, marker, label, service-stat, and auto-tour props as `EthiopiaMap`, except it requires `children` and does not accept `className`, `svgText`, `svgUrl`, or `terrainImageUrl`.
164
-
165
- Use this when you want shared state across multiple package components.
166
-
167
- ### `EthiopiaMapSurface` Props
168
-
169
- | Prop | Type | Default | Description |
170
- | --- | --- | --- | --- |
171
- | `className` | `string` | `undefined` | Extra class for the surface wrapper. |
172
- | `svgText` | `string` | Bundled SVG | Raw SVG text override. |
173
- | `svgUrl` | `string` | `undefined` | Runtime SVG URL override. |
174
- | `terrainImageUrl` | `string` | Bundled WebP | Terrain raster URL override. |
175
-
176
- `EthiopiaMapSurface` reads all map behavior from `EthiopiaMapProvider`.
177
-
178
- ## Panel Components
179
-
180
- ### `EthiopiaMapLegend`
181
-
182
- Renders a sorted clickable legend using the current provider data.
183
-
184
- | Prop | Type | Default | Description |
185
- | --- | --- | --- | --- |
186
- | `className` | `string` | `undefined` | Extra class for the legend panel. |
187
- | `title` | `string` | `"Region index"` | Legend heading. |
188
- | `kicker` | `string` | `"Legend"` | Small label above the heading. |
189
- | `maxItems` | `number` | All regions | Limit visible legend rows. |
190
- | `onRegionClick` | `(regionId: EthiopiaRegionId) => void` | `undefined` | Called when a non-active region is clicked. |
191
-
192
- ### `EthiopiaSelectedRegionCard`
193
-
194
- Shows selected-region copy, preview SVG, and summary stats.
195
-
196
- | Prop | Type | Default | Description |
197
- | --- | --- | --- | --- |
198
- | `className` | `string` | `undefined` | Extra class for the panel. |
199
- | `emptyTitle` | `string` | `"Click a region"` | Title shown when nothing is selected. |
200
- | `emptyCopy` | `string` | Built-in helper copy | Body text shown when nothing is selected. |
201
- | `showStats` | `boolean` | `true` | Show or hide the three summary-stat boxes. |
202
- | `previewSelectionAnimation` | `SelectionAnimationMode` | Provider value | Override preview animation mode. |
203
- | `summaryStats` | `(selection) => readonly RegionSummaryStat[]` | Built-in stats | Custom stat rows for the card. |
204
- | `renderPreview` | `(selection) => ReactNode` | Built-in SVG preview | Replace the selected-region preview area. |
205
-
206
- ### `EthiopiaRegionServicesCard`
207
-
208
- Shows service indicators for the selected region.
209
-
210
- | Prop | Type | Default | Description |
211
- | --- | --- | --- | --- |
212
- | `className` | `string` | `undefined` | Extra class for the service panel. |
213
- | `emptyText` | `string` | `"Select a region to inspect service statistics."` | Empty state text. |
214
-
215
- ### `EthiopiaLocationsPanel`
216
-
217
- Lists provided locations and their coordinates.
218
-
219
- | Prop | Type | Default | Description |
220
- | --- | --- | --- | --- |
221
- | `className` | `string` | `undefined` | Extra class for the locations panel. |
222
- | `title` | `string` | `"Locations"` | Panel heading. |
223
- | `kicker` | `string` | `"Lat/lng overlay"` | Small label above the heading. |
224
- | `showMarkerToggle` | `boolean` | `true` | Show current marker on/off state. |
225
-
226
- ## Data Types
227
-
228
- ### Region Data
229
-
230
- Each region must be present in the `data` object.
231
-
232
- ```tsx
233
- import type { RegionRecord, RegionDatum } from "ethio-map-kit";
124
+ ## Exports
234
125
 
235
- const data: RegionRecord<RegionDatum> = {
236
- amhara: {
237
- name: "Amhara",
238
- value: 78,
239
- trend: "+12%",
240
- copy: "High regional index with several sample cities.",
241
- color: "#176b54",
242
- summaryStats: [
243
- { label: "Index", value: 78 },
244
- { label: "Trend", value: "+12%" },
245
- ],
246
- },
247
- // include the remaining EthiopiaRegionId keys...
248
- };
249
- ```
126
+ - `EthiopiaMap`
127
+ - `EthiopiaMapProvider`
128
+ - `EthiopiaMapSurface`
129
+ - `EthiopiaMapLegend`
130
+ - `EthiopiaSelectedRegionCard`
131
+ - `EthiopiaRegionServicesCard`
132
+ - `EthiopiaLocationsPanel`
133
+ - `useEthiopiaMap`
134
+ - `useSelectedRegionId`
135
+ - `defaultRegionData`
136
+ - `defaultRegionServiceStats`
137
+ - `defaultLocations`
138
+ - `ETHIOPIA_REGION_IDS`
139
+ - `ETHIOPIA_AUTO_TOUR_SEQUENCE`
250
140
 
251
- Valid region IDs:
141
+ ## Region IDs
252
142
 
253
143
  ```text
254
144
  tigray
@@ -266,163 +156,3 @@ somali
266
156
  dire-dawa
267
157
  harari
268
158
  ```
269
-
270
- ### Service Stats
271
-
272
- ```tsx
273
- import type { RegionServiceStats } from "ethio-map-kit";
274
-
275
- const serviceStats: RegionServiceStats = {
276
- amhara: [
277
- {
278
- label: "Maternal death rate",
279
- valueKind: "percent",
280
- value: 67,
281
- comparison: {
282
- enabled: true,
283
- percent: 12,
284
- direction: "increase",
285
- period: "last month",
286
- outcome: "negative",
287
- },
288
- },
289
- {
290
- label: "Hospitals",
291
- valueKind: "number",
292
- value: 86,
293
- comparison: {
294
- enabled: true,
295
- percent: 5,
296
- direction: "increase",
297
- period: "last year",
298
- outcome: "positive",
299
- },
300
- },
301
- ],
302
- };
303
- ```
304
-
305
- ### Locations
306
-
307
- ```tsx
308
- import type { LatLngLocation } from "ethio-map-kit";
309
-
310
- const locations: LatLngLocation[] = [
311
- {
312
- name: "Bahir Dar",
313
- region: "amhara",
314
- lat: 11.59,
315
- lng: 37.39,
316
- category: "hospital",
317
- color: "#f7c948",
318
- radius: 5,
319
- intensity: 76,
320
- },
321
- ];
322
- ```
323
-
324
- ## Customization Examples
325
-
326
- ### Controlled Selection
327
-
328
- ```tsx
329
- const [selectedRegionId, setSelectedRegionId] =
330
- useState<EthiopiaRegionId | null>(null);
331
-
332
- <EthiopiaMap
333
- data={defaultRegionData}
334
- selectedRegionId={selectedRegionId}
335
- onRegionSelect={({ regionId }) => setSelectedRegionId(regionId)}
336
- />;
337
- ```
338
-
339
- ### Custom Region Colors
340
-
341
- ```tsx
342
- <EthiopiaMap
343
- data={defaultRegionData}
344
- regionColors={{
345
- amhara: "#2563eb",
346
- oromia: "#16a34a",
347
- "addis-ababa": "#dc2626",
348
- }}
349
- />
350
- ```
351
-
352
- ### Custom Terrain Asset
353
-
354
- ```tsx
355
- <EthiopiaMap
356
- data={defaultRegionData}
357
- layer="terrain"
358
- terrainImageUrl="/assets/ethiopia-terrain.webp"
359
- />
360
- ```
361
-
362
- The bundled terrain asset is a transparent WebP so it works in both light and dark mode.
363
-
364
- ### Auto Tour
365
-
366
- ```tsx
367
- <EthiopiaMap
368
- data={defaultRegionData}
369
- autoTour
370
- autoTourIntervalMs={4500}
371
- autoTourSequence={["amhara", "oromia", "addis-ababa", null]}
372
- />
373
- ```
374
-
375
- The default route is:
376
-
377
- ```text
378
- Afar -> Tigray -> Amhara -> Benishangul-Gumuz -> Gambela -> South West Ethiopia -> South Ethiopia -> Sidama -> Central Ethiopia -> Addis Ababa -> Dire Dawa -> Harari -> Somali -> Oromia -> reset
379
- ```
380
-
381
- ### Custom Selected-Region Preview
382
-
383
- ```tsx
384
- <EthiopiaSelectedRegionCard
385
- renderPreview={({ region }) =>
386
- region ? <strong>{region.name}</strong> : <span>No region</span>
387
- }
388
- />
389
- ```
390
-
391
- ## Package Boundary And Source Visibility
392
-
393
- The published npm package contains compiled output from `dist` and this README. It does not publish the TypeScript source files or the original private repository structure.
394
-
395
- This is the normal model for frontend npm packages: consumers receive JavaScript, CSS, type declarations, and assets needed to run the component. The code can still be inspected by determined users after installation, even when it is compiled or minified. Minification and narrow package exports are useful for distribution and casual obfuscation, but they are not a security boundary.
396
-
397
- The same rule applies to browser deployments: any JavaScript, SVG, image, or CSS needed by a public client-side page can be downloaded by the browser. Keep sensitive business logic on a server if it must be private.
398
-
399
- ## Local Development
400
-
401
- From the repository root:
402
-
403
- ```bash
404
- npm install
405
- npm run dev:react
406
- npm run typecheck --workspace ethio-map-kit
407
- npm run build --workspace ethio-map-kit
408
- ```
409
-
410
- Open the local demo at:
411
-
412
- ```text
413
- http://localhost:5174/
414
- ```
415
-
416
- ## Publishing
417
-
418
- Before publishing a new package version:
419
-
420
- ```bash
421
- npm run typecheck --workspace ethio-map-kit
422
- npm run build --workspace ethio-map-kit
423
- npm pack --workspace ethio-map-kit --dry-run
424
- npm version patch --workspace ethio-map-kit
425
- npm publish --workspace ethio-map-kit --access public
426
- ```
427
-
428
- npm package versions are immutable. If `ethio-map-kit@0.1.0` has already been published, publish the next patch, minor, or major version instead of trying to overwrite it.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ethio-map-kit",
3
- "version": "0.1.1",
3
+ "version": "0.1.2",
4
4
  "description": "Type-safe React components for an interactive Ethiopia regional SVG map.",
5
5
  "type": "module",
6
6
  "license": "MIT",