@bicharts/chart-host 0.6.1 → 0.6.3

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/README.md CHANGED
@@ -2,16 +2,15 @@
2
2
 
3
3
  > **Make Generative AI for Charts *Better*.**
4
4
 
5
- That is what **RegiaBI** is for; this package is the part that runs the result in your page,
6
- so a generated chart behaves the same wherever it lands.
5
+ Describe the chart you want, or just hand over the data, and RegiaBI gives you back a working, interactive chart that fits your data on the first try — as source code you own. It goes into your repo and runs in the framework you already use: React, a plain web page, or whatever your coding agent is scaffolding. At run time there's no key, no call to us and nothing to pay per render: `@bicharts/chart-host`, the open-source runtime, makes the chart behave in your page — clicks, cross-filtering, selection — so that's code you don't have to write. You start from something that already works and spend your time on the last ten percent, in plain language or in the code itself; reading the code is an advantage, never the price of entry. And because the engine knows what each chart type can honestly say, it'll sometimes show you a view of your data you hadn't thought to ask for.
7
6
 
8
- Run a D3 chart generated by
9
- [Business Intelligence Champions](https://bizintelligencechampions.com) (BIC) in any web page.
7
+ **[Live demo](https://codexguy.github.io/bicharts-react-demo/)** ·
8
+ [RegiaBI for developers](https://bizintelligencechampions.com/regiabi/developers?loc=npmhost)
10
9
 
11
- A BIC chart is *generated source you own* — a plain `render(container, data, options)` function
12
- you commit to your repo. There is no API key at run time, no per-render cost, and no network
13
- call. This package is the host side: the ~80 lines every integrator would otherwise write, and
14
- the handful they would get subtly wrong.
10
+ This package is the runtime: it makes the chart you were handed behave in your page. A
11
+ generated chart is a plain `render(container, data, options)` function you commit to your repo,
12
+ and this is the host side — the ~80 lines every integrator would otherwise write, and the
13
+ handful they would get subtly wrong.
15
14
 
16
15
  It is the same contract the BIC Power BI visual implements, minus Power BI — so a chart looks
17
16
  and behaves the same wherever it runs.
@@ -211,55 +211,55 @@ var require_papaparse_min = __commonJS({
211
211
  return e.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
212
212
  }
213
213
  function E4(C) {
214
- var S = (C = C || {}).delimiter, O3 = C.newline, x4 = C.comments, I2 = C.step, A = C.preview, T3 = C.fastMode, D3 = null, L2 = false, F4 = null == C.quoteChar ? '"' : C.quoteChar, j3 = F4;
215
- if (void 0 !== C.escapeChar && (j3 = C.escapeChar), ("string" != typeof S || -1 < v2.BAD_DELIMITERS.indexOf(S)) && (S = ","), x4 === S) throw new Error("Comment character same as delimiter");
216
- true === x4 ? x4 = "#" : ("string" != typeof x4 || -1 < v2.BAD_DELIMITERS.indexOf(x4)) && (x4 = false), "\n" !== O3 && "\r" !== O3 && "\r\n" !== O3 && (O3 = "\n");
214
+ var S2 = (C = C || {}).delimiter, O3 = C.newline, x3 = C.comments, I2 = C.step, A = C.preview, T3 = C.fastMode, D4 = null, L2 = false, F3 = null == C.quoteChar ? '"' : C.quoteChar, j3 = F3;
215
+ if (void 0 !== C.escapeChar && (j3 = C.escapeChar), ("string" != typeof S2 || -1 < v2.BAD_DELIMITERS.indexOf(S2)) && (S2 = ","), x3 === S2) throw new Error("Comment character same as delimiter");
216
+ true === x3 ? x3 = "#" : ("string" != typeof x3 || -1 < v2.BAD_DELIMITERS.indexOf(x3)) && (x3 = false), "\n" !== O3 && "\r" !== O3 && "\r\n" !== O3 && (O3 = "\n");
217
217
  var z3 = 0, M2 = false;
218
218
  this.parse = function(i2, t, r2) {
219
219
  if ("string" != typeof i2) throw new Error("Input must be a string");
220
- var n2 = i2.length, e = S.length, s2 = O3.length, a5 = x4.length, o2 = q4(I2), h4 = [], u4 = [], d3 = [], f5 = z3 = 0;
221
- if (!i2) return w3();
222
- if (T3 || false !== T3 && -1 === i2.indexOf(F4)) {
220
+ var n2 = i2.length, e = S2.length, s2 = O3.length, a5 = x3.length, o2 = q4(I2), h4 = [], u4 = [], d3 = [], f5 = z3 = 0;
221
+ if (!i2) return w2();
222
+ if (T3 || false !== T3 && -1 === i2.indexOf(F3)) {
223
223
  for (var l2 = i2.split(O3), c4 = 0; c4 < l2.length; c4++) {
224
224
  if (d3 = l2[c4], z3 += d3.length, c4 !== l2.length - 1) z3 += O3.length;
225
- else if (r2) return w3();
226
- if (!x4 || d3.substring(0, a5) !== x4) {
225
+ else if (r2) return w2();
226
+ if (!x3 || d3.substring(0, a5) !== x3) {
227
227
  if (o2) {
228
- if (h4 = [], k2(d3.split(S)), R2(), M2) return w3();
229
- } else k2(d3.split(S));
230
- if (A && A <= c4) return h4 = h4.slice(0, A), w3(true);
228
+ if (h4 = [], k2(d3.split(S2)), R2(), M2) return w2();
229
+ } else k2(d3.split(S2));
230
+ if (A && A <= c4) return h4 = h4.slice(0, A), w2(true);
231
231
  }
232
232
  }
233
- return w3();
233
+ return w2();
234
234
  }
235
- for (var p4 = i2.indexOf(S, z3), g4 = i2.indexOf(O3, z3), _3 = new RegExp(U2(j3) + U2(F4), "g"), m4 = i2.indexOf(F4, z3); ; ) if (i2[z3] === F4) for (m4 = z3, z3++; ; ) {
236
- if (-1 === (m4 = i2.indexOf(F4, m4 + 1))) return r2 || u4.push({ type: "Quotes", code: "MissingQuotes", message: "Quoted field unterminated", row: h4.length, index: z3 }), E5();
237
- if (m4 === n2 - 1) return E5(i2.substring(z3, m4).replace(_3, F4));
238
- if (F4 === j3 && i2[m4 + 1] === j3) m4++;
239
- else if (F4 === j3 || 0 === m4 || i2[m4 - 1] !== j3) {
240
- -1 !== p4 && p4 < m4 + 1 && (p4 = i2.indexOf(S, m4 + 1));
235
+ for (var p4 = i2.indexOf(S2, z3), g4 = i2.indexOf(O3, z3), _3 = new RegExp(U2(j3) + U2(F3), "g"), m4 = i2.indexOf(F3, z3); ; ) if (i2[z3] === F3) for (m4 = z3, z3++; ; ) {
236
+ if (-1 === (m4 = i2.indexOf(F3, m4 + 1))) return r2 || u4.push({ type: "Quotes", code: "MissingQuotes", message: "Quoted field unterminated", row: h4.length, index: z3 }), E5();
237
+ if (m4 === n2 - 1) return E5(i2.substring(z3, m4).replace(_3, F3));
238
+ if (F3 === j3 && i2[m4 + 1] === j3) m4++;
239
+ else if (F3 === j3 || 0 === m4 || i2[m4 - 1] !== j3) {
240
+ -1 !== p4 && p4 < m4 + 1 && (p4 = i2.indexOf(S2, m4 + 1));
241
241
  var y6 = v3(-1 === (g4 = -1 !== g4 && g4 < m4 + 1 ? i2.indexOf(O3, m4 + 1) : g4) ? p4 : Math.min(p4, g4));
242
- if (i2.substr(m4 + 1 + y6, e) === S) {
243
- d3.push(i2.substring(z3, m4).replace(_3, F4)), i2[z3 = m4 + 1 + y6 + e] !== F4 && (m4 = i2.indexOf(F4, z3)), p4 = i2.indexOf(S, z3), g4 = i2.indexOf(O3, z3);
242
+ if (i2.substr(m4 + 1 + y6, e) === S2) {
243
+ d3.push(i2.substring(z3, m4).replace(_3, F3)), i2[z3 = m4 + 1 + y6 + e] !== F3 && (m4 = i2.indexOf(F3, z3)), p4 = i2.indexOf(S2, z3), g4 = i2.indexOf(O3, z3);
244
244
  break;
245
245
  }
246
246
  y6 = v3(g4);
247
247
  if (i2.substring(m4 + 1 + y6, m4 + 1 + y6 + s2) === O3) {
248
- if (d3.push(i2.substring(z3, m4).replace(_3, F4)), b5(m4 + 1 + y6 + s2), p4 = i2.indexOf(S, z3), m4 = i2.indexOf(F4, z3), o2 && (R2(), M2)) return w3();
249
- if (A && h4.length >= A) return w3(true);
248
+ if (d3.push(i2.substring(z3, m4).replace(_3, F3)), b5(m4 + 1 + y6 + s2), p4 = i2.indexOf(S2, z3), m4 = i2.indexOf(F3, z3), o2 && (R2(), M2)) return w2();
249
+ if (A && h4.length >= A) return w2(true);
250
250
  break;
251
251
  }
252
252
  u4.push({ type: "Quotes", code: "InvalidQuotes", message: "Trailing quote on quoted field is malformed", row: h4.length, index: z3 }), m4++;
253
253
  }
254
254
  }
255
- else if (x4 && 0 === d3.length && i2.substring(z3, z3 + a5) === x4) {
256
- if (-1 === g4) return w3();
257
- z3 = g4 + s2, g4 = i2.indexOf(O3, z3), p4 = i2.indexOf(S, z3);
258
- } else if (-1 !== p4 && (p4 < g4 || -1 === g4)) d3.push(i2.substring(z3, p4)), z3 = p4 + e, p4 = i2.indexOf(S, z3);
255
+ else if (x3 && 0 === d3.length && i2.substring(z3, z3 + a5) === x3) {
256
+ if (-1 === g4) return w2();
257
+ z3 = g4 + s2, g4 = i2.indexOf(O3, z3), p4 = i2.indexOf(S2, z3);
258
+ } else if (-1 !== p4 && (p4 < g4 || -1 === g4)) d3.push(i2.substring(z3, p4)), z3 = p4 + e, p4 = i2.indexOf(S2, z3);
259
259
  else {
260
260
  if (-1 === g4) break;
261
- if (d3.push(i2.substring(z3, g4)), b5(g4 + s2), o2 && (R2(), M2)) return w3();
262
- if (A && h4.length >= A) return w3(true);
261
+ if (d3.push(i2.substring(z3, g4)), b5(g4 + s2), o2 && (R2(), M2)) return w2();
262
+ if (A && h4.length >= A) return w2(true);
263
263
  }
264
264
  return E5();
265
265
  function k2(e2) {
@@ -270,12 +270,12 @@ var require_papaparse_min = __commonJS({
270
270
  return t2 = -1 !== e2 && (e2 = i2.substring(m4 + 1, e2)) && "" === e2.trim() ? e2.length : t2;
271
271
  }
272
272
  function E5(e2) {
273
- return r2 || (void 0 === e2 && (e2 = i2.substring(z3)), d3.push(e2), z3 = n2, k2(d3), o2 && R2()), w3();
273
+ return r2 || (void 0 === e2 && (e2 = i2.substring(z3)), d3.push(e2), z3 = n2, k2(d3), o2 && R2()), w2();
274
274
  }
275
275
  function b5(e2) {
276
276
  z3 = e2, k2(d3), d3 = [], g4 = i2.indexOf(O3, z3);
277
277
  }
278
- function w3(e2) {
278
+ function w2(e2) {
279
279
  if (C.header && !t && h4.length && !L2) {
280
280
  var s4 = h4[0], a6 = /* @__PURE__ */ Object.create(null), o4 = new Set(s4);
281
281
  let n4 = false;
@@ -284,16 +284,16 @@ var require_papaparse_min = __commonJS({
284
284
  if (a6[i4 = q4(C.transformHeader) ? C.transformHeader(i4, r4) : i4]) {
285
285
  let e4, t2 = a6[i4];
286
286
  for (; e4 = i4 + "_" + t2, t2++, o4.has(e4); ) ;
287
- o4.add(e4), s4[r4] = e4, a6[i4]++, n4 = true, (D3 = null === D3 ? {} : D3)[e4] = i4;
287
+ o4.add(e4), s4[r4] = e4, a6[i4]++, n4 = true, (D4 = null === D4 ? {} : D4)[e4] = i4;
288
288
  } else a6[i4] = 1, s4[r4] = i4;
289
289
  o4.add(i4);
290
290
  }
291
291
  n4 && console.warn("Duplicate headers found and renamed."), L2 = true;
292
292
  }
293
- return { data: h4, errors: u4, meta: { delimiter: S, linebreak: O3, aborted: M2, truncated: !!e2, cursor: f5 + (t || 0), renamedHeaders: D3 } };
293
+ return { data: h4, errors: u4, meta: { delimiter: S2, linebreak: O3, aborted: M2, truncated: !!e2, cursor: f5 + (t || 0), renamedHeaders: D4 } };
294
294
  }
295
295
  function R2() {
296
- I2(w3()), h4 = [], u4 = [];
296
+ I2(w2()), h4 = [], u4 = [];
297
297
  }
298
298
  }, this.abort = function() {
299
299
  M2 = true;
@@ -435,12 +435,13 @@ var require_papaparse_min = __commonJS({
435
435
  });
436
436
 
437
437
  // src/contract.ts
438
- var HOST_CONTRACT_VERSION = "1.11.0";
438
+ var HOST_CONTRACT_VERSION = "1.12.0";
439
439
  var GEO_POINT_PRECISIONS = ["latlon", "city", "zip3", "state", "country"];
440
440
  var MARK_CLASS = "d3-mark";
441
441
  var LEGEND_MARK_CLASS = "d3-legend-mark";
442
442
  var AXIS_FILTER_CLASS = "d3-axis-filter";
443
443
  var LIFT_SELECTED_CLASS = "d3-lift-selected";
444
+ var CONTROL_CLASS = "lch-control";
444
445
  var ROW_IDX_ATTR = "data-row-idx";
445
446
  var XFILTER_REFRESH_EVENT = "llm-xfilter-refresh";
446
447
  var CONTAINER_SLOT_ANIM_STOP = "__llmAnimStop";
@@ -507,11 +508,11 @@ function f(t) {
507
508
  return t > EPS ? Math.cbrt(t) : (KAPPA * t + 16) / 116;
508
509
  }
509
510
  function rgbToLab(r, g3, b4) {
510
- const R2 = linearise(r), G2 = linearise(g3), B2 = linearise(b4);
511
- const X2 = 0.4124564 * R2 + 0.3575761 * G2 + 0.1804375 * B2;
512
- const Y2 = 0.2126729 * R2 + 0.7151522 * G2 + 0.072175 * B2;
513
- const Z3 = 0.0193339 * R2 + 0.119192 * G2 + 0.9503041 * B2;
514
- const fx = f(X2 / Xn), fy = f(Y2 / Yn), fz = f(Z3 / Zn);
511
+ const R2 = linearise(r), G3 = linearise(g3), B2 = linearise(b4);
512
+ const X2 = 0.4124564 * R2 + 0.3575761 * G3 + 0.1804375 * B2;
513
+ const Y2 = 0.2126729 * R2 + 0.7151522 * G3 + 0.072175 * B2;
514
+ const Z2 = 0.0193339 * R2 + 0.119192 * G3 + 0.9503041 * B2;
515
+ const fx = f(X2 / Xn), fy = f(Y2 / Yn), fz = f(Z2 / Zn);
515
516
  return { L: 116 * fy - 16, a: 500 * (fx - fy), b: 200 * (fy - fz) };
516
517
  }
517
518
  function hexToLab(hex2) {
@@ -527,8 +528,8 @@ function deltaE2000(c1, c2) {
527
528
  const C1 = Math.hypot(c1.a, c1.b), C2 = Math.hypot(c2.a, c2.b);
528
529
  const Cbar = (C1 + C2) / 2;
529
530
  const C7 = Math.pow(Cbar, 7);
530
- const G2 = 0.5 * (1 - Math.sqrt(C7 / (C7 + Math.pow(25, 7))));
531
- const a1p = (1 + G2) * c1.a, a2p = (1 + G2) * c2.a;
531
+ const G3 = 0.5 * (1 - Math.sqrt(C7 / (C7 + Math.pow(25, 7))));
532
+ const a1p = (1 + G3) * c1.a, a2p = (1 + G3) * c2.a;
532
533
  const C1p = Math.hypot(a1p, c1.b), C2p = Math.hypot(a2p, c2.b);
533
534
  const neutral = C1p < NEUTRAL_CHROMA || C2p < NEUTRAL_CHROMA;
534
535
  const h1p = C1p < NEUTRAL_CHROMA ? 0 : (Math.atan2(c1.b, a1p) * DEG + 360) % 360;
@@ -568,11 +569,11 @@ function labToHex(lab) {
568
569
  const fy = (lab.L + 16) / 116, fx = fy + lab.a / 500, fz = fy - lab.b / 200;
569
570
  const X2 = Xn * finv(fx);
570
571
  const Y2 = Yn * (lab.L > KAPPA * EPS ? fy * fy * fy : lab.L / KAPPA);
571
- const Z3 = Zn * finv(fz);
572
+ const Z2 = Zn * finv(fz);
572
573
  const lin = [
573
- 3.2404542 * X2 - 1.5371385 * Y2 - 0.4985314 * Z3,
574
- -0.969266 * X2 + 1.8760108 * Y2 + 0.041556 * Z3,
575
- 0.0556434 * X2 - 0.2040259 * Y2 + 1.0572252 * Z3
574
+ 3.2404542 * X2 - 1.5371385 * Y2 - 0.4985314 * Z2,
575
+ -0.969266 * X2 + 1.8760108 * Y2 + 0.041556 * Z2,
576
+ 0.0556434 * X2 - 0.2040259 * Y2 + 1.0572252 * Z2
576
577
  ];
577
578
  return "#" + lin.map((v2) => {
578
579
  const c2 = Math.max(0, Math.min(1, v2));
@@ -1237,20 +1238,20 @@ function A3(n) {
1237
1238
  if (r && i && c3(r) !== i && (r = null), n.city !== void 0 && n.city !== null) {
1238
1239
  let a4 = u(String(n.city)), s = O(a4), f4 = s ? F(s, n.mapKind) : null;
1239
1240
  if (f4 && f4.length) {
1240
- let d2 = n.state === void 0 || n.state === null ? "" : String(n.state).trim(), R2 = d2 ? u(d2) : "", g3 = d2 ? Y(d2) : null, S = [], m2 = -1;
1241
+ let d2 = n.state === void 0 || n.state === null ? "" : String(n.state).trim(), R2 = d2 ? u(d2) : "", g3 = d2 ? Y(d2) : null, S2 = [], m2 = -1;
1241
1242
  for (let c2 of f4) {
1242
1243
  let l = c2.row, A = 0;
1243
1244
  if (d2 && l.a1 !== "") if (g3 && l.a1 === g3 || u(l.a1) === R2) A++;
1244
1245
  else continue;
1245
1246
  if (i) if (T(l.cc) === i) A++;
1246
1247
  else continue;
1247
- A > m2 ? (m2 = A, S = [c2]) : A === m2 && S.push(c2);
1248
+ A > m2 ? (m2 = A, S2 = [c2]) : A === m2 && S2.push(c2);
1248
1249
  }
1249
- S.some((c2) => c2.primary) && (S = S.filter((c2) => c2.primary));
1250
+ S2.some((c2) => c2.primary) && (S2 = S2.filter((c2) => c2.primary));
1250
1251
  let p2 = /* @__PURE__ */ new Map();
1251
- for (let c2 of S) p2.set(c2.row.lon.toFixed(2) + "," + c2.row.lat.toFixed(2), c2.row);
1252
+ for (let c2 of S2) p2.set(c2.row.lon.toFixed(2) + "," + c2.row.lat.toFixed(2), c2.row);
1252
1253
  if (p2.size === 1) {
1253
- let c2 = S[0].row;
1254
+ let c2 = S2[0].row;
1254
1255
  return { lat: c2.lat, lon: c2.lon, precision: "city" };
1255
1256
  }
1256
1257
  if (p2.size > 1) return { ambiguous: true, matches: p2.size };
@@ -1273,7 +1274,7 @@ function A3(n) {
1273
1274
  var G = { latlon: 0, city: 1, zip3: 2, state: 3, country: 4 };
1274
1275
  var x = 8;
1275
1276
  function y3(n, e) {
1276
- let t = new Array(n.length), o = new Array(n.length), i = new Array(n.length), r = /* @__PURE__ */ new Set(), a4 = [], s = /* @__PURE__ */ new Set(), f4 = [], d2 = /* @__PURE__ */ new Set(), R2 = [], g3 = { latlon: 0, city: 0, zip3: 0, state: 0, country: 0 }, S = 0, m2 = 0, p2 = null;
1277
+ let t = new Array(n.length), o = new Array(n.length), i = new Array(n.length), r = /* @__PURE__ */ new Set(), a4 = [], s = /* @__PURE__ */ new Set(), f4 = [], d2 = /* @__PURE__ */ new Set(), R2 = [], g3 = { latlon: 0, city: 0, zip3: 0, state: 0, country: 0 }, S2 = 0, m2 = 0, p2 = null;
1277
1278
  for (let l = 0; l < n.length; ++l) {
1278
1279
  let A = n[l], C = A3({ ...A, mapKind: e });
1279
1280
  if (S3(C)) {
@@ -1281,7 +1282,7 @@ function y3(n, e) {
1281
1282
  let M2 = K(A);
1282
1283
  M2 && !d2.has(M2.toLowerCase()) && (d2.add(M2.toLowerCase()), R2.length < x && R2.push(M2));
1283
1284
  } else if (C) {
1284
- if (t[l] = C.lat, o[l] = C.lon, i[l] = C.precision, S++, g3[C.precision]++, (p2 === null || G[C.precision] > G[p2]) && (p2 = C.precision), G[C.precision] > G.city) {
1285
+ if (t[l] = C.lat, o[l] = C.lon, i[l] = C.precision, S2++, g3[C.precision]++, (p2 === null || G[C.precision] > G[p2]) && (p2 = C.precision), G[C.precision] > G.city) {
1285
1286
  let M2 = K(A);
1286
1287
  M2 && !s.has(M2.toLowerCase()) && (s.add(M2.toLowerCase()), f4.length < x && f4.push(M2));
1287
1288
  }
@@ -1292,7 +1293,7 @@ function y3(n, e) {
1292
1293
  }
1293
1294
  }
1294
1295
  let c2 = !n3() && n.some((l) => l.city !== null && l.city !== void 0 && String(l.city).trim() !== "");
1295
- return { lat: t, lon: o, precisions: i, precision: p2, precisionCounts: g3, coarseExamples: f4, unmatched: a4, ambiguousRows: m2, ambiguousExamples: R2, matchedRows: S, totalRows: n.length, ...c2 ? { cityTableMissing: true } : {} };
1296
+ return { lat: t, lon: o, precisions: i, precision: p2, precisionCounts: g3, coarseExamples: f4, unmatched: a4, ambiguousRows: m2, ambiguousExamples: R2, matchedRows: S2, totalRows: n.length, ...c2 ? { cityTableMissing: true } : {} };
1296
1297
  }
1297
1298
  function K(n) {
1298
1299
  let e = [n.city, n.state, n.zip, n.country].filter((t) => t != null && String(t).trim() !== "").map((t) => String(t).trim()).join(", ");
@@ -1434,11 +1435,11 @@ function It(n, s) {
1434
1435
  }
1435
1436
  function Wt(n, s) {
1436
1437
  let i = new Array(n.length), r = /* @__PURE__ */ new Set(), M2 = [], h3 = 0;
1437
- for (let N2 = 0; N2 < n.length; ++N2) {
1438
- let I2 = Mt(n[N2], s), O3 = I2 !== null && It(I2, s) ? I2 : null;
1439
- if (i[N2] = O3, O3 !== null) h3++;
1438
+ for (let N3 = 0; N3 < n.length; ++N3) {
1439
+ let I2 = Mt(n[N3], s), O3 = I2 !== null && It(I2, s) ? I2 : null;
1440
+ if (i[N3] = O3, O3 !== null) h3++;
1440
1441
  else {
1441
- let d2 = n[N2];
1442
+ let d2 = n[N3];
1442
1443
  if (d2 != null) {
1443
1444
  let p2 = String(d2).trim();
1444
1445
  if (p2.length > 0) {
@@ -1558,147 +1559,147 @@ var ct2 = new RegExp([String.raw`\bisMeasure\b`, String.raw`\bdataType\b`, Strin
1558
1559
 
1559
1560
  // ../shape-core/dist/index.mjs
1560
1561
  /*! @bicharts/shape-core — Apache-2.0. Bundled reference data: GeoNames (https://www.geonames.org/) CC BY 4.0; US Census/TIGER (public domain). Full text: NOTICE in this package. */
1561
- var E2 = 2;
1562
- var Z2 = 400;
1563
- function O2(o) {
1564
- return !!E(o);
1565
- }
1566
- function P2(o) {
1567
- let e = /* @__PURE__ */ new Set();
1568
- for (let t of o) {
1562
+ var G2 = 2;
1563
+ var q3 = 400;
1564
+ function E2(i) {
1565
+ return !!E(i);
1566
+ }
1567
+ function S(i) {
1568
+ let n = /* @__PURE__ */ new Set();
1569
+ for (let t of i) {
1569
1570
  if (t == null) continue;
1570
- let i = u(String(t));
1571
- if (!V(i) && !e.has(i) && (e.add(i), e.size >= Z2)) break;
1571
+ let r = u(String(t));
1572
+ if (!V(r) && !n.has(r) && (n.add(r), n.size >= q3)) break;
1572
1573
  }
1573
- return Array.from(e);
1574
+ return Array.from(n);
1574
1575
  }
1575
- function x3(o) {
1576
- let e = P2(o);
1577
- if (e.length === 0 || z2(o) < 95) return false;
1578
- let t = e.filter((c2) => O2(c2) && !Y(c2)).length, i = e.filter((c2) => !O2(c2) && !!Y(c2)).length;
1579
- return t >= 1 && t >= i;
1576
+ function P2(i) {
1577
+ let n = S(i);
1578
+ if (n.length === 0 || O2(i) < 95) return false;
1579
+ let t = n.filter((c2) => E2(c2) && !Y(c2)).length, r = n.filter((c2) => !E2(c2) && !!Y(c2)).length;
1580
+ return t >= 1 && t >= r;
1580
1581
  }
1581
- function j2(o, e) {
1582
- if (!Y(o)) return false;
1583
- let t = E(o);
1584
- return t ? e === "world" ? true : s3.has(t) : false;
1582
+ function V2(i, n) {
1583
+ if (!Y(i)) return false;
1584
+ let t = E(i);
1585
+ return t ? n === "world" ? true : s3.has(t) : false;
1585
1586
  }
1586
- function z2(o) {
1587
- let e = P2(o);
1588
- if (e.length === 0) return 0;
1587
+ function O2(i) {
1588
+ let n = S(i);
1589
+ if (n.length === 0) return 0;
1589
1590
  let t = 0;
1590
- for (let i of e) O2(i) && t++;
1591
- return Math.round(t / e.length * 1e3) / 10;
1591
+ for (let r of n) E2(r) && t++;
1592
+ return Math.round(t / n.length * 1e3) / 10;
1592
1593
  }
1593
- function w2(o) {
1594
- let e = P2(o);
1595
- if (e.length === 0) return 0;
1594
+ function D3(i) {
1595
+ let n = S(i);
1596
+ if (n.length === 0) return 0;
1596
1597
  let t = 0;
1597
- for (let i of e) Y(i) && t++;
1598
- return Math.round(t / e.length * 1e3) / 10;
1598
+ for (let r of n) Y(r) && t++;
1599
+ return Math.round(t / n.length * 1e3) / 10;
1599
1600
  }
1600
- function H2(o) {
1601
- let e = /* @__PURE__ */ new Set();
1602
- for (let t of o) {
1601
+ function $2(i) {
1602
+ let n = /* @__PURE__ */ new Set();
1603
+ for (let t of i) {
1603
1604
  if (t == null) continue;
1604
- let i = String(t).trim();
1605
- if (!V(u(i)) && !e.has(i) && (e.add(i), e.size >= Z2)) break;
1605
+ let r = String(t).trim();
1606
+ if (!V(u(r)) && !n.has(r) && (n.add(r), n.size >= q3)) break;
1606
1607
  }
1607
- return Array.from(e);
1608
+ return Array.from(n);
1608
1609
  }
1609
- function $2(o) {
1610
- let e = H2(o);
1611
- if (e.length === 0) return 0;
1610
+ function z2(i) {
1611
+ let n = $2(i);
1612
+ if (n.length === 0) return 0;
1612
1613
  let t = 0;
1613
- for (let i of e) Z(i).length > 0 && t++;
1614
- return Math.round(t / e.length * 1e3) / 10;
1614
+ for (let r of n) Z(r).length > 0 && t++;
1615
+ return Math.round(t / n.length * 1e3) / 10;
1615
1616
  }
1616
- function q3(o, e) {
1617
- return y2(e, rt) ? true : H2(o).some((t) => /^\d{5}(-\d{4})?$/.test(t.replace(/\.0+$/, "")));
1617
+ function j2(i, n) {
1618
+ return y2(n, rt) ? true : $2(i).some((t) => /^\d{5}(-\d{4})?$/.test(t.replace(/\.0+$/, "")));
1618
1619
  }
1619
- function yt2(o, e) {
1620
- let t = P2(o);
1620
+ function At2(i, n) {
1621
+ let t = S(i);
1621
1622
  if (t.length === 0) return 0;
1622
- let i = 0;
1623
- for (let c2 of t) p3(c2, e) && i++;
1624
- return Math.round(i / t.length * 1e3) / 10;
1623
+ let r = 0;
1624
+ for (let c2 of t) p3(c2, n) && r++;
1625
+ return Math.round(r / t.length * 1e3) / 10;
1625
1626
  }
1626
- function F3(o, e) {
1627
+ function N2(i, n) {
1627
1628
  let t = 0;
1628
- for (let i of P2(o)) e(i) && t++;
1629
+ for (let r of S(i)) n(r) && t++;
1629
1630
  return t;
1630
1631
  }
1631
- function Ct(o, e) {
1632
+ function Tt(i, n) {
1632
1633
  let t = 0;
1633
- for (let i of H2(o)) e(i) && t++;
1634
+ for (let r of $2(i)) n(r) && t++;
1634
1635
  return t;
1635
1636
  }
1636
- function ht(o, e, t, i, c2) {
1637
- let u2 = [], a4 = [], r = {}, T3 = {}, h3 = new Set(o), f4 = (n) => e.map((s) => s[n]);
1638
- for (let n of ["city", "country"]) {
1639
- let s = t?.[n];
1640
- s && h3.has(s) && (r[n] = s);
1637
+ function bt(i, n, t, r, c2) {
1638
+ let l = [], a4 = [], o = {}, R2 = {}, h3 = new Set(i), f4 = (e) => n.map((s) => s[e]);
1639
+ for (let e of ["city", "country"]) {
1640
+ let s = t?.[e];
1641
+ s && h3.has(s) && (o[e] = s);
1641
1642
  }
1642
- let Y2 = new Set(c2 ?? o);
1643
- for (let n of ["lat", "lon"]) {
1644
- let s = t?.[n];
1645
- s && Y2.has(s) && (r[n] = s);
1643
+ let Y2 = new Set(c2 ?? i);
1644
+ for (let e of ["lat", "lon"]) {
1645
+ let s = t?.[e];
1646
+ s && Y2.has(s) && (o[e] = s);
1646
1647
  }
1647
1648
  let g3 = t?.zip;
1648
1649
  if (g3 && h3.has(g3)) {
1649
- let n = f4(g3), s = $2(n);
1650
- s < 95 ? a4.push(`zip=${g3} (only ${s}% of values read as ZIPs)`) : q3(n, g3) ? r.zip = g3 : a4.push(`zip=${g3} (all values are 3-4 digits with nothing to say they are postal)`);
1650
+ let e = f4(g3), s = z2(e);
1651
+ s < 95 ? a4.push(`zip=${g3} (only ${s}% of values read as ZIPs)`) : j2(e, g3) ? o.zip = g3 : a4.push(`zip=${g3} (all values are 3-4 digits with nothing to say they are postal)`);
1651
1652
  }
1652
1653
  let p2 = t?.state;
1653
1654
  if (p2 && h3.has(p2)) {
1654
- let n = f4(p2), s = P2(n);
1655
- s.length > 0 && s.every((l) => j2(l, i)) ? a4.push(`state=${p2} (every value is "CA", which is both Canada and California)`) : x3(n) ? (a4.push(`state=${p2} (every value is a country, not a state)`), r.country || (r.country = p2)) : w2(n) < 95 ? a4.push(`state=${p2} (only ${w2(n)}% of values are states/provinces)`) : r.state = p2;
1655
+ let e = f4(p2), s = S(e);
1656
+ s.length > 0 && s.every((u2) => V2(u2, r)) ? a4.push(`state=${p2} (every value is "CA", which is both Canada and California)`) : P2(e) ? (a4.push(`state=${p2} (every value is a country, not a state)`), o.country || (o.country = p2)) : D3(e) < 95 ? a4.push(`state=${p2} (only ${D3(e)}% of values are states/provinces)`) : o.state = p2;
1656
1657
  }
1657
- let y5 = new Set(Object.values(r).filter(Boolean)), A = o.filter((n) => !y5.has(n) && !n.startsWith("__"));
1658
- if (!r.state) {
1659
- let n = null;
1658
+ let y5 = new Set(Object.values(o).filter(Boolean)), A = i.filter((e) => !y5.has(e) && !e.startsWith("__"));
1659
+ if (!o.state) {
1660
+ let e = null;
1660
1661
  for (let s of A) {
1661
- let l = f4(s);
1662
- if (x3(l)) continue;
1663
- let m2 = w2(l);
1662
+ let u2 = f4(s);
1663
+ if (P2(u2)) continue;
1664
+ let m2 = D3(u2);
1664
1665
  if (m2 < 95) continue;
1665
- let D3 = F3(l, (R2) => !!Y(R2)), ee = F3(l, (R2) => !!Y(R2) && !j2(R2, i));
1666
- D3 < E2 && ee < 1 || (!n || m2 > n.pct) && (n = { name: s, pct: m2 });
1666
+ let F3 = N2(u2, (T3) => !!Y(T3)), Q3 = N2(u2, (T3) => !!Y(T3) && !V2(T3, r));
1667
+ F3 < G2 && Q3 < 1 || (!e || m2 > e.pct) && (e = { name: s, pct: m2 });
1667
1668
  }
1668
- n && (r.state = n.name, y5.add(n.name), u2.push(`state=${n.name} (${n.pct}% states/provinces)`));
1669
+ e && (o.state = e.name, y5.add(e.name), l.push(`state=${e.name} (${e.pct}% states/provinces)`));
1669
1670
  }
1670
- if (!r.zip) for (let n of A) {
1671
- if (y5.has(n)) continue;
1672
- let s = f4(n), l = $2(s);
1673
- if (!(l < 95) && q3(s, n) && !(Ct(s, (m2) => Z(m2).length > 0) < E2)) {
1674
- r.zip = n, y5.add(n), u2.push(`zip=${n} (${l}% ZIP codes)`);
1671
+ if (!o.zip) for (let e of A) {
1672
+ if (y5.has(e)) continue;
1673
+ let s = f4(e), u2 = z2(s);
1674
+ if (!(u2 < 95) && j2(s, e) && !(Tt(s, (m2) => Z(m2).length > 0) < G2)) {
1675
+ o.zip = e, y5.add(e), l.push(`zip=${e} (${u2}% ZIP codes)`);
1675
1676
  break;
1676
1677
  }
1677
1678
  }
1678
- let S = r.country;
1679
- if (!S || !x3(f4(S))) {
1680
- let n = null;
1679
+ let x3 = o.country;
1680
+ if (!x3 || !P2(f4(x3))) {
1681
+ let e = null;
1681
1682
  for (let s of A) {
1682
- if (y5.has(s) || !x3(f4(s))) continue;
1683
- let l = z2(f4(s));
1684
- (!n || l > n.pct) && (n = { name: s, pct: l });
1683
+ if (y5.has(s) || !P2(f4(s))) continue;
1684
+ let u2 = O2(f4(s));
1685
+ (!e || u2 > e.pct) && (e = { name: s, pct: u2 });
1685
1686
  }
1686
- n && (S && (a4.push(`country=${S} (only ${z2(f4(S))}% of values are country identifiers; using ${n.name} instead)`), T3.country = S), r.country = n.name, y5.add(n.name), u2.push(`country=${n.name}`));
1687
+ e && (x3 && (a4.push(`country=${x3} (only ${O2(f4(x3))}% of values are country identifiers; using ${e.name} instead)`), R2.country = x3), o.country = e.name, y5.add(e.name), l.push(`country=${e.name}`));
1687
1688
  }
1688
- if (!r.city) {
1689
- let n = null;
1689
+ if (!o.city) {
1690
+ let e = null;
1690
1691
  for (let s of A) {
1691
1692
  if (y5.has(s)) continue;
1692
- let l = f4(s), m2 = yt2(l, i);
1693
- m2 < m3 || F3(l, (D3) => p3(D3, i)) < E2 || (!n || m2 > n.pct) && (n = { name: s, pct: m2 });
1693
+ let u2 = f4(s), m2 = At2(u2, r);
1694
+ m2 < m3 || N2(u2, (F3) => p3(F3, r)) < G2 || (!e || m2 > e.pct) && (e = { name: s, pct: m2 });
1694
1695
  }
1695
- n && (r.city = n.name, u2.push(`city=${n.name} (${n.pct}% known cities)`));
1696
+ e && (o.city = e.name, l.push(`city=${e.name} (${e.pct}% known cities)`));
1696
1697
  }
1697
- let B2 = r.country ? f4(r.country) : [], k2 = !!r.country && x3(B2), Q3 = k2 ? new Set(B2.map((n) => E(n == null ? null : String(n))).filter(Boolean)).size : 0, K3 = k2 && Q3 >= 2, _2 = !!(r.lat && r.lon) && e.some((n) => {
1698
- let s = +String(n[r.lat] ?? "").trim(), l = +String(n[r.lon] ?? "").trim();
1699
- return isFinite(s) && isFinite(l) && s >= -90 && s <= 90 && l >= -180 && l <= 180 && String(n[r.lat] ?? "").trim() !== "" && String(n[r.lon] ?? "").trim() !== "";
1698
+ let B2 = o.country ? f4(o.country) : [], _2 = !!o.country && P2(B2), J2 = _2 ? new Set(B2.map((e) => E(e == null ? null : String(e))).filter(Boolean)).size : 0, H2 = _2 && J2 >= 2, w2 = !!(o.lat && o.lon) && n.some((e) => {
1699
+ let s = +String(e[o.lat] ?? "").trim(), u2 = +String(e[o.lon] ?? "").trim();
1700
+ return isFinite(s) && isFinite(u2) && s >= -90 && s <= 90 && u2 >= -180 && u2 <= 180 && String(e[o.lat] ?? "").trim() !== "" && String(e[o.lon] ?? "").trim() !== "";
1700
1701
  });
1701
- return r.lat && r.lon && !_2 && a4.push(`lat/lon=${r.lat}/${r.lon} (no row holds a usable coordinate pair)`), r.country && !K3 && !(r.city || r.state || r.zip || _2) && a4.push(k2 ? `country=${r.country} (every row resolves to the same country - nothing to place apart)` : `country=${r.country} (values are not country identifiers)`), { bind: !!(r.city || r.state || r.zip || K3 || _2) ? r : null, backfilled: u2, refused: a4, ...Object.keys(T3).length ? { labelFallback: T3 } : {} };
1702
+ return o.lat && o.lon && !w2 && a4.push(`lat/lon=${o.lat}/${o.lon} (no row holds a usable coordinate pair)`), o.country && !H2 && !(o.city || o.state || o.zip || w2) && a4.push(_2 ? `country=${o.country} (every row resolves to the same country - nothing to place apart)` : `country=${o.country} (values are not country identifiers)`), { bind: !!(o.city || o.state || o.zip || H2 || w2) ? o : null, backfilled: l, refused: a4, ...Object.keys(R2).length ? { labelFallback: R2 } : {} };
1702
1703
  }
1703
1704
 
1704
1705
  // src/payload.ts
@@ -1713,7 +1714,7 @@ function resolvePointChannel(cols, rowObjs, point) {
1713
1714
  let labelCol;
1714
1715
  if (bind) {
1715
1716
  const dims = cols.filter((c2) => !c2.isMeasure).map((c2) => c2.name);
1716
- const res = ht(dims, rowObjs, bind, point?.mapKind, cols.map((c2) => c2.name));
1717
+ const res = bt(dims, rowObjs, bind, point?.mapKind, cols.map((c2) => c2.name));
1717
1718
  bind = res.bind;
1718
1719
  rolesBackfilled = res.backfilled;
1719
1720
  rolesRefused = res.refused;
@@ -1992,6 +1993,15 @@ function stripJsComments(code) {
1992
1993
  }
1993
1994
 
1994
1995
  // src/selection.ts
1996
+ function isInsideControl(target, container) {
1997
+ let el = target;
1998
+ if (el && el.nodeType !== 1) el = el.parentElement ?? el.parentNode ?? null;
1999
+ while (el && el !== container) {
2000
+ if (el.nodeType === 1 && el.classList?.contains?.(CONTROL_CLASS)) return true;
2001
+ el = el.parentElement ?? el.parentNode ?? null;
2002
+ }
2003
+ return false;
2004
+ }
1995
2005
  function createMarkResolver(env) {
1996
2006
  const { root, doc, log } = env;
1997
2007
  const isElement = (t) => {
@@ -2015,26 +2025,26 @@ function createMarkResolver(env) {
2015
2025
  const so = parseFloat(el.getAttribute("stroke-opacity") || "1");
2016
2026
  return s === "transparent" || s === "none" || so <= 0.01;
2017
2027
  };
2018
- const distToPathCenterline = (el, x4, y5) => {
2028
+ const distToPathCenterline = (el, x3, y5) => {
2019
2029
  const L2 = el.getTotalLength();
2020
2030
  if (!(L2 > 0)) return Number.MAX_VALUE;
2021
2031
  const m2 = el.getScreenCTM();
2022
2032
  if (!m2) return Number.MAX_VALUE;
2023
2033
  let best = Number.MAX_VALUE;
2024
- const N2 = 64;
2025
- for (let i = 0; i <= N2; i++) {
2026
- const pt = el.getPointAtLength(L2 * i / N2);
2027
- const dx = m2.a * pt.x + m2.c * pt.y + m2.e - x4;
2034
+ const N3 = 64;
2035
+ for (let i = 0; i <= N3; i++) {
2036
+ const pt = el.getPointAtLength(L2 * i / N3);
2037
+ const dx = m2.a * pt.x + m2.c * pt.y + m2.e - x3;
2028
2038
  const dy = m2.b * pt.x + m2.d * pt.y + m2.f - y5;
2029
2039
  const d2 = dx * dx + dy * dy;
2030
2040
  if (d2 < best) best = d2;
2031
2041
  }
2032
2042
  return Math.sqrt(best);
2033
2043
  };
2034
- const refineHitCorridor = (mark, x4, y5, sel) => {
2044
+ const refineHitCorridor = (mark, x3, y5, sel) => {
2035
2045
  try {
2036
2046
  if (!mark || !isInvisibleStrokePath(mark) || !mark.getAttribute("data-row-idx")) return mark;
2037
- const stack = doc.elementsFromPoint(x4, y5);
2047
+ const stack = doc.elementsFromPoint(x3, y5);
2038
2048
  const candidates = [];
2039
2049
  for (const el of stack) {
2040
2050
  if (!root.contains(el)) continue;
@@ -2048,7 +2058,7 @@ function createMarkResolver(env) {
2048
2058
  let best = mark;
2049
2059
  let bestD = Number.MAX_VALUE;
2050
2060
  for (const el of candidates) {
2051
- const d2 = distToPathCenterline(el, x4, y5);
2061
+ const d2 = distToPathCenterline(el, x3, y5);
2052
2062
  if (d2 < bestD) {
2053
2063
  bestD = d2;
2054
2064
  best = el;
@@ -2085,9 +2095,9 @@ function createMarkResolver(env) {
2085
2095
  }
2086
2096
  return out;
2087
2097
  };
2088
- const penetrateOverlayAt = (x4, y5, sel) => {
2098
+ const penetrateOverlayAt = (x3, y5, sel) => {
2089
2099
  try {
2090
- const stack = doc.elementsFromPoint(x4, y5);
2100
+ const stack = doc.elementsFromPoint(x3, y5);
2091
2101
  for (const el of stack) {
2092
2102
  if (!root.contains(el) || !isElement(el)) continue;
2093
2103
  const cand = el.matches(sel) ? el : el.closest(sel);
@@ -2099,7 +2109,7 @@ function createMarkResolver(env) {
2099
2109
  }
2100
2110
  return null;
2101
2111
  };
2102
- const resolveByGeometry = (x4, y5, sel) => {
2112
+ const resolveByGeometry = (x3, y5, sel) => {
2103
2113
  try {
2104
2114
  const cands = root.querySelectorAll(sel);
2105
2115
  let best = null, bestArea = Number.MAX_VALUE;
@@ -2108,7 +2118,7 @@ function createMarkResolver(env) {
2108
2118
  if (!el.getAttribute("data-row-idx")) continue;
2109
2119
  const r = el.getBoundingClientRect ? el.getBoundingClientRect() : null;
2110
2120
  if (!r || r.width <= 0 || r.height <= 0) continue;
2111
- if (x4 < r.left || x4 > r.right || y5 < r.top || y5 > r.bottom) continue;
2121
+ if (x3 < r.left || x3 > r.right || y5 < r.top || y5 > r.bottom) continue;
2112
2122
  const area = r.width * r.height;
2113
2123
  if (area < bestArea) {
2114
2124
  bestArea = area;
@@ -2305,13 +2315,13 @@ function censusHitBands(container, doc) {
2305
2315
  if (!OPEN_TAGS.has(tag)) continue;
2306
2316
  const cs = styleOf2(el, ownerDoc);
2307
2317
  const open = isUnfilled(attrOrComputed(el, "fill", cs));
2308
- const w3 = widthPx(attrOrComputed(el, "stroke-width", cs) || "1");
2318
+ const w2 = widthPx(attrOrComputed(el, "stroke-width", cs) || "1");
2309
2319
  const geom = String(el.getAttribute?.("d") ?? "") || `${tag}#${String(el.getAttribute?.(ROW_IDX_ATTR) ?? "")}`;
2310
2320
  const inert = String(cs?.pointerEvents ?? el.style?.pointerEvents ?? "") === "none";
2311
- rows.push({ el, geom, w: w3, open, inert });
2312
- if (isFinite(w3)) {
2321
+ rows.push({ el, geom, w: w2, open, inert });
2322
+ if (isFinite(w2)) {
2313
2323
  const prev = widestByGeom.get(geom);
2314
- if (prev === void 0 || w3 > prev) widestByGeom.set(geom, w3);
2324
+ if (prev === void 0 || w2 > prev) widestByGeom.set(geom, w2);
2315
2325
  }
2316
2326
  }
2317
2327
  const out = { ...EMPTY3 };
@@ -2388,10 +2398,10 @@ function censusValuePlacement(container, data) {
2388
2398
  if (!/^\d+$/.test(raw)) continue;
2389
2399
  const i = +raw;
2390
2400
  const row = rows[i];
2391
- const x4 = num(el, "cx"), y5 = num(el, "cy"), r = num(el, "r");
2392
- if (!row || !Number.isFinite(x4) || !Number.isFinite(y5) || !(r > 0)) continue;
2401
+ const x3 = num(el, "cx"), y5 = num(el, "cy"), r = num(el, "r");
2402
+ if (!row || !Number.isFinite(x3) || !Number.isFinite(y5) || !(r > 0)) continue;
2393
2403
  seen.add(i);
2394
- dots.push({ row, x: x4, y: y5, r });
2404
+ dots.push({ row, x: x3, y: y5, r });
2395
2405
  }
2396
2406
  if (dots.length < MIN_MARKS2 || seen.size < dots.length * 0.9) return EMPTY4;
2397
2407
  let best = null;
@@ -2482,12 +2492,12 @@ function contentExtentOf(boxes) {
2482
2492
  if (usable.length === 0) return { w: 0, h: 0, source: "none" };
2483
2493
  const inFlow = usable.filter((b4) => !b4.floating);
2484
2494
  const counted = inFlow.length > 0 ? inFlow : usable;
2485
- let w3 = 0, h3 = 0;
2495
+ let w2 = 0, h3 = 0;
2486
2496
  for (const b4 of counted) {
2487
- if (b4.right > w3) w3 = b4.right;
2497
+ if (b4.right > w2) w2 = b4.right;
2488
2498
  if (b4.bottom > h3) h3 = b4.bottom;
2489
2499
  }
2490
- return { w: w3, h: h3, source: inFlow.length > 0 ? "in-flow" : "all-floating" };
2500
+ return { w: w2, h: h3, source: inFlow.length > 0 ? "in-flow" : "all-floating" };
2491
2501
  }
2492
2502
  function scrollFitFor(contentW, contentH, viewportW, viewportH, slackPx = SCROLL_SLACK_PX) {
2493
2503
  return {
@@ -2497,8 +2507,8 @@ function scrollFitFor(contentW, contentH, viewportW, viewportH, slackPx = SCROLL
2497
2507
  }
2498
2508
  var FIT_CONTENT_SELECTOR = "text, .d3-mark, .d3-legend-mark";
2499
2509
  var PHANTOM_FRACTION = 0.95;
2500
- function isPhantomBox(w3, h3, refW, refH) {
2501
- return w3 > refW * PHANTOM_FRACTION || h3 > refH * PHANTOM_FRACTION;
2510
+ function isPhantomBox(w2, h3, refW, refH) {
2511
+ return w2 > refW * PHANTOM_FRACTION || h3 > refH * PHANTOM_FRACTION;
2502
2512
  }
2503
2513
  var MAX_FRAME_GROW_FACTOR = 20;
2504
2514
  function planFrameGrow(inkBottomPx, elHeightPx, viewBoxH, ctmScale, slackPx = SCROLL_SLACK_PX, maxFactor = MAX_FRAME_GROW_FACTOR) {
@@ -3197,31 +3207,31 @@ function applyLabelContrast(container, opts = {}) {
3197
3207
  const glyphArea = tr.width * tr.height;
3198
3208
  const txRoot = paintRoot(tx, container);
3199
3209
  let over = 0;
3200
- const boxed = rects.map((mk) => ({ mk, ov: ovArea(mk.r) })).filter((x4) => {
3201
- if (!(x4.ov > 0)) return false;
3202
- if (drawnBeneath(x4.mk, tx, txRoot)) return true;
3203
- if (effAlpha(x4.mk) >= PILL_MIN_ALPHA) over++;
3210
+ const boxed = rects.map((mk) => ({ mk, ov: ovArea(mk.r) })).filter((x3) => {
3211
+ if (!(x3.ov > 0)) return false;
3212
+ if (drawnBeneath(x3.mk, tx, txRoot)) return true;
3213
+ if (effAlpha(x3.mk) >= PILL_MIN_ALPHA) over++;
3204
3214
  return false;
3205
3215
  });
3206
3216
  if (over > 0) report.paintedOver++;
3207
3217
  const pts = glyphSampleGrid({ left: tr.left, top: tr.top, width: tr.width, height: tr.height });
3208
3218
  const painted = pts.map(() => false);
3209
3219
  let unmeasured = 0;
3210
- const under = boxed.map((x4) => {
3211
- const mask = backedSamples(x4.mk.el, pts);
3220
+ const under = boxed.map((x3) => {
3221
+ const mask = backedSamples(x3.mk.el, pts);
3212
3222
  if (mask === null) {
3213
3223
  unmeasured++;
3214
- return x4;
3224
+ return x3;
3215
3225
  }
3216
3226
  let inside = 0;
3217
- const paints = effAlpha(x4.mk) >= PILL_MIN_ALPHA;
3227
+ const paints = effAlpha(x3.mk) >= PILL_MIN_ALPHA;
3218
3228
  for (let i = 0; i < mask.length; i++) {
3219
3229
  if (!mask[i]) continue;
3220
3230
  inside++;
3221
3231
  if (paints) painted[i] = true;
3222
3232
  }
3223
- return { mk: x4.mk, ov: glyphArea * (inside / mask.length) };
3224
- }).filter((x4) => x4.ov > 0);
3233
+ return { mk: x3.mk, ov: glyphArea * (inside / mask.length) };
3234
+ }).filter((x3) => x3.ov > 0);
3225
3235
  if (under.length === 0 && boxed.length > 0) report.offFill++;
3226
3236
  if (under.length === 0) continue;
3227
3237
  if (unmeasured === 0 && pts.length > 0) {
@@ -3233,10 +3243,10 @@ function applyLabelContrast(container, opts = {}) {
3233
3243
  }
3234
3244
  }
3235
3245
  report.scanned++;
3236
- const opaqueUnder = under.filter((x4) => effAlpha(x4.mk) >= PILL_OPAQUE_ALPHA);
3246
+ const opaqueUnder = under.filter((x3) => effAlpha(x3.mk) >= PILL_OPAQUE_ALPHA);
3237
3247
  const cellEntry = (opaqueUnder.length ? opaqueUnder : under).reduce((a4, b4) => b4.ov > a4.ov || b4.ov === a4.ov && b4.mk.ord > a4.mk.ord ? b4 : a4);
3238
3248
  const cell = cellEntry.mk;
3239
- const pill = under.find((x4) => x4.mk !== cell && isPillBackdropAlpha(effAlpha(x4.mk)) && x4.mk.ord > cell.ord && pillBacksGlyph(x4.ov, glyphArea))?.mk;
3249
+ const pill = under.find((x3) => x3.mk !== cell && isPillBackdropAlpha(effAlpha(x3.mk)) && x3.mk.ord > cell.ord && pillBacksGlyph(x3.ov, glyphArea))?.mk;
3240
3250
  const cellRGBA = toRGBA(cell.fill);
3241
3251
  let bgRGB = cellRGBA ? compositeOver([cellRGBA[0], cellRGBA[1], cellRGBA[2], cellRGBA[3] * cell.op], pageRGB) : pageRGB;
3242
3252
  if (pill) {
@@ -3297,7 +3307,7 @@ function noopViewStateProvider() {
3297
3307
  return { load: () => ({}), save: () => {
3298
3308
  } };
3299
3309
  }
3300
- var parseRowIdxs = (s) => (s || "").split(",").map((x4) => parseInt(x4, 10)).filter((n) => Number.isFinite(n));
3310
+ var parseRowIdxs = (s) => (s || "").split(",").map((x3) => parseInt(x3, 10)).filter((n) => Number.isFinite(n));
3301
3311
  var D3_PLUGIN_PACKAGES = {
3302
3312
  sankey: "d3-sankey",
3303
3313
  sankeyLinkHorizontal: "d3-sankey",
@@ -3555,6 +3565,7 @@ function createChartHost(container, config) {
3555
3565
  const clickSel = `.${MARK_CLASS}[${ROW_IDX_ATTR}], .${LEGEND_MARK_CLASS}[${ROW_IDX_ATTR}], .${AXIS_FILTER_CLASS}[${ROW_IDX_ATTR}]`;
3556
3566
  const onClick = (e) => {
3557
3567
  if (Date.now() - xfAt < XF_ECHO_MS) return;
3568
+ if (isInsideControl(e?.target, container)) return;
3558
3569
  let el = resolver.findMark(e?.target, clickSel, e);
3559
3570
  if (!el) el = resolver.penetrateOverlayAt(e?.clientX, e?.clientY, clickSel);
3560
3571
  if (!el) el = resolver.resolveByGeometry(e?.clientX, e?.clientY, clickSel);
@@ -3812,6 +3823,7 @@ export {
3812
3823
  LEGEND_MARK_CLASS,
3813
3824
  AXIS_FILTER_CLASS,
3814
3825
  LIFT_SELECTED_CLASS,
3826
+ CONTROL_CLASS,
3815
3827
  ROW_IDX_ATTR,
3816
3828
  XFILTER_REFRESH_EVENT,
3817
3829
  CONTAINER_SLOT_ANIM_STOP,
@@ -3863,15 +3875,16 @@ export {
3863
3875
  registerGeo,
3864
3876
  registerGeoAsset,
3865
3877
  clearGeoCache,
3866
- L3,
3867
3878
  M,
3868
3879
  a2 as a,
3880
+ L3,
3869
3881
  Oe,
3870
3882
  Le,
3871
3883
  Qt,
3872
3884
  Jt,
3873
3885
  buildRenderPayload,
3874
3886
  stripJsComments,
3887
+ isInsideControl,
3875
3888
  createMarkResolver,
3876
3889
  ensureCrossfilterHitTargets,
3877
3890
  censusMarks,
package/dist/index.mjs CHANGED
@@ -27,6 +27,7 @@ import {
27
27
  CONTAINER_SLOT_INITIAL_XF_MARK,
28
28
  CONTAINER_SLOT_UI_STATE,
29
29
  CONTAINER_SLOT_XF_CLEAR,
30
+ CONTROL_CLASS,
30
31
  DARK_TEXT,
31
32
  DIM_OPACITY_DEFAULT,
32
33
  DIM_OPACITY_VAR,
@@ -105,6 +106,7 @@ import {
105
106
  invalidSentinelReason,
106
107
  isBlankRender,
107
108
  isHorizontalLabelRow,
109
+ isInsideControl,
108
110
  isInvalidSentinelError,
109
111
  isPhantomBox,
110
112
  isPillBackdropAlpha,
@@ -133,7 +135,7 @@ import {
133
135
  unpinScrolledAxis,
134
136
  valuePlacementFlag,
135
137
  withoutViewOnlyKeys
136
- } from "./chunk-RO6O22YG.mjs";
138
+ } from "./chunk-BNVHRDDL.mjs";
137
139
  import "./chunk-A2GMXZP7.mjs";
138
140
  import "./chunk-GHODWOAL.mjs";
139
141
 
@@ -2438,6 +2440,7 @@ export {
2438
2440
  CONTAINER_SLOT_INITIAL_XF_MARK,
2439
2441
  CONTAINER_SLOT_UI_STATE,
2440
2442
  CONTAINER_SLOT_XF_CLEAR,
2443
+ CONTROL_CLASS,
2441
2444
  DARK_TEXT,
2442
2445
  DIM_OPACITY_DEFAULT,
2443
2446
  DIM_OPACITY_VAR,
@@ -2556,6 +2559,7 @@ export {
2556
2559
  isBlindMarker,
2557
2560
  isExcelDateFormat,
2558
2561
  isHorizontalLabelRow,
2562
+ isInsideControl,
2559
2563
  isInvalidSentinelError,
2560
2564
  isPhantomBox,
2561
2565
  isPillBackdropAlpha,
package/dist/react.mjs CHANGED
@@ -4,7 +4,7 @@ import {
4
4
  createChartHost,
5
5
  geoFromCache,
6
6
  loadGeo
7
- } from "./chunk-RO6O22YG.mjs";
7
+ } from "./chunk-BNVHRDDL.mjs";
8
8
  import "./chunk-A2GMXZP7.mjs";
9
9
  import "./chunk-GHODWOAL.mjs";
10
10
 
@@ -1,4 +1,4 @@
1
- export declare const HOST_CONTRACT_VERSION = "1.11.0";
1
+ export declare const HOST_CONTRACT_VERSION = "1.12.0";
2
2
  export type GeoPointPrecision = "latlon" | "city" | "zip3" | "state" | "country";
3
3
  /** Every valid tier, ordered most precise → coarsest. Runtime form of GeoPointPrecision. */
4
4
  export declare const GEO_POINT_PRECISIONS: readonly GeoPointPrecision[];
@@ -11,6 +11,7 @@ export declare const MARK_CLASS = "d3-mark";
11
11
  export declare const LEGEND_MARK_CLASS = "d3-legend-mark";
12
12
  export declare const AXIS_FILTER_CLASS = "d3-axis-filter";
13
13
  export declare const LIFT_SELECTED_CLASS = "d3-lift-selected";
14
+ export declare const CONTROL_CLASS = "lch-control";
14
15
  export declare const ROW_IDX_ATTR = "data-row-idx";
15
16
  export declare const XFILTER_REFRESH_EVENT = "llm-xfilter-refresh";
16
17
  export declare const CONTAINER_SLOT_ANIM_STOP = "__llmAnimStop";
@@ -1,4 +1,4 @@
1
- export { HOST_CONTRACT_VERSION, GEO_POINT_PRECISIONS, MARK_CLASS, LEGEND_MARK_CLASS, AXIS_FILTER_CLASS, ROW_IDX_ATTR, LIFT_SELECTED_CLASS, XFILTER_REFRESH_EVENT, CONTAINER_SLOT_ANIM_STOP, CONTAINER_SLOT_XF_CLEAR, CONTAINER_SLOT_INITIAL_XF_MARK, CONTAINER_SLOT_UI_STATE, VIEW_ONLY_UI_STATE_KEYS, withoutViewOnlyKeys, HOST_CONTAINER_CLASS, SELECTION_ACTIVE_CLASS, MARK_SELECTED_CLASS, ACTIVE_TICK_CLASS, DIM_OPACITY_VAR, DIM_OPACITY_DEFAULT, chartOwnsTimeline, periodTickSuppressesFeedback, ANIM_PLAY_SPEED_DEFAULT, ANIM_PLAY_SPEED_MIN, ANIM_PLAY_SPEED_MAX, ANIM_LOOP_DELAY_DEFAULT, ANIM_LOOP_DELAY_MIN, ANIM_MAX_IDEAL_FRAMES_DEFAULT, ANIM_MAX_IDEAL_FRAMES_MIN, ANIM_MAX_IDEAL_FRAMES_MAX, ANIMATION_OPTION_KEYS, COLOR_SCALE_SELF_CLAMP_PCT_DEFAULT, COLOR_SCALE_SELF_CLAMP_PCT_MIN, COLOR_SCALE_SELF_CLAMP_PCT_MAX, FLIP_MODE_DEFAULT, APPROXIMATE_POSITIONS_DEFAULT, VALUE_AXIS_BASELINE_DEFAULT, SEASONAL_MARKERS_DEFAULT, MAX_MAP_POINTS_DEFAULT, type GeoPointPrecision, type GeoMapKind, type TimelineStyle, type FlipMode, type ApproximatePositions, type ValueAxisBaseline, type SeasonalMarkers, type ColorScaleScope, type RenderOptions, type ViewStateProvider, type ChartControlChange, } from "./contract";
1
+ export { HOST_CONTRACT_VERSION, GEO_POINT_PRECISIONS, MARK_CLASS, LEGEND_MARK_CLASS, AXIS_FILTER_CLASS, ROW_IDX_ATTR, LIFT_SELECTED_CLASS, CONTROL_CLASS, XFILTER_REFRESH_EVENT, CONTAINER_SLOT_ANIM_STOP, CONTAINER_SLOT_XF_CLEAR, CONTAINER_SLOT_INITIAL_XF_MARK, CONTAINER_SLOT_UI_STATE, VIEW_ONLY_UI_STATE_KEYS, withoutViewOnlyKeys, HOST_CONTAINER_CLASS, SELECTION_ACTIVE_CLASS, MARK_SELECTED_CLASS, ACTIVE_TICK_CLASS, DIM_OPACITY_VAR, DIM_OPACITY_DEFAULT, chartOwnsTimeline, periodTickSuppressesFeedback, ANIM_PLAY_SPEED_DEFAULT, ANIM_PLAY_SPEED_MIN, ANIM_PLAY_SPEED_MAX, ANIM_LOOP_DELAY_DEFAULT, ANIM_LOOP_DELAY_MIN, ANIM_MAX_IDEAL_FRAMES_DEFAULT, ANIM_MAX_IDEAL_FRAMES_MIN, ANIM_MAX_IDEAL_FRAMES_MAX, ANIMATION_OPTION_KEYS, COLOR_SCALE_SELF_CLAMP_PCT_DEFAULT, COLOR_SCALE_SELF_CLAMP_PCT_MIN, COLOR_SCALE_SELF_CLAMP_PCT_MAX, FLIP_MODE_DEFAULT, APPROXIMATE_POSITIONS_DEFAULT, VALUE_AXIS_BASELINE_DEFAULT, SEASONAL_MARKERS_DEFAULT, MAX_MAP_POINTS_DEFAULT, type GeoPointPrecision, type GeoMapKind, type TimelineStyle, type FlipMode, type ApproximatePositions, type ValueAxisBaseline, type SeasonalMarkers, type ColorScaleScope, type RenderOptions, type ViewStateProvider, type ChartControlChange, } from "./contract";
2
2
  export { resolveOptions, type ResolveOptionsInput } from "./defaults";
3
3
  export { loadGeo, geoFromCache, registerGeo, registerGeoAsset, geoAssetFor, clearGeoCache, type GeoAssetName, } from "./geoLazy";
4
4
  /** REPLACE the bundled city gazetteer with another packed table. Rarely needed — see the
@@ -7,7 +7,7 @@ export declare function registerCityTable(packed: string): void;
7
7
  export { buildRenderPayload, type RenderPayload, type GeoPointBinding } from "./payload";
8
8
  export { codeReadsDatesInLocalTime, vegaSpecReadsDatesInLocalTime } from "./dateCells";
9
9
  export { createChartHost, compileRenderFn, stripEsmExports, requiredD3Plugins, explainRenderFailure, sessionViewStateProvider, noopViewStateProvider, type ChartHost, type ChartHostConfig, type RenderFn } from "./host";
10
- export { createMarkResolver, type MarkResolver, type MarkResolverEnv } from "./selection";
10
+ export { createMarkResolver, isInsideControl, type MarkResolver, type MarkResolverEnv } from "./selection";
11
11
  export { planTrivialChart, compileTrivialSource, type TrivialPlan, type TrivialShapeKind } from "./trivial";
12
12
  export { captureSvgSnapshot, svgToDataUrl, svgNaturalSize, rasterizeSvgToPngDataUrl, type SnapshotOptions } from "./snapshot";
13
13
  export { shouldReview, buildReviewWire, bareBase64, actionFor, type ReviewGate, type ReviewWire, type ReviewVerdict, type ReviewAction } from "./review";
@@ -1,3 +1,10 @@
1
+ /**
2
+ * True when a click's target sits inside a reader-operated control the chart drew (CONTROL_CLASS
3
+ * on the target or an ancestor), looking no further out than `container` - a page that wraps the
4
+ * whole chart in the class does not make every click a control click. A text node is read through
5
+ * its parent. A click inside a control is neither a selection nor a click on empty canvas.
6
+ */
7
+ export declare function isInsideControl(target: EventTarget | Node | null | undefined, container: Element): boolean;
1
8
  export interface MarkResolverEnv {
2
9
  root: HTMLElement;
3
10
  doc: Document;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bicharts/chart-host",
3
- "version": "0.6.1",
3
+ "version": "0.6.3",
4
4
  "description": "Run a BIC-generated D3 chart in any web host: compiles the generated render() function, applies the shared option defaults, resolves mark clicks (through tooltip overlays), owns the selection affordance, and translates row indices between cross-filtered charts. The same contract the BIC Power BI visual implements, minus Power BI. React bindings at @bicharts/chart-host/react.",
5
5
  "license": "Apache-2.0",
6
6
  "type": "module",