@diagrammo/dgmo 0.20.3 → 0.21.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (48) hide show
  1. package/dist/advanced.cjs +867 -286
  2. package/dist/advanced.js +866 -286
  3. package/dist/auto.cjs +635 -284
  4. package/dist/auto.js +113 -113
  5. package/dist/auto.mjs +635 -284
  6. package/dist/cli.cjs +156 -156
  7. package/dist/editor.cjs +6 -2
  8. package/dist/editor.js +6 -2
  9. package/dist/highlight.cjs +6 -2
  10. package/dist/highlight.js +6 -2
  11. package/dist/index.cjs +628 -281
  12. package/dist/index.js +628 -281
  13. package/dist/internal.cjs +867 -286
  14. package/dist/internal.js +866 -286
  15. package/dist/map-data/PROVENANCE.json +1 -1
  16. package/dist/map-data/mountain-ranges.json +1 -0
  17. package/docs/language-reference.md +27 -25
  18. package/gallery/fixtures/map-choropleth.dgmo +7 -7
  19. package/gallery/fixtures/map-direct-color.dgmo +10 -0
  20. package/gallery/fixtures/map-pois.dgmo +4 -4
  21. package/gallery/fixtures/map-region-scope.dgmo +8 -8
  22. package/gallery/fixtures/map-route.dgmo +5 -6
  23. package/package.json +1 -1
  24. package/src/advanced.ts +14 -0
  25. package/src/completion.ts +10 -4
  26. package/src/d3.ts +15 -9
  27. package/src/editor/keywords.ts +6 -2
  28. package/src/map/data/PROVENANCE.json +1 -1
  29. package/src/map/data/mountain-ranges.json +1 -0
  30. package/src/map/geo-query.ts +277 -0
  31. package/src/map/geo.ts +258 -1
  32. package/src/map/invert.ts +111 -0
  33. package/src/map/layout.ts +333 -139
  34. package/src/map/load-data.ts +7 -1
  35. package/src/map/parser.ts +142 -33
  36. package/src/map/renderer.ts +57 -6
  37. package/src/map/resolved-types.ts +21 -2
  38. package/src/map/resolver.ts +219 -53
  39. package/src/map/types.ts +57 -14
  40. package/src/utils/reserved-key-registry.ts +7 -7
  41. package/dist/advanced.d.cts +0 -5290
  42. package/dist/advanced.d.ts +0 -5290
  43. package/dist/auto.d.cts +0 -39
  44. package/dist/auto.d.ts +0 -39
  45. package/dist/index.d.cts +0 -336
  46. package/dist/index.d.ts +0 -336
  47. package/dist/internal.d.cts +0 -5290
  48. package/dist/internal.d.ts +0 -5290
package/dist/auto.mjs CHANGED
@@ -758,13 +758,9 @@ var init_reserved_key_registry = __esm({
758
758
  "icon"
759
759
  ]);
760
760
  MAP_REGISTRY = staticRegistry([
761
- "score",
761
+ "value",
762
762
  "label",
763
- "size",
764
- "description",
765
- "weight",
766
- "style",
767
- "date"
763
+ "style"
768
764
  ]);
