@bicharts/chart-host 0.6.102 → 0.6.105

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 (33) hide show
  1. package/dist/adapters.mjs +3 -3
  2. package/dist/card.mjs +2 -2
  3. package/dist/chunk-5WTQN5DL.mjs +96 -0
  4. package/dist/{chunk-M7MBTLDP.mjs → chunk-7XRQUFVH.mjs} +3 -1
  5. package/dist/{chunk-ASLRGGLV.mjs → chunk-CPLWAW3Z.mjs} +1 -1
  6. package/dist/{chunk-B6BLSIID.mjs → chunk-IE426WU6.mjs} +2 -2
  7. package/dist/{chunk-3JBJ2SIF.mjs → chunk-IE7TM6DX.mjs} +1 -1
  8. package/dist/{chunk-ALX4D2I2.mjs → chunk-K6UXTDMR.mjs} +675 -132
  9. package/dist/{chunk-D6A37G2G.mjs → chunk-MU4BWWO6.mjs} +10 -10
  10. package/dist/{chunk-5OCL4EFM.mjs → chunk-P2DLK7WZ.mjs} +1 -1
  11. package/dist/{chunk-PMA56BKD.mjs → chunk-PA5V6J6K.mjs} +1 -1
  12. package/dist/{chunk-CNT3QA3R.mjs → chunk-SYUJ4TPX.mjs} +961 -771
  13. package/dist/{chunk-WSNDXS3Z.mjs → chunk-TLIBO5PT.mjs} +1 -1
  14. package/dist/index.mjs +207 -17
  15. package/dist/legend-fit.mjs +3 -3
  16. package/dist/page.mjs +4 -4
  17. package/dist/provinces.mjs +229 -0
  18. package/dist/react.mjs +12 -10
  19. package/dist/testing.mjs +1 -1
  20. package/dist/types/admin1LookupLoader.d.ts +26 -0
  21. package/dist/types/contract.d.ts +9 -1
  22. package/dist/types/exportTable.d.ts +100 -0
  23. package/dist/types/host.d.ts +3 -2
  24. package/dist/types/hostLinks.d.ts +11 -0
  25. package/dist/types/index.d.ts +5 -2
  26. package/dist/types/optionsVocabulary.d.ts +5 -0
  27. package/dist/types/payload.d.ts +63 -4
  28. package/dist/types/provinceGeo.d.ts +38 -0
  29. package/dist/types/provinceHost.d.ts +47 -0
  30. package/dist/types/provinces.d.ts +3 -0
  31. package/dist/types/shareRate.d.ts +90 -0
  32. package/dist/zoom-memory.mjs +1 -1
  33. package/package.json +6 -1
@@ -1,7 +1,7 @@
1
1
  /*! @bicharts/chart-host — Apache-2.0. Bundled reference data: GeoNames (https://www.geonames.org/) CC BY 4.0; Natural Earth and US Census/TIGER (public domain). Full text: NOTICE in this package. */
2
2
  import {
3
3
  LASSO_KNOB_KEY
4
- } from "./chunk-B6BLSIID.mjs";
4
+ } from "./chunk-IE426WU6.mjs";
5
5
 
6
6
  // src/filterScope.ts
