@kahwee/sf-map-svg 4.1.0 → 4.2.0
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/CHANGELOG.md +14 -0
- package/README.md +2 -2
- package/dist/src/appearance.d.ts +5 -0
- package/dist/src/appearance.js +54 -0
- package/dist/src/configuration.js +32 -23
- package/dist/src/controller-types.d.ts +53 -6
- package/dist/src/explorer-core.d.ts +14 -2
- package/dist/src/explorer-core.js +168 -37
- package/dist/src/guide-map.js +1 -1
- package/dist/src/guide-static.js +3 -3
- package/dist/src/map-core.d.ts +14 -0
- package/dist/src/map-core.js +4 -1
- package/dist/src/map.js +125 -20
- package/dist/src/static.d.ts +1 -1
- package/dist/src/static.js +31 -2
- package/dist/src/types.d.ts +8 -2
- package/docs/API.md +53 -1
- package/docs/api-audit.md +3 -1
- package/docs/developer-guide.md +5 -3
- package/llms-full.txt +160 -25
- package/llms.txt +1 -1
- package/package.json +3 -2
package/llms-full.txt
CHANGED
|
@@ -2,19 +2,19 @@
|
|
|
2
2
|
|
|
3
3
|
> Offline San Francisco SVG maps with explicit geographic imports, no runtime dependencies, static rendering, and a browser controller.
|
|
4
4
|
|
|
5
|
-
@kahwee/sf-map-svg 4.
|
|
5
|
+
@kahwee/sf-map-svg 4.2.0 · local working tree. Node >=24.0.0 for server rendering; browsers need a DOM and a JSON-capable bundler.
|
|
6
6
|
|
|
7
7
|
These are working-tree docs. Unreleased changelog entries may describe APIs absent from npm; verify the installed version before copying them.
|
|
8
8
|
|
|
9
9
|
Use renderMap(data, options) for SVG strings; createMap(data, options) returns a controller. Mount map.element and destroy it on unmount. Choose mode explicitly: createMap defaults to basemap. Geography is separate; staticMapData and fullMapData have different shapes.
|
|
10
10
|
|
|
11
|
-
<!-- Generated from README.md; @kahwee/sf-map-svg 4.
|
|
11
|
+
<!-- Generated from README.md; @kahwee/sf-map-svg 4.2.0 · local working tree. -->
|
|
12
12
|
|
|
13
13
|
# SF Map SVG
|
|
14
14
|
|
|
15
15
|
Offline, self-contained San Francisco SVG maps. The package has no runtime dependencies. Geography is always an explicit import; the root entry does not bundle data.
|
|
16
16
|
|
|
17
|
-
[Live examples](https://kahwee.github.io/sf-map-svg/examples.html) · [Storybook source](https://github.com/kahwee/sf-map-svg/blob/main/stories/) · [Geographic sources](https://github.com/kahwee/sf-map-svg/blob/main/SOURCES.md) · [v3 migration](https://github.com/kahwee/sf-map-svg/blob/main/docs/migration-v3.md)
|
|
17
|
+
[Design playground](https://kahwee.github.io/sf-map-svg/playground.html) · [Live examples](https://kahwee.github.io/sf-map-svg/examples.html) · [Storybook source](https://github.com/kahwee/sf-map-svg/blob/main/stories/) · [Geographic sources](https://github.com/kahwee/sf-map-svg/blob/main/SOURCES.md) · [v3 migration](https://github.com/kahwee/sf-map-svg/blob/main/docs/migration-v3.md)
|
|
18
18
|
|
|
19
19
|
## Install
|
|
20
20
|
|
|
@@ -64,7 +64,7 @@ map.camera.zoom(1.5);
|
|
|
64
64
|
map.destroy();
|
|
65
65
|
```
|
|
66
66
|
|
|
67
|
-
`createMap(data, options)` returns a controller. Use `map.element` for mounting, `map.configure({ features, layers, controls })` for runtime switches, `map.camera` for pan/zoom/fit/reset, and `map.on()` for typed events. Appearance
|
|
67
|
+
`createMap(data, options)` returns a controller. Use `map.element` for mounting, `map.configure({ features, layers, controls, appearance, mode, source, year, labels })` for runtime switches, `map.camera` for pan/zoom/fit/reset, and `map.on()` for typed events. Appearance can change live while preserving camera, selection, and focus. `getResolvedConfiguration()` explains effective layers; `getCapabilities()` reports supplied geography. SFAR realtor neighborhoods are the default when supplied; SF Find and analysis are explicit alternate sources. The `/data/full` preset includes all three collections and historical districts.
|
|
68
68
|
|
|
69
69
|
See [controller options, events, and lifecycle](https://github.com/kahwee/sf-map-svg/blob/main/docs/API.md#interactive-maps),
|
|
70
70
|
[examples](https://github.com/kahwee/sf-map-svg/blob/main/docs/EXAMPLES.md), and [consumer integration](https://github.com/kahwee/sf-map-svg/blob/main/docs/consumer-integration.md).
|
|
@@ -91,7 +91,7 @@ The [contributing guide](https://github.com/kahwee/sf-map-svg/blob/main/CONTRIBU
|
|
|
91
91
|
|
|
92
92
|
---
|
|
93
93
|
|
|
94
|
-
<!-- Generated from docs/developer-guide.md; @kahwee/sf-map-svg 4.
|
|
94
|
+
<!-- Generated from docs/developer-guide.md; @kahwee/sf-map-svg 4.2.0 · local working tree. -->
|
|
95
95
|
|
|
96
96
|
# Developer guide
|
|
97
97
|
|
|
@@ -183,13 +183,13 @@ SFAR realtor neighborhoods are the default when supplied. If only an alternative
|
|
|
183
183
|
|
|
184
184
|
| Change | Call |
|
|
185
185
|
| --- | --- |
|
|
186
|
-
| Layers, controls, behaviors | `map.configure({ layers, controls, features })` |
|
|
186
|
+
| Layers, controls, behaviors | `map.configure({ layers, controls, features, appearance, mode, source, year, labels })` |
|
|
187
187
|
| Map mode or neighborhood source | `map.setMode(mode)`, `map.setSource(source)` |
|
|
188
188
|
| District boundaries or choropleth | `map.setDistrictYear(year)`, `map.setDistrictStyle(callback)` |
|
|
189
189
|
| Master text visibility | `map.setLabels(visible)` |
|
|
190
190
|
| Markers or route overlays | `map.setMarkers(items)`, `map.setOverlays(items)` |
|
|
191
191
|
| Camera | `map.camera.set/pan/zoom/fit/reset(...)` |
|
|
192
|
-
| Palette, typography, control styling |
|
|
192
|
+
| Palette, typography, control styling | `map.configure({ appearance })`; retains camera, selection and focus |
|
|
193
193
|
|
|
194
194
|
`configure` merges supplied keys; omitted keys keep their existing values. Set a layer or control key to `undefined` to remove its override. Set a whole group to `undefined` to reset that group. Set a feature to `false` to disable it. Explicit layer overrides keep winning after mode changes.
|
|
195
195
|
|
|
@@ -200,7 +200,7 @@ map.configure({ features: { motion: false } });
|
|
|
200
200
|
map.configure({ layers: undefined }); // clear all explicit layer overrides
|
|
201
201
|
```
|
|
202
202
|
|
|
203
|
-
`getConfiguration()` returns a detached snapshot of these groups, including explicit layer overrides. It is not a full serialization of mode, source, year, camera, selection,
|
|
203
|
+
`getConfiguration()` returns a detached snapshot of these groups, including explicit layer overrides. It is not a full serialization of mode, source, year, camera, or selection. Appearance overrides are included. Use `getResolvedConfiguration()` for current mode/source/year/labels and effective layer switches, and `getCapabilities()` for supplied geography. Invalid configuration patches leave the current map unchanged.
|
|
204
204
|
|
|
205
205
|
## Markers, routes and camera coordinates
|
|
206
206
|
|
|
@@ -231,9 +231,11 @@ The generated `llms.txt` index links to Markdown documentation; `llms-full.txt`
|
|
|
231
231
|
|
|
232
232
|
See [API options](https://github.com/kahwee/sf-map-svg/blob/main/docs/API.md), [worked examples](https://github.com/kahwee/sf-map-svg/blob/main/docs/EXAMPLES.md), [consumer integration](https://github.com/kahwee/sf-map-svg/blob/main/docs/consumer-integration.md), and [v3 migration](https://github.com/kahwee/sf-map-svg/blob/main/docs/migration-v3.md).
|
|
233
233
|
|
|
234
|
+
Appearance token objects merge by key; `undefined` removes an override and `appearance: undefined` resets the group. Static maps accept grouped `layers` and the shared `appearance` keys (`theme`, `colors`, `districtStyle`) too. See [the API contract](https://github.com/kahwee/sf-map-svg/blob/main/docs/API.md#live-configuration-and-inspection) and [the design playground](https://kahwee.github.io/sf-map-svg/playground.html).
|
|
235
|
+
|
|
234
236
|
---
|
|
235
237
|
|
|
236
|
-
<!-- Generated from docs/API.md; @kahwee/sf-map-svg 4.
|
|
238
|
+
<!-- Generated from docs/API.md; @kahwee/sf-map-svg 4.2.0 · local working tree. -->
|
|
237
239
|
|
|
238
240
|
# Map options and lifecycle
|
|
239
241
|
|
|
@@ -243,7 +245,20 @@ and event types are exported by [src/api.ts](https://github.com/kahwee/sf-map-sv
|
|
|
243
245
|
|
|
244
246
|
## Static maps
|
|
245
247
|
|
|
246
|
-
Static
|
|
248
|
+
Static maps accept the same grouped presentation vocabulary as interactive maps:
|
|
249
|
+
|
|
250
|
+
```ts
|
|
251
|
+
const presentation = {
|
|
252
|
+
layers: { landmarks: true, bartStations: true },
|
|
253
|
+
appearance: { theme: 'districts' as const, colors: { water: '#e7f0f3' } },
|
|
254
|
+
};
|
|
255
|
+
const { svg } = renderMap(staticMapData, presentation);
|
|
256
|
+
const map = createMap(fullMapData, presentation);
|
|
257
|
+
```
|
|
258
|
+
|
|
259
|
+
Static `layers` supports every interactive layer switch except `neighborhoodLabels`. Static `appearance` supports `theme`, `colors`, and `districtStyle`; browser typography, area interaction styles, and screen-space marker sizing remain interactive settings. Unknown grouped keys are rejected. Supplied grouped keys override flat compatibility keys; omitted or `undefined` grouped keys preserve the flat value or renderer default. The two renderers retain their existing defaults. Marker arrays accept readonly inputs.
|
|
260
|
+
|
|
261
|
+
Flat compatibility options include `theme`, `width`, `height`, `padding`, `year` (2002, 2012, 2022), `districtLines`, `districtFills`, `districtStyle`, `districtLabels`, `neighborhoodLines`, `labels`, `highways`, `keyRoads`, `roadLabels`, `landmarks`, `bartStations`, `markers`, `overlays`, `title`, `idPrefix`, `colors`, and `animation`. Each optional layer is independent. User-supplied text and attributes are escaped in SVG output.
|
|
247
262
|
|
|
248
263
|
Custom district IDs must be finite numbers. An empty `labelPoints` array uses the district's primary `label` position.
|
|
249
264
|
|
|
@@ -269,9 +284,48 @@ Two opt-in features animate the map's lines and layers. `features.layerTransitio
|
|
|
269
284
|
|
|
270
285
|
District style callbacks are evaluated once per district at construction and on style or year updates. Hover, selection, and layer toggles reuse the prepared styles; call `setDistrictStyle()` again when external styling data changes. Invalid styles leave the current map unchanged. District fades respect reduced motion and are removed on interruption or destruction.
|
|
271
286
|
|
|
287
|
+
## Live configuration and inspection
|
|
288
|
+
|
|
289
|
+
`map.configure({ appearance, mode, source, year, labels, layers, features, controls })` updates an existing map. Appearance updates preserve the camera, selections, retained marker nodes, and keyboard focus. Mode/source changes through `configure` preserve the camera; existing `setMode` and `setSource` convenience methods retain their reset behavior. Switching neighborhood source clears the neighborhood selection. Changing district year retains a selected district when it exists in the new year. Unsupported datasets, invalid appearance values, and invalid district-style callback results fail during preparation before commit. A reentrant styling callback can supersede the pending patch.
|
|
290
|
+
|
|
291
|
+
Appearance token objects (`colors`, `style`, `labelStyle`, `labelSize`, `areaStyle`) merge supplied keys; other appearance properties replace. Omitted keys retain their value, an explicit `undefined` property removes that override, and `appearance: undefined` resets the whole appearance group. Feature objects retain their existing replacement semantics. Mode/source/year/labels ignore `undefined`; reset them with an explicit value. Patch types explicitly permit these resets with TypeScript’s `exactOptionalPropertyTypes` enabled.
|
|
292
|
+
|
|
293
|
+
```ts
|
|
294
|
+
map.configure({
|
|
295
|
+
appearance: { colors: { water: '#142d45' }, labelStyle: { fontFamily: 'Georgia,serif' } },
|
|
296
|
+
layers: { bartStations: false },
|
|
297
|
+
});
|
|
298
|
+
map.configure({ appearance: undefined }); // restore construction defaults, not initial overrides
|
|
299
|
+
|
|
300
|
+
const overrides = map.getConfiguration();
|
|
301
|
+
const effective = map.getResolvedConfiguration();
|
|
302
|
+
const available = map.getCapabilities();
|
|
303
|
+
```
|
|
304
|
+
|
|
305
|
+
`getConfiguration()` returns detached feature, layer, control, and appearance overrides; district style callbacks retain their function identity. `getResolvedConfiguration()` adds the current mode, source, year and master labels and resolves **layer switches** through mode defaults, available data, and the master label switch. Appearance/control fields remain overrides. It does not claim that every label is visible: zoom and collision filtering still apply. `getCapabilities()` returns supplied `sources`, usable district `years`, and layer data availability for the current source/year, independent of visibility overrides. These reads throw after destruction.
|
|
306
|
+
|
|
307
|
+
## Common selection event
|
|
308
|
+
|
|
309
|
+
`selectionchange` adds a consistent envelope without changing existing event payloads:
|
|
310
|
+
|
|
311
|
+
```ts
|
|
312
|
+
map.on('selectionchange', (event) => {
|
|
313
|
+
// kind narrows current and previous to the corresponding selection type.
|
|
314
|
+
if (event.kind === 'marker') console.log(event.current?.id, event.previous?.id);
|
|
315
|
+
});
|
|
316
|
+
```
|
|
317
|
+
|
|
318
|
+
`kind` is `marker`, `neighborhood`, or `district`. `current` and `previous` are detached selection snapshots or `null`. The event follows committed selection changes, including clearing and a changed district vintage; it does not represent every activation. Existing `markerchange`, `neighborhoodchange`, and `districtchange` events remain supported.
|
|
319
|
+
|
|
320
|
+
## Coordinates and units
|
|
321
|
+
|
|
322
|
+
GeoJSON and static projection inputs use `[longitude, latitude]` in WGS84; markers use `{ lng, lat }`. Static `project` returns SVG units. `projectToScreen(lng, lat)` returns pixels relative to the mounted canvas. Camera viewports and pan deltas use the fixed 800 × 800 projected map space, independent of canvas size. Marker radius uses screen pixels in browser maps and SVG units in static output.
|
|
323
|
+
|
|
324
|
+
Explore presentation options in the [live map design playground](https://kahwee.github.io/sf-map-svg/playground.html). The page identifies its package version; released builds use compatible options for that installed version.
|
|
325
|
+
|
|
272
326
|
---
|
|
273
327
|
|
|
274
|
-
<!-- Generated from docs/EXAMPLES.md; @kahwee/sf-map-svg 4.
|
|
328
|
+
<!-- Generated from docs/EXAMPLES.md; @kahwee/sf-map-svg 4.2.0 · local working tree. -->
|
|
275
329
|
|
|
276
330
|
# Examples
|
|
277
331
|
|
|
@@ -382,7 +436,7 @@ For the controller and explicit data imports, see [the v3 migration guide](https
|
|
|
382
436
|
|
|
383
437
|
---
|
|
384
438
|
|
|
385
|
-
<!-- Generated from docs/consumer-integration.md; @kahwee/sf-map-svg 4.
|
|
439
|
+
<!-- Generated from docs/consumer-integration.md; @kahwee/sf-map-svg 4.2.0 · local working tree. -->
|
|
386
440
|
|
|
387
441
|
# Consumer integration
|
|
388
442
|
|
|
@@ -410,7 +464,7 @@ For server rendering, import `renderMap` from the root and pass `guideMapData.ma
|
|
|
410
464
|
|
|
411
465
|
---
|
|
412
466
|
|
|
413
|
-
<!-- Generated from docs/migration-v3.md; @kahwee/sf-map-svg 4.
|
|
467
|
+
<!-- Generated from docs/migration-v3.md; @kahwee/sf-map-svg 4.2.0 · local working tree. -->
|
|
414
468
|
|
|
415
469
|
# Migrate to version 3
|
|
416
470
|
|
|
@@ -451,7 +505,7 @@ District styles are now prepared once per district on construction and style/yea
|
|
|
451
505
|
|
|
452
506
|
---
|
|
453
507
|
|
|
454
|
-
<!-- Generated from SOURCES.md; @kahwee/sf-map-svg 4.
|
|
508
|
+
<!-- Generated from SOURCES.md; @kahwee/sf-map-svg 4.2.0 · local working tree. -->
|
|
455
509
|
|
|
456
510
|
# Geometry and provenance
|
|
457
511
|
|
|
@@ -635,12 +689,26 @@ display geometry, and no precinct polygons or raw workbook data are shipped.
|
|
|
635
689
|
|
|
636
690
|
---
|
|
637
691
|
|
|
638
|
-
<!-- Generated from CHANGELOG.md; @kahwee/sf-map-svg 4.
|
|
692
|
+
<!-- Generated from CHANGELOG.md; @kahwee/sf-map-svg 4.2.0 · local working tree. -->
|
|
639
693
|
|
|
640
694
|
# Changelog
|
|
641
695
|
|
|
642
696
|
User-visible changes are recorded here. Unreleased entries describe changes on `main` that are not part of a tagged package release.
|
|
643
697
|
|
|
698
|
+
## Unreleased
|
|
699
|
+
|
|
700
|
+
## 4.2.0 — 2026-10-01
|
|
701
|
+
|
|
702
|
+
- Reuse one native dropdown treatment across Pages, with an inset chevron, a reserved end gutter, and preserved labels, keyboard behavior, and mobile pickers.
|
|
703
|
+
- Strengthen the playground with strict TypeScript, checked JavaScript/TypeScript snippets, versioned design links, persistent explicit layer choices and independent static rendering. Keep mobile controls unobstructed and picker labels legible in dark mode.
|
|
704
|
+
- Express explicit configuration resets for consumers using `exactOptionalPropertyTypes`, including nested appearance tokens. Make Pages API and guide references describe their actual package version without internal preview warnings.
|
|
705
|
+
|
|
706
|
+
- Share grouped `layers` and supported `appearance` options between static and interactive maps, retaining flat static options and existing defaults; accept readonly static marker arrays.
|
|
707
|
+
- Update interactive appearance, mode, source, district year and labels through `configure`, preserving camera and retained marker nodes. Merge appearance tokens by key and validate combined patches before commit.
|
|
708
|
+
- Add `getResolvedConfiguration()` and `getCapabilities()` for effective layer switches and supplied geography, plus an additive `selectionchange` event with consistent current/previous snapshots.
|
|
709
|
+
- Add a live Pages map design playground with six editable palettes, layers, typography, sample pins/routes, browser/static previews, undo/redo, shareable designs, copyable code and full-city SVG export. Keep released-package previews compatible with their installed API.
|
|
710
|
+
- Refresh the Pages site: a new SF Map SVG mark traced from the real coastline, a reframed header with a release link, card-style reference tables that no longer collapse, a live filter for the API reference, an aligned playground with one-row-per-colour inks, and 12px minimum type for labels and badges.
|
|
711
|
+
|
|
644
712
|
## 4.1.0 — 2026-10-01
|
|
645
713
|
|
|
646
714
|
- Validate canonical and generated GeoJSON during data checks, rejecting invalid WGS84 coordinates and malformed polygon rings before release.
|
|
@@ -932,7 +1000,7 @@ consistent home, and makes animation and subscription ownership predictable.
|
|
|
932
1000
|
|
|
933
1001
|
# Published type contracts
|
|
934
1002
|
|
|
935
|
-
@kahwee/sf-map-svg 4.
|
|
1003
|
+
@kahwee/sf-map-svg 4.2.0 · local working tree. These declarations are generated by TypeScript. Use package export paths, not the internal filenames below. Imported relative contracts are included for context, not as additional public entry points.
|
|
936
1004
|
|
|
937
1005
|
| Public import | Declaration |
|
|
938
1006
|
| --- | --- |
|
|
@@ -987,25 +1055,67 @@ export declare function createMap(data: InteractiveSFMapData, options?: MapOptio
|
|
|
987
1055
|
```ts
|
|
988
1056
|
import type { Geometry, NeighborhoodSource } from '../data/types.js';
|
|
989
1057
|
import type { CameraOptions, DistrictSelection, DistrictStyle, DistrictYear, InteractiveLayers, MapFeatures, MapMarker, MapOverlay, MapPadding, MapViewport, NeighborhoodExplorerOptions, NeighborhoodSelection } from './types.js';
|
|
990
|
-
|
|
1058
|
+
/** Patch properties can explicitly remove overrides, including with exactOptionalPropertyTypes. */
|
|
1059
|
+
type Resettable<T> = {
|
|
1060
|
+
[K in keyof T]?: T[K] | undefined;
|
|
1061
|
+
};
|
|
1062
|
+
type AppearanceOptions = Pick<NeighborhoodExplorerOptions, 'theme' | 'colors' | 'labelStyle' | 'areaStyle' | 'districtStyle' | 'labelSize' | 'style' | 'markerRadius' | 'markerHitSize' | 'markerColor' | 'selectedMarkerColor'>;
|
|
1063
|
+
export type MapAppearance = {
|
|
1064
|
+
[K in keyof AppearanceOptions]?: K extends 'colors' | 'style' | 'labelStyle' | 'labelSize' | 'areaStyle' ? Resettable<NonNullable<AppearanceOptions[K]>> | undefined : AppearanceOptions[K] | undefined;
|
|
1065
|
+
};
|
|
991
1066
|
export type MapControls = NonNullable<NeighborhoodExplorerOptions['controls']>;
|
|
992
|
-
/** Omitted
|
|
1067
|
+
/** Omitted keys retain values. Undefined presentation groups reset; undefined mode/source/year/labels retain their current value. */
|
|
993
1068
|
export interface MapConfiguration {
|
|
994
|
-
features?: MapFeatures;
|
|
995
|
-
layers?: InteractiveLayers;
|
|
996
|
-
controls?: MapControls;
|
|
1069
|
+
features?: Resettable<MapFeatures> | undefined;
|
|
1070
|
+
layers?: Resettable<InteractiveLayers> | undefined;
|
|
1071
|
+
controls?: Resettable<MapControls> | undefined;
|
|
1072
|
+
appearance?: MapAppearance | undefined;
|
|
1073
|
+
mode?: NonNullable<NeighborhoodExplorerOptions['mode']> | undefined;
|
|
1074
|
+
source?: NeighborhoodSource | undefined;
|
|
1075
|
+
year?: DistrictYear | undefined;
|
|
1076
|
+
labels?: boolean | undefined;
|
|
997
1077
|
}
|
|
998
1078
|
export interface MapOptions extends Omit<NeighborhoodExplorerOptions, keyof MapFeatures | keyof MapAppearance | 'interface' | 'onMarkerActivate' | 'onOverlayActivate'> {
|
|
999
1079
|
features?: MapFeatures;
|
|
1000
|
-
appearance?: MapAppearance;
|
|
1080
|
+
appearance?: MapAppearance | undefined;
|
|
1001
1081
|
}
|
|
1002
1082
|
export interface MapConfigurationSnapshot {
|
|
1003
1083
|
features: MapFeatures;
|
|
1004
1084
|
/** Explicit overrides; absent values continue to follow the current mode. */
|
|
1005
1085
|
layers: InteractiveLayers;
|
|
1006
1086
|
controls: MapControls;
|
|
1087
|
+
appearance: MapAppearance;
|
|
1088
|
+
}
|
|
1089
|
+
export interface MapCapabilities {
|
|
1090
|
+
sources: readonly NeighborhoodSource[];
|
|
1091
|
+
years: readonly DistrictYear[];
|
|
1092
|
+
/** Data availability, independent of requested layer visibility. */
|
|
1093
|
+
layers: Readonly<Record<keyof InteractiveLayers, boolean>>;
|
|
1094
|
+
}
|
|
1095
|
+
export interface ResolvedMapConfiguration extends MapConfigurationSnapshot {
|
|
1096
|
+
mode: NonNullable<MapOptions['mode']>;
|
|
1097
|
+
source: NeighborhoodSource;
|
|
1098
|
+
year: DistrictYear;
|
|
1099
|
+
labels: boolean;
|
|
1100
|
+
/** Effective switches after mode defaults and data availability; label switches honor labels. */
|
|
1101
|
+
layers: Record<keyof InteractiveLayers, boolean>;
|
|
1007
1102
|
}
|
|
1103
|
+
export type MapSelectionChange = {
|
|
1104
|
+
kind: 'marker';
|
|
1105
|
+
current: MapMarker | null;
|
|
1106
|
+
previous: MapMarker | null;
|
|
1107
|
+
} | {
|
|
1108
|
+
kind: 'neighborhood';
|
|
1109
|
+
current: NeighborhoodSelection | null;
|
|
1110
|
+
previous: NeighborhoodSelection | null;
|
|
1111
|
+
} | {
|
|
1112
|
+
kind: 'district';
|
|
1113
|
+
current: DistrictSelection | null;
|
|
1114
|
+
previous: DistrictSelection | null;
|
|
1115
|
+
};
|
|
1008
1116
|
export interface MapEvents {
|
|
1117
|
+
/** Common selection envelope; existing change events retain their payloads. */
|
|
1118
|
+
selectionchange: MapSelectionChange;
|
|
1009
1119
|
districtchange: DistrictSelection | {
|
|
1010
1120
|
id: null;
|
|
1011
1121
|
year: DistrictYear;
|
|
@@ -1043,11 +1153,13 @@ export interface MapEvents {
|
|
|
1043
1153
|
mapresize: undefined;
|
|
1044
1154
|
}
|
|
1045
1155
|
export interface MapCamera {
|
|
1156
|
+
/** Fixed 800 × 800 projected space, not longitude/latitude. */
|
|
1046
1157
|
get(): MapViewport;
|
|
1047
1158
|
set(view: MapViewport, options?: CameraOptions): void;
|
|
1048
1159
|
fit(geometry: Geometry, options?: CameraOptions & {
|
|
1049
1160
|
padding?: number | MapPadding;
|
|
1050
1161
|
}): void;
|
|
1162
|
+
/** Delta in projected map units. */
|
|
1051
1163
|
pan(x: number, y: number, options?: CameraOptions): void;
|
|
1052
1164
|
zoom(factor: number, options?: CameraOptions): void;
|
|
1053
1165
|
reset(options?: CameraOptions): void;
|
|
@@ -1061,6 +1173,8 @@ export interface MapController {
|
|
|
1061
1173
|
readonly destroyed: boolean;
|
|
1062
1174
|
configure(patch: MapConfiguration): void;
|
|
1063
1175
|
getConfiguration(): MapConfigurationSnapshot;
|
|
1176
|
+
getResolvedConfiguration(): ResolvedMapConfiguration;
|
|
1177
|
+
getCapabilities(): MapCapabilities;
|
|
1064
1178
|
on<K extends keyof MapEvents>(type: K, listener: (detail: MapEvents[K]) => void): () => void;
|
|
1065
1179
|
/** Reconcile stable IDs; retained markers preserve nodes, focus, and entrance animations. */
|
|
1066
1180
|
setMarkers(markers: readonly MapMarker[]): void;
|
|
@@ -1091,6 +1205,7 @@ export interface MapController {
|
|
|
1091
1205
|
/** Idempotent; stops work and managed subscriptions. Does not remove host-owned DOM. */
|
|
1092
1206
|
destroy(): void;
|
|
1093
1207
|
}
|
|
1208
|
+
export {};
|
|
1094
1209
|
```
|
|
1095
1210
|
|
|
1096
1211
|
### dist/data/types.d.ts
|
|
@@ -1264,6 +1379,9 @@ export interface MapOverlay {
|
|
|
1264
1379
|
label?: string;
|
|
1265
1380
|
}
|
|
1266
1381
|
export interface SFMapOptions {
|
|
1382
|
+
/** Grouped presentation; supplied keys take precedence over flat compatibility options. */
|
|
1383
|
+
layers?: StaticMapLayers;
|
|
1384
|
+
appearance?: StaticMapAppearance;
|
|
1267
1385
|
theme?: 'districts' | 'transit';
|
|
1268
1386
|
width?: number;
|
|
1269
1387
|
height?: number;
|
|
@@ -1282,7 +1400,7 @@ export interface SFMapOptions {
|
|
|
1282
1400
|
roadLabels?: boolean;
|
|
1283
1401
|
landmarks?: boolean;
|
|
1284
1402
|
bartStations?: boolean;
|
|
1285
|
-
markers?: MapMarker[];
|
|
1403
|
+
markers?: readonly MapMarker[];
|
|
1286
1404
|
overlays?: readonly MapOverlay[];
|
|
1287
1405
|
title?: string;
|
|
1288
1406
|
idPrefix?: string;
|
|
@@ -1298,6 +1416,9 @@ export interface SFMapOptions {
|
|
|
1298
1416
|
};
|
|
1299
1417
|
colors?: Partial<Record<'water' | 'land' | 'district' | 'neighborhood' | 'highway' | 'road' | 'park' | 'landmark' | 'bart' | 'label' | 'marker' | 'selected', string>>;
|
|
1300
1418
|
}
|
|
1419
|
+
/** Presentation supported by both the static and interactive renderers. */
|
|
1420
|
+
export type StaticMapLayers = Omit<InteractiveLayers, 'neighborhoodLabels'>;
|
|
1421
|
+
export type StaticMapAppearance = Pick<SFMapOptions, 'theme' | 'colors' | 'districtStyle'>;
|
|
1301
1422
|
/** Serializable viewport in the interactive map's fixed 800 × 800 projected space. */
|
|
1302
1423
|
export type MapViewport = readonly [x: number, y: number, size: number];
|
|
1303
1424
|
export type ExplorerMode = 'neighborhoods' | 'districts' | 'basemap';
|
|
@@ -1476,7 +1597,7 @@ export interface NeighborhoodExplorerElement extends HTMLElement {
|
|
|
1476
1597
|
export interface TransitAnimationElement extends HTMLElement {
|
|
1477
1598
|
destroy(): void;
|
|
1478
1599
|
}
|
|
1479
|
-
export type { MapAppearance, MapCamera, MapConfiguration, MapController, MapEvents, MapOptions, } from './controller-types.js';
|
|
1600
|
+
export type { MapAppearance, MapCamera, MapCapabilities, MapConfiguration, MapConfigurationSnapshot, MapController, MapControls, MapEvents, MapOptions, MapSelectionChange, ResolvedMapConfiguration, } from './controller-types.js';
|
|
1480
1601
|
```
|
|
1481
1602
|
|
|
1482
1603
|
### dist/src/explorer-data.d.ts
|
|
@@ -1578,6 +1699,20 @@ export declare function getLayerPathsWithData(options: SFMapOptions, data: SFMap
|
|
|
1578
1699
|
point: [number, number];
|
|
1579
1700
|
}[];
|
|
1580
1701
|
};
|
|
1702
|
+
export declare function resolveMapColors(theme: SFMapOptions['theme'], colors?: SFMapOptions['colors']): {
|
|
1703
|
+
water: string;
|
|
1704
|
+
land: string;
|
|
1705
|
+
district: string;
|
|
1706
|
+
neighborhood: string;
|
|
1707
|
+
highway: string;
|
|
1708
|
+
road: string;
|
|
1709
|
+
park: string;
|
|
1710
|
+
landmark: string;
|
|
1711
|
+
bart: string;
|
|
1712
|
+
label: string;
|
|
1713
|
+
marker: string;
|
|
1714
|
+
selected: string;
|
|
1715
|
+
};
|
|
1581
1716
|
/** Make an offline SVG and the matching longitude/latitude projection. */
|
|
1582
1717
|
export declare function createSFMapWithData(options: SFMapOptions, data: SFMapData): {
|
|
1583
1718
|
svg: string;
|
|
@@ -1592,7 +1727,7 @@ export declare function createSFMapWithData(options: SFMapOptions, data: SFMapDa
|
|
|
1592
1727
|
import { type SFMapData } from './map-core.js';
|
|
1593
1728
|
import type { SFMapOptions } from './types.js';
|
|
1594
1729
|
export type { DistrictRowData, SFMapData as StaticMapData } from './map-core.js';
|
|
1595
|
-
export type { DistrictStyle, DistrictYear, SFMapOptions as StaticMapOptions } from './types.js';
|
|
1730
|
+
export type { DistrictStyle, DistrictYear, SFMapOptions as StaticMapOptions, StaticMapAppearance, StaticMapLayers, } from './types.js';
|
|
1596
1731
|
/** Server-safe SVG rendering with explicit data; returns SVG plus projection helpers. */
|
|
1597
1732
|
export declare function renderMap(data: SFMapData, options?: SFMapOptions): {
|
|
1598
1733
|
svg: string;
|
package/llms.txt
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
> Offline San Francisco SVG maps with explicit geographic imports, no runtime dependencies, static rendering, and a browser controller.
|
|
4
4
|
|
|
5
|
-
@kahwee/sf-map-svg 4.
|
|
5
|
+
@kahwee/sf-map-svg 4.2.0 · local working tree. Node >=24.0.0 for server rendering; browsers need a DOM and a JSON-capable bundler.
|
|
6
6
|
|
|
7
7
|
These are working-tree docs. Unreleased changelog entries may describe APIs absent from npm; verify the installed version before copying them.
|
|
8
8
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kahwee/sf-map-svg",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.2.0",
|
|
4
4
|
"description": "Offline SVG maps of San Francisco with district boundaries, parks, landmarks, and BART stations.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/src/api.js",
|
|
@@ -175,13 +175,14 @@
|
|
|
175
175
|
"demo": "pnpm build && node examples/build.mjs",
|
|
176
176
|
"format": "biome check --write .",
|
|
177
177
|
"format:check": "biome format .",
|
|
178
|
-
"check": "pnpm peers check && pnpm lint && pnpm check:docs && pnpm data:check && pnpm typecheck && pnpm typecheck:stories && pnpm test && pnpm test:bundle",
|
|
178
|
+
"check": "pnpm peers check && pnpm lint && pnpm check:docs && pnpm data:check && pnpm typecheck && pnpm typecheck:stories && pnpm typecheck:website && pnpm test && pnpm test:bundle",
|
|
179
179
|
"check:docs": "pnpm build && node scripts/check-docs.mjs && node scripts/build-llm-docs.mjs --check",
|
|
180
180
|
"storybook": "pnpm build && storybook dev -p 6006 --host 127.0.0.1 --no-open",
|
|
181
181
|
"build-storybook": "pnpm build && storybook build",
|
|
182
182
|
"data:catalog": "node scripts/build-data-catalog.mjs",
|
|
183
183
|
"data:check": "node scripts/build-data-catalog.mjs --check",
|
|
184
184
|
"typecheck": "pnpm build && tsc -p tsconfig.json",
|
|
185
|
+
"typecheck:website": "pnpm build && tsc -p tsconfig.website.json",
|
|
185
186
|
"typecheck:stories": "tsc -p tsconfig.stories.json",
|
|
186
187
|
"data:normalize-realtor": "node scripts/normalize-realtor.mjs",
|
|
187
188
|
"data:guide": "node scripts/build-guide-data.mjs",
|