769
765
  ORG_REGISTRY = staticRegistry([
770
766
  "color",
@@ -15795,7 +15791,8 @@ function parseMap(content) {
15795
15791
  continue;
15796
15792
  }
15797
15793
  if (open.route && indent > open.route.indent) {
15798
- open.route.route.stops.push(parseStop(trimmed, lineNumber));
15794
+ const leg = parseLeg(trimmed, lineNumber, open.route.route.style);
15795
+ open.route.route.legs.push(leg);
15799
15796
  continue;
15800
15797
  }
15801
15798
  if (open.poi && indent > open.poi.indent) {
@@ -15826,6 +15823,10 @@ function parseMap(content) {
15826
15823
  handleTag(trimmed, lineNumber);
15827
15824
  continue;
15828
15825
  }
15826
+ if ((firstWord === "muted" || firstWord === "natural") && trimmed === firstWord) {
15827
+ handleDirective(firstWord, "", lineNumber);
15828
+ continue;
15829
+ }
15829
15830
  if (DIRECTIVE_SET.has(firstWord) && !trimmed.slice(firstWord.length).trimStart().startsWith(":")) {
15830
15831
  handleDirective(
15831
15832
  firstWord,
@@ -15890,13 +15891,20 @@ function parseMap(content) {
15890
15891
  );
15891
15892
  d.projection = value;
15892
15893
  break;
15893
- case "metric":
15894
- dup(d.metric);
15895
- d.metric = value;
15894
+ case "region-metric": {
15895
+ dup(d.regionMetric);
15896
+ const { label: rmLabel, colorName: rmColor } = peelTrailingColorName(value);
15897
+ d.regionMetric = rmLabel;
15898
+ if (rmColor) d.regionMetricColor = rmColor;
15899
+ break;
15900
+ }
15901
+ case "poi-metric":
15902
+ dup(d.poiMetric);
15903
+ d.poiMetric = value;
15896
15904
  break;
15897
- case "size-metric":
15898
- dup(d.sizeMetric);
15899
- d.sizeMetric = value;
15905
+ case "flow-metric":
15906
+ dup(d.flowMetric);
15907
+ d.flowMetric = value;
15900
15908
  break;
15901
15909
  case "scale":
15902
15910
  dup(d.scale);
@@ -15938,6 +15946,21 @@ function parseMap(content) {
15938
15946
  case "no-legend":
15939
15947
  d.noLegend = true;
15940
15948
  break;
15949
+ case "no-insets":
15950
+ d.noInsets = true;
15951
+ break;
15952
+ case "relief":
15953
+ d.relief = true;
15954
+ break;
15955
+ case "muted":
15956
+ case "natural":
15957
+ if (d.basemapStyle !== void 0 && d.basemapStyle !== key)
15958
+ pushWarning(
15959
+ line12,
15960
+ `Conflicting basemap dress \u2014 "${d.basemapStyle}" then "${key}"; last wins.`
15961
+ );
15962
+ d.basemapStyle = key;
15963
+ break;
15941
15964
  case "subtitle":
15942
15965
  dup(d.subtitle);
15943
15966
  d.subtitle = value;
@@ -16015,14 +16038,14 @@ function parseMap(content) {
16015
16038
  line12
16016
16039
  );
16017
16040
  const { tags, meta } = partitionMeta(split.meta, tagGroupNames());
16018
- let scoreNum;
16019
- const score = meta["score"];
16020
- if (score !== void 0) {
16021
- delete meta["score"];
16022
- scoreNum = Number(score);
16023
- if (!Number.isFinite(scoreNum)) {
16024
- pushError(line12, `score must be a number (got "${score}").`);
16025
- scoreNum = void 0;
16041
+ let valueNum;
16042
+ const value = meta["value"];
16043
+ if (value !== void 0) {
16044
+ delete meta["value"];
16045
+ valueNum = Number(value);
16046
+ if (!Number.isFinite(valueNum)) {
16047
+ pushError(line12, `value must be a number (got "${value}").`);
16048
+ valueNum = void 0;
16026
16049
  }
16027
16050
  }
16028
16051
  let regionName = split.name;
@@ -16040,7 +16063,8 @@ function parseMap(content) {
16040
16063
  lineNumber: line12
16041
16064
  };
16042
16065
  if (regionScope !== void 0) region.scope = regionScope;
16043
- if (scoreNum !== void 0) region.score = scoreNum;
16066
+ if (valueNum !== void 0) region.value = valueNum;
16067
+ if (split.color) region.color = split.color;
16044
16068
  regions.push(region);
16045
16069
  }
16046
16070
  function handlePoi(rest, line12, indent) {
@@ -16065,28 +16089,81 @@ function parseMap(content) {
16065
16089
  const poi = { pos, tags, meta, lineNumber: line12 };
16066
16090
  if (split.alias) poi.alias = split.alias;
16067
16091
  if (label !== void 0) poi.label = label;
16092
+ if (split.color) poi.color = split.color;
16068
16093
  pois.push(poi);
16069
16094
  open.poi = { poi, indent };
16070
16095
  }
16071
16096
  function handleRoute(rest, line12, indent) {
16072
- const meta = rest ? splitNameAndMeta(rest, registry(), aliasMap).meta : {};
16073
- const route = { stops: [], meta, lineNumber: line12 };
16097
+ const split = rest ? splitNameAndMeta(
16098
+ rest,
16099
+ registry(),
16100
+ aliasMap,
16101
+ void 0,
16102
+ diagnostics,
16103
+ line12
16104
+ ) : { name: "", meta: {}, alias: void 0 };
16105
+ const pos = parsePos(split.name, line12);
16106
+ if (!pos || pos.kind === "name" && !pos.name) {
16107
+ pushError(
16108
+ line12,
16109
+ "route requires an origin: `route <origin> [style: arc]`."
16110
+ );
16111
+ return;
16112
+ }
16113
+ const { tags, meta } = partitionMeta(split.meta, tagGroupNames());
16114
+ const originLabel = meta["label"];
16115
+ const originValue = meta["value"];
16116
+ const style = meta["style"] === "arc" ? "arc" : "straight";
16117
+ const route = {
16118
+ origin: pos,
16119
+ ...split.alias !== void 0 && { originAlias: split.alias },
16120
+ ...originLabel !== void 0 && { originLabel },
16121
+ ...originValue !== void 0 && { originValue },
16122
+ originTags: tags,
16123
+ style,
16124
+ legs: [],
16125
+ lineNumber: line12
16126
+ };
16074
16127
  routes.push(route);
16075
16128
  open.route = { route, indent };
16076
16129
  }
16077
- function parseStop(trimmed, line12) {
16078
- const split = splitNameAndMeta(trimmed, registry(), aliasMap);
16079
- const ref = parsePos(split.name, line12) ?? {
16130
+ function parseLeg(trimmed, line12, headerStyle) {
16131
+ let arrowStyle = "straight";
16132
+ let label;
16133
+ let rest = trimmed;
16134
+ const m = trimmed.match(LEG_ARROW_RE);
16135
+ if (m) {
16136
+ const arr = classifyArrow(m[1], line12);
16137
+ arrowStyle = arr.style;
16138
+ label = arr.label;
16139
+ rest = m[2];
16140
+ }
16141
+ const split = splitNameAndMeta(
16142
+ rest,
16143
+ registry(),
16144
+ aliasMap,
16145
+ void 0,
16146
+ diagnostics,
16147
+ line12
16148
+ );
16149
+ const pos = parsePos(split.name, line12) ?? {
16080
16150
  kind: "name",
16081
16151
  name: split.name
16082
16152
  };
16083
- const stop = {
16084
- ref,
16085
- meta: split.meta,
16153
+ const { tags, meta } = partitionMeta(split.meta, tagGroupNames());
16154
+ const value = meta["value"];
16155
+ const destLabel = meta["label"];
16156
+ const style = arrowStyle === "arc" || headerStyle === "arc" ? "arc" : "straight";
16157
+ return {
16158
+ ...label !== void 0 && { label },
16159
+ style,
16160
+ ...value !== void 0 && { value },
16161
+ dest: pos,
16162
+ ...split.alias !== void 0 && { destAlias: split.alias },
16163
+ ...destLabel !== void 0 && { destLabel },
16164
+ destTags: tags,
16086
16165
  lineNumber: line12
16087
16166
  };
16088
- if (split.alias) stop.alias = split.alias;
16089
- return stop;
16090
16167
  }
16091
16168
  function handleEdges(trimmed, line12) {
16092
16169
  const parts = trimmed.split(ARROW_SPLIT);
@@ -16188,7 +16265,7 @@ function partitionMeta(meta, tagGroupNames) {
16188
16265
  function poiName(pos) {
16189
16266
  return pos.kind === "name" ? pos.name : void 0;
16190
16267
  }
16191
- var COORD_RE, NUMERIC_LEAD_RE, SCOPE_RE, ARROW_SPLIT, HUB_RE, AT_RE, DIRECTIVE_SET;
16268
+ var COORD_RE, NUMERIC_LEAD_RE, SCOPE_RE, ARROW_SPLIT, HUB_RE, LEG_ARROW_RE, AT_RE, DIRECTIVE_SET;
16192
16269
  var init_parser12 = __esm({
16193
16270
  "src/map/parser.ts"() {
16194
16271
  "use strict";
@@ -16202,12 +16279,14 @@ var init_parser12 = __esm({
16202
16279
  SCOPE_RE = /^[A-Z]{2}(?:-[A-Z0-9]{1,3})?$/;
16203
16280
  ARROW_SPLIT = /\s+(-[^>]*?->|->|~[^>]*?~>|~>|--)\s+/;
16204
16281
  HUB_RE = /^(->|~>)\s+(.+)$/;
16282
+ LEG_ARROW_RE = /^(-[^>]*?->|->|~[^>]*?~>|~>|--)\s+(.+)$/;
16205
16283
  AT_RE = /(^|[\s,])at\s*:/i;
16206
16284
  DIRECTIVE_SET = /* @__PURE__ */ new Set([
16207
16285
  "region",
16208
16286
  "projection",
16209
- "metric",
16210
- "size-metric",
16287
+ "region-metric",
16288
+ "poi-metric",
16289
+ "flow-metric",
16211
16290
  "scale",
16212
16291
  "region-labels",
16213
16292
  "poi-labels",
@@ -16215,6 +16294,8 @@ var init_parser12 = __esm({
16215
16294
  "default-state",
16216
16295
  "active-tag",
16217
16296
  "no-legend",
16297
+ "no-insets",
16298
+ "relief",
16218
16299
  "subtitle",
16219
16300
  "caption"
16220
16301
  ]);
@@ -45413,7 +45494,7 @@ var init_renderer15 = __esm({
45413
45494
 
45414
45495
  // src/map/geo.ts
45415
45496
  import { feature } from "topojson-client";
45416
- import { geoBounds } from "d3-geo";
45497
+ import { geoBounds, geoArea } from "d3-geo";
45417
45498
  function geomObject(topo) {
45418
45499
  const key = Object.keys(topo.objects)[0];
45419
45500
  return topo.objects[key];
@@ -45441,6 +45522,74 @@ function featureBbox(topo, geomId) {
45441
45522
  [b[1][0], b[1][1]]
45442
45523
  ];
45443
45524
  }
45525
+ function explodePolygons(gj) {
45526
+ const g = gj.geometry ?? gj;
45527
+ const t = g.type;
45528
+ const coords = g.coordinates;
45529
+ if (t === "Polygon") {
45530
+ return [
45531
+ { type: "Feature", geometry: { type: "Polygon", coordinates: coords } }
45532
+ ];
45533
+ }
45534
+ if (t === "MultiPolygon") {
45535
+ return coords.map((rings) => ({
45536
+ type: "Feature",
45537
+ geometry: { type: "Polygon", coordinates: rings }
45538
+ }));
45539
+ }
45540
+ return [];
45541
+ }
45542
+ function bboxGap(a, b) {
45543
+ const lonGap = Math.max(0, a[0][0] - b[1][0], b[0][0] - a[1][0]);
45544
+ const latGap = Math.max(0, a[0][1] - b[1][1], b[0][1] - a[1][1]);
45545
+ return Math.max(lonGap, latGap);
45546
+ }
45547
+ function featureBboxPrimary(topo, geomId) {
45548
+ const geom = geomObject(topo).geometries.find((g) => g.id === geomId);
45549
+ if (!geom) return null;
45550
+ const gj = feature(topo, geom);
45551
+ const parts = explodePolygons(gj);
45552
+ if (parts.length <= 1) return featureBbox(topo, geomId);
45553
+ const polys = parts.map((p) => {
45554
+ const b = geoBounds(p);
45555
+ if (!b || !Number.isFinite(b[0][0])) return null;
45556
+ const wraps = b[1][0] < b[0][0];
45557
+ const bbox = [
45558
+ [b[0][0], b[0][1]],
45559
+ [b[1][0], b[1][1]]
45560
+ ];
45561
+ return { bbox, area: geoArea(p), wraps };
45562
+ }).filter(
45563
+ (p) => p !== null
45564
+ );
45565
+ if (polys.length <= 1 || polys.some((p) => p.wraps))
45566
+ return featureBbox(topo, geomId);
45567
+ const maxArea = Math.max(...polys.map((p) => p.area));
45568
+ const anchor = polys.find((p) => p.area === maxArea);
45569
+ const cluster = [
45570
+ [anchor.bbox[0][0], anchor.bbox[0][1]],
45571
+ [anchor.bbox[1][0], anchor.bbox[1][1]]
45572
+ ];
45573
+ const remaining = polys.filter((p) => p !== anchor);
45574
+ let added = true;
45575
+ while (added) {
45576
+ added = false;
45577
+ for (let i = remaining.length - 1; i >= 0; i--) {
45578
+ const p = remaining[i];
45579
+ const near = bboxGap(p.bbox, cluster) <= DETACH_GAP_DEG;
45580
+ const large = p.area >= DETACH_AREA_FRAC * maxArea;
45581
+ if (near || large) {
45582
+ cluster[0][0] = Math.min(cluster[0][0], p.bbox[0][0]);
45583
+ cluster[0][1] = Math.min(cluster[0][1], p.bbox[0][1]);
45584
+ cluster[1][0] = Math.max(cluster[1][0], p.bbox[1][0]);
45585
+ cluster[1][1] = Math.max(cluster[1][1], p.bbox[1][1]);
45586
+ remaining.splice(i, 1);
45587
+ added = true;
45588
+ }
45589
+ }
45590
+ }
45591
+ return cluster;
45592
+ }
45444
45593
  function unionExtent(boxes, points) {
45445
45594
  const lats = [];
45446
45595
  const lons = [];
@@ -45479,11 +45628,13 @@ function unionLongitudes(lons) {
45479
45628
  }
45480
45629
  return { west: pts[gapIdx], east: pts[gapIdx - 1] + 360 };
45481
45630
  }
45482
- var fold;
45631
+ var fold, DETACH_GAP_DEG, DETACH_AREA_FRAC;
45483
45632
  var init_geo = __esm({
45484
45633
  "src/map/geo.ts"() {
45485
45634
  "use strict";
45486
45635
  fold = (s) => s.normalize("NFD").replace(/\p{Diacritic}/gu, "").toLowerCase().trim();
45636
+ DETACH_GAP_DEG = 10;
45637
+ DETACH_AREA_FRAC = 0.25;
45487
45638
  }
45488
45639
  });
45489
45640
 
@@ -45492,6 +45643,11 @@ var resolver_exports = {};
45492
45643
  __export(resolver_exports, {
45493
45644
  resolveMap: () => resolveMap
45494
45645
  });
45646
+ function usStateFromBareScope(scope) {
45647
+ if (!scope) return null;
45648
+ const up = scope.toUpperCase();
45649
+ return US_STATE_POSTAL.has(up) ? `US-${up}` : null;
45650
+ }
45495
45651
  function looksUS(lat, lon) {
45496
45652
  if (lat < 15 || lat > 72) return false;
45497
45653
  return lon >= -180 && lon <= -64 || lon >= 172;
@@ -45541,9 +45697,9 @@ function resolveMap(parsed, data) {
45541
45697
  const f = fold(r.name);
45542
45698
  return usStateIndex.has(f) && !countryIndex.has(f);
45543
45699
  }) || parsed.regions.some(
45544
- (r) => r.scope === "US" || r.scope?.startsWith("US-")
45700
+ (r) => r.scope === "US" || r.scope?.startsWith("US-") || usStateFromBareScope(r.scope) !== null
45545
45701
  ) || parsed.pois.some(
45546
- (p) => p.pos.kind === "name" && p.pos.scope?.startsWith("US-")
45702
+ (p) => p.pos.kind === "name" && (p.pos.scope?.startsWith("US-") || usStateFromBareScope(p.pos.scope) !== null)
45547
45703
  );
45548
45704
  const regions = [];
45549
45705
  const seenRegion = /* @__PURE__ */ new Map();
@@ -45582,12 +45738,12 @@ function resolveMap(parsed, data) {
45582
45738
  chosen = { ...inState, layer: "us-state" };
45583
45739
  } else {
45584
45740
  chosen = { ...inCountry, layer: "country" };
45741
+ warn2(
45742
+ r.lineNumber,
45743
+ `"${r.name}" is both a country and a US state \u2014 resolved as ${chosen.layer} (${chosen.id}). Pin it with an ISO code (${inState.id} / ${inCountry.id}) or name + scope ("${r.name} US" / "${r.name} ${inCountry.id}").`,
45744
+ "W_MAP_REGION_AMBIGUOUS"
45745
+ );
45585
45746
  }
45586
- warn2(
45587
- r.lineNumber,
45588
- `"${r.name}" is both a country and a US state \u2014 resolved as ${chosen.layer} (${chosen.id}). Pin it with an ISO code (${inState.id} / ${inCountry.id}) or name + scope ("${r.name} US" / "${r.name} ${inCountry.id}").`,
45589
- "W_MAP_REGION_AMBIGUOUS"
45590
- );
45591
45747
  } else if (inState) {
45592
45748
  chosen = { ...inState, layer: "us-state" };
45593
45749
  } else if (inCountry) {
@@ -45610,7 +45766,8 @@ function resolveMap(parsed, data) {
45610
45766
  iso: chosen.id,
45611
45767
  name: chosen.name,
45612
45768
  layer: chosen.layer,
45613
- ...r.score !== void 0 && { score: r.score },
45769
+ ...r.value !== void 0 && { value: r.value },
45770
+ ...r.color !== void 0 && { color: r.color },
45614
45771
  tags: r.tags,
45615
45772
  meta: r.meta,
45616
45773
  lineNumber: r.lineNumber
@@ -45668,9 +45825,10 @@ function resolveMap(parsed, data) {
45668
45825
  let cands = idxs.map((i) => data.gazetteer.cities[i]);
45669
45826
  const scopeUse = scope ?? scopeHint;
45670
45827
  if (scopeUse) {
45671
- const isSub = /^[A-Za-z]{2}-/.test(scopeUse);
45828
+ const bareState = usStateFromBareScope(scopeUse);
45829
+ const subScope = /^[A-Za-z]{2}-/.test(scopeUse) ? scopeUse : bareState;
45672
45830
  const filtered = cands.filter(
45673
- (c2) => isSub ? c2[5] === scopeUse : c2[2] === scopeUse
45831
+ (c2) => subScope ? c2[5] === subScope : c2[2] === scopeUse
45674
45832
  );
45675
45833
  if (filtered.length) cands = filtered;
45676
45834
  else if (scope) {
@@ -45751,6 +45909,7 @@ function resolveMap(parsed, data) {
45751
45909
  lat,
45752
45910
  lon,
45753
45911
  ...p.label !== void 0 && { label: p.label },
45912
+ ...p.color !== void 0 && { color: p.color },
45754
45913
  tags: p.tags,
45755
45914
  meta: p.meta,
45756
45915
  lineNumber: p.lineNumber
@@ -45799,33 +45958,89 @@ function resolveMap(parsed, data) {
45799
45958
  lineNumber: e.lineNumber
45800
45959
  });
45801
45960
  }
45802
- const routes = [];
45803
- for (const rt of parsed.routes) {
45804
- const stopIds = [];
45805
- for (const stop of rt.stops) {
45806
- let id;
45807
- if (stop.ref.kind === "coords") {
45808
- id = stop.alias ? fold(stop.alias) : `@${stop.ref.lat},${stop.ref.lon}`;
45809
- if (!looksUS(stop.ref.lat, stop.ref.lon)) anyNonUsPoi = true;
45810
- if (!registry.has(id)) {
45811
- const poi = {
45961
+ const resolveStop = (pos, alias, label, tags, sizeValue, line12) => {
45962
+ const meta = sizeValue !== void 0 ? { value: sizeValue } : {};
45963
+ if (pos.kind === "coords") {
45964
+ const id = alias ? fold(alias) : `@${pos.lat},${pos.lon}`;
45965
+ if (!looksUS(pos.lat, pos.lon)) anyNonUsPoi = true;
45966
+ if (!registry.has(id)) {
45967
+ registerPoi(
45968
+ id,
45969
+ {
45812
45970
  id,
45813
- ...stop.alias !== void 0 && { name: stop.alias },
45814
- lat: stop.ref.lat,
45815
- lon: stop.ref.lon,
45816
- tags: {},
45817
- meta: stop.meta,
45818
- lineNumber: stop.lineNumber,
45819
- implicit: true
45820
- };
45821
- registerPoi(id, poi, stop.lineNumber);
45822
- }
45823
- } else {
45824
- id = stop.alias && registry.has(fold(stop.alias)) ? fold(stop.alias) : resolveEndpoint2(stop.ref.name, stop.lineNumber);
45971
+ ...alias !== void 0 && { name: alias },
45972
+ lat: pos.lat,
45973
+ lon: pos.lon,
45974
+ ...label !== void 0 && { label },
45975
+ tags,
45976
+ meta,
45977
+ lineNumber: line12
45978
+ },
45979
+ line12
45980
+ );
45825
45981
  }
45826
- if (id) stopIds.push(id);
45982
+ return id;
45983
+ }
45984
+ const f = fold(pos.name);
45985
+ if (registry.has(f)) return f;
45986
+ const aliased = declaredByName.get(f);
45987
+ if (aliased) return aliased;
45988
+ const got = lookupName(pos.name, pos.scope, line12, inferredCountry, true);
45989
+ if (got.kind !== "ok") return null;
45990
+ noteCountry(got.iso);
45991
+ registerPoi(
45992
+ f,
45993
+ {
45994
+ id: f,
45995
+ name: pos.name,
45996
+ lat: got.lat,
45997
+ lon: got.lon,
45998
+ ...label !== void 0 && { label },
45999
+ tags,
46000
+ meta,
46001
+ lineNumber: line12
46002
+ },
46003
+ line12
46004
+ );
46005
+ return f;
46006
+ };
46007
+ const routes = [];
46008
+ for (const rt of parsed.routes) {
46009
+ const originId = resolveStop(
46010
+ rt.origin,
46011
+ rt.originAlias,
46012
+ rt.originLabel,
46013
+ rt.originTags,
46014
+ rt.originValue,
46015
+ rt.lineNumber
46016
+ );
46017
+ if (!originId) continue;
46018
+ const stopIds = [originId];
46019
+ const legs = [];
46020
+ let prevId = originId;
46021
+ for (const leg of rt.legs) {
46022
+ const destId = resolveStop(
46023
+ leg.dest,
46024
+ leg.destAlias,
46025
+ leg.destLabel,
46026
+ leg.destTags,
46027
+ void 0,
46028
+ // a leg's `value:` is leg thickness, not the dest's size
46029
+ leg.lineNumber
46030
+ );
46031
+ if (!destId) continue;
46032
+ legs.push({
46033
+ fromId: prevId,
46034
+ toId: destId,
46035
+ ...leg.label !== void 0 && { label: leg.label },
46036
+ style: leg.style,
46037
+ ...leg.value !== void 0 && { value: leg.value },
46038
+ lineNumber: leg.lineNumber
46039
+ });
46040
+ if (!stopIds.includes(destId)) stopIds.push(destId);
46041
+ prevId = destId;
45827
46042
  }
45828
- routes.push({ stopIds, meta: rt.meta, lineNumber: rt.lineNumber });
46043
+ routes.push({ stopIds, legs, lineNumber: rt.lineNumber });
45829
46044
  }
45830
46045
  const subdivisions = [];
45831
46046
  if (usSubdivisionReferenced || parsed.directives.region === "us-states")
@@ -45837,7 +46052,7 @@ function resolveMap(parsed, data) {
45837
46052
  }
45838
46053
  for (const r of regions) {
45839
46054
  if (r.layer === "country") {
45840
- const bb = featureBbox(data.worldCoarse, r.iso);
46055
+ const bb = featureBboxPrimary(data.worldCoarse, r.iso);
45841
46056
  if (bb) regionBoxes.push(bb);
45842
46057
  }
45843
46058
  }
@@ -45851,6 +46066,7 @@ function resolveMap(parsed, data) {
45851
46066
  const lonSpan = extent2[1][0] - extent2[0][0];
45852
46067
  const latSpan = extent2[1][1] - extent2[0][1];
45853
46068
  const span = Math.max(lonSpan, latSpan);
46069
+ const maxAbsLat = Math.max(Math.abs(extent2[0][1]), Math.abs(extent2[1][1]));
45854
46070
  const usDominant = (subdivisions.includes("us-states") || regions.some((r) => r.layer === "us-state")) && !regions.some((r) => r.layer === "country" && r.iso !== "US") && !anyNonUsPoi;
45855
46071
  let projection;
45856
46072
  const override = parsed.directives.projection;
@@ -45858,12 +46074,10 @@ function resolveMap(parsed, data) {
45858
46074
  projection = override;
45859
46075
  } else if (usDominant) {
45860
46076
  projection = "albers-usa";
45861
- } else if (span > WORLD_SPAN) {
46077
+ } else if (span > WORLD_SPAN || maxAbsLat > MERCATOR_MAX_LAT) {
45862
46078
  projection = "equirectangular";
45863
- } else if (span < MERCATOR_MAX_SPAN) {
45864
- projection = "mercator";
45865
46079
  } else {
45866
- projection = "equirectangular";
46080
+ projection = "mercator";
45867
46081
  }
45868
46082
  if (lonSpan >= 180) {
45869
46083
  extent2 = [
@@ -45917,14 +46131,14 @@ function firstError(diags) {
45917
46131
  const e = diags.find((d) => d.severity === "error");
45918
46132
  return e ? formatDgmoError(e) : null;
45919
46133
  }
45920
- var WORLD_SPAN, MERCATOR_MAX_SPAN, PAD_FRACTION, WORLD_LAT_SOUTH, WORLD_LAT_NORTH, REGION_ALIASES;
46134
+ var WORLD_SPAN, MERCATOR_MAX_LAT, PAD_FRACTION, WORLD_LAT_SOUTH, WORLD_LAT_NORTH, REGION_ALIASES, US_STATE_POSTAL;
45921
46135
  var init_resolver2 = __esm({
45922
46136
  "src/map/resolver.ts"() {
45923
46137
  "use strict";
45924
46138
  init_diagnostics();
45925
46139
  init_geo();
45926
46140
  WORLD_SPAN = 90;
45927
- MERCATOR_MAX_SPAN = 25;
46141
+ MERCATOR_MAX_LAT = 80;
45928
46142
  PAD_FRACTION = 0.05;
45929
46143
  WORLD_LAT_SOUTH = -58;
45930
46144
  WORLD_LAT_NORTH = 78;
@@ -45949,114 +46163,59 @@ var init_resolver2 = __esm({
45949
46163
  "north macedonia": "macedonia",
45950
46164
  "czech republic": "czechia"
45951
46165
  };
45952
- }
45953
- });
45954
-
45955
- // src/map/load-data.ts
45956
- var load_data_exports = {};
45957
- __export(load_data_exports, {
45958
- loadMapData: () => loadMapData
45959
- });
45960
- async function loadNodeBuiltins() {
45961
- const [{ readFile }, { fileURLToPath }, { dirname, resolve }] = await Promise.all([
45962
- import("fs/promises"),
45963
- import("url"),
45964
- import("path")
45965
- ]);
45966
- return { readFile, fileURLToPath, dirname, resolve };
45967
- }
45968
- async function readJson(nb, dir, name) {
45969
- return JSON.parse(await nb.readFile(nb.resolve(dir, name), "utf8"));
45970
- }
45971
- async function firstExistingDir(nb, baseDir) {
45972
- for (const rel of CANDIDATE_DIRS) {
45973
- const dir = nb.resolve(baseDir, rel);
45974
- try {
45975
- await nb.readFile(nb.resolve(dir, FILES.gazetteer), "utf8");
45976
- return dir;
45977
- } catch {
45978
- }
45979
- }
45980
- throw new Error(
45981
- `map data assets not found near ${baseDir} (looked in ${CANDIDATE_DIRS.join(", ")}). Run \`pnpm build:map-data\` and \`pnpm build\`.`
45982
- );
45983
- }
45984
- function validate(data) {
45985
- const topoOk = (t) => !!t && t.type === "Topology" && !!t.objects;
45986
- if (!topoOk(data.worldCoarse) || !topoOk(data.worldDetail) || !topoOk(data.usStates) || !data.gazetteer || !Array.isArray(data.gazetteer.cities) || !data.gazetteer.byName) {
45987
- throw new Error("map data assets are malformed (failed shape validation)");
45988
- }
45989
- return data;
45990
- }
45991
- function moduleBaseDir(nb) {
45992
- try {
45993
- const url = import.meta.url;
45994
- if (url) return nb.dirname(nb.fileURLToPath(url));
45995
- } catch {
45996
- }
45997
- if (typeof __dirname !== "undefined") return __dirname;
45998
- return process.cwd();
45999
- }
46000
- function loadMapData() {
46001
- cache ??= (async () => {
46002
- const nb = await loadNodeBuiltins();
46003
- const dir = await firstExistingDir(nb, moduleBaseDir(nb));
46004
- const [
46005
- worldCoarse,
46006
- worldDetail,
46007
- usStates,
46008
- lakes,
46009
- rivers,
46010
- naLand,
46011
- naLakes,
46012
- gazetteer
46013
- ] = await Promise.all([
46014
- readJson(nb, dir, FILES.worldCoarse),
46015
- readJson(nb, dir, FILES.worldDetail),
46016
- readJson(nb, dir, FILES.usStates),
46017
- // Lakes/rivers/NA assets are optional — older bundles may predate them.
46018
- readJson(nb, dir, FILES.lakes).catch(() => void 0),
46019
- readJson(nb, dir, FILES.rivers).catch(() => void 0),
46020
- readJson(nb, dir, FILES.naLand).catch(() => void 0),
46021
- readJson(nb, dir, FILES.naLakes).catch(() => void 0),
46022
- readJson(nb, dir, FILES.gazetteer)
46166
+ US_STATE_POSTAL = /* @__PURE__ */ new Set([
46167
+ "AL",
46168
+ "AK",
46169
+ "AZ",
46170
+ "AR",
46171
+ "CA",
46172
+ "CO",
46173
+ "CT",
46174
+ "DE",
46175
+ "FL",
46176
+ "GA",
46177
+ "HI",
46178
+ "ID",
46179
+ "IL",
46180
+ "IN",
46181
+ "IA",
46182
+ "KS",
46183
+ "KY",
46184
+ "LA",
46185
+ "ME",
46186
+ "MD",
46187
+ "MA",
46188
+ "MI",
46189
+ "MN",
46190
+ "MS",
46191
+ "MO",
46192
+ "MT",
46193
+ "NE",
46194
+ "NV",
46195
+ "NH",
46196
+ "NJ",
46197
+ "NM",
46198
+ "NY",
46199
+ "NC",
46200
+ "ND",
46201
+ "OH",
46202
+ "OK",
46203
+ "OR",
46204
+ "PA",
46205
+ "RI",
46206
+ "SC",
46207
+ "SD",
46208
+ "TN",
46209
+ "TX",
46210
+ "UT",
46211
+ "VT",
46212
+ "VA",
46213
+ "WA",
46214
+ "WV",
46215
+ "WI",
46216
+ "WY",
46217
+ "DC"
46023
46218
  ]);
46024
- return validate({
46025
- worldCoarse,
46026
- worldDetail,
46027
- usStates,
46028
- gazetteer,
46029
- ...lakes && { lakes },
46030
- ...rivers && { rivers },
46031
- ...naLand && { naLand },
46032
- ...naLakes && { naLakes }
46033
- });
46034
- })().catch((e) => {
46035
- cache = void 0;
46036
- throw e;
46037
- });
46038
- return cache;
46039
- }
46040
- var FILES, CANDIDATE_DIRS, cache;
46041
- var init_load_data = __esm({
46042
- "src/map/load-data.ts"() {
46043
- "use strict";
46044
- FILES = {
46045
- worldCoarse: "world-coarse.json",
46046
- worldDetail: "world-detail.json",
46047
- usStates: "us-states.json",
46048
- lakes: "lakes.json",
46049
- rivers: "rivers.json",
46050
- naLand: "na-land.json",
46051
- naLakes: "na-lakes.json",
46052
- gazetteer: "gazetteer.json"
46053
- };
46054
- CANDIDATE_DIRS = [
46055
- "./data",
46056
- "./map-data",
46057
- "../map-data",
46058
- "../src/map/data"
46059
- ];
46060
46219
  }
46061
46220
  });
46062
46221
 
@@ -46096,8 +46255,19 @@ function projectionFor(family) {
46096
46255
  return geoEquirectangular();
46097
46256
  }
46098
46257
  }
46099
- function mapBackgroundColor(palette) {
46100
- return mix(palette.colors.blue, palette.bg, WATER_TINT);
46258
+ function mapBackgroundColor(palette, isDark = false, _dataActive = false) {
46259
+ return mix(
46260
+ palette.colors.blue,
46261
+ palette.bg,
46262
+ isDark ? WATER_TINT_DARK : WATER_TINT_LIGHT
46263
+ );
46264
+ }
46265
+ function mapNeutralLandColor(palette, isDark, _dataActive = false) {
46266
+ return mix(
46267
+ palette.colors.green,
46268
+ palette.bg,
46269
+ isDark ? LAND_TINT_DARK : LAND_TINT_LIGHT
46270
+ );
46101
46271
  }
46102
46272
  function layoutMap(resolved, data, size, opts) {
46103
46273
  const { palette, isDark } = opts;
@@ -46118,28 +46288,19 @@ function layoutMap(resolved, data, size, opts) {
46118
46288
  }
46119
46289
  }
46120
46290
  const usLayer = wantsUsStates ? decodeLayer(data.usStates) : null;
46121
- const landTint = isDark ? LAND_TINT_DARK : LAND_TINT_LIGHT;
46122
- const neutralFill = mix(palette.colors.green, palette.bg, landTint);
46123
- const water = mapBackgroundColor(palette);
46124
46291
  const usContext = usLayer !== null;
46125
- const foreignFill = mix(
46126
- palette.colors.gray,
46127
- palette.bg,
46128
- isDark ? FOREIGN_TINT_DARK : FOREIGN_TINT_LIGHT
46129
- );
46130
46292
  const regionStroke = isDark ? mix(palette.bg, palette.text, 78) : mix(palette.text, palette.bg, 78);
46131
- const scores = resolved.regions.filter((r) => r.score !== void 0).map((r) => r.score);
46293
+ const values = resolved.regions.filter((r) => r.value !== void 0).map((r) => r.value);
46132
46294
  const scaleOverride = resolved.directives.scale;
46133
- const rampMin = scaleOverride ? scaleOverride.min : Math.min(...scores);
46134
- const rampMax = scaleOverride ? scaleOverride.max : Math.max(...scores);
46135
- const rampHue = palette.colors.red;
46136
- const hasRamp = scores.length > 0;
46137
- const SCORE_NAME = hasRamp ? resolved.directives.metric?.trim() || "Score" : null;
46295
+ const rampMin = scaleOverride ? scaleOverride.min : Math.min(...values);
46296
+ const rampMax = scaleOverride ? scaleOverride.max : Math.max(...values);
46297
+ const rampHue = resolveColor(resolved.directives.regionMetricColor ?? "", palette) ?? palette.colors.red;
46298
+ const hasRamp = values.length > 0;
46299
+ const VALUE_NAME = hasRamp ? resolved.directives.regionMetric?.trim() || "Value" : null;
46138
46300
  const matchColorGroup = (v) => {
46139
46301
  const lv = v.trim().toLowerCase();
46140
46302
  if (lv === "none") return null;
46141
- if (SCORE_NAME && (lv === "score" || lv === SCORE_NAME.toLowerCase()))
46142
- return SCORE_NAME;
46303
+ if (lv === VALUE_NAME?.toLowerCase()) return VALUE_NAME;
46143
46304
  const tg = resolved.tagGroups.find((g) => g.name.toLowerCase() === lv);
46144
46305
  return tg ? tg.name : v;
46145
46306
  };
@@ -46150,11 +46311,20 @@ function layoutMap(resolved, data, size, opts) {
46150
46311
  } else if (resolved.directives.activeTag !== void 0) {
46151
46312
  activeGroup = matchColorGroup(resolved.directives.activeTag);
46152
46313
  } else {
46153
- activeGroup = SCORE_NAME ?? (resolved.tagGroups.length > 0 ? resolved.tagGroups[0].name : null);
46314
+ activeGroup = VALUE_NAME ?? (resolved.tagGroups.length > 0 ? resolved.tagGroups[0].name : null);
46154
46315
  }
46155
- const activeIsScore = SCORE_NAME !== null && activeGroup === SCORE_NAME;
46316
+ const activeIsScore = VALUE_NAME !== null && activeGroup === VALUE_NAME;
46317
+ const mutedBasemap = resolved.directives.basemapStyle === "muted" ? true : resolved.directives.basemapStyle === "natural" ? false : activeGroup !== null;
46318
+ const neutralFill = mapNeutralLandColor(palette, isDark, mutedBasemap);
46319
+ const water = mapBackgroundColor(palette, isDark, mutedBasemap);
46320
+ const lakeStroke = mix(regionStroke, water, 45);
46321
+ const foreignFill = mix(
46322
+ palette.colors.gray,
46323
+ palette.bg,
46324
+ mutedBasemap ? isDark ? MUTED_FOREIGN_DARK : MUTED_FOREIGN_LIGHT : isDark ? FOREIGN_TINT_DARK : FOREIGN_TINT_LIGHT
46325
+ );
46156
46326
  const rampBase = isDark ? mix(palette.surface, palette.text, 28) : palette.bg;
46157
- const fillForScore = (s) => {
46327
+ const fillForValue = (s) => {
46158
46328
  const t = rampMax > rampMin ? (s - rampMin) / (rampMax - rampMin) : 1;
46159
46329
  const pct = RAMP_FLOOR + Math.max(0, Math.min(1, t)) * (100 - RAMP_FLOOR);
46160
46330
  return mix(rampHue, rampBase, pct);
@@ -46177,9 +46347,16 @@ function layoutMap(resolved, data, size, opts) {
46177
46347
  isDark ? TAG_TINT_DARK : TAG_TINT_LIGHT
46178
46348
  );
46179
46349
  };
46350
+ const directFill = (name) => {
46351
+ const hex = name ? resolveColor(name, palette) : null;
46352
+ if (!hex) return null;
46353
+ return mix(hex, palette.bg, isDark ? TAG_TINT_DARK : TAG_TINT_LIGHT);
46354
+ };
46180
46355
  const regionFill = (r) => {
46356
+ const direct = directFill(r.color);
46357
+ if (direct) return direct;
46181
46358
  if (activeIsScore) {
46182
- return r.score !== void 0 ? fillForScore(r.score) : neutralFill;
46359
+ return r.value !== void 0 ? fillForValue(r.value) : neutralFill;
46183
46360
  }
46184
46361
  return tagFill(r.tags, activeGroup) ?? neutralFill;
46185
46362
  };
@@ -46231,6 +46408,7 @@ function layoutMap(resolved, data, size, opts) {
46231
46408
  const fitIsGlobal = fitGB[1][0] - fitGB[0][0] >= 270 || fitGB[1][1] - fitGB[0][1] >= 130;
46232
46409
  let path;
46233
46410
  let project;
46411
+ let stretchParams = null;
46234
46412
  if (fitIsGlobal) {
46235
46413
  const cb = geoPath(projection).bounds(fitTarget);
46236
46414
  const bx0 = cb[0][0];
@@ -46241,6 +46419,7 @@ function layoutMap(resolved, data, size, opts) {
46241
46419
  const oy = fitBox[0][1];
46242
46420
  const sx = cw > 0 ? (fitBox[1][0] - ox) / cw : 1;
46243
46421
  const sy = ch > 0 ? (fitBox[1][1] - oy) / ch : 1;
46422
+ stretchParams = { sx, sy, ox, oy, bx0, by0 };
46244
46423
  const stretch = (x, y) => [
46245
46424
  ox + (x - bx0) * sx,
46246
46425
  oy + (y - by0) * sy
@@ -46272,7 +46451,7 @@ function layoutMap(resolved, data, size, opts) {
46272
46451
  const insets = [];
46273
46452
  const insetRegions = [];
46274
46453
  const insetLabelSeeds = [];
46275
- if (resolved.projection === "albers-usa" && usLayer) {
46454
+ if (resolved.projection === "albers-usa" && usLayer && !resolved.directives.noInsets) {
46276
46455
  const PAD = 8;
46277
46456
  const GAP = 12;
46278
46457
  const yB = height - FIT_PAD;
@@ -46303,38 +46482,14 @@ function layoutMap(resolved, data, size, opts) {
46303
46482
  }
46304
46483
  return y;
46305
46484
  };
46306
- const coastTop = (x0, xr) => {
46485
+ const coastFloor = (x0, xr) => {
46307
46486
  const n = 24;
46308
- const pts = [];
46309
46487
  let maxY = -Infinity;
46310
46488
  for (let i = 0; i <= n; i++) {
46311
- const x = x0 + (xr - x0) * i / n;
46312
- const y = at(x);
46313
- if (y > -Infinity) {
46314
- pts.push([x, y]);
46315
- if (y > maxY) maxY = y;
46316
- }
46317
- }
46318
- if (pts.length === 0) return () => yB - height * 0.42;
46319
- let m = 0;
46320
- if (pts.length >= 2) {
46321
- let sx = 0, sy = 0, sxx = 0, sxy = 0;
46322
- for (const [x, y] of pts) {
46323
- sx += x;
46324
- sy += y;
46325
- sxx += x * x;
46326
- sxy += x * y;
46327
- }
46328
- const den = pts.length * sxx - sx * sx;
46329
- if (den !== 0) m = (pts.length * sxy - sx * sy) / den;
46330
- }
46331
- m = Math.max(-0.35, Math.min(0.35, m));
46332
- let c = -Infinity;
46333
- for (const [x, y] of pts) {
46334
- const need = y - m * x + GAP;
46335
- if (need > c) c = need;
46336
- }
46337
- return (x) => m * x + c;
46489
+ const y = at(x0 + (xr - x0) * i / n);
46490
+ if (y > maxY) maxY = y;
46491
+ }
46492
+ return maxY;
46338
46493
  };
46339
46494
  const placeInset = (iso, proj, boxX, iwReq) => {
46340
46495
  const f = usLayer.get(iso);
@@ -46343,19 +46498,15 @@ function layoutMap(resolved, data, size, opts) {
46343
46498
  const iw = Math.min(iwReq, width - FIT_PAD - x0 - 2 * PAD);
46344
46499
  if (iw < 24) return boxX;
46345
46500
  const xr = x0 + iw + 2 * PAD;
46346
- const top = coastTop(x0, xr);
46347
- const yL = top(x0);
46348
- const yR = top(xr);
46501
+ const floor = coastFloor(x0, xr);
46502
+ const topGuess = floor > -Infinity ? floor + GAP : yB - height * 0.42;
46349
46503
  proj.fitWidth(iw, f);
46350
46504
  const bb = geoPath(proj).bounds(f);
46351
46505
  const sh = Number.isFinite(bb[0][0]) ? bb[1][1] - bb[0][1] : iw;
46352
46506
  const needH = sh + 2 * PAD;
46353
- let topFit = Math.max(yL, yR);
46507
+ let topFit = topGuess;
46354
46508
  const bottom = Math.min(topFit + needH, yB);
46355
46509
  if (bottom - topFit < needH) topFit = bottom - needH;
46356
- const lift = topFit - Math.max(yL, yR);
46357
- const topL = yL + lift;
46358
- const topR = yR + lift;
46359
46510
  proj.fitExtent(
46360
46511
  [
46361
46512
  [x0 + PAD, topFit + PAD],
@@ -46374,15 +46525,18 @@ function layoutMap(resolved, data, size, opts) {
46374
46525
  }
46375
46526
  insets.push({
46376
46527
  x: x0,
46377
- y: Math.min(topL, topR),
46528
+ y: topFit,
46378
46529
  w: xr - x0,
46379
- h: bottom - Math.min(topL, topR),
46530
+ h: bottom - topFit,
46380
46531
  points: [
46381
- [x0, topL],
46382
- [xr, topR],
46532
+ [x0, topFit],
46533
+ [xr, topFit],
46383
46534
  [xr, bottom],
46384
46535
  [x0, bottom]
46385
- ]
46536
+ ],
46537
+ // The FITTED inset projection (just fit to this box) — captured so the
46538
+ // geo-query can invert pixels inside the frame back to AK/HI coords.
46539
+ projection: proj
46386
46540
  });
46387
46541
  insetRegions.push({
46388
46542
  id: iso,
@@ -46391,7 +46545,7 @@ function layoutMap(resolved, data, size, opts) {
46391
46545
  stroke: regionStroke,
46392
46546
  lineNumber,
46393
46547
  layer: "us-state",
46394
- ...r?.score !== void 0 && { score: r.score },
46548
+ ...r?.value !== void 0 && { value: r.value },
46395
46549
  ...r && Object.keys(r.tags).length > 0 && { tags: r.tags }
46396
46550
  });
46397
46551
  const ctr = geoPath(proj).centroid(f);
@@ -46534,7 +46688,7 @@ function layoutMap(resolved, data, size, opts) {
46534
46688
  lineNumber,
46535
46689
  layer,
46536
46690
  ...label !== void 0 && { label },
46537
- ...isThisLayer && r.score !== void 0 && { score: r.score },
46691
+ ...isThisLayer && r.value !== void 0 && { value: r.value },
46538
46692
  ...isThisLayer && Object.keys(r.tags).length > 0 && { tags: r.tags }
46539
46693
  });
46540
46694
  }
@@ -46552,13 +46706,40 @@ function layoutMap(resolved, data, size, opts) {
46552
46706
  id: "lake",
46553
46707
  d,
46554
46708
  fill: water,
46555
- stroke: "none",
46709
+ stroke: lakeStroke,
46556
46710
  lineNumber: -1,
46557
46711
  layer: "base"
46558
46712
  });
46559
46713
  }
46560
46714
  }
46561
- const riverColor = water;
46715
+ const relief = [];
46716
+ let reliefHatch = null;
46717
+ if (resolved.directives.relief === true && data.mountainRanges) {
46718
+ for (const [, f] of decodeLayer(data.mountainRanges)) {
46719
+ const viewF = isGlobalView ? dropFrameFillers(f) : cullFeatureToView(f);
46720
+ if (!viewF) continue;
46721
+ const area2 = path.area(viewF);
46722
+ if (!Number.isFinite(area2) || area2 < RELIEF_MIN_AREA) continue;
46723
+ const box = path.bounds(viewF);
46724
+ if (box[1][0] - box[0][0] < RELIEF_MIN_DIM || box[1][1] - box[0][1] < RELIEF_MIN_DIM)
46725
+ continue;
46726
+ const d = path(viewF) ?? "";
46727
+ if (!d) continue;
46728
+ relief.push({ d });
46729
+ }
46730
+ if (relief.length) {
46731
+ const darkTone = isDark ? palette.bg : palette.text;
46732
+ const lightTone = isDark ? palette.text : palette.bg;
46733
+ const landLum = relativeLuminance(neutralFill);
46734
+ const tone = Math.abs(landLum - relativeLuminance(darkTone)) > 0.04 ? darkTone : lightTone;
46735
+ reliefHatch = {
46736
+ color: mix(tone, neutralFill, RELIEF_HATCH_STRENGTH),
46737
+ spacing: RELIEF_HATCH_SPACING,
46738
+ width: RELIEF_HATCH_WIDTH
46739
+ };
46740
+ }
46741
+ }
46742
+ const riverColor = mix(water, regionStroke, 16);
46562
46743
  const rivers = [];
46563
46744
  if (data.rivers) {
46564
46745
  for (const [, f] of decodeLayer(data.rivers)) {
@@ -46569,16 +46750,19 @@ function layoutMap(resolved, data, size, opts) {
46569
46750
  rivers.push({ d, color: riverColor, width: RIVER_WIDTH });
46570
46751
  }
46571
46752
  }
46572
- const sizeVals = resolved.pois.map((p) => Number(p.meta["size"])).filter((n) => Number.isFinite(n) && n > 0);
46753
+ const sizeVals = resolved.pois.map((p) => Number(p.meta["value"])).filter((n) => Number.isFinite(n) && n > 0);
46573
46754
  const sizeMin = sizeVals.length ? Math.min(...sizeVals) : 0;
46574
46755
  const sizeMax = sizeVals.length ? Math.max(...sizeVals) : 0;
46575
46756
  const radiusFor = (p) => {
46576
- const v = Number(p.meta["size"]);
46757
+ const v = Number(p.meta["value"]);
46577
46758
  if (!Number.isFinite(v) || v <= 0 || sizeMax <= 0) return R_DEFAULT;
46578
46759
  const t = sizeMax > sizeMin ? (Math.sqrt(v) - Math.sqrt(sizeMin)) / (Math.sqrt(sizeMax) - Math.sqrt(sizeMin)) : 1;
46579
46760
  return R_MIN + Math.max(0, Math.min(1, t)) * (R_MAX - R_MIN);
46580
46761
  };
46581
46762
  const poiFill = (p) => {
46763
+ const directHex = p.color ? resolveColor(p.color, palette) : null;
46764
+ if (directHex)
46765
+ return { fill: directHex, stroke: mix(directHex, palette.text, 18) };
46582
46766
  for (const group of resolved.tagGroups) {
46583
46767
  const val = p.tags[group.name.toLowerCase()];
46584
46768
  if (!val) continue;
@@ -46640,7 +46824,8 @@ function layoutMap(resolved, data, size, opts) {
46640
46824
  lineNumber: e.p.lineNumber,
46641
46825
  implicit: !!e.p.implicit,
46642
46826
  isOrigin: originIds.has(e.p.id),
46643
- ...num !== void 0 && { routeNumber: num }
46827
+ ...num !== void 0 && { routeNumber: num },
46828
+ ...Object.keys(e.p.tags).length > 0 && { tags: e.p.tags }
46644
46829
  });
46645
46830
  });
46646
46831
  }
@@ -46676,26 +46861,40 @@ function layoutMap(resolved, data, size, opts) {
46676
46861
  const by = b.cy - (b.cy - py) / tb * trimB;
46677
46862
  return `M${ax},${ay}Q${px},${py} ${bx},${by}`;
46678
46863
  };
46864
+ const routeLegVals = resolved.routes.flatMap((rt) => rt.legs).map((l) => Number(l.value)).filter((n) => Number.isFinite(n) && n > 0);
46865
+ const rlMin = routeLegVals.length ? Math.min(...routeLegVals) : 0;
46866
+ const rlMax = routeLegVals.length ? Math.max(...routeLegVals) : 0;
46867
+ const routeWidthFor = (v) => {
46868
+ if (!Number.isFinite(v) || v <= 0 || rlMax <= 0) return W_MIN;
46869
+ const t = rlMax > rlMin ? (v - rlMin) / (rlMax - rlMin) : 1;
46870
+ return W_MIN + t * (W_MAX - W_MIN);
46871
+ };
46679
46872
  for (const rt of resolved.routes) {
46680
- const curved = rt.meta["style"] === "arc";
46681
- for (let i = 1; i < rt.stopIds.length; i++) {
46682
- const a = poiScreen.get(rt.stopIds[i - 1]);
46683
- const b = poiScreen.get(rt.stopIds[i]);
46873
+ for (const leg of rt.legs) {
46874
+ const a = poiScreen.get(leg.fromId);
46875
+ const b = poiScreen.get(leg.toId);
46684
46876
  if (!a || !b) continue;
46877
+ const mx = (a.cx + b.cx) / 2;
46878
+ const my = (a.cy + b.cy) / 2;
46685
46879
  legs.push({
46686
- d: legPath(a, b, curved, 0),
46687
- width: W_MIN,
46880
+ d: legPath(a, b, leg.style === "arc", 0),
46881
+ width: routeWidthFor(Number(leg.value)),
46688
46882
  color: mix(palette.text, palette.bg, 72),
46689
46883
  arrow: true,
46690
- lineNumber: rt.lineNumber
46884
+ lineNumber: leg.lineNumber,
46885
+ ...leg.label !== void 0 && {
46886
+ label: leg.label,
46887
+ labelX: mx,
46888
+ labelY: my - 4
46889
+ }
46691
46890
  });
46692
46891
  }
46693
46892
  }
46694
- const weightVals = resolved.edges.map((e) => Number(e.meta["weight"])).filter((n) => Number.isFinite(n) && n > 0);
46893
+ const weightVals = resolved.edges.map((e) => Number(e.meta["value"])).filter((n) => Number.isFinite(n) && n > 0);
46695
46894
  const wMin = weightVals.length ? Math.min(...weightVals) : 0;
46696
46895
  const wMax = weightVals.length ? Math.max(...weightVals) : 0;
46697
46896
  const widthFor = (e) => {
46698
- const v = Number(e.meta["weight"]);
46897
+ const v = Number(e.meta["value"]);
46699
46898
  if (!Number.isFinite(v) || v <= 0 || wMax <= 0) return W_MIN;
46700
46899
  const t = wMax > wMin ? (v - wMin) / (wMax - wMin) : 1;
46701
46900
  return W_MIN + t * (W_MAX - W_MIN);
@@ -46958,8 +47157,8 @@ function layoutMap(resolved, data, size, opts) {
46958
47157
  activeGroup,
46959
47158
  ...hasRamp && {
46960
47159
  ramp: {
46961
- ...resolved.directives.metric !== void 0 && {
46962
- metric: resolved.directives.metric
47160
+ ...resolved.directives.regionMetric !== void 0 && {
47161
+ metric: resolved.directives.regionMetric
46963
47162
  },
46964
47163
  min: rampMin,
46965
47164
  max: rampMax,
@@ -46979,19 +47178,24 @@ function layoutMap(resolved, data, size, opts) {
46979
47178
  ...resolved.caption !== void 0 && { caption: resolved.caption },
46980
47179
  regions,
46981
47180
  rivers,
47181
+ relief,
47182
+ reliefHatch,
46982
47183
  legs,
46983
47184
  pois,
46984
47185
  labels,
46985
47186
  legend,
46986
47187
  insets,
46987
- insetRegions
47188
+ insetRegions,
47189
+ projection,
47190
+ stretch: stretchParams
46988
47191
  };
46989
47192
  }
46990
- var FIT_PAD, RAMP_FLOOR, R_DEFAULT, R_MIN, R_MAX, W_MIN, W_MAX, FONT, COLO_EPS, LAND_TINT_LIGHT, LAND_TINT_DARK, TAG_TINT_LIGHT, TAG_TINT_DARK, WATER_TINT, RIVER_WIDTH, FOREIGN_TINT_LIGHT, FOREIGN_TINT_DARK, COLO_R, GOLDEN_ANGLE, FAN_STEP, ARC_CURVE_FRAC, usConusProjection, alaskaProjection, hawaiiProjection, INSET_STATES, US_NON_CONUS;
47193
+ var FIT_PAD, RAMP_FLOOR, R_DEFAULT, R_MIN, R_MAX, W_MIN, W_MAX, FONT, COLO_EPS, LAND_TINT_LIGHT, LAND_TINT_DARK, TAG_TINT_LIGHT, TAG_TINT_DARK, WATER_TINT_LIGHT, WATER_TINT_DARK, RIVER_WIDTH, RELIEF_MIN_AREA, RELIEF_MIN_DIM, RELIEF_HATCH_SPACING, RELIEF_HATCH_WIDTH, RELIEF_HATCH_STRENGTH, FOREIGN_TINT_LIGHT, FOREIGN_TINT_DARK, MUTED_FOREIGN_LIGHT, MUTED_FOREIGN_DARK, COLO_R, GOLDEN_ANGLE, FAN_STEP, ARC_CURVE_FRAC, usConusProjection, alaskaProjection, hawaiiProjection, INSET_STATES, US_NON_CONUS;
46991
47194
  var init_layout15 = __esm({
46992
47195
  "src/map/layout.ts"() {
46993
47196
  "use strict";
46994
47197
  init_color_utils();
47198
+ init_colors();
46995
47199
  init_label_layout();
46996
47200
  init_legend_constants();
46997
47201
  init_title_constants();
@@ -47004,14 +47208,22 @@ var init_layout15 = __esm({
47004
47208
  W_MAX = 8;
47005
47209
  FONT = 11;
47006
47210
  COLO_EPS = 1.5;
47007
- LAND_TINT_LIGHT = 58;
47008
- LAND_TINT_DARK = 75;
47211
+ LAND_TINT_LIGHT = 12;
47212
+ LAND_TINT_DARK = 24;
47009
47213
  TAG_TINT_LIGHT = 60;
47010
47214
  TAG_TINT_DARK = 68;
47011
- WATER_TINT = 55;
47215
+ WATER_TINT_LIGHT = 13;
47216
+ WATER_TINT_DARK = 14;
47012
47217
  RIVER_WIDTH = 1.3;
47218
+ RELIEF_MIN_AREA = 12;
47219
+ RELIEF_MIN_DIM = 2;
47220
+ RELIEF_HATCH_SPACING = 3;
47221
+ RELIEF_HATCH_WIDTH = 0.25;
47222
+ RELIEF_HATCH_STRENGTH = 32;
47013
47223
  FOREIGN_TINT_LIGHT = 30;
47014
47224
  FOREIGN_TINT_DARK = 62;
47225
+ MUTED_FOREIGN_LIGHT = 28;
47226
+ MUTED_FOREIGN_DARK = 16;
47015
47227
  COLO_R = 9;
47016
47228
  GOLDEN_ANGLE = 2.399963229728653;
47017
47229
  FAN_STEP = 16;
@@ -47066,7 +47278,7 @@ function renderMap(container, resolved, data, palette, isDark, onClickItem, expo
47066
47278
  const p = g.append("path").attr("d", r.d).attr("fill", r.fill).attr("stroke", r.stroke).attr("stroke-width", strokeWidth);
47067
47279
  if (r.layer !== "base") {
47068
47280
  p.classed("dgmo-map-region", true).attr("data-region", r.id);
47069
- if (r.score !== void 0) p.attr("data-score", r.score);
47281
+ if (r.value !== void 0) p.attr("data-value", r.value);
47070
47282
  if (r.tags) {
47071
47283
  for (const [group, value] of Object.entries(r.tags)) {
47072
47284
  p.attr(`data-tag-${group.toLowerCase()}`, value.toLowerCase());
@@ -47084,6 +47296,20 @@ function renderMap(container, resolved, data, palette, isDark, onClickItem, expo
47084
47296
  }
47085
47297
  };
47086
47298
  for (const r of layout.regions) drawRegion(gRegions, r, 0.5);
47299
+ if (layout.relief.length && layout.reliefHatch) {
47300
+ const h = layout.reliefHatch;
47301
+ const rangeClipId = "dgmo-relief-clip";
47302
+ const landClipId = "dgmo-relief-land";
47303
+ const rangeClip = defs.append("clipPath").attr("id", rangeClipId);
47304
+ for (const s of layout.relief) rangeClip.append("path").attr("d", s.d);
47305
+ const landClip = defs.append("clipPath").attr("id", landClipId);
47306
+ for (const r of layout.regions)
47307
+ if (r.id !== "lake") landClip.append("path").attr("d", r.d);
47308
+ const gRelief = svg.append("g").attr("clip-path", `url(#${landClipId})`).append("g").attr("class", "dgmo-map-relief").attr("clip-path", `url(#${rangeClipId})`).attr("stroke", h.color).attr("stroke-width", h.width).attr("vector-effect", "non-scaling-stroke");
47309
+ for (let y = h.spacing; y < height; y += h.spacing) {
47310
+ gRelief.append("line").attr("x1", 0).attr("y1", y).attr("x2", width).attr("y2", y);
47311
+ }
47312
+ }
47087
47313
  if (layout.rivers.length) {
47088
47314
  const gRivers = svg.append("g").attr("class", "dgmo-map-rivers").attr("fill", "none");
47089
47315
  for (const r of layout.rivers) {
@@ -47127,6 +47353,11 @@ function renderMap(container, resolved, data, palette, isDark, onClickItem, expo
47127
47353
  gPois.append("circle").attr("cx", poi.cx).attr("cy", poi.cy).attr("r", poi.r + 3).attr("fill", "none").attr("stroke", poi.stroke).attr("stroke-width", 1.5);
47128
47354
  }
47129
47355
  const c = gPois.append("circle").attr("cx", poi.cx).attr("cy", poi.cy).attr("r", poi.r).attr("fill", poi.fill).attr("stroke", poi.stroke).attr("stroke-width", 1).attr("data-line-number", poi.lineNumber).attr("data-poi", poi.id);
47356
+ if (poi.tags) {
47357
+ for (const [group, value] of Object.entries(poi.tags)) {
47358
+ c.attr(`data-tag-${group.toLowerCase()}`, value.toLowerCase());
47359
+ }
47360
+ }
47130
47361
  if (onClickItem) {
47131
47362
  c.style("cursor", "pointer").on(
47132
47363
  "click",
@@ -47176,7 +47407,7 @@ function renderMap(container, resolved, data, palette, isDark, onClickItem, expo
47176
47407
  const legendG = svg.append("g").attr("class", "dgmo-map-legend").attr("transform", `translate(0, ${legendY})`);
47177
47408
  const ramp = layout.legend.ramp;
47178
47409
  const scoreGroup = ramp ? {
47179
- name: ramp.metric?.trim() || "Score",
47410
+ name: ramp.metric?.trim() || "Value",
47180
47411
  entries: [],
47181
47412
  gradient: {
47182
47413
  min: ramp.min,
@@ -47203,7 +47434,7 @@ function renderMap(container, resolved, data, palette, isDark, onClickItem, expo
47203
47434
  }
47204
47435
  }
47205
47436
  if (layout.title) {
47206
- svg.append("text").attr("x", width / 2).attr("y", TITLE_Y).attr("text-anchor", "middle").attr("font-size", TITLE_FONT_SIZE).attr("font-weight", TITLE_FONT_WEIGHT).attr("fill", palette.text).attr("paint-order", "stroke fill").attr("stroke", palette.bg).attr("stroke-width", 4).attr("stroke-linejoin", "round").attr("stroke-opacity", 0.7).text(layout.title);
47437
+ svg.append("text").attr("class", "dgmo-map-title").attr("x", width / 2).attr("y", TITLE_Y).attr("text-anchor", "middle").attr("font-size", TITLE_FONT_SIZE).attr("font-weight", TITLE_FONT_WEIGHT).attr("fill", palette.text).attr("paint-order", "stroke fill").attr("stroke", palette.bg).attr("stroke-width", 4).attr("stroke-linejoin", "round").attr("stroke-opacity", 0.7).text(layout.title);
47207
47438
  }
47208
47439
  if (layout.subtitle) {
47209
47440
  svg.append("text").attr("x", width / 2).attr("y", TITLE_Y + TITLE_FONT_SIZE).attr("text-anchor", "middle").attr("font-size", LABEL_FONT + 1).attr("fill", palette.textMuted).attr("paint-order", "stroke fill").attr("stroke", palette.bg).attr("stroke-width", 3).attr("stroke-linejoin", "round").attr("stroke-opacity", 0.7).text(layout.subtitle);
@@ -47235,6 +47466,120 @@ var init_renderer16 = __esm({
47235
47466
  }
47236
47467
  });
47237
47468
 
47469
+ // src/map/load-data.ts
47470
+ var load_data_exports = {};
47471
+ __export(load_data_exports, {
47472
+ loadMapData: () => loadMapData
47473
+ });
47474
+ async function loadNodeBuiltins() {
47475
+ const [{ readFile }, { fileURLToPath }, { dirname, resolve }] = await Promise.all([
47476
+ import("fs/promises"),
47477
+ import("url"),
47478
+ import("path")
47479
+ ]);
47480
+ return { readFile, fileURLToPath, dirname, resolve };
47481
+ }
47482
+ async function readJson(nb, dir, name) {
47483
+ return JSON.parse(await nb.readFile(nb.resolve(dir, name), "utf8"));
47484
+ }
47485
+ async function firstExistingDir(nb, baseDir) {
47486
+ for (const rel of CANDIDATE_DIRS) {
47487
+ const dir = nb.resolve(baseDir, rel);
47488
+ try {
47489
+ await nb.readFile(nb.resolve(dir, FILES.gazetteer), "utf8");
47490
+ return dir;
47491
+ } catch {
47492
+ }
47493
+ }
47494
+ throw new Error(
47495
+ `map data assets not found near ${baseDir} (looked in ${CANDIDATE_DIRS.join(", ")}). Run \`pnpm build:map-data\` and \`pnpm build\`.`
47496
+ );
47497
+ }
47498
+ function validate(data) {
47499
+ const topoOk = (t) => !!t && t.type === "Topology" && !!t.objects;
47500
+ if (!topoOk(data.worldCoarse) || !topoOk(data.worldDetail) || !topoOk(data.usStates) || !data.gazetteer || !Array.isArray(data.gazetteer.cities) || !data.gazetteer.byName) {
47501
+ throw new Error("map data assets are malformed (failed shape validation)");
47502
+ }
47503
+ return data;
47504
+ }
47505
+ function moduleBaseDir(nb) {
47506
+ try {
47507
+ const url = import.meta.url;
47508
+ if (url) return nb.dirname(nb.fileURLToPath(url));
47509
+ } catch {
47510
+ }
47511
+ if (typeof __dirname !== "undefined") return __dirname;
47512
+ return process.cwd();
47513
+ }
47514
+ function loadMapData() {
47515
+ cache ??= (async () => {
47516
+ const nb = await loadNodeBuiltins();
47517
+ const dir = await firstExistingDir(nb, moduleBaseDir(nb));
47518
+ const [
47519
+ worldCoarse,
47520
+ worldDetail,
47521
+ usStates,
47522
+ lakes,
47523
+ rivers,
47524
+ mountainRanges,
47525
+ naLand,
47526
+ naLakes,
47527
+ gazetteer
47528
+ ] = await Promise.all([
47529
+ readJson(nb, dir, FILES.worldCoarse),
47530
+ readJson(nb, dir, FILES.worldDetail),
47531
+ readJson(nb, dir, FILES.usStates),
47532
+ // Lakes/rivers/mountain/NA assets are optional — older bundles may predate them.
47533
+ readJson(nb, dir, FILES.lakes).catch(() => void 0),
47534
+ readJson(nb, dir, FILES.rivers).catch(() => void 0),
47535
+ readJson(nb, dir, FILES.mountainRanges).catch(
47536
+ () => void 0
47537
+ ),
47538
+ readJson(nb, dir, FILES.naLand).catch(() => void 0),
47539
+ readJson(nb, dir, FILES.naLakes).catch(() => void 0),
47540
+ readJson(nb, dir, FILES.gazetteer)
47541
+ ]);
47542
+ return validate({
47543
+ worldCoarse,
47544
+ worldDetail,
47545
+ usStates,
47546
+ gazetteer,
47547
+ ...lakes && { lakes },
47548
+ ...rivers && { rivers },
47549
+ ...mountainRanges && { mountainRanges },
47550
+ ...naLand && { naLand },
47551
+ ...naLakes && { naLakes }
47552
+ });
47553
+ })().catch((e) => {
47554
+ cache = void 0;
47555
+ throw e;
47556
+ });
47557
+ return cache;
47558
+ }
47559
+ var FILES, CANDIDATE_DIRS, cache;
47560
+ var init_load_data = __esm({
47561
+ "src/map/load-data.ts"() {
47562
+ "use strict";
47563
+ FILES = {
47564
+ worldCoarse: "world-coarse.json",
47565
+ worldDetail: "world-detail.json",
47566
+ usStates: "us-states.json",
47567
+ lakes: "lakes.json",
47568
+ rivers: "rivers.json",
47569
+ mountainRanges: "mountain-ranges.json",
47570
+ naLand: "na-land.json",
47571
+ naLakes: "na-lakes.json",
47572
+ gazetteer: "gazetteer.json"
47573
+ };
47574
+ CANDIDATE_DIRS = [
47575
+ "./data",
47576
+ "./map-data",
47577
+ "../map-data",
47578
+ "../src/map/data"
47579
+ ];
47580
+ }
47581
+ });
47582
+
47238
47583
  // src/pyramid/renderer.ts
47239
47584
  var renderer_exports17 = {};
47240
47585
  __export(renderer_exports17, {
@@ -55363,15 +55708,17 @@ async function renderForExport(content, theme, palette, viewState, options) {
55363
55708
  if (detectedType === "map") {
55364
55709
  const { parseMap: parseMap2 } = await Promise.resolve().then(() => (init_parser12(), parser_exports11));
55365
55710
  const { resolveMap: resolveMap2 } = await Promise.resolve().then(() => (init_resolver2(), resolver_exports));
55366
- const { loadMapData: loadMapData2 } = await Promise.resolve().then(() => (init_load_data(), load_data_exports));
55367
55711
  const { renderMapForExport: renderMapForExport2 } = await Promise.resolve().then(() => (init_renderer16(), renderer_exports16));
55368
55712
  const effectivePalette2 = await resolveExportPalette(theme, palette);
55369
55713
  const mapParsed = parseMap2(content);
55370
- let mapData;
55371
- try {
55372
- mapData = await loadMapData2();
55373
- } catch {
55374
- return "";
55714
+ let mapData = options?.mapData;
55715
+ if (!mapData) {
55716
+ const { loadMapData: loadMapData2 } = await Promise.resolve().then(() => (init_load_data(), load_data_exports));
55717
+ try {
55718
+ mapData = await loadMapData2();
55719
+ } catch {
55720
+ return "";
55721
+ }
55375
55722
  }
55376
55723
  const mapResolved = resolveMap2(mapParsed, mapData);
55377
55724
  const container2 = createExportContainer(EXPORT_WIDTH, EXPORT_HEIGHT);
@@ -56405,13 +56752,17 @@ var DIRECTIVE_KEYWORDS = /* @__PURE__ */ new Set([
56405
56752
  // Map (§24B) directives
56406
56753
  "region",
56407
56754
  "projection",
56408
- "metric",
56409
- "size-metric",
56755
+ "region-metric",
56756
+ "poi-metric",
56757
+ "flow-metric",
56410
56758
  "region-labels",
56411
56759
  "poi-labels",
56412
56760
  "default-country",
56413
56761
  "default-state",
56414
56762
  "no-legend",
56763
+ "no-insets",
56764
+ "muted",
56765
+ "natural",
56415
56766
  "subtitle",
56416
56767
  "caption",
56417
56768
  "poi",
@@ -57079,7 +57430,7 @@ pre.dgmo, code.language-dgmo, pre > code.language-dgmo,
57079
57430
 
57080
57431
  // src/auto/index.ts
57081
57432
  init_safe_href();
57082
- var VERSION = "0.20.3";
57433
+ var VERSION = "0.21.1";
57083
57434
  var DEFAULTS = {
57084
57435
  theme: "auto",
57085
57436
  palette: "nord",