@kahwee/sf-map-svg 5.1.4 → 6.0.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 CHANGED
@@ -4,6 +4,13 @@ User-visible changes are recorded here. Unreleased entries describe changes on `
4
4
 
5
5
  ## Unreleased
6
6
 
7
+ ## 6.0.0 — 2026-11-05
8
+
9
+ - Breaking: remove flat static presentation options. Use `layers` for geographic switches and `appearance` for theme, colors and district styles.
10
+ - Breaking: remove element-based `createGuideMap` and `mountGuideMap` factories and their option/element aliases. Use `createGuideController` and `mountGuideController`, mount `.element`, and dispose the controller.
11
+ - Remove older-package capability adapters from the site and snippet generator; require v6 or newer for Pages builds and versioned playground share links. Add a v6 migration guide and rejection coverage for removed contracts.
12
+ - Use official sources only on the Pages election views: remove all newspaper and agency-compilation tallies, projections, history and their validation from the feed, views, trend charts and tests. Local measures without official counts read Pending until official counts are imported.
13
+
7
14
  ## 5.1.4 — 2026-11-05
8
15
 
9
16
  - Group internal browser controllers, renderers and shells under `src/interactive`, and SVG generation under `src/rendering`. Rename the general map engine, controls and marker renderer to match their responsibilities; clarify selection-detail, neighborhood-results and layer-composition operations. Keep public package entry points unchanged.
package/README.md CHANGED
@@ -27,11 +27,7 @@ Upgrading from v3 to v4: update your Node runtime to 24 or newer. The map API, b
27
27
  import { renderMap } from '@kahwee/sf-map-svg';
28
28
  import { staticMapData } from '@kahwee/sf-map-svg/data/static';
29
29
 
30
- const { svg, project, viewBox } = renderMap(staticMapData, {
31
- year: 2022,
32
- landmarks: true,
33
- bartStations: true,
34
- });
30
+ const { svg, project, viewBox } = renderMap(staticMapData, { year: 2022, layers: { landmarks: true, bartStations: true } });
35
31
  ```
36
32
 
37
33
  `renderMap(data, options)` returns SVG markup and matching projection helpers. `/data/static` includes the complete static map without interactive lookup collections. Small maps can compose selected JSON exports from `/data/*` and pass them as `StaticMapData`. `getLayerPaths(data, options)` returns fitted geographic paths without SVG markup.