7
7
  function viewToken(view) {
package/dist/index.mjs CHANGED
@@ -5,7 +5,7 @@ import {
5
5
  formatSourceDateFor,
6
6
  isExcelDateFormat,
7
7
  normaliseAggregation
8
- } from "./chunk-D6A37G2G.mjs";
8
+ } from "./chunk-MU4BWWO6.mjs";
9
9
  import {
10
10
  captureSvgSnapshot,
11
11
  chartSvgOf,
@@ -15,7 +15,7 @@ import {
15
15
  svgNaturalSize,
16
16
  svgToDataUrl,
17
17
  tableHostOf
18
- } from "./chunk-PMA56BKD.mjs";
18
+ } from "./chunk-PA5V6J6K.mjs";
19
19
  import {
20
20
  ANNOTATION_CLASS,
21
21
  ANNOTATION_LAYER_CLASS,
@@ -24,8 +24,10 @@ import {
24
24
  AUTO_RAMP_MIN_STEP_DELTA_E,
25
25
  BACKING_MAJORITY,
26
26
  CLIP_TOLERANCE_PX,
27
+ CSV_MIME,
27
28
  D3_PLUGIN_PACKAGES,
28
29
  DARK_TEXT,
30
+ EXPORT_FORMATS,
29
31
  GLYPH_SAMPLE_N,
30
32
  LABEL_CONTRAST_CAP,
31
33
  LABEL_CONTRAST_DONE_ATTR,
@@ -45,19 +47,22 @@ import {
45
47
  STRADDLE_TARGET_CONTRAST,
46
48
  VALUE_AXIS_MIN_FIT,
47
49
  WHITE_TEXT_BG_LUM,
50
+ XLSX_MIME,
48
51
  applyLabelContrast,
49
52
  assembleD3,
50
53
  autoRampCanvas,
51
54
  autoRampMinStep,
52
55
  backingHoldsGlyph,
53
56
  blankRenderFlag,
57
+ browserSaveFile,
58
+ buildExportFile,
54
59
  buildRenderPayload,
60
+ bytesToBase64,
55
61
  cellSuppressesNormalize,
56
62
  censusClippedText,
57
63
  censusColourSpread,
58
64
  censusMarks,
59
65
  censusValuePlacement,
60
- clearGeoCache,
61
66
  clippedTextFlag,
62
67
  colourSpreadFlag,
63
68
  compileRenderFn,
@@ -67,37 +72,40 @@ import {
67
72
  createChartHost,
68
73
  decideLabelColor,
69
74
  deltaEHex,
75
+ excelNumberFormat,
76
+ excelSerial,
70
77
  explainRenderFailure,
71
- geoAssetFor,
72
- geoFromCache,
78
+ exportFileName,
79
+ exportFormatsFor,
80
+ exportTableService,
73
81
  glyphSampleGrid,
74
82
  invalidSentinelReason,
75
83
  isBlankRender,
76
84
  isInvalidSentinelError,
77
85
  isPillBackdropAlpha,
78
- loadGeo,
79
86
  minContrastOver,
80
87
  newIdScope,
81
88
  noopViewStateProvider,
82
89
  pickColorOver,
83
90
  pillBacksGlyph,
84
- registerGeo,
85
- registerGeoAsset,
86
91
  relativeLuminance,
87
92
  requiredD3Plugins,
88
93
  resolveAutoColorScale,
89
94
  resolveOptions,
90
95
  scopeChartIds,
91
96
  sessionViewStateProvider,
97
+ sheetName,
92
98
  straddleSampleGrid,
93
99
  straddles,
94
100
  stripEsmExports,
95
101
  stripJsComments,
96
102
  syncMemberSelection,
103
+ tableToCsv,
104
+ tableToXlsx,
97
105
  toRGBA,
98
106
  toSourceRows,
99
107
  valuePlacementFlag
100
- } from "./chunk-ALX4D2I2.mjs";
108
+ } from "./chunk-K6UXTDMR.mjs";
101
109
  import {
102
110
  LASSO_AXES_SLOT,
103
111
  LASSO_COUNT_CLASS,
@@ -124,13 +132,13 @@ import {
124
132
  lassoVerdict,
125
133
  pointInShape,
126
134
  registerLassoAction
127
- } from "./chunk-B6BLSIID.mjs";
135
+ } from "./chunk-IE426WU6.mjs";
128
136
  import {
129
137
  MIN_HIT_BAND_PX,
130
138
  censusHitBands,
131
139
  ensureCrossfilterHitTargets,
132
140
  hitBandFlag
133
- } from "./chunk-ASLRGGLV.mjs";
141
+ } from "./chunk-CPLWAW3Z.mjs";
134
142
  import {
135
143
  CONTAINER_SLOT_PRESS_AT,
136
144
  DRAG_NOT_CLICK_PX,
@@ -155,7 +163,7 @@ import {
155
163
  selectionRuleOf,
156
164
  trackPress,
157
165
  validRowSet
158
- } from "./chunk-5OCL4EFM.mjs";
166
+ } from "./chunk-P2DLK7WZ.mjs";
159
167
  import {
160
168
  AXIS_PIN_BAND_PAD_PX,
161
169
  AXIS_PIN_MAX_BAND_FRACTION,
@@ -184,12 +192,20 @@ import {
184
192
  svgInkReach,
185
193
  takeScroll,
186
194
  unpinScrolledAxis
187
- } from "./chunk-3JBJ2SIF.mjs";
195
+ } from "./chunk-IE7TM6DX.mjs";
196
+ import {
197
+ clearGeoCache,
198
+ geoAssetFor,
199
+ geoFromCache,
200
+ loadGeo,
201
+ registerGeo,
202
+ registerGeoAsset
203
+ } from "./chunk-5WTQN5DL.mjs";
188
204
  import {
189
- _3,
205
+ Kt,
190
206
  l,
191
207
  o
192
- } from "./chunk-CNT3QA3R.mjs";
208
+ } from "./chunk-SYUJ4TPX.mjs";
193
209
  import "./chunk-A2GMXZP7.mjs";