@@ -135,7 +135,7 @@ Run `pnpm data:normalize-realtor` when updating realtor geometry, then `pnpm dat
135
135
 
136
136
  ## Lightweight guide preset
137
137
 
138
- Import `@kahwee/sf-map-svg/guide` for the guide preset. It statically imports only a simplified coastline, simplified SFAR neighborhoods, six major park outlines, selected US 101 / I-280 / Highway 1 segments, six curated streets, and eight BART points. It does not import historical districts, alternate neighborhood sources, or the full catalog. `createGuideMap()` uses this overview by default. `loadGuideDetailedData()` explicitly loads detailed versions of those same selected datasets; it does not add historical or alternative datasets. Regenerate derived geometry with `pnpm data:guide` after updating canonical source files.
138
+ Import `@kahwee/sf-map-svg/guide` for the guide preset. It statically imports only a simplified coastline, simplified SFAR neighborhoods, six major park outlines, selected US 101 / I-280 / Highway 1 segments, six curated streets, and eight BART points. It does not import historical districts, alternate neighborhood sources, or the full catalog. `createGuideController()` uses this overview by default. `loadGuideDetailedData()` explicitly loads detailed versions of those same selected datasets; it does not add historical or alternative datasets. Regenerate derived geometry with `pnpm data:guide` after updating canonical source files.
139
139
 
140
140
  Neighborhood overview boundaries use a shared coordinate graph: connected boundary arcs are simplified once and retained vertices are applied to all adjacent polygons. The 0.00009 degree tolerance is approximately subpixel at an 800px city map; overview coastline and park geometry use similarly subpixel tolerances. Roads crossing park polygons remain separate overlays and are drawn above park fills. Detailed collections retain their canonical source coordinates.
141
141
 
@@ -1,5 +1,5 @@
1
1
  import type { DistrictRowData } from './rendering/svg-map-renderer.js';
2
- import type { DistrictStyle, DistrictYear, SFMapOptions } from './types.js';
2
+ import type { DistrictStyle, DistrictYear, SvgRenderOptions } from './types.js';
3
3
  /** Apply prepared styles and interaction state without invoking consumer callbacks. */
4
4
  export declare function renderDistrictAppearance({ svg, rows, styles, selectedDistrict, hoveredDistrict, year, theme, colors, fills, lines, }: {
5
5
  svg: SVGSVGElement;
@@ -8,8 +8,8 @@ export declare function renderDistrictAppearance({ svg, rows, styles, selectedDi
8
8
  selectedDistrict: number | null;
9
9
  hoveredDistrict: number | null;
10
10
  year: DistrictYear;
11
- theme: SFMapOptions['theme'];
12
- colors: NonNullable<SFMapOptions['colors']>;
11
+ theme: SvgRenderOptions['theme'];
12
+ colors: NonNullable<SvgRenderOptions['colors']>;
13
13
  fills: boolean;
14
14
  lines: boolean;
15
15
  }): void;
@@ -1,4 +1,4 @@
1
1
  import type { DistrictRowData } from './rendering/svg-map-renderer.js';
2
- import type { DistrictStyle, SFMapOptions } from './types.js';
2
+ import type { DistrictStyle, SvgRenderOptions } from './types.js';
3
3
  /** Evaluate user code once and copy its result before changing the map. */
4
- export declare function prepareDistrictStyles(rows: readonly DistrictRowData[], callback: SFMapOptions['districtStyle']): ReadonlyMap<number, DistrictStyle>;
4
+ export declare function prepareDistrictStyles(rows: readonly DistrictRowData[], callback: SvgRenderOptions['districtStyle']): ReadonlyMap<number, DistrictStyle>;
@@ -1,12 +1,5 @@
1
1
  import type { MapController, MapOptions } from './controller-types.js';
2
- import type { NeighborhoodExplorerElement as InteractiveSFMapElement, NeighborhoodExplorerOptions as InteractiveSFMapOptions } from './types.js';
3
2
  /** Preferred guide API: the same grouped options, events, camera and lifecycle as createMap. */
4
3
  export declare function createGuideController(options?: MapOptions): MapController;
5
4
  /** Enhance a static guide shell and return its owning controller. */
6
5
  export declare function mountGuideController(shell: HTMLElement, options?: MapOptions): MapController;
7
- /** Element-based compatibility API. Prefer createGuideController for new integrations. */
8
- export declare function createGuideMap(options?: InteractiveSFMapOptions): InteractiveSFMapElement;
9
- /** Enhance createGuideShell() in place with a fixed compact chrome layout.
10
- * Keep an accessible external place list when hiding the native pickers.
11
- */
12
- export declare function mountGuideMap(shell: HTMLElement, options?: InteractiveSFMapOptions): InteractiveSFMapElement;
@@ -1,10 +1,7 @@
1
1
  import { expandMapOptions, prepareConfiguration } from './configuration.js';
2
2
  import { guideMapData } from './guide-data.js';
3
- import { createMapEngine } from './interactive/map-engine.js';
4
- import { createMapShell } from './interactive/map-shell.js';
5
3
  import { createMap } from './map.js';
6
4
  import { guideOptions } from './presets.js';
7
- import { validateExplorerOptions } from './validation.js';
8
5
  function controllerOptions(options) {
9
6
  expandMapOptions(options);
10
7
  const config = prepareConfiguration({ features: {}, layers: guideOptions.layers ?? {}, controls: {}, appearance: {} }, {
@@ -59,33 +56,3 @@ function mountFrame(frame, map) {
59
56
  map.querySelector('.sf-explorer-map-column > details')?.classList.add('sf-guide-sources');
60
57
  frame.replaceWith(map);
61
58
  }
62
- /** Element-based compatibility API. Prefer createGuideController for new integrations. */
63
- export function createGuideMap(options = {}) {
64
- validateExplorerOptions(options);
65
- return createMapEngine({
66
- mode: 'neighborhoods',
67
- ...options,
68
- layers: {
69
- ...guideOptions.layers,
70
- ...options.layers,
71
- },
72
- interface: 'map',
73
- }, guideMapData, { createShell: createMapShell });
74
- }
75
- /** Enhance createGuideShell() in place with a fixed compact chrome layout.
76
- * Keep an accessible external place list when hiding the native pickers.
77
- */
78
- export function mountGuideMap(shell, options = {}) {
79
- validateExplorerOptions(options);
80
- const frame = shellFrame(shell, options.attribution);
81
- const map = createGuideMap({
82
- ...options,
83
- attribution: 'compact',
84
- controls: {
85
- ...shellControls,
86
- ...options.controls,
87
- },
88
- });
89
- mountFrame(frame, map);
90
- return map;
91
- }
@@ -1,9 +1,9 @@
1
- import type { SFMapOptions } from './types.js';
1
+ import type { StaticMapOptions } from './types.js';
2
2
  /** Server-safe overview using exactly the guide browser geography. */
3
- export declare function createGuideSVG(options?: SFMapOptions): {
3
+ export declare function createGuideSVG(options?: StaticMapOptions): {
4
4
  svg: string;
5
5
  project: (coordinates: import("./geometry.js").Position) => [number, number];
6
6
  viewBox: [number, number, number, number];
7
7
  };
8
- /** Stable compact frame, progressively enhanced with mountGuideMap(). No browser globals. */
9
- export declare function createGuideShell(options?: SFMapOptions): string;
8
+ /** Stable compact frame, progressively enhanced with mountGuideController(). No browser globals. */
9
+ export declare function createGuideShell(options?: StaticMapOptions): string;
@@ -4,20 +4,23 @@ import { renderMap } from './static.js';
4
4
  /** Server-safe overview using exactly the guide browser geography. */
5
5
  export function createGuideSVG(options = {}) {
6
6
  return renderMap(guideMapData.map, {
7
- theme: 'transit',
8
- districtFills: false,
9
- districtLines: false,
10
- districtLabels: false,
11
- neighborhoodLines: true,
12
- neighborhoodLabels: options.labelLayout !== undefined,
13
- landmarks: true,
14
- highways: true,
15
- keyRoads: true,
16
- bartStations: true,
17
7
  ...options,
8
+ appearance: { theme: 'transit', ...options.appearance },
9
+ layers: {
10
+ districtFills: false,
11
+ districtLines: false,
12
+ districtLabels: false,
13
+ neighborhoodLines: true,
14
+ neighborhoodLabels: options.labelLayout !== undefined,
15
+ landmarks: true,
16
+ highways: true,
17
+ keyRoads: true,
18
+ bartStations: true,
19
+ ...options.layers,
20
+ },
18
21
  });
19
22
  }
20
- /** Stable compact frame, progressively enhanced with mountGuideMap(). No browser globals. */
23
+ /** Stable compact frame, progressively enhanced with mountGuideController(). No browser globals. */
21
24
  export function createGuideShell(options = {}) {
22
25
  if ((options.width !== undefined && options.width !== 800) ||
23
26
  (options.height !== undefined && options.height !== 800) ||
@@ -2,5 +2,5 @@ export type { MapController, MapOptions } from './controller-types.js';
2
2
  export type { InteractiveSFMapData } from './explorer-data.js';
3
3
  export { guideMapData } from './guide-data.js';
4
4
  export { loadGuideDetailedData } from './guide-detailed.js';
5
- export { createGuideController, createGuideMap, mountGuideController, mountGuideMap, } from './guide-map.js';
6
- export type { CameraOptions, MapFeatures, MapMarker, NeighborhoodExplorerElement as InteractiveSFMapElement, NeighborhoodExplorerOptions as InteractiveSFMapOptions, } from './types.js';
5
+ export { createGuideController, mountGuideController, } from './guide-map.js';
6
+ export type { CameraOptions, MapFeatures, MapMarker, } from './types.js';
package/dist/src/guide.js CHANGED
@@ -1,3 +1,3 @@
1
1
  export { guideMapData } from './guide-data.js';
2
2
  export { loadGuideDetailedData } from './guide-detailed.js';
3
- export { createGuideController, createGuideMap, mountGuideController, mountGuideMap, } from './guide-map.js';
3
+ export { createGuideController, mountGuideController, } from './guide-map.js';
@@ -1,7 +1,7 @@
1
- import type { SFMapOptions } from './types.js';
1
+ import type { SvgRenderOptions } from './types.js';
2
2
  /** Shared tokens for static SVGs, interactive maps, and consumer-owned place cards. */
3
3
  export interface MapPalette {
4
- readonly colors: NonNullable<SFMapOptions['colors']>;
4
+ readonly colors: NonNullable<SvgRenderOptions['colors']>;
5
5
  readonly haloColor: string;
6
6
  readonly markerColor: string;
7
7
  readonly selectedMarkerColor: string;
@@ -2,14 +2,14 @@ import type { Geometry } from '../../data/types.js';
2
2
  import type { DistrictRow } from '../data.js';
3
3
  import type { Project } from '../geometry.js';
4
4
  import type { BartStation, KeyRoad, Landmark } from '../overlays.js';
5
- import type { MapMarker, SFMapOptions } from '../types.js';
5
+ import type { MapMarker, SvgRenderOptions } from '../types.js';
6
6
  interface LayerContext {
7
7
  labels: boolean;
8
8
  /** Animated static maps index items for staggering and measure lines for drawing. */
9
9
  animated?: boolean;
10
- theme: NonNullable<SFMapOptions['theme']>;
10
+ theme: NonNullable<SvgRenderOptions['theme']>;
11
11
  idPrefix: string;
12
- colors: Required<NonNullable<SFMapOptions['colors']>>;
12
+ colors: Required<NonNullable<SvgRenderOptions['colors']>>;
13
13
  project: Project;
14
14
  path: (geometry: Geometry | null | undefined) => string;
15
15
  }
@@ -1,6 +1,6 @@
1
1
  import type { Geometry, Position } from '../../data/types.js';
2
- import type { DistrictYear, SFMapOptions } from '../types.js';
3
- export type { DistrictYear, MapMarker, MapOverlay, SFMapOptions } from '../types.js';
2
+ import type { DistrictYear, SvgRenderOptions } from '../types.js';
3
+ export type { DistrictYear, MapMarker, MapOverlay, SvgRenderOptions } from '../types.js';
4
4
  import { type Project } from '../geometry.js';
5
5
  export interface SFMapData {
6
6
  coast: Geometry;
@@ -50,7 +50,7 @@ export interface BartStationData {
50
50
  export declare const districtYears: readonly DistrictYear[];
51
51
  export declare const districtColors: readonly string[];
52
52
  /** Canonical geometry in the same fitted coordinate space used by renderMap. */
53
- export declare function getLayerPathsWithData(options: SFMapOptions, data: SFMapData, complete?: boolean): {
53
+ export declare function getLayerPathsWithData(options: SvgRenderOptions, data: SFMapData, complete?: boolean): {
54
54
  year: DistrictYear;
55
55
  viewBox: [number, number, number, number];
56
56
  project: (coordinates: Position) => [number, number];
@@ -82,7 +82,7 @@ export declare function getLayerPathsWithData(options: SFMapOptions, data: SFMap
82
82
  point: [number, number];
83
83
  }[];
84
84
  };
85
- export declare function resolveMapColors(theme: SFMapOptions['theme'], colors?: SFMapOptions['colors']): {
85
+ export declare function resolveMapColors(theme: SvgRenderOptions['theme'], colors?: SvgRenderOptions['colors']): {
86
86
  water: string;
87
87
  land: string;
88
88
  district: string;
@@ -97,7 +97,7 @@ export declare function resolveMapColors(theme: SFMapOptions['theme'], colors?:
97
97
  selected: string;
98
98
  };
99
99
  /** Make an offline SVG and the matching longitude/latitude projection. */
100
- export declare function createSFMapWithData(options: SFMapOptions, data: SFMapData, renderLabels?: (project: Project) => string): {
100
+ export declare function createSFMapWithData(options: SvgRenderOptions, data: SFMapData, renderLabels?: (project: Project) => string): {
101
101
  svg: string;
102
102
  project: (coordinates: Position) => [number, number];
103
103
  viewBox: [number, number, number, number];
@@ -1,10 +1,10 @@
1
- import type { SFMapOptions } from './types.js';
1
+ import type { SvgRenderOptions } from './types.js';
2
2
  export interface StaticAnimation {
3
3
  duration: number;
4
4
  delay: number;
5
5
  }
6
6
  /** Validate `animation` and return timings, or null when animation is off. */
7
- export declare function normalizeStaticAnimation(value: SFMapOptions['animation']): StaticAnimation | null;
7
+ export declare function normalizeStaticAnimation(value: SvgRenderOptions['animation']): StaticAnimation | null;
8
8
  /**
9
9
  * Scoped, self-contained CSS for an animated static map. It runs when the SVG is
10
10
  * inserted into a page or loaded as an image, and stays still under reduced motion.
@@ -1,7 +1,7 @@
1
1
  import type { Project } from './geometry.js';
2
2
  import type { SFMapData } from './rendering/svg-map-renderer.js';
3
- import type { SFMapOptions } from './types.js';
3
+ import type { SvgRenderOptions } from './types.js';
4
4
  /** Conservative portable metrics; the browser refines these with its actual font. */
5
5
  export declare function estimateLabelWidth(text: string, fontSize: number): number;
6
6
  /** Interactive overview rules, expressed entirely in screen pixels before serialization. */
7
- export declare function staticLabels(data: SFMapData, options: SFMapOptions, project: Project): string;
7
+ export declare function staticLabels(data: SFMapData, options: SvgRenderOptions, project: Project): string;
@@ -97,7 +97,7 @@ export function staticLabels(data, options, project) {
97
97
  : []),
98
98
  ...markers.map((item) => {
99
99
  const [x, y] = point(item.position);
100
- // Also cover the legacy SVG marker when it is larger than its interactive counterpart.
100
+ // Also cover the static SVG marker when it is larger than its interactive counterpart.
101
101
  const radius = Math.max(item.radius ?? 6, (item.radius ?? (item.selected ? 8 : 5)) / unit) + 3;
102
102
  return [x - radius, y - radius, x + radius, y + radius];
103
103
  }),
@@ -1,18 +1,18 @@
1
1
  import type { InteractiveSFMapData } from './explorer-data.js';
2
2
  import { type SFMapData } from './rendering/svg-map-renderer.js';
3
- import type { SFMapOptions } from './types.js';
3
+ import type { StaticMapOptions } from './types.js';
4
4
  /** Either compact static geography or the same source-aware geography used by createMap. */
5
5
  export type StaticMapInput = SFMapData | InteractiveSFMapData;
6
6
  export type { DistrictRowData, SFMapData as StaticMapData } from './rendering/svg-map-renderer.js';
7
- export type { DistrictStyle, DistrictYear, SFMapOptions as StaticMapOptions, StaticMapAppearance, StaticMapLayers, } from './types.js';
7
+ export type { DistrictStyle, DistrictYear, StaticMapAppearance, StaticMapLayers, StaticMapOptions, } from './types.js';
8
8
  /** Server-safe SVG rendering with explicit data; returns SVG plus projection helpers. */
9
- export declare function renderMap(data: StaticMapInput, options?: SFMapOptions): {
9
+ export declare function renderMap(data: StaticMapInput, options?: StaticMapOptions): {
10
10
  svg: string;
11
11
  project: (coordinates: import("./geometry.js").Position) => [number, number];
12
12
  viewBox: [number, number, number, number];
13
13
  };
14
14
  /** Project canonical layer geometry without constructing an SVG string. */
15
- export declare function getLayerPaths(data: StaticMapInput, options?: SFMapOptions): {
15
+ export declare function getLayerPaths(data: StaticMapInput, options?: StaticMapOptions): {
16
16
  year: import("./types.js").DistrictYear;
17
17
  viewBox: [number, number, number, number];
18
18
  project: (coordinates: import("./geometry.js").Position) => [number, number];
@@ -55,15 +55,11 @@ const staticLayerKeys = [
55
55
  'keyRoads',
56
56
  'roadLabels',
57
57
  ];
58
- /** Grouped keys override flat compatibility keys; omitted keys preserve renderer defaults. */
58
+ /** Validate the public grouped contract before preparing internal renderer options. */
59
59
  function expandStaticOptions(options) {
60
60
  assertOptions(options, 'static map', [
61
- ...staticLayerKeys,
62
61
  'layers',
63
62
  'appearance',
64
- 'theme',
65
- 'colors',
66
- 'districtStyle',
67
63
  'width',
68
64
  'height',
69
65
  'padding',
@@ -77,7 +73,7 @@ function expandStaticOptions(options) {
77
73
  'idPrefix',
78
74
  'animation',
79
75
  ]);
80
- for (const key of [...staticLayerKeys, 'labels'])
76
+ for (const key of ['labels'])
81
77
  if (options[key] !== undefined && typeof options[key] !== 'boolean')
82
78
  throw new TypeError(`${key} must be boolean.`);
83
79
  for (const key of ['title', 'idPrefix'])
@@ -117,11 +113,10 @@ function expandStaticOptions(options) {
117
113
  if (options.appearance !== undefined) {
118
114
  assertOptions(options.appearance, 'static appearance', ['theme', 'colors', 'districtStyle']);
119
115
  }
120
- const { layers, appearance, theme, colors, districtStyle, ...flat } = options;
116
+ const { layers, appearance, ...flat } = options;
121
117
  const supplied = (group = {}) => Object.fromEntries(Object.entries(group).filter(([, value]) => value !== undefined));
122
118
  return {
123
119
  ...flat,
124
- ...prepareAppearance({}, { theme, colors, districtStyle }),
125
120
  ...supplied(layers),
126
121
  ...supplied(appearance === undefined ? undefined : prepareAppearance({}, appearance)),
127
122
  };
@@ -39,10 +39,7 @@ export interface MapOverlay {
39
39
  visible?: boolean;
40
40
  label?: string;
41
41
  }
42
- export interface SFMapOptions {
43
- /** Grouped presentation; supplied keys take precedence over flat compatibility options. */
44
- layers?: StaticMapLayers;
45
- appearance?: StaticMapAppearance;
42
+ export interface SvgRenderOptions {
46
43
  theme?: 'districts' | 'transit';
47
44
  width?: number;
48
45
  height?: number;
@@ -96,7 +93,12 @@ export interface SFMapOptions {
96
93
  }
97
94
  /** Presentation supported by both the static and interactive renderers. */
98
95
  export type StaticMapLayers = InteractiveLayers;
99
- export type StaticMapAppearance = Pick<SFMapOptions, 'theme' | 'colors' | 'districtStyle'>;
96
+ export type StaticMapAppearance = Pick<SvgRenderOptions, 'theme' | 'colors' | 'districtStyle'>;
97
+ /** Public static presentation uses the same grouped vocabulary as the map controller. */
98
+ export type StaticMapOptions = Omit<SvgRenderOptions, keyof StaticMapLayers | keyof StaticMapAppearance> & {
99
+ layers?: StaticMapLayers;
100
+ appearance?: StaticMapAppearance;
101
+ };
100
102
  /** Serializable viewport in the interactive map's fixed 800 × 800 projected space. */
101
103
  export type MapViewport = readonly [x: number, y: number, size: number];
102
104
  export type ExplorerMode = 'neighborhoods' | 'districts' | 'basemap';
@@ -166,8 +168,8 @@ export interface NeighborhoodExplorerOptions extends MapFeatures {
166
168
  source?: NeighborhoodSource;
167
169
  neighborhood?: string;
168
170
  year?: DistrictYear;
169
- theme?: SFMapOptions['theme'];
170
- colors?: SFMapOptions['colors'];
171
+ theme?: SvgRenderOptions['theme'];
172
+ colors?: SvgRenderOptions['colors'];
171
173
  labelStyle?: {
172
174
  fontFamily?: string;
173
175
  fontWeight?: number;
@@ -179,7 +181,7 @@ export interface NeighborhoodExplorerOptions extends MapFeatures {
179
181
  hoverFill?: string;
180
182
  hoverStroke?: string;
181
183
  };
182
- districtStyle?: SFMapOptions['districtStyle'];
184
+ districtStyle?: SvgRenderOptions['districtStyle'];
183
185
  legend?: {
184
186
  builtins?: boolean;
185
187
  hidden?: readonly ('bart' | 'park' | 'highway' | 'road')[];
@@ -245,7 +247,7 @@ export interface NeighborhoodExplorerElement extends HTMLElement {
245
247
  } & CameraOptions): boolean;
246
248
  getSelectedDistrict(): DistrictSelection | null;
247
249
  setDistrictYear(year: DistrictYear, options?: CameraOptions): void;
248
- setDistrictStyle(style: SFMapOptions['districtStyle']): void;
250
+ setDistrictStyle(style: SvgRenderOptions['districtStyle']): void;
249
251
  setSource(source: NeighborhoodSource): void;
250
252
  setMode(mode: ExplorerMode): void;
251
253
  setLabels(visible: boolean): void;
package/docs/API.md CHANGED
@@ -54,9 +54,9 @@ const { svg } = renderMap(staticMapData, presentation);
54
54
  const map = createMap(fullMapData, presentation);
55
55
  ```
56
56
 
57
- Static `layers` supports every interactive layer switch. `neighborhoodLabels` applies to the opt-in `labelLayout` described below. Static `appearance` supports `theme`, `colors`, and `districtStyle`; browser typography, area interaction styles, and screen-space marker sizing remain interactive settings. Unknown keys and invalid values are rejected for both flat and grouped options. Supplied grouped keys override flat compatibility keys; omitted or `undefined` grouped keys preserve the flat value or renderer default. Undefined color tokens use the theme default instead of entering SVG attributes. The two renderers retain their existing defaults. Marker arrays accept readonly inputs.
57
+ Static `layers` supports every interactive layer switch. `neighborhoodLabels` applies to the opt-in `labelLayout` described below. Static `appearance` supports `theme`, `colors`, and `districtStyle`; browser typography, area interaction styles, and screen-space marker sizing remain interactive settings. Unknown keys and invalid values are rejected. Presentation belongs under `layers` and `appearance`; flat presentation keys are rejected. Omitted or `undefined` grouped keys preserve renderer defaults. Undefined color tokens use the theme default instead of entering SVG attributes. The two renderers retain their existing defaults. Marker arrays accept readonly inputs.
58
58
 
59
- Flat compatibility options include `theme`, `width`, `height`, `padding`, `year` (2002, 2012, 2022), `districtLines`, `districtFills`, `districtStyle`, `districtLabels`, `neighborhoodLines`, `neighborhoodLabels`, `labels`, `labelLayout`, `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.
59
+ Top-level static options are `width`, `height`, `padding`, `year`, `source`, `labels`, `labelLayout`, `markers`, `overlays`, `title`, `idPrefix`, and `animation`, alongside `layers` and `appearance`. Each optional layer is independent. User-supplied text and attributes are escaped in SVG output.
60
60
 
61
61
  Custom district IDs must be finite numbers. An empty `labelPoints` array uses the district's primary `label` position.
62
62
 
@@ -64,22 +64,18 @@ The SVG description names the selected neighborhood source for source-aware data
64
64
 
65
65
  `animation: true` (or `{ duration, delay }`) makes a static map draw itself with self-contained, scoped CSS: land fades in, the coast and lines draw, districts grow, then labels and points appear. It plays when the SVG is inserted into a page or loaded as an image, needs no JavaScript, and stays still under `prefers-reduced-motion`. Re-insert the markup to replay it. Default output is unchanged.
66
66
 
67
- Static `labelLayout: { width: 390 }` opts into shared interactive **overview** label priorities, sizes, anchors and collision rules. `width` must be a positive finite CSS canvas width; it does not alter the SVG viewBox. Set `neighborhoodLabels: true` (flat or under `layers`) to add area names in this layout. Guide SVGs and shells enable neighborhood names by default only when opting into `labelLayout`. `labels: false` remains the master switch. Default static output is unchanged.
67
+ Static `labelLayout: { width: 390 }` opts into shared interactive **overview** label priorities, sizes, anchors and collision rules. `width` must be a positive finite CSS canvas width; it does not alter the SVG viewBox. Set `layers: { neighborhoodLabels: true }` to add area names in this layout. Guide SVGs and shells enable neighborhood names by default only when opting into `labelLayout`. `labels: false` remains the master switch. Default static output is unchanged.
68
68
 
69
69
  For editorial previews, `labelLayout` also accepts `maxLabels` (a nonnegative safe integer), `haloColor` (an SVG color string), and `compact: { width, maxLabels }`. The compact width must be positive, finite, and smaller than the main layout width. Each layout places labels around pins independently, then chooses up to its budget for spatial coverage and nearby-pin context (selected marker first when it fits). Without a budget the existing overview order is unchanged. Equal spatial scores retain the original priority order. A zero budget hides text, never pins. The default halo remains white; use the land color for a quieter dark map.
70
70
 
71
71
  Compact mode embeds two label groups and a media query in the same SVG. At or below the compact width it shows the compact group; above it shows the main group. In an `<img>` or standalone SVG, the breakpoint follows the SVG viewport. In inline SVG it follows the document viewport, so use `<img>` for cards whose width differs from the page. No JavaScript, duplicated geometry, external fonts, or extra image requests are needed. The compact width is also its font-layout hint; very narrow images still scale the text. The interactive renderer continues to use its live collision layout after enhancement.
72
72
 
73
73
  ```js