194
210
  import {
195
211
  ACTIVE_TICK_CLASS,
@@ -230,6 +246,7 @@ import {
230
246
  MARK_KEY_ATTR,
231
247
  MARK_SELECTED_CLASS,
232
248
  MAX_MAP_POINTS_DEFAULT,
249
+ NOTE_STYLE_ATTR,
233
250
  NO_ROW_MARKS_ATTR,
234
251
  ROW_IDX_ATTR,
235
252
  SEASONAL_MARKERS_DEFAULT,
@@ -243,9 +260,32 @@ import {
243
260
  chartOwnsTimeline,
244
261
  periodTickSuppressesFeedback,
245
262
  withoutViewOnlyKeys
246
- } from "./chunk-M7MBTLDP.mjs";
263
+ } from "./chunk-7XRQUFVH.mjs";
247
264
  import "./chunk-GHODWOAL.mjs";
248
265
 
266
+ // src/hostLinks.ts
267
+ var LINK_SCHEME_RE = /^(https?:\/\/|mailto:)/i;
268
+ function hostLinkServices(open, clipboard) {
269
+ const out = {};
270
+ if (clipboard) {
271
+ out.copyText = (text) => {
272
+ try {
273
+ if (typeof clipboard.writeText !== "function") return false;
274
+ return clipboard.writeText(String(text ?? "")).then(() => true, () => false);
275
+ } catch {
276
+ return false;
277
+ }
278
+ };
279
+ }
280
+ if (typeof open === "function") {
281
+ out.openUrl = (url) => {
282
+ const u2 = String(url ?? "").trim();
283
+ if (LINK_SCHEME_RE.test(u2)) open(u2);
284
+ };
285
+ }
286
+ return out;
287
+ }
288
+
249
289
  // src/optionsVocabulary.ts
250
290
  var MAX_MAP_POINTS_MIN = 10;
251
291
  var MAX_MAP_POINTS_MAX = 1e5;
@@ -296,7 +336,12 @@ var OPTIONS_VOCABULARY = Object.freeze({
296
336
  * that made the chart asked for them. "on" / "off" is a reader's choice and wins either way.
297
337
  */
298
338
  hoverDropLines: entry({ timing: "live", default: "", values: ["", "on", "off"] }),
339
+ /** A province map draws the national borders over its provinces unless this is false (a reader's "Country borders"). */
340
+ geoBorders: entry({ timing: "live", default: true }),
299
341
  // ---- the next generated chart ----
342
+ /** A reader's "Derive provinces": false measures no city or coordinate rollup, so only a real province column offers
343
+ * a province map. It changes what the profile measures, so it travels in the shape rather than as a field. */
344
+ deriveProvinces: entry({ timing: "next-generate", default: true }),
300
345
  levelOfDetail: entry({ timing: "next-generate", default: "", values: ["", "High", "Medium", "Low"], wire: "clientHints" }),
301
346
  favorLimitTo: entry({ timing: "next-generate", default: "", values: ["", "latest", "top / greatest", "bottom / smallest", "most common", "outliers"], wire: "clientHints" }),
302
347
  /** 0 asks for no limit, and travels as absent (`wireLimitCount`): any value the server receives is a limit. */
@@ -911,6 +956,133 @@ function safely(fn) {
911
956
  }
912
957
  }
913
958
 
959
+ // src/shareRate.ts
960
+ var TARGET_ID = /^[a-z0-9]{1,8}$/;
961
+ function httpsUrl(raw) {
962
+ if (typeof raw !== "string" || !raw) return null;
963
+ try {
964
+ const u2 = new URL(raw);
965
+ return u2.protocol === "https:" ? u2.href : null;
966
+ } catch {
967
+ return null;
968
+ }
969
+ }
970
+ function shareRateLineModel(ask) {
971
+ if (!ask || typeof ask !== "object") return null;
972
+ const rateUrl = httpsUrl(ask.rateUrl ?? ask.RateUrl);
973
+ const share = [];
974
+ const seen = /* @__PURE__ */ new Set();
975
+ for (const t2 of ask.targets ?? ask.Targets ?? []) {
976
+ if (!t2 || typeof t2 !== "object") continue;
977
+ const id = String(t2.id ?? t2.Id ?? "");
978
+ const label = String(t2.label ?? t2.Label ?? "").trim();
979
+ const url = httpsUrl(t2.url ?? t2.Url);
980
+ if (!TARGET_ID.test(id) || !label || !url || seen.has(id)) continue;
981
+ seen.add(id);
982
+ share.push({ id, label, url });
983
+ }
984
+ if (!rateUrl && share.length === 0) return null;
985
+ return { share, rateUrl };
986
+ }
987
+ var DEFAULT_TEXT3 = {
988
+ lead: "Like it? Share it on",
989
+ separator: " \xB7 ",
990
+ or: ", or",
991
+ rate: "rate it on AppSource",
992
+ rateAlone: "Like it? Rate it on AppSource",
993
+ note: "Your ratings and feedback encourage us to do more.",
994
+ thanks: "Thanks for rating it.",
995
+ rateToo: "Rate it on AppSource too",
996
+ shareMenu: "Share it"
997
+ };
998
+ function mountShareRateLine(container, opts) {
999
+ const model = shareRateLineModel(opts.ask);
1000
+ if (!model) return null;
1001
+ const doc = container.ownerDocument ?? document;
1002
+ const text = { ...DEFAULT_TEXT3, ...opts.text ?? {} };
1003
+ const wrap = doc.createElement("div");
1004
+ wrap.className = "bic-share-rate" + (opts.className ? " " + opts.className : "");
1005
+ const span = (cls, s2) => {
1006
+ const el = doc.createElement("span");
1007
+ el.className = cls;
1008
+ el.textContent = s2;
1009
+ return el;
1010
+ };
1011
+ const link = (cls, label, url, onClick) => {
1012
+ const a2 = doc.createElement("a");
1013
+ a2.className = cls;
1014
+ a2.href = url;
1015
+ a2.textContent = label;
1016
+ a2.rel = "noopener noreferrer";
1017
+ a2.addEventListener("click", (e2) => {
1018
+ e2.preventDefault();
1019
+ safely2(() => opts.open(url));
1020
+ safely2(onClick);
1021
+ });
1022
+ return a2;
1023
+ };
1024
+ const appendNetworks = (into) => model.share.forEach((t2, i2) => {
1025
+ if (i2 > 0) into.append(span("bic-share-rate-sep", text.separator));
1026
+ const a2 = link("bic-share-rate-share", t2.label, t2.url, () => opts.onShare?.(t2.id));
1027
+ a2.setAttribute("data-target", t2.id);
1028
+ into.append(a2);
1029
+ });
1030
+ if (opts.layout === "menu") {
1031
+ wrap.setAttribute("data-layout", "menu");
1032
+ wrap.append(span("bic-share-rate-lead", text.thanks + " "));
1033
+ if (model.rateUrl) wrap.append(link("bic-share-rate-rate", text.rateToo, model.rateUrl, () => opts.onRate?.()));
1034
+ if (model.share.length > 0) {
1035
+ if (model.rateUrl) wrap.append(span("bic-share-rate-sep", text.separator));
1036
+ const toggle = doc.createElement("button");
1037
+ toggle.type = "button";
1038
+ toggle.className = "bic-share-rate-toggle";
1039
+ toggle.textContent = text.shareMenu;
1040
+ toggle.setAttribute("aria-expanded", "false");
1041
+ const menu = doc.createElement("span");
1042
+ menu.className = "bic-share-rate-menu";
1043
+ menu.hidden = true;
1044
+ menu.append(span("bic-share-rate-menu-gap", " "));
1045
+ appendNetworks(menu);
1046
+ toggle.addEventListener("click", () => {
1047
+ const open = menu.hidden;
1048
+ menu.hidden = !open;
1049
+ toggle.setAttribute("aria-expanded", String(open));
1050
+ if (open) safely2(() => opts.onMenu?.());
1051
+ });
1052
+ wrap.append(toggle, menu);
1053
+ }
1054
+ } else if (model.share.length > 0) {
1055
+ wrap.append(span("bic-share-rate-lead", text.lead + " "));
1056
+ appendNetworks(wrap);
1057
+ if (model.rateUrl) {
1058
+ wrap.append(span("bic-share-rate-or", text.or + " "));
1059
+ wrap.append(link("bic-share-rate-rate", text.rate, model.rateUrl, () => opts.onRate?.()));
1060
+ }
1061
+ wrap.append(span("bic-share-rate-end", "."));
1062
+ } else {
1063
+ wrap.append(link("bic-share-rate-rate", text.rateAlone, model.rateUrl, () => opts.onRate?.()));
1064
+ wrap.append(span("bic-share-rate-end", "."));
1065
+ }
1066
+ if (text.note && opts.layout !== "menu") wrap.append(span("bic-share-rate-note", " " + text.note));
1067
+ const stop = (e2) => e2.stopPropagation();
1068
+ wrap.addEventListener("click", stop);
1069
+ container.appendChild(wrap);
1070
+ safely2(() => opts.onShown?.());
1071
+ return {
1072
+ element: wrap,
1073
+ destroy() {
1074
+ wrap.removeEventListener("click", stop);
1075
+ wrap.remove();
1076
+ }
1077
+ };
1078
+ }
1079
+ function safely2(fn) {
1080
+ try {
1081
+ fn();
1082
+ } catch {
1083
+ }
1084
+ }
1085
+
914
1086
  // src/qualifyGroups.ts
915
1087
  function newQualifyGroupState() {
916
1088
  return { preview: false, previewClosed: false, projected: false, notRecommended: false, rankedSeen: false };
@@ -2125,7 +2297,7 @@ function fingerprintComponentDigest(components) {
2125
2297
 
2126
2298
  // src/index.ts
2127
2299
  function registerCityTable(packed) {
2128
- _3(packed);
2300
+ Kt(packed);
2129
2301
  }
2130
2302
  export {
2131
2303
  ACTIVE_TICK_CLASS,
@@ -2164,6 +2336,7 @@ export {
2164
2336
  CONTAINER_SLOT_UI_STATE,
2165
2337
  CONTAINER_SLOT_XF_CLEAR,
2166
2338
  CONTROL_CLASS,
2339
+ CSV_MIME,
2167
2340
  D3_PLUGIN_PACKAGES,
2168
2341
  DARK_TEXT,
2169
2342
  DEFAULT_FILTER_MATCH_STYLE,
@@ -2173,6 +2346,7 @@ export {
2173
2346
  DIM_OPACITY_VAR,
2174
2347
  DRAG_NOT_CLICK_PX,
2175
2348
  DUPLICATE_GENERATE_WINDOW_MS,
2349
+ EXPORT_FORMATS,
2176
2350
  FILTER_MIN_HEIGHT_PX,
2177
2351
  FILTER_MIN_TERM_CHARS,
2178
2352
  FILTER_MIN_WIDTH_PX,
@@ -2228,6 +2402,7 @@ export {
2228
2402
  MIN_DELTA_E,
2229
2403
  MIN_HIT_BAND_PX,
2230
2404
  MIN_RAMP_FILLS,
2405
+ NOTE_STYLE_ATTR,
2231
2406
  NO_ROW_MARKS_ATTR,
2232
2407
  OPTIONS_VOCABULARY,
2233
2408
  PAGE_MATCH_TOLERANCE,
@@ -2270,6 +2445,7 @@ export {
2270
2445
  VIEW_ONLY_UI_STATE_KEYS,
2271
2446
  WHITE_TEXT_BG_LUM,
2272
2447
  XFILTER_REFRESH_EVENT,
2448
+ XLSX_MIME,
2273
2449
  actionFor,
2274
2450
  applyLabelContrast,
2275
2451
  armGenerateGuard,
@@ -2281,11 +2457,14 @@ export {
2281
2457
  backingHoldsGlyph,
2282
2458
  bareBase64,
2283
2459
  blankRenderFlag,
2460
+ browserSaveFile,
2461
+ buildExportFile,
2284
2462
  buildPalette,
2285
2463
  buildPaletteFromSeed,
2286
2464
  buildProductFeedbackPayload,
2287
2465
  buildRenderPayload,
2288
2466
  buildReviewWire,
2467
+ bytesToBase64,
2289
2468
  canConfirmLaunch,
2290
2469
  canShowLastChart,
2291
2470
  captureSvgSnapshot,
@@ -2328,7 +2507,13 @@ export {
2328
2507
  dispatchRowSet,
2329
2508
  encodePendingGenerate,
2330
2509
  ensureCrossfilterHitTargets,
2510
+ excelNumberFormat,
2511
+ excelSerial,
2331
2512
  explainRenderFailure,
2513
+ exportFileName,
2514
+ exportFormatsFor,
2515
+ sheetName as exportSheetName,
2516
+ exportTableService,
2332
2517
  filterFitsChooser,
2333
2518
  filterMatchStyleOf,
2334
2519
  filterQualifyRows,
@@ -2344,6 +2529,7 @@ export {
2344
2529
  glyphSampleGrid,
2345
2530
  hasRefusalsToShow,
2346
2531
  hitBandFlag,
2532
+ hostLinkServices,
2347
2533
  htmlNaturalSize,
2348
2534
  htmlToSvgDataUrl,
2349
2535
  inlineFilterGate,
@@ -2379,6 +2565,7 @@ export {
2379
2565
  measureContainerBoxes,
2380
2566
  minContrastOver,
2381
2567
  mountProductFeedbackBox,
2568
+ mountShareRateLine,
2382
2569
  needsScroll,
2383
2570
  newIdScope,
2384
2571
  newQualifyGroupState,
@@ -2451,6 +2638,7 @@ export {
2451
2638
  selectionRuleOf,
2452
2639
  servedCorrelationProves,
2453
2640
  sessionViewStateProvider,
2641
+ shareRateLineModel,
2454
2642
  shouldCaptureThumbnail,
2455
2643
  shouldOpenChooserOnGenerate,
2456
2644
  shouldOpenInlineChooserOnGenerate,
@@ -2466,6 +2654,8 @@ export {
2466
2654
  svgToDataUrl,
2467
2655
  syncMemberSelection,
2468
2656
  tableHostOf,
2657
+ tableToCsv,
2658
+ tableToXlsx,
2469
2659
  takeScroll,
2470
2660
  toRGBA,
2471
2661
  toSourceRows,
@@ -2,13 +2,13 @@
2
2
  import {
3
3
  chartSvgOf,
4
4
  tableHostOf
5
- } from "./chunk-PMA56BKD.mjs";
5
+ } from "./chunk-PA5V6J6K.mjs";
6
6
  import {
7
7
  FIT_CONTENT_SELECTOR,
8
8
  ctmScaleOf,
9
9
  isPhantomBox
10
- } from "./chunk-3JBJ2SIF.mjs";
11
- import "./chunk-M7MBTLDP.mjs";
10
+ } from "./chunk-IE7TM6DX.mjs";
11
+ import "./chunk-7XRQUFVH.mjs";
12
12
  import "./chunk-GHODWOAL.mjs";
13
13
 
14
14
  // src/legendFit/legendReconcile.ts
package/dist/page.mjs CHANGED
@@ -14,10 +14,10 @@ import {
14
14
  readControls,
15
15
  viewFromToken,
16
16
  viewToken
17
- } from "./chunk-WSNDXS3Z.mjs";
18
- import "./chunk-B6BLSIID.mjs";
19
- import "./chunk-5OCL4EFM.mjs";
20
- import "./chunk-M7MBTLDP.mjs";
17
+ } from "./chunk-TLIBO5PT.mjs";
18
+ import "./chunk-IE426WU6.mjs";
19
+ import "./chunk-P2DLK7WZ.mjs";
20
+ import "./chunk-7XRQUFVH.mjs";
21
21
  import "./chunk-GHODWOAL.mjs";
22
22
  export {
23
23
  LINKED_HOVER_CLASS,
@@ -0,0 +1,229 @@
1
+ /*! @bicharts/chart-host — Apache-2.0. Bundled reference data: GeoNames (https://www.geonames.org/) CC BY 4.0; Natural Earth and US Census/TIGER (public domain). Full text: NOTICE in this package. */
2
+ import {
3
+ geoFromCache,
4
+ registerGeo
5
+ } from "./chunk-5WTQN5DL.mjs";
6
+ import {
7
+ Si,
8
+ W,
9
+ bt
10
+ } from "./chunk-SYUJ4TPX.mjs";
11
+ import "./chunk-A2GMXZP7.mjs";
12
+ import "./chunk-GHODWOAL.mjs";
13
+
14
+ // src/provinceGeo.ts
15
+ var PROVINCE_REGIONS = ["europe", "asia", "africa", "south-america", "north-america", "oceania"];
16
+ function provinceGeoPath(region) {
17
+ return `/geo/admin1-${String(region).toLowerCase()}.v1.json`;
18
+ }
19
+ function provinceGeoKey(region) {
20
+ return `admin1:${String(region).toLowerCase()}`;
21
+ }
22
+ function geoKeyFor(res) {
23
+ if (res.geoGrain && res.geoGrain.toLowerCase() === "admin1" && res.geoRegion) return provinceGeoKey(res.geoRegion);
24
+ return res.geoKind ?? null;
25
+ }
26
+ var inflight = /* @__PURE__ */ new Map();
27
+ async function loadProvinceGeo(region, opts = {}) {
28
+ const key = provinceGeoKey(region);
29
+ const cached = geoFromCache(key);
30
+ if (cached) return cached;
31
+ if (!PROVINCE_REGIONS.includes(String(region).toLowerCase())) return void 0;
32
+ const url = opts.url ?? (opts.origin ? opts.origin.replace(/\/+$/, "") : "") + provinceGeoPath(region);
33
+ let p = inflight.get(key);
34
+ if (!p) {
35
+ const started = Date.now();
36
+ p = (async () => {
37
+ try {
38
+ const doc = opts.fetchJson ? await opts.fetchJson(url) : await (await fetch(url, { credentials: "omit" })).json();
39
+ if (!doc || doc.type !== "FeatureCollection" || !Array.isArray(doc.features) || doc.features.length === 0)
40
+ throw new Error("not a FeatureCollection");
41
+ registerGeo(key, doc);
42
+ opts.log?.("province-geo-loaded", { region, ms: Date.now() - started, features: doc.features.length });
43
+ return doc;
44
+ } catch (e) {
45
+ opts.log?.("province-geo-failed", { region, url, error: String(e).slice(0, 200) });
46
+ return void 0;
47
+ } finally {
48
+ inflight.delete(key);
49
+ }
50
+ })();
51
+ inflight.set(key, p);
52
+ }
53
+ return p;
54
+ }
55
+ var PROVINCE_SNAP_DEG = 0.05;
56
+ function shapesOf(geo) {
57
+ const out = [];
58
+ for (const f of geo?.features ?? []) {
59
+ const g = f?.geometry;
60
+ if (!g || f?.properties?.kind === "border" || f.id === null || f.id === void 0) continue;
61
+ const polys = g.type === "Polygon" ? [g.coordinates] : g.type === "MultiPolygon" ? g.coordinates : [];
62
+ if (!polys.length) continue;
63
+ let x0 = Infinity, y0 = Infinity, x1 = -Infinity, y1 = -Infinity;
64
+ for (const poly of polys) for (const [x, y] of poly[0] ?? []) {
65
+ if (x < x0) x0 = x;
66
+ if (x > x1) x1 = x;
67
+ if (y < y0) y0 = y;
68
+ if (y > y1) y1 = y;
69
+ }
70
+ out.push({ id: String(f.id), polys, box: [x0, y0, x1, y1] });
71
+ }
72
+ return out;
73
+ }
74
+ function inRing(x, y, ring) {
75
+ let inside = false;
76
+ for (let i = 0, j = ring.length - 1; i < ring.length; j = i++) {
77
+ const [xi, yi] = ring[i], [xj, yj] = ring[j];
78
+ if (yi > y !== yj > y && x < (xj - xi) * (y - yi) / (yj - yi) + xi) inside = !inside;
79
+ }
80
+ return inside;
81
+ }
82
+ function inShape(x, y, s) {
83
+ if (x < s.box[0] || x > s.box[2] || y < s.box[1] || y > s.box[3]) return false;
84
+ return s.polys.some((poly) => poly.length > 0 && inRing(x, y, poly[0]) && !poly.slice(1).some((h) => inRing(x, y, h)));
85
+ }
86
+ function segDist2(px, py, ax, ay, bx, by) {
87
+ const dx = bx - ax, dy = by - ay;
88
+ const t = dx === 0 && dy === 0 ? 0 : Math.max(0, Math.min(1, ((px - ax) * dx + (py - ay) * dy) / (dx * dx + dy * dy)));
89
+ const ex = ax + t * dx - px, ey = ay + t * dy - py;
90
+ return ex * ex + ey * ey;
91
+ }
92
+ var locators = /* @__PURE__ */ new WeakMap();
93
+ function provinceLocator(geo, snapDeg = PROVINCE_SNAP_DEG) {
94
+ if (geo && typeof geo === "object" && snapDeg === PROVINCE_SNAP_DEG) {
95
+ const hit = locators.get(geo);
96
+ if (hit) return hit;
97
+ }
98
+ const shapes = shapesOf(geo);
99
+ const locate = (lat, lon) => {
100
+ if (!isFinite(lat) || !isFinite(lon)) return null;
101
+ for (const x of [lon, lon + 360, lon - 360]) {
102
+ for (const s of shapes) if (inShape(x, lat, s)) return s.id;
103
+ }
104
+ const k = Math.cos(lat * Math.PI / 180) || 1e-6;
105
+ let best = null, bestD = snapDeg * snapDeg;
106
+ for (const s of shapes) {
107
+ if (lon < s.box[0] - snapDeg / k || lon > s.box[2] + snapDeg / k || lat < s.box[1] - snapDeg || lat > s.box[3] + snapDeg) continue;
108
+ for (const poly of s.polys) for (const ring of poly) for (let i = 1; i < ring.length; i++) {
109
+ const d = segDist2(lon * k, lat, ring[i - 1][0] * k, ring[i - 1][1], ring[i][0] * k, ring[i][1]);
110
+ if (d <= bestD) {
111
+ bestD = d;
112
+ best = s.id;
113
+ }
114
+ }
115
+ }
116
+ return best;
117
+ };
118
+ if (geo && typeof geo === "object" && snapDeg === PROVINCE_SNAP_DEG) locators.set(geo, locate);
119
+ return locate;
120
+ }
121
+
122
+ // src/admin1LookupLoader.ts
123
+ var ADMIN1_LOOKUP_PATH = "/geo/admin1-lookup.v1.json";
124
+ var inflight2 = null;
125
+ async function loadAdmin1Lookup(url, opts = {}) {
126
+ if (W()) return true;
127
+ const log = opts.log;
128
+ if (!inflight2) {
129
+ const started = Date.now();
130
+ inflight2 = (async () => {
131
+ try {
132
+ const doc = opts.fetchJson ? await opts.fetchJson(url) : await (await fetch(url, { credentials: "omit" })).json();
133
+ const counts = bt(doc);
134
+ log?.("admin1-lookup-loaded", { url, ms: Date.now() - started, ...counts });
135
+ return true;
136
+ } catch (e) {
137
+ log?.("admin1-lookup-failed", { url, ms: Date.now() - started, error: String(e).slice(0, 200) });
138
+ inflight2 = null;
139
+ return false;
140
+ }
141
+ })();
142
+ }
143
+ const timeoutMs = opts.timeoutMs ?? 3e3;
144
+ let timer;
145
+ const timeout = new Promise((resolve) => {
146
+ timer = setTimeout(() => {
147
+ log?.("admin1-lookup-timeout", { url, timeoutMs });
148
+ resolve(false);
149
+ }, timeoutMs);
150
+ });
151
+ try {
152
+ return await Promise.race([inflight2, timeout]);
153
+ } finally {
154
+ if (timer) clearTimeout(timer);
155
+ }
156
+ }
157
+ var PLACE_TOKENS = /(^|[^a-z])(city|cities|town|ville|stadt|ciudad|citta|cidade|state|province|provincia|provinz|county|department|departement|departamento|prefecture|oblast|canton|kanton|bundesland|municipality)([^a-z]|$)/i;
158
+ function needsAdmin1Lookup(columns) {
159
+ if (!columns) return false;
160
+ const geographic = columns.some((c) => {
161
+ const kind = (c?.geoKind ?? "").toLowerCase();
162
+ return kind.startsWith("country") || kind.startsWith("city");
163
+ });
164
+ if (geographic) return true;
165
+ return columns.some((c) => !!c && !c.isMeasure && !!c.name && PLACE_TOKENS.test(c.name.replace(/[_-]+/g, " ")));
166
+ }
167
+
168
+ // src/provinceHost.ts
169
+ async function prepareProvinceProfile(profile, opts) {
170
+ if (!profile || typeof profile.getColumnsWithStats !== "function") return;
171
+ let invalidate = false;
172
+ if (profile.deriveProvinces !== opts.deriveProvinces) {
173
+ profile.deriveProvinces = opts.deriveProvinces;
174
+ invalidate = true;
175
+ }
176
+ const origin = typeof opts.origin === "string" ? opts.origin.trim() : "";
177
+ if (!W() && origin) {
178
+ let cols = [];
179
+ try {
180
+ cols = profile.getColumnsWithStats(opts.privacyLevel, opts.locale);
181
+ } catch {
182
+ }
183
+ if (needsAdmin1Lookup(cols)) {
184
+ const ok = await loadAdmin1Lookup(
185
+ origin.replace(/\/+$/, "") + ADMIN1_LOOKUP_PATH,
186
+ { timeoutMs: opts.timeoutMs ?? 3e3, fetchJson: opts.fetchJson, log: opts.log }
187
+ );
188
+ invalidate = invalidate || ok;
189
+ }
190
+ }
191
+ if (invalidate) profile.invalidateStats?.();
192
+ }
193
+ function provinceBinding(res, cols, opts) {
194
+ if (!res.geoColumn || !res.geoKind) return null;
195
+ if (String(res.geoGrain ?? "").toLowerCase() !== "admin1") return { column: res.geoColumn, kind: res.geoKind };
196
+ const dims = cols.filter((c) => !c.isMeasure && c.name !== res.geoColumn);
197
+ const kindOf = (c) => String(c.geoKind ?? "");
198
+ const words = (n) => n.replace(/([a-z])([A-Z])/g, "$1 $2").toLowerCase().split(/[^a-z]+/);
199
+ const named = (re) => cols.find((c) => words(c.name).some((w) => re.test(w)))?.name ?? null;
200
+ return {
201
+ column: res.geoColumn,
202
+ kind: res.geoKind,
203
+ grain: "admin1",
204
+ region: res.geoRegion || null,
205
+ fallback: {
206
+ city: dims.find((c) => kindOf(c).startsWith("city"))?.name ?? null,
207
+ country: dims.find((c) => kindOf(c).startsWith("country"))?.name ?? null,
208
+ lat: named(/^(lat|latitude)$/),
209
+ lon: named(/^(lon|lng|long|longitude)$/)
210
+ },
211
+ deriveProvinces: opts.deriveProvinces,
212
+ join: Si,
213
+ locate: opts.geo ? provinceLocator(opts.geo) : null
214
+ };
215
+ }
216
+ function geoKeyOfFields(res) {
217
+ return geoKeyFor({ geoKind: res.geoKind, geoRegion: res.geoRegion, geoGrain: res.geoGrain });
218
+ }
219
+ export {
220
+ ADMIN1_LOOKUP_PATH,
221
+ geoKeyFor,
222
+ geoKeyOfFields,
223
+ loadAdmin1Lookup,
224
+ loadProvinceGeo,
225
+ needsAdmin1Lookup,
226
+ prepareProvinceProfile,
227
+ provinceBinding,
228
+ provinceLocator
229
+ };