74
- createGuideSVG({
75
- labelLayout: {
74
+ createGuideSVG({ labelLayout: {
76
75
  width: 800,
77
76
  haloColor: '#1b2c28',
78
77
  compact: { width: 480, maxLabels: 4 },
79
- },
80
- colors: { water: '#0a1412', land: '#1b2c28', label: '#d5e3e8' },
81
- markers: places,
82
- });
78
+ }, markers: places, appearance: { colors: { water: '#0a1412', land: '#1b2c28', label: '#d5e3e8' } } });
83
79
  ```
84
80
 
85
81
  See the [field-guide preview recipe](consumer-integration.md#editorial-map-previews) for a complete build-time example.
@@ -110,9 +106,9 @@ Visible markers and clusters share one tab stop. Use `[` and `]` to move focus,
110
106
 
111
107
  Activating coincident pins opens a place chooser, including when compact embeds hide the native marker picker. Clusters zoom when their members can separate at maximum zoom; otherwise they open the chooser. Escape or Close returns focus to the originating pin or cluster when it remains visible. Choosing a place selects its marker; replacing markers or destroying the map closes the chooser. `clusteractivate` still reports the activated cluster's markers.
112
108
 
113
- For a small guide, import `guideMapData` from `/guide/data` and pass it to `createMap`. The optional `/guide` entry also provides `createGuideMap`, `mountGuideMap`, and detailed-data loading for existing guide layouts. `/transit` provides the standalone schematic transit animation. See [examples](EXAMPLES.md) and [consumer integration](consumer-integration.md).
109
+ For a small guide, import `guideMapData` from `/guide/data` and pass it to `createMap`. The optional `/guide` entry also provides `createGuideController`, `mountGuideController`, and detailed-data loading for existing guide layouts. `/transit` provides the standalone schematic transit animation. See [examples](EXAMPLES.md) and [consumer integration](consumer-integration.md).
114
110
 
115
- For the guide preset with the same controller API, use `createGuideController(options)` from `/guide` (or `/guide/map`). It accepts grouped `MapOptions` and returns `MapController`; `mountGuideController(shell, options)` enhances a `createGuideShell()` container. Both use the lightweight guide geography. Existing `createGuideMap` and `mountGuideMap` calls retain their element-based API.
111
+ For the guide preset with the same controller API, use `createGuideController(options)` from `/guide` (or `/guide/map`). It accepts grouped `MapOptions` and returns `MapController`; `mountGuideController(shell, options)` enhances a `createGuideShell()` container. Both use the lightweight guide geography. See [migration to v6](migration-v6.md) for removed compatibility APIs.
116
112
 
117
113
  Two opt-in features animate the map's lines and layers. `features.layerTransitions` fades layers as `configure({ layers })` and `setMode()` switch them, crossfades neighborhood boundaries when `setSource()` changes the definition, and crossfades district fills on `setDistrictStyle()`. `features.districtMorph` moves district outlines from one map year to the next on `setDistrictYear()`, then settles on the exact published geometry; pass `{ animate: false }` for an instant change. Both default off, own and cancel their animations, and yield to reduced motion.
118
114
 
package/docs/EXAMPLES.md CHANGED
@@ -20,18 +20,13 @@ import { writeFile } from 'node:fs/promises';
20
20
  import { renderMap } from '@kahwee/sf-map-svg';
21
21
  import { staticMapData } from '@kahwee/sf-map-svg/data/static';
22
22
 
23
- const svg = renderMap(staticMapData, {
24
- year: 2022,
25
- landmarks: true,
26
- bartStations: true,
27
- idPrefix: 'example',
28
- }).svg;
23
+ const svg = renderMap(staticMapData, { year: 2022, idPrefix: 'example', layers: { landmarks: true, bartStations: true } }).svg;
29
24
  await writeFile('districts.svg', svg);
30
25
  ```
31
26
 
32
27
  The static preset includes the packaged map layers without interactive lookup collections. For smaller bundles, pass selected data to the root or `/static` renderer. See the [static recipe](../README.md#static-svg).
33
28
 
34
- For an election choropleth, use `renderMap(data, { year, districtStyle })` or
29
+ For an election choropleth, use `renderMap(data, { year, appearance: { districtStyle } })` or
35
30
  `createMap({ map: data, districts: districtMaps, neighborhoods: {} }, options)`.
36
31
  The controller exposes `setDistrictYear`, `setDistrictStyle`, `selectDistrict`, and typed
37
32
  district events; `getLayerPaths(data, { year })` returns fitted paths without SVG markup.
package/docs/api-audit.md CHANGED
@@ -28,7 +28,7 @@ unbounded geographic data can never fail.
28
28
  | Label metrics and camera movement | Reuse screen-space text measurements and nodes across frames. Font loading invalidates measurements; hidden or removed candidates do not remain in the visible layer. |
29
29
  | Marker replacement | Reconcile stable IDs, preserve retained nodes/picker options and entrance animations, cancel removed entrances, and restore focus after reordering. Identical ordered values do not mutate the DOM or restart work. |
30
30
  | Camera and label scheduling | A shared frame advances the camera before rendering dependent labels, marker sizes, and clusters. State/events remain synchronous; cancellation preserves pending layout, and destruction cancels both kinds of work. |
31
- | Guide controllers and compatibility factories | `createGuideController`/`mountGuideController` share grouped options and lifecycle with `createMap`. Existing element factories retain flat options and their return types. |
31
+ | Guide controllers | `createGuideController`/`mountGuideController` share grouped options and lifecycle with `createMap`. Element compatibility factories were removed in v6. |
32
32
  | Layer hidden and bundle cost | Visibility never unloads imported geography. Use narrow entrypoints or data injection to save bytes. |
33
33
 
34
34
  Live appearance patches prepare values, district styles and source replacement before committing; token objects merge by key. Styling callbacks that issue a newer presentation update supersede the pending patch. Resolved layer reads distinguish visibility settings from data availability and from zoom/collision label filtering. The additive selection envelope preserves existing event contracts.
@@ -58,8 +58,8 @@ exceptions are not transactional validation errors and do not roll back an alrea
58
58
  committed change. Direct mutation of the returned DOM can invalidate invariants;
59
59
  use the public methods and `overlayElement` extension point.
60
60
 
61
- Static flat and grouped options reject unknown keys and invalid values before
62
- rendering. Grouped options take precedence over flat compatibility options;
61
+ Static grouped options reject unknown keys and invalid values before
62
+ rendering. Flat presentation keys were removed in v6;
63
63
  static and interactive schemas retain their documented differences. Host layout, delayed images, fonts, and application cards need their
64
64
  own CLS tests. The scale bar is an approximate local Mercator scale, not survey
65
65
  instrumentation. Coincident locations use a place chooser rather than spiderfying. Geographic
@@ -80,7 +80,7 @@ function disposeGuide() {
80
80
 
81
81
  Compact attribution is required for an existing shell. Invalid configuration leaves its static frame intact. `destroy()` disposes listeners and animation work; your application owns removal of the containing view. Motion is opt-in and follows reduced-motion preferences.
82
82
 
83
- For a new browser-only guide, use `createGuideController()` and mount its `.element` as shown in the developer guide. Existing `createGuideMap()` and `mountGuideMap()` retain their augmented-element return types and flat options for compatibility.
83
+ For a new browser-only guide, use `createGuideController()` and mount its `.element` as shown in the developer guide. Both guide factories return controllers; mount `map.element` and dispose with `map.destroy()`.
84
84
 
85
85
  ## Choose the data boundary
86
86
 
@@ -22,12 +22,7 @@ import { writeFile } from 'node:fs/promises';
22
22
  import { renderMap } from '@kahwee/sf-map-svg/static';
23
23
  import { staticMapData } from '@kahwee/sf-map-svg/data/static';
24
24
 
25
- const { svg } = renderMap(staticMapData, {
26
- year: 2022,
27
- landmarks: true,
28
- bartStations: true,
29
- title: 'San Francisco districts, 2022',
30
- });
25
+ const { svg } = renderMap(staticMapData, { year: 2022, title: 'San Francisco districts, 2022', layers: { landmarks: true, bartStations: true } });
31
26
  await writeFile('san-francisco.svg', svg);
32
27
  ```
33
28
 
@@ -0,0 +1,57 @@
1
+ # Migrating to v6
2
+
3
+ Version 6 removes the remaining compatibility APIs. Geographic datasets, coordinate
4
+ conventions, defaults and rendering precision are unchanged.
5
+
6
+ ## Static presentation
7
+
8
+ Move flat geographic switches into `layers`, and `theme`, `colors` and
9
+ `districtStyle` into `appearance`. Flat presentation keys now throw.
10
+
11
+ ```js
12
+ const { svg } = renderMap(staticMapData, {
13
+ width: 800,
14
+ labels: true,
15
+ layers: { landmarks: true, bartStations: true, districtFills: false },
16
+ appearance: { theme: 'transit', colors: { water: '#e7f0f3' } },
17
+ });
18
+ ```
19
+
20
+ The same contract applies to `getLayerPaths`, `createGuideSVG` and
21
+ `createGuideShell`. Dimensions, year, source, master labels, label layout,
22
+ markers, overlays, title, ID prefix and animation remain top-level options.
23
+
24
+ ## Guide controllers
25
+
26
+ Replace `createGuideMap` with `createGuideController`, and `mountGuideMap` with
27
+ `mountGuideController`. Both return `MapController`; DOM methods live on `.element`.
28
+ The `InteractiveSFMapElement` and `InteractiveSFMapOptions` guide aliases are removed.
29
+ Use `MapController` and `MapOptions`.
30
+
31
+ ```js
32
+ import { createGuideController } from '@kahwee/sf-map-svg/guide';
33
+ const map = createGuideController({
34
+ features: { motion: true, clustering: true },
35
+ appearance: { colors: { water: '#e7f0f3' } },
36
+ });
37
+ document.querySelector('#map').append(map.element);
38
+ map.configure({ layers: { landmarks: false } });
39
+ map.camera.reset();
40
+ map.on('markerchange', ({ marker }) => console.log(marker));
41
+ // On unmount:
42
+ map.destroy();
43
+ map.element.remove();
44
+ ```
45
+
46
+ Use `configure` for feature, layer, control and appearance changes; use `camera`
47
+ for viewport operations. Replace construction callbacks with `map.on` subscriptions.
48
+ For static-shell enhancement, call `mountGuideController(shell, options)` and keep
49
+ the returned controller for disposal.
50
+
51
+ ## Site integrations
52
+
53
+ Pages builds require a v6-or-newer package and generate examples directly for that
54
+ contract. Older-package feature detection and flat-option fallback generation are
55
+ removed. Playground links must include `version: 1` in their design payload;
56
+ links produced by the current Share control already include it. Unversioned
57
+ handwritten links must add that field.
package/llms-full.txt CHANGED
@@ -2,13 +2,13 @@
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 5.1.4 · local working tree. Node >=24.0.0 for server rendering; browsers need a DOM and a JSON-capable bundler.
5
+ @kahwee/sf-map-svg 6.0.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 5.1.4 · local working tree. -->
11
+ <!-- Generated from README.md; @kahwee/sf-map-svg 6.0.0 · local working tree. -->
12
12
 
13
13
  # SF Map SVG
14
14
 
@@ -39,11 +39,7 @@ Upgrading from v3 to v4: update your Node runtime to 24 or newer. The map API, b
39
39
  import { renderMap } from '@kahwee/sf-map-svg';
40
40
  import { staticMapData } from '@kahwee/sf-map-svg/data/static';
41
41
 
42
- const { svg, project, viewBox } = renderMap(staticMapData, {
43
- year: 2022,
44
- landmarks: true,
45
- bartStations: true,
46
- });
42
+ const { svg, project, viewBox } = renderMap(staticMapData, { year: 2022, layers: { landmarks: true, bartStations: true } });
47
43
  ```
48
44
 
49
45
  `renderMap(data, options)` returns SVG markup and matching projection helpers. `/data/static` includes the complete static map without interactive lookup collections. Small maps can compose selected JSON exports from `/data/*` and pass them as `StaticMapData`. `getLayerPaths(data, options)` returns fitted geographic paths without SVG markup.
@@ -267,7 +263,7 @@ for raw samples, output-equivalence checks, and reproducible commands.
267
263
 
268
264
  ---
269
265
 
270
- <!-- Generated from docs/developer-guide.md; @kahwee/sf-map-svg 5.1.4 · local working tree. -->
266
+ <!-- Generated from docs/developer-guide.md; @kahwee/sf-map-svg 6.0.0 · local working tree. -->
271
267
 
272
268
  # Developer guide
273
269
 
@@ -293,12 +289,7 @@ import { writeFile } from 'node:fs/promises';
293
289
  import { renderMap } from '@kahwee/sf-map-svg/static';
294
290
  import { staticMapData } from '@kahwee/sf-map-svg/data/static';
295
291
 
296
- const { svg } = renderMap(staticMapData, {
297
- year: 2022,
298
- landmarks: true,
299
- bartStations: true,
300
- title: 'San Francisco districts, 2022',
301
- });
292
+ const { svg } = renderMap(staticMapData, { year: 2022, title: 'San Francisco districts, 2022', layers: { landmarks: true, bartStations: true } });
302
293
  await writeFile('san-francisco.svg', svg);
303
294
  ```
304
295
 
@@ -433,7 +424,7 @@ See [API options](https://github.com/kahwee/sf-map-svg/blob/main/docs/API.md), [
433
424
 
434
425
  ---
435
426
 
436
- <!-- Generated from docs/API.md; @kahwee/sf-map-svg 5.1.4 · local working tree. -->
427
+ <!-- Generated from docs/API.md; @kahwee/sf-map-svg 6.0.0 · local working tree. -->
437
428
 
438
429
  # Map options and lifecycle
439
430
 
@@ -491,9 +482,9 @@ const { svg } = renderMap(staticMapData, presentation);
491
482
  const map = createMap(fullMapData, presentation);
492
483
  ```
493
484
 
494
- Static `layers` supports every interactive layer switch. `neighborhoodLabels` applies to the opt-in `labelLayout` described below. Static `appearance` supports `theme`, `colors`, and `districtStyle`; browser typography, area interaction styles, and screen-space marker sizing remain interactive settings. Unknown keys and invalid values are rejected for both flat and grouped options. Supplied grouped keys override flat compatibility keys; omitted or `undefined` grouped keys preserve the flat value or renderer default. Undefined color tokens use the theme default instead of entering SVG attributes. The two renderers retain their existing defaults. Marker arrays accept readonly inputs.
485
+ Static `layers` supports every interactive layer switch. `neighborhoodLabels` applies to the opt-in `labelLayout` described below. Static `appearance` supports `theme`, `colors`, and `districtStyle`; browser typography, area interaction styles, and screen-space marker sizing remain interactive settings. Unknown keys and invalid values are rejected. Presentation belongs under `layers` and `appearance`; flat presentation keys are rejected. Omitted or `undefined` grouped keys preserve renderer defaults. Undefined color tokens use the theme default instead of entering SVG attributes. The two renderers retain their existing defaults. Marker arrays accept readonly inputs.
495
486
 
496
- Flat compatibility options include `theme`, `width`, `height`, `padding`, `year` (2002, 2012, 2022), `districtLines`, `districtFills`, `districtStyle`, `districtLabels`, `neighborhoodLines`, `neighborhoodLabels`, `labels`, `labelLayout`, `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.
487
+ Top-level static options are `width`, `height`, `padding`, `year`, `source`, `labels`, `labelLayout`, `markers`, `overlays`, `title`, `idPrefix`, and `animation`, alongside `layers` and `appearance`. Each optional layer is independent. User-supplied text and attributes are escaped in SVG output.
497
488
 
498
489
  Custom district IDs must be finite numbers. An empty `labelPoints` array uses the district's primary `label` position.
499
490
 
@@ -501,22 +492,18 @@ The SVG description names the selected neighborhood source for source-aware data
501
492
 
502
493
  `animation: true` (or `{ duration, delay }`) makes a static map draw itself with self-contained, scoped CSS: land fades in, the coast and lines draw, districts grow, then labels and points appear. It plays when the SVG is inserted into a page or loaded as an image, needs no JavaScript, and stays still under `prefers-reduced-motion`. Re-insert the markup to replay it. Default output is unchanged.
503
494
 
504
- Static `labelLayout: { width: 390 }` opts into shared interactive **overview** label priorities, sizes, anchors and collision rules. `width` must be a positive finite CSS canvas width; it does not alter the SVG viewBox. Set `neighborhoodLabels: true` (flat or under `layers`) to add area names in this layout. Guide SVGs and shells enable neighborhood names by default only when opting into `labelLayout`. `labels: false` remains the master switch. Default static output is unchanged.
495
+ Static `labelLayout: { width: 390 }` opts into shared interactive **overview** label priorities, sizes, anchors and collision rules. `width` must be a positive finite CSS canvas width; it does not alter the SVG viewBox. Set `layers: { neighborhoodLabels: true }` to add area names in this layout. Guide SVGs and shells enable neighborhood names by default only when opting into `labelLayout`. `labels: false` remains the master switch. Default static output is unchanged.
505
496
 
506
497
  For editorial previews, `labelLayout` also accepts `maxLabels` (a nonnegative safe integer), `haloColor` (an SVG color string), and `compact: { width, maxLabels }`. The compact width must be positive, finite, and smaller than the main layout width. Each layout places labels around pins independently, then chooses up to its budget for spatial coverage and nearby-pin context (selected marker first when it fits). Without a budget the existing overview order is unchanged. Equal spatial scores retain the original priority order. A zero budget hides text, never pins. The default halo remains white; use the land color for a quieter dark map.
507
498
 
508
499
  Compact mode embeds two label groups and a media query in the same SVG. At or below the compact width it shows the compact group; above it shows the main group. In an `<img>` or standalone SVG, the breakpoint follows the SVG viewport. In inline SVG it follows the document viewport, so use `<img>` for cards whose width differs from the page. No JavaScript, duplicated geometry, external fonts, or extra image requests are needed. The compact width is also its font-layout hint; very narrow images still scale the text. The interactive renderer continues to use its live collision layout after enhancement.
509
500
 
510
501
  ```js
511
- createGuideSVG({
512
- labelLayout: {
502
+ createGuideSVG({ labelLayout: {
513
503
  width: 800,
514
504
  haloColor: '#1b2c28',
515
505
  compact: { width: 480, maxLabels: 4 },
516
- },
517
- colors: { water: '#0a1412', land: '#1b2c28', label: '#d5e3e8' },
518
- markers: places,
519
- });
506
+ }, markers: places, appearance: { colors: { water: '#0a1412', land: '#1b2c28', label: '#d5e3e8' } } });
520
507
  ```
521
508
 
522
509
  See the [field-guide preview recipe](https://github.com/kahwee/sf-map-svg/blob/main/docs/consumer-integration.md#editorial-map-previews) for a complete build-time example.
@@ -547,9 +534,9 @@ Visible markers and clusters share one tab stop. Use `[` and `]` to move focus,
547
534
 
548
535
  Activating coincident pins opens a place chooser, including when compact embeds hide the native marker picker. Clusters zoom when their members can separate at maximum zoom; otherwise they open the chooser. Escape or Close returns focus to the originating pin or cluster when it remains visible. Choosing a place selects its marker; replacing markers or destroying the map closes the chooser. `clusteractivate` still reports the activated cluster's markers.
549
536
 
550
- For a small guide, import `guideMapData` from `/guide/data` and pass it to `createMap`. The optional `/guide` entry also provides `createGuideMap`, `mountGuideMap`, and detailed-data loading for existing guide layouts. `/transit` provides the standalone schematic transit animation. See [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).
537
+ For a small guide, import `guideMapData` from `/guide/data` and pass it to `createMap`. The optional `/guide` entry also provides `createGuideController`, `mountGuideController`, and detailed-data loading for existing guide layouts. `/transit` provides the standalone schematic transit animation. See [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).
551
538
 
552
- For the guide preset with the same controller API, use `createGuideController(options)` from `/guide` (or `/guide/map`). It accepts grouped `MapOptions` and returns `MapController`; `mountGuideController(shell, options)` enhances a `createGuideShell()` container. Both use the lightweight guide geography. Existing `createGuideMap` and `mountGuideMap` calls retain their element-based API.
539
+ For the guide preset with the same controller API, use `createGuideController(options)` from `/guide` (or `/guide/map`). It accepts grouped `MapOptions` and returns `MapController`; `mountGuideController(shell, options)` enhances a `createGuideShell()` container. Both use the lightweight guide geography. See [migration to v6](https://github.com/kahwee/sf-map-svg/blob/main/docs/migration-v6.md) for removed compatibility APIs.
553
540
 
554
541
  Two opt-in features animate the map's lines and layers. `features.layerTransitions` fades layers as `configure({ layers })` and `setMode()` switch them, crossfades neighborhood boundaries when `setSource()` changes the definition, and crossfades district fills on `setDistrictStyle()`. `features.districtMorph` moves district outlines from one map year to the next on `setDistrictYear()`, then settles on the exact published geometry; pass `{ animate: false }` for an instant change. Both default off, own and cancel their animations, and yield to reduced motion.
555
542
 
@@ -619,7 +606,7 @@ Call `binding.setMarkers(next)` after `map.setMarkers(next)` when the catalog ch
619
606
 
620
607
  ---
621
608
 
622
- <!-- Generated from docs/EXAMPLES.md; @kahwee/sf-map-svg 5.1.4 · local working tree. -->
609
+ <!-- Generated from docs/EXAMPLES.md; @kahwee/sf-map-svg 6.0.0 · local working tree. -->
623
610
 
624
611
  # Examples
625
612
 
@@ -643,18 +630,13 @@ import { writeFile } from 'node:fs/promises';
643
630
  import { renderMap } from '@kahwee/sf-map-svg';
644
631
  import { staticMapData } from '@kahwee/sf-map-svg/data/static';
645
632
 
646
- const svg = renderMap(staticMapData, {
647
- year: 2022,
648
- landmarks: true,
649
- bartStations: true,
650
- idPrefix: 'example',
651
- }).svg;
633
+ const svg = renderMap(staticMapData, { year: 2022, idPrefix: 'example', layers: { landmarks: true, bartStations: true } }).svg;
652
634
  await writeFile('districts.svg', svg);
653
635
  ```
654
636
 
655
637
  The static preset includes the packaged map layers without interactive lookup collections. For smaller bundles, pass selected data to the root or `/static` renderer. See the [static recipe](https://github.com/kahwee/sf-map-svg/blob/main/README.md#static-svg).
656
638
 
657
- For an election choropleth, use `renderMap(data, { year, districtStyle })` or
639
+ For an election choropleth, use `renderMap(data, { year, appearance: { districtStyle } })` or
658
640
  `createMap({ map: data, districts: districtMaps, neighborhoods: {} }, options)`.
659
641
  The controller exposes `setDistrictYear`, `setDistrictStyle`, `selectDistrict`, and typed
660
642
  district events; `getLayerPaths(data, { year })` returns fitted paths without SVG markup.
@@ -760,7 +742,7 @@ See [query semantics and limitations](https://github.com/kahwee/sf-map-svg/blob/
760
742
 
761
743
  ---
762
744
 
763
- <!-- Generated from docs/consumer-integration.md; @kahwee/sf-map-svg 5.1.4 · local working tree. -->
745
+ <!-- Generated from docs/consumer-integration.md; @kahwee/sf-map-svg 6.0.0 · local working tree. -->
764
746
 
765
747
  # Embedding and progressive enhancement
766
748
 
@@ -844,7 +826,7 @@ function disposeGuide() {
844
826
 
845
827
  Compact attribution is required for an existing shell. Invalid configuration leaves its static frame intact. `destroy()` disposes listeners and animation work; your application owns removal of the containing view. Motion is opt-in and follows reduced-motion preferences.
846
828
 
847
- For a new browser-only guide, use `createGuideController()` and mount its `.element` as shown in the developer guide. Existing `createGuideMap()` and `mountGuideMap()` retain their augmented-element return types and flat options for compatibility.
829
+ For a new browser-only guide, use `createGuideController()` and mount its `.element` as shown in the developer guide. Both guide factories return controllers; mount `map.element` and dispose with `map.destroy()`.
848
830
 
849
831
  ## Choose the data boundary
850
832
 
@@ -938,7 +920,69 @@ keyboard, focus, and dismissal behavior. See [coordinates and units](https://git
938
920
 
939
921
  ---
940
922
 
941
- <!-- Generated from docs/migration-v5.md; @kahwee/sf-map-svg 5.1.4 · local working tree. -->
923
+ <!-- Generated from docs/migration-v6.md; @kahwee/sf-map-svg 6.0.0 · local working tree. -->
924
+
925
+ # Migrating to v6
926
+
927
+ Version 6 removes the remaining compatibility APIs. Geographic datasets, coordinate
928
+ conventions, defaults and rendering precision are unchanged.
929
+
930
+ ## Static presentation
931
+
932
+ Move flat geographic switches into `layers`, and `theme`, `colors` and
933
+ `districtStyle` into `appearance`. Flat presentation keys now throw.
934
+
935
+ ```js
936
+ const { svg } = renderMap(staticMapData, {
937
+ width: 800,
938
+ labels: true,
939
+ layers: { landmarks: true, bartStations: true, districtFills: false },
940
+ appearance: { theme: 'transit', colors: { water: '#e7f0f3' } },
941
+ });
942
+ ```
943
+
944
+ The same contract applies to `getLayerPaths`, `createGuideSVG` and
945
+ `createGuideShell`. Dimensions, year, source, master labels, label layout,
946
+ markers, overlays, title, ID prefix and animation remain top-level options.
947
+
948
+ ## Guide controllers
949
+
950
+ Replace `createGuideMap` with `createGuideController`, and `mountGuideMap` with
951
+ `mountGuideController`. Both return `MapController`; DOM methods live on `.element`.
952
+ The `InteractiveSFMapElement` and `InteractiveSFMapOptions` guide aliases are removed.
953
+ Use `MapController` and `MapOptions`.
954
+
955
+ ```js
956
+ import { createGuideController } from '@kahwee/sf-map-svg/guide';
957
+ const map = createGuideController({
958
+ features: { motion: true, clustering: true },
959
+ appearance: { colors: { water: '#e7f0f3' } },
960
+ });
961
+ document.querySelector('#map').append(map.element);
962
+ map.configure({ layers: { landmarks: false } });
963
+ map.camera.reset();
964
+ map.on('markerchange', ({ marker }) => console.log(marker));
965
+ // On unmount:
966
+ map.destroy();
967
+ map.element.remove();
968
+ ```
969
+
970
+ Use `configure` for feature, layer, control and appearance changes; use `camera`
971
+ for viewport operations. Replace construction callbacks with `map.on` subscriptions.
972
+ For static-shell enhancement, call `mountGuideController(shell, options)` and keep
973
+ the returned controller for disposal.
974
+
975
+ ## Site integrations
976
+
977
+ Pages builds require a v6-or-newer package and generate examples directly for that
978
+ contract. Older-package feature detection and flat-option fallback generation are
979
+ removed. Playground links must include `version: 1` in their design payload;
980
+ links produced by the current Share control already include it. Unversioned
981
+ handwritten links must add that field.
982
+
983
+ ---
984
+
985
+ <!-- Generated from docs/migration-v5.md; @kahwee/sf-map-svg 6.0.0 · local working tree. -->
942
986
 
943
987
  # Migrating to v5
944
988
 
@@ -1043,7 +1087,7 @@ collections. Shared edges can match more than one feature. See the
1043
1087
 
1044
1088
  ---
1045
1089
 
1046
- <!-- Generated from docs/migration-v3.md; @kahwee/sf-map-svg 5.1.4 · local working tree. -->
1090
+ <!-- Generated from docs/migration-v3.md; @kahwee/sf-map-svg 6.0.0 · local working tree. -->
1047
1091
 
1048
1092
  # Migrate to version 3
1049
1093
 
@@ -1084,7 +1128,7 @@ District styles are now prepared once per district on construction and style/yea
1084
1128
 
1085
1129
  ---
1086
1130
 
1087
- <!-- Generated from SOURCES.md; @kahwee/sf-map-svg 5.1.4 · local working tree. -->
1131
+ <!-- Generated from SOURCES.md; @kahwee/sf-map-svg 6.0.0 · local working tree. -->
1088
1132
 
1089
1133
  # Geometry and provenance
1090
1134
 
@@ -1321,7 +1365,7 @@ Report-history points preserve only actual validated source counts and their dis
1321
1365
 
1322
1366
  ---
1323
1367
 
1324
- <!-- Generated from CHANGELOG.md; @kahwee/sf-map-svg 5.1.4 · local working tree. -->
1368
+ <!-- Generated from CHANGELOG.md; @kahwee/sf-map-svg 6.0.0 · local working tree. -->
1325
1369
 
1326
1370
  # Changelog
1327
1371
 
@@ -1329,6 +1373,13 @@ User-visible changes are recorded here. Unreleased entries describe changes on `
1329
1373
 
1330
1374
  ## Unreleased
1331
1375
 
1376
+ ## 6.0.0 — 2026-11-05
1377
+
1378
+ - Breaking: remove flat static presentation options. Use `layers` for geographic switches and `appearance` for theme, colors and district styles.
1379
+ - Breaking: remove element-based `createGuideMap` and `mountGuideMap` factories and their option/element aliases. Use `createGuideController` and `mountGuideController`, mount `.element`, and dispose the controller.
1380
+ - Remove older-package capability adapters from the site and snippet generator; require v6 or newer for Pages builds and versioned playground share links. Add a v6 migration guide and rejection coverage for removed contracts.
1381
+ - Use official sources only on the Pages election views: remove all newspaper and agency-compilation tallies, projections, history and their validation from the feed, views, trend charts and tests. Local measures without official counts read Pending until official counts are imported.
1382
+
1332
1383
  ## 5.1.4 — 2026-11-05
1333
1384
 
1334
1385
  - Group internal browser controllers, renderers and shells under `src/interactive`, and SVG generation under `src/rendering`. Rename the general map engine, controls and marker renderer to match their responsibilities; clarify selection-detail, neighborhood-results and layer-composition operations. Keep public package entry points unchanged.
@@ -1729,7 +1780,7 @@ consistent home, and makes animation and subscription ownership predictable.
1729
1780
 
1730
1781
  # Published type contracts
1731
1782
 
1732
- @kahwee/sf-map-svg 5.1.4 · 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.
1783
+ @kahwee/sf-map-svg 6.0.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.
1733
1784
 
1734
1785
  | Public import | Declaration |
1735
1786
  | --- | --- |
@@ -2143,10 +2194,7 @@ export interface MapOverlay {
2143
2194
  visible?: boolean;
2144
2195
  label?: string;
2145
2196
  }
2146
- export interface SFMapOptions {
2147
- /** Grouped presentation; supplied keys take precedence over flat compatibility options. */
2148
- layers?: StaticMapLayers;
2149
- appearance?: StaticMapAppearance;
2197
+ export interface SvgRenderOptions {
2150
2198
  theme?: 'districts' | 'transit';
2151
2199
  width?: number;
2152
2200
  height?: number;
@@ -2200,7 +2248,12 @@ export interface SFMapOptions {
2200
2248
  }
2201
2249
  /** Presentation supported by both the static and interactive renderers. */
2202
2250
  export type StaticMapLayers = InteractiveLayers;
2203
- export type StaticMapAppearance = Pick<SFMapOptions, 'theme' | 'colors' | 'districtStyle'>;
2251
+ export type StaticMapAppearance = Pick<SvgRenderOptions, 'theme' | 'colors' | 'districtStyle'>;
2252
+ /** Public static presentation uses the same grouped vocabulary as the map controller. */
2253
+ export type StaticMapOptions = Omit<SvgRenderOptions, keyof StaticMapLayers | keyof StaticMapAppearance> & {
2254
+ layers?: StaticMapLayers;
2255
+ appearance?: StaticMapAppearance;
2256
+ };
2204
2257
  /** Serializable viewport in the interactive map's fixed 800 × 800 projected space. */
2205
2258
  export type MapViewport = readonly [x: number, y: number, size: number];
2206
2259
  export type ExplorerMode = 'neighborhoods' | 'districts' | 'basemap';
@@ -2270,8 +2323,8 @@ export interface NeighborhoodExplorerOptions extends MapFeatures {
2270
2323
  source?: NeighborhoodSource;
2271
2324
  neighborhood?: string;
2272
2325
  year?: DistrictYear;
2273
- theme?: SFMapOptions['theme'];
2274
- colors?: SFMapOptions['colors'];
2326
+ theme?: SvgRenderOptions['theme'];
2327
+ colors?: SvgRenderOptions['colors'];
2275
2328
  labelStyle?: {
2276
2329
  fontFamily?: string;
2277
2330
  fontWeight?: number;
@@ -2283,7 +2336,7 @@ export interface NeighborhoodExplorerOptions extends MapFeatures {
2283
2336
  hoverFill?: string;
2284
2337
  hoverStroke?: string;
2285
2338
  };
2286
- districtStyle?: SFMapOptions['districtStyle'];
2339
+ districtStyle?: SvgRenderOptions['districtStyle'];
2287
2340
  legend?: {
2288
2341
  builtins?: boolean;
2289
2342
  hidden?: readonly ('bart' | 'park' | 'highway' | 'road')[];
@@ -2349,7 +2402,7 @@ export interface NeighborhoodExplorerElement extends HTMLElement {
2349
2402
  } & CameraOptions): boolean;
2350
2403
  getSelectedDistrict(): DistrictSelection | null;
2351
2404
  setDistrictYear(year: DistrictYear, options?: CameraOptions): void;
2352
- setDistrictStyle(style: SFMapOptions['districtStyle']): void;
2405
+ setDistrictStyle(style: SvgRenderOptions['districtStyle']): void;
2353
2406
  setSource(source: NeighborhoodSource): void;
2354
2407
  setMode(mode: ExplorerMode): void;
2355
2408
  setLabels(visible: boolean): void;
@@ -2396,8 +2449,8 @@ export interface InteractiveSFMapData {
2396
2449
 
2397
2450
  ```ts
2398
2451
  import type { Geometry, Position } from '../../data/types.js';
2399
- import type { DistrictYear, SFMapOptions } from '../types.js';
2400
- export type { DistrictYear, MapMarker, MapOverlay, SFMapOptions } from '../types.js';
2452
+ import type { DistrictYear, SvgRenderOptions } from '../types.js';
2453
+ export type { DistrictYear, MapMarker, MapOverlay, SvgRenderOptions } from '../types.js';
2401
2454
  import { type Project } from '../geometry.js';
2402
2455
  export interface SFMapData {
2403
2456
  coast: Geometry;
@@ -2447,7 +2500,7 @@ export interface BartStationData {
2447
2500
  export declare const districtYears: readonly DistrictYear[];
2448
2501
  export declare const districtColors: readonly string[];
2449
2502
  /** Canonical geometry in the same fitted coordinate space used by renderMap. */
2450
- export declare function getLayerPathsWithData(options: SFMapOptions, data: SFMapData, complete?: boolean): {
2503
+ export declare function getLayerPathsWithData(options: SvgRenderOptions, data: SFMapData, complete?: boolean): {
2451
2504
  year: DistrictYear;
2452
2505
  viewBox: [number, number, number, number];
2453
2506
  project: (coordinates: Position) => [number, number];
@@ -2479,7 +2532,7 @@ export declare function getLayerPathsWithData(options: SFMapOptions, data: SFMap
2479
2532
  point: [number, number];
2480
2533
  }[];
2481
2534
  };
2482
- export declare function resolveMapColors(theme: SFMapOptions['theme'], colors?: SFMapOptions['colors']): {
2535
+ export declare function resolveMapColors(theme: SvgRenderOptions['theme'], colors?: SvgRenderOptions['colors']): {
2483
2536
  water: string;
2484
2537
  land: string;
2485
2538
  district: string;
@@ -2494,7 +2547,7 @@ export declare function resolveMapColors(theme: SFMapOptions['theme'], colors?:
2494
2547
  selected: string;
2495
2548
  };
2496
2549
  /** Make an offline SVG and the matching longitude/latitude projection. */
2497
- export declare function createSFMapWithData(options: SFMapOptions, data: SFMapData, renderLabels?: (project: Project) => string): {
2550
+ export declare function createSFMapWithData(options: SvgRenderOptions, data: SFMapData, renderLabels?: (project: Project) => string): {
2498
2551
  svg: string;
2499
2552
  project: (coordinates: Position) => [number, number];
2500
2553
  viewBox: [number, number, number, number];
@@ -2521,19 +2574,19 @@ export declare function geometryContainsPoint(geometry: Geometry | null | undefi
2521
2574
  ```ts
2522
2575
  import type { InteractiveSFMapData } from './explorer-data.js';
2523
2576
  import { type SFMapData } from './rendering/svg-map-renderer.js';
2524
- import type { SFMapOptions } from './types.js';
2577
+ import type { StaticMapOptions } from './types.js';
2525
2578
  /** Either compact static geography or the same source-aware geography used by createMap. */
2526
2579
  export type StaticMapInput = SFMapData | InteractiveSFMapData;
2527
2580
  export type { DistrictRowData, SFMapData as StaticMapData } from './rendering/svg-map-renderer.js';
2528
- export type { DistrictStyle, DistrictYear, SFMapOptions as StaticMapOptions, StaticMapAppearance, StaticMapLayers, } from './types.js';
2581
+ export type { DistrictStyle, DistrictYear, StaticMapAppearance, StaticMapLayers, StaticMapOptions, } from './types.js';
2529
2582
  /** Server-safe SVG rendering with explicit data; returns SVG plus projection helpers. */
2530
- export declare function renderMap(data: StaticMapInput, options?: SFMapOptions): {
2583
+ export declare function renderMap(data: StaticMapInput, options?: StaticMapOptions): {
2531
2584
  svg: string;
2532
2585
  project: (coordinates: import("./geometry.js").Position) => [number, number];
2533
2586
  viewBox: [number, number, number, number];
2534
2587
  };
2535
2588
  /** Project canonical layer geometry without constructing an SVG string. */
2536
- export declare function getLayerPaths(data: StaticMapInput, options?: SFMapOptions): {
2589
+ export declare function getLayerPaths(data: StaticMapInput, options?: StaticMapOptions): {
2537
2590
  year: import("./types.js").DistrictYear;
2538
2591
  viewBox: [number, number, number, number];
2539
2592
  project: (coordinates: import("./geometry.js").Position) => [number, number];
@@ -2707,8 +2760,8 @@ export type { MapController, MapOptions } from './controller-types.js';
2707
2760
  export type { InteractiveSFMapData } from './explorer-data.js';
2708
2761
  export { guideMapData } from './guide-data.js';
2709
2762
  export { loadGuideDetailedData } from './guide-detailed.js';
2710
- export { createGuideController, createGuideMap, mountGuideController, mountGuideMap, } from './guide-map.js';
2711
- export type { CameraOptions, MapFeatures, MapMarker, NeighborhoodExplorerElement as InteractiveSFMapElement, NeighborhoodExplorerOptions as InteractiveSFMapOptions, } from './types.js';
2763
+ export { createGuideController, mountGuideController, } from './guide-map.js';
2764
+ export type { CameraOptions, MapFeatures, MapMarker, } from './types.js';
2712
2765
  ```
2713
2766
 
2714
2767
  ### dist/src/guide-data.d.ts
@@ -2731,17 +2784,10 @@ export declare function loadGuideDetailedData(): Promise<InteractiveSFMapData>;
2731
2784
 
2732
2785
  ```ts
2733
2786
  import type { MapController, MapOptions } from './controller-types.js';
2734
- import type { NeighborhoodExplorerElement as InteractiveSFMapElement, NeighborhoodExplorerOptions as InteractiveSFMapOptions } from './types.js';
2735
2787
  /** Preferred guide API: the same grouped options, events, camera and lifecycle as createMap. */
2736
2788
  export declare function createGuideController(options?: MapOptions): MapController;
2737
2789
  /** Enhance a static guide shell and return its owning controller. */
2738
2790
  export declare function mountGuideController(shell: HTMLElement, options?: MapOptions): MapController;
2739
- /** Element-based compatibility API. Prefer createGuideController for new integrations. */
2740
- export declare function createGuideMap(options?: InteractiveSFMapOptions): InteractiveSFMapElement;
2741
- /** Enhance createGuideShell() in place with a fixed compact chrome layout.
2742
- * Keep an accessible external place list when hiding the native pickers.
2743
- */
2744
- export declare function mountGuideMap(shell: HTMLElement, options?: InteractiveSFMapOptions): InteractiveSFMapElement;
2745
2791
  ```
2746
2792
 
2747
2793
  ### ./dist/src/transit.d.ts
@@ -2755,15 +2801,15 @@ export declare function createTransitAnimation(): TransitAnimationElement;
2755
2801
  ### ./dist/src/guide-static.d.ts
2756
2802
 
2757
2803
  ```ts
2758
- import type { SFMapOptions } from './types.js';
2804
+ import type { StaticMapOptions } from './types.js';
2759
2805
  /** Server-safe overview using exactly the guide browser geography. */
2760
- export declare function createGuideSVG(options?: SFMapOptions): {
2806
+ export declare function createGuideSVG(options?: StaticMapOptions): {
2761
2807
  svg: string;
2762
2808
  project: (coordinates: import("./geometry.js").Position) => [number, number];
2763
2809
  viewBox: [number, number, number, number];
2764
2810
  };
2765
- /** Stable compact frame, progressively enhanced with mountGuideMap(). No browser globals. */
2766
- export declare function createGuideShell(options?: SFMapOptions): string;
2811
+ /** Stable compact frame, progressively enhanced with mountGuideController(). No browser globals. */
2812
+ export declare function createGuideShell(options?: StaticMapOptions): string;
2767
2813
  ```
2768
2814
 
2769
2815
  ### ./dist/src/presets.d.ts
@@ -2778,10 +2824,10 @@ export { type MapPalette, mapPalettes } from './palettes.js';
2778
2824
  ### dist/src/palettes.d.ts
2779
2825
 
2780
2826
  ```ts
2781
- import type { SFMapOptions } from './types.js';
2827
+ import type { SvgRenderOptions } from './types.js';
2782
2828
  /** Shared tokens for static SVGs, interactive maps, and consumer-owned place cards. */
2783
2829
  export interface MapPalette {
2784
- readonly colors: NonNullable<SFMapOptions['colors']>;
2830
+ readonly colors: NonNullable<SvgRenderOptions['colors']>;
2785
2831
  readonly haloColor: string;
2786
2832
  readonly markerColor: string;
2787
2833
  readonly selectedMarkerColor: 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 5.1.4 · local working tree. Node >=24.0.0 for server rendering; browsers need a DOM and a JSON-capable bundler.
5
+ @kahwee/sf-map-svg 6.0.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
 
@@ -15,6 +15,7 @@ Use renderMap(data, options) for SVG strings; createMap(data, options) returns a
15
15
  - [API options and lifecycle](https://kahwee.github.io/sf-map-svg/api-options.md)
16
16
  - [Worked examples](https://kahwee.github.io/sf-map-svg/examples.md)
17
17
  - [Consumer integration](https://kahwee.github.io/sf-map-svg/consumer-integration.md)
18
+ - [Migration to v6](https://kahwee.github.io/sf-map-svg/migration-v6.md)
18
19
  - [Migration to v5](https://kahwee.github.io/sf-map-svg/migration-v5.md)
19
20
  - [Migration from removed APIs](https://kahwee.github.io/sf-map-svg/migration-v3.md)
20
21
  - [Exact TypeScript contracts](https://kahwee.github.io/sf-map-svg/types.md)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kahwee/sf-map-svg",
3
- "version": "5.1.4",
3
+ "version": "6.0.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",
@@ -128,6 +128,7 @@
128
128
  "docs/guide-bundle-report.md",
129
129
  "docs/migration-v3.md",
130
130
  "docs/migration-v5.md",
131
+ "docs/migration-v6.md",
131
132
  "CHANGELOG.md",
132
133
  "docs/API.md",
133
134
  "docs/developer-guide.md",