@decidables/discountable-elements 0.3.3 → 0.3.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -3,6 +3,22 @@
3
3
  All notable changes to this project will be documented in this file.
4
4
  See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
5
5
 
6
+ ## [0.3.5](https://github.com/decidables/decidables/compare/@decidables/discountable-elements@0.3.4...@decidables/discountable-elements@0.3.5) (2024-01-27)
7
+
8
+ **Note:** Version bump only for package @decidables/discountable-elements
9
+
10
+
11
+
12
+
13
+
14
+ ## [0.3.4](https://github.com/decidables/decidables/compare/@decidables/discountable-elements@0.3.3...@decidables/discountable-elements@0.3.4) (2024-01-09)
15
+
16
+ **Note:** Version bump only for package @decidables/discountable-elements
17
+
18
+
19
+
20
+
21
+
6
22
  ## [0.3.3](https://github.com/decidables/decidables/compare/@decidables/discountable-elements@0.3.2...@decidables/discountable-elements@0.3.3) (2023-12-31)
7
23
 
8
24
  **Note:** Version bump only for package @decidables/discountable-elements
@@ -732,7 +732,6 @@ function* numbers(values, valueof) {
732
732
  const ascendingBisect = bisector(ascending$1);
733
733
  const bisectRight = ascendingBisect.right;
734
734
  bisector(number$4).center;
735
- var bisect = bisectRight;
736
735
 
737
736
  function count(values, valueof) {
738
737
  let count = 0;
@@ -6049,7 +6048,6 @@ function areaPoint(x, y) {
6049
6048
  function areaRingEnd() {
6050
6049
  areaPoint(x00$2, y00$2);
6051
6050
  }
6052
- var pathArea = areaStream;
6053
6051
 
6054
6052
  var x0$2 = Infinity,
6055
6053
  y0$2 = x0$2,
@@ -6073,7 +6071,6 @@ function boundsPoint(x, y) {
6073
6071
  if (y < y0$2) y0$2 = y;
6074
6072
  if (y > y1) y1 = y;
6075
6073
  }
6076
- var boundsStream$1 = boundsStream;
6077
6074
 
6078
6075
  // TODO Enforce positive area for exterior, negative area for interior?
6079
6076
 
@@ -6156,7 +6153,6 @@ function centroidPointRing(x, y) {
6156
6153
  Z2 += z * 3;
6157
6154
  centroidPoint(x0$1 = x, y0$1 = y);
6158
6155
  }
6159
- var pathCentroid = centroidStream;
6160
6156
 
6161
6157
  function PathContext(context) {
6162
6158
  this._context = context;
@@ -6239,7 +6235,6 @@ function lengthPoint(x, y) {
6239
6235
  lengthSum.add(sqrt$1(x0 * x0 + y0 * y0));
6240
6236
  x0 = x, y0 = y;
6241
6237
  }
6242
- var pathMeasure = lengthStream;
6243
6238
 
6244
6239
  // Simple caching for constant-radius points.
6245
6240
  let cacheDigits, cacheAppend, cacheRadius, cacheCircle;
@@ -6341,20 +6336,20 @@ function geoPath (projection, context) {
6341
6336
  return contextStream.result();
6342
6337
  }
6343
6338
  path.area = function (object) {
6344
- geoStream(object, projectionStream(pathArea));
6345
- return pathArea.result();
6339
+ geoStream(object, projectionStream(areaStream));
6340
+ return areaStream.result();
6346
6341
  };
6347
6342
  path.measure = function (object) {
6348
- geoStream(object, projectionStream(pathMeasure));
6349
- return pathMeasure.result();
6343
+ geoStream(object, projectionStream(lengthStream));
6344
+ return lengthStream.result();
6350
6345
  };
6351
6346
  path.bounds = function (object) {
6352
- geoStream(object, projectionStream(boundsStream$1));
6353
- return boundsStream$1.result();
6347
+ geoStream(object, projectionStream(boundsStream));
6348
+ return boundsStream.result();
6354
6349
  };
6355
6350
  path.centroid = function (object) {
6356
- geoStream(object, projectionStream(pathCentroid));
6357
- return pathCentroid.result();
6351
+ geoStream(object, projectionStream(centroidStream));
6352
+ return centroidStream.result();
6358
6353
  };
6359
6354
  path.projection = function (_) {
6360
6355
  if (!arguments.length) return projection;
@@ -6425,8 +6420,8 @@ function fit(projection, fitBounds, object) {
6425
6420
  var clip = projection.clipExtent && projection.clipExtent();
6426
6421
  projection.scale(150).translate([0, 0]);
6427
6422
  if (clip != null) projection.clipExtent(null);
6428
- geoStream(object, projection.stream(boundsStream$1));
6429
- fitBounds(boundsStream$1.result());
6423
+ geoStream(object, projection.stream(boundsStream));
6424
+ fitBounds(boundsStream.result());
6430
6425
  if (clip != null) projection.clipExtent(clip);
6431
6426
  return projection;
6432
6427
  }
@@ -7298,7 +7293,7 @@ function polymap(domain, range, interpolate) {
7298
7293
  r[i] = interpolate(range[i], range[i + 1]);
7299
7294
  }
7300
7295
  return function (x) {
7301
- var i = bisect(domain, x, 1, j) - 1;
7296
+ var i = bisectRight(domain, x, 1, j) - 1;
7302
7297
  return r[i](d[i](x));
7303
7298
  };
7304
7299
  }
@@ -7656,7 +7651,7 @@ function quantile() {
7656
7651
  return scale;
7657
7652
  }
7658
7653
  function scale(x) {
7659
- return x == null || isNaN(x = +x) ? unknown : range[bisect(thresholds, x)];
7654
+ return x == null || isNaN(x = +x) ? unknown : range[bisectRight(thresholds, x)];
7660
7655
  }
7661
7656
  scale.invertExtent = function (y) {
7662
7657
  var i = range.indexOf(y);
@@ -7690,7 +7685,7 @@ function threshold() {
7690
7685
  unknown,
7691
7686
  n = 1;
7692
7687
  function scale(x) {
7693
- return x != null && x <= x ? range[bisect(domain, x, 0, n)] : unknown;
7688
+ return x != null && x <= x ? range[bisectRight(domain, x, 0, n)] : unknown;
7694
7689
  }
7695
7690
  scale.domain = function (_) {
7696
7691
  return arguments.length ? (domain = Array.from(_), n = Math.min(domain.length, range.length - 1), scale) : domain.slice();
@@ -13616,17 +13611,19 @@ for (const [name, interval] of utcIntervals) {
13616
13611
  interval[intervalDuration] = durations.get(name);
13617
13612
  interval[intervalType] = "utc";
13618
13613
  }
13614
+ const utcFormatIntervals = [["year", utcYear, "utc"], ["month", utcMonth, "utc"], ["day", unixDay, "utc", 6 * durationMonth], ["hour", utcHour, "utc", 3 * durationDay], ["minute", utcMinute, "utc", 6 * durationHour], ["second", second$1, "utc", 30 * durationMinute]];
13615
+ const timeFormatIntervals = [["year", timeYear, "time"], ["month", timeMonth, "time"], ["day", timeDay, "time", 6 * durationMonth], ["hour", timeHour, "time", 3 * durationDay], ["minute", timeMinute, "time", 6 * durationHour], ["second", second$1, "time", 30 * durationMinute]];
13619
13616
 
13620
13617
  // An interleaved array of UTC and local time intervals, in descending order
13621
13618
  // from largest to smallest, used to determine the most specific standard time
13622
13619
  // format for a given array of dates. This is a subset of the tick intervals
13623
13620
  // listed above; we only need the breakpoints where the format changes.
13624
- const formatIntervals = [["year", utcYear, "utc"], ["year", timeYear, "time"], ["month", utcMonth, "utc"], ["month", timeMonth, "time"], ["day", unixDay, "utc", 6 * durationMonth], ["day", timeDay, "time", 6 * durationMonth],
13621
+ const formatIntervals = [utcFormatIntervals[0], timeFormatIntervals[0], utcFormatIntervals[1], timeFormatIntervals[1], utcFormatIntervals[2], timeFormatIntervals[2],
13625
13622
  // Below day, local time typically has an hourly offset from UTC and hence the
13626
13623
  // two are aligned and indistinguishable; therefore, we only consider UTC, and
13627
13624
  // we don’t consider these if the domain only has a single value.
13628
- ["hour", utcHour, "utc", 3 * durationDay], ["minute", utcMinute, "utc", 6 * durationHour], ["second", second$1, "utc", 30 * durationMinute]];
13629
- function parseInterval(input, intervals, type) {
13625
+ ...utcFormatIntervals.slice(3)];
13626
+ function parseTimeInterval(input) {
13630
13627
  let name = `${input}`.toLowerCase();
13631
13628
  if (name.endsWith("s")) name = name.slice(0, -1); // drop plural
13632
13629
  let period = 1;
@@ -13645,22 +13642,26 @@ function parseInterval(input, intervals, type) {
13645
13642
  period *= 6;
13646
13643
  break;
13647
13644
  }
13648
- let interval = intervals.get(name);
13645
+ let interval = utcIntervals.get(name);
13649
13646
  if (!interval) throw new Error(`unknown interval: ${input}`);
13647
+ if (period > 1 && !interval.every) throw new Error(`non-periodic interval: ${name}`);
13648
+ return [name, period];
13649
+ }
13650
+ function maybeTimeInterval(input) {
13651
+ return asInterval(parseTimeInterval(input), "time");
13652
+ }
13653
+ function maybeUtcInterval(input) {
13654
+ return asInterval(parseTimeInterval(input), "utc");
13655
+ }
13656
+ function asInterval([name, period], type) {
13657
+ let interval = (type === "time" ? timeIntervals : utcIntervals).get(name);
13650
13658
  if (period > 1) {
13651
- if (!interval.every) throw new Error(`non-periodic interval: ${name}`);
13652
13659
  interval = interval.every(period);
13653
13660
  interval[intervalDuration] = durations.get(name) * period;
13654
13661
  interval[intervalType] = type;
13655
13662
  }
13656
13663
  return interval;
13657
13664
  }
13658
- function maybeTimeInterval(interval) {
13659
- return parseInterval(interval, timeIntervals, "time");
13660
- }
13661
- function maybeUtcInterval(interval) {
13662
- return parseInterval(interval, utcIntervals, "utc");
13663
- }
13664
13665
 
13665
13666
  // If the given interval is a standard time interval, we may be able to promote
13666
13667
  // it a larger aligned time interval, rather than showing every nth tick.
@@ -13702,17 +13703,20 @@ function getTimeTemplate(anchor) {
13702
13703
  return anchor === "left" || anchor === "right" ? (f1, f2) => `\n${f1}\n${f2}` // extra newline to keep f1 centered
13703
13704
  : anchor === "top" ? (f1, f2) => `${f2}\n${f1}` : (f1, f2) => `${f1}\n${f2}`;
13704
13705
  }
13706
+ function getFormatIntervals(type) {
13707
+ return type === "time" ? timeFormatIntervals : type === "utc" ? utcFormatIntervals : formatIntervals;
13708
+ }
13705
13709
 
13706
13710
  // Given an array of dates, returns the largest compatible standard time
13707
13711
  // interval. If no standard interval is compatible (other than milliseconds,
13708
13712
  // which is universally compatible), returns undefined.
13709
- function inferTimeFormat(dates, anchor) {
13713
+ function inferTimeFormat(type, dates, anchor) {
13710
13714
  const step = max(pairs(dates, (a, b) => Math.abs(b - a))); // maybe undefined!
13711
13715
  if (step < 1000) return formatTimeInterval("millisecond", "utc", anchor);
13712
- for (const [name, interval, type, maxStep] of formatIntervals) {
13716
+ for (const [name, interval, intervalType, maxStep] of getFormatIntervals(type)) {
13713
13717
  if (step > maxStep) break; // e.g., 52 weeks
13714
13718
  if (name === "hour" && !step) break; // e.g., domain with a single date
13715
- if (dates.every(d => interval.floor(d) >= d)) return formatTimeInterval(name, type, anchor);
13719
+ if (dates.every(d => interval.floor(d) >= d)) return formatTimeInterval(name, intervalType, anchor);
13716
13720
  }
13717
13721
  }
13718
13722
  function formatConditional(format1, format2, template) {
@@ -15634,7 +15638,9 @@ function getGeometryChannels(channel) {
15634
15638
  return [x, y];
15635
15639
  }
15636
15640
 
15637
- const categoricalSchemes = new Map([["accent", schemeAccent], ["category10", schemeCategory10], ["dark2", schemeDark2], ["paired", schemePaired], ["pastel1", schemePastel1], ["pastel2", schemePastel2], ["set1", schemeSet1], ["set2", schemeSet2], ["set3", schemeSet3], ["tableau10", schemeTableau10]]);
15641
+ // TODO https://github.com/d3/d3-scale-chromatic/pull/51
15642
+ const schemeObservable10 = ["#4269d0", "#efb118", "#ff725c", "#6cc5b0", "#3ca951", "#ff8ab7", "#a463f2", "#97bbf5", "#9c6b4e", "#9498a0"];
15643
+ const categoricalSchemes = new Map([["accent", schemeAccent], ["category10", schemeCategory10], ["dark2", schemeDark2], ["observable10", schemeObservable10], ["paired", schemePaired], ["pastel1", schemePastel1], ["pastel2", schemePastel2], ["set1", schemeSet1], ["set2", schemeSet2], ["set3", schemeSet3], ["tableau10", schemeTableau10]]);
15638
15644
  function isCategoricalScheme(scheme) {
15639
15645
  return scheme != null && categoricalSchemes.has(`${scheme}`.toLowerCase());
15640
15646
  }
@@ -16217,7 +16223,7 @@ function createScaleOrdinal(key, channels, {
16217
16223
  if (range !== undefined) scheme = undefined; // Don’t re-apply scheme.
16218
16224
  }
16219
16225
  if (scheme === undefined && range === undefined) {
16220
- scheme = type === "ordinal" ? "turbo" : "tableau10";
16226
+ scheme = type === "ordinal" ? "turbo" : "observable10";
16221
16227
  }
16222
16228
  if (scheme !== undefined) {
16223
16229
  if (range !== undefined) {
@@ -16296,8 +16302,7 @@ function inferHint(channels, key) {
16296
16302
  } of channels) {
16297
16303
  const candidate = hint?.[key];
16298
16304
  if (candidate === undefined) continue; // no hint here
16299
- if (value === undefined) value = candidate;
16300
- // first hint
16305
+ if (value === undefined) value = candidate; // first hint
16301
16306
  else if (value !== candidate) return; // inconsistent hint
16302
16307
  }
16303
16308
  return value;
@@ -16437,6 +16442,13 @@ function inferScaleLabel(channels = [], scale) {
16437
16442
  };
16438
16443
  }
16439
16444
 
16445
+ // Determines whether the scale points in the “positive” (right or down) or
16446
+ // “negative” (left or up) direction; if the scale order cannot be determined,
16447
+ // returns NaN; used to assign an appropriate label arrow.
16448
+ function inferScaleOrder(scale) {
16449
+ return Math.sign(orderof(scale.domain())) * Math.sign(orderof(scale.range()));
16450
+ }
16451
+
16440
16452
  // Returns the dimensions of the outer frame; this is subdivided into facets
16441
16453
  // with the margins of each facet collapsing into the outer margins.
16442
16454
  function outerDimensions(dimensions) {
@@ -16661,6 +16673,9 @@ function createScale(key, channels = [], options = {}) {
16661
16673
  function formatScaleType(type) {
16662
16674
  return typeof type === "symbol" ? type.description : type;
16663
16675
  }
16676
+ function maybeScaleType(type) {
16677
+ return typeof type === "string" ? `${type}`.toLowerCase() : type;
16678
+ }
16664
16679
 
16665
16680
  // A special type symbol when the x and y scales are replaced with a projection.
16666
16681
  const typeProjection = {
@@ -16674,6 +16689,8 @@ function inferScaleType(key, channels, {
16674
16689
  pivot,
16675
16690
  projection
16676
16691
  }) {
16692
+ type = maybeScaleType(type);
16693
+
16677
16694
  // The facet scales are always band scales; this cannot be changed.
16678
16695
  if (key === "fx" || key === "fy") return "band";
16679
16696
 
@@ -16685,9 +16702,8 @@ function inferScaleType(key, channels, {
16685
16702
  // If a channel dictates a scale type, make sure that it is consistent with
16686
16703
  // the user-specified scale type (if any) and all other channels. For example,
16687
16704
  // barY requires x to be a band scale and disallows any other scale type.
16688
- for (const {
16689
- type: t
16690
- } of channels) {
16705
+ for (const channel of channels) {
16706
+ const t = maybeScaleType(channel.type);
16691
16707
  if (t === undefined) continue;else if (type === undefined) type = t;else if (type !== t) throw new Error(`scale incompatible with channel: ${type} !== ${t}`);
16692
16708
  }
16693
16709
 
@@ -16785,6 +16801,7 @@ function coerceType(channels, {
16785
16801
  }, coerceValues) {
16786
16802
  for (const c of channels) {
16787
16803
  if (c.value !== undefined) {
16804
+ if (domain === undefined) domain = c.value?.domain; // promote channel domain
16788
16805
  c.value = coerceValues(c.value);
16789
16806
  }
16790
16807
  }
@@ -17710,15 +17727,14 @@ function legendRamp(color, options) {
17710
17727
  if (tickFormat === null) tickFormat = () => null;
17711
17728
  const svg = create("svg", context).attr("class", `${className}-ramp`).attr("font-family", "system-ui, sans-serif").attr("font-size", 10).attr("width", width).attr("height", height).attr("viewBox", `0 0 ${width} ${height}`).call(svg =>
17712
17729
  // Warning: if you edit this, change defaultClassName.
17713
- svg.append("style").text(`.${className}-ramp {
17730
+ svg.append("style").text(`:where(.${className}-ramp) {
17714
17731
  display: block;
17715
- background: white;
17716
17732
  height: auto;
17717
17733
  height: intrinsic;
17718
17734
  max-width: 100%;
17719
17735
  overflow: visible;
17720
17736
  }
17721
- .${className}-ramp text {
17737
+ :where(.${className}-ramp text) {
17722
17738
  white-space: pre;
17723
17739
  }`)).call(applyInlineStyles, style);
17724
17740
  let tickAdjust = g => g.selectAll(".tick line").attr("y1", marginTop + marginBottom - height);
@@ -17820,6 +17836,12 @@ function maybeMarker(marker) {
17820
17836
  return markerCircleFill;
17821
17837
  case "circle-stroke":
17822
17838
  return markerCircleStroke;
17839
+ case "tick":
17840
+ return markerTick("auto");
17841
+ case "tick-x":
17842
+ return markerTick(90);
17843
+ case "tick-y":
17844
+ return markerTick(0);
17823
17845
  }
17824
17846
  throw new Error(`invalid marker: ${marker}`);
17825
17847
  }
@@ -17830,10 +17852,13 @@ function markerDot(color, context) {
17830
17852
  return create("svg:marker", context).attr("viewBox", "-5 -5 10 10").attr("markerWidth", 6.67).attr("markerHeight", 6.67).attr("fill", color).attr("stroke", "none").call(marker => marker.append("circle").attr("r", 2.5)).node();
17831
17853
  }
17832
17854
  function markerCircleFill(color, context) {
17833
- return create("svg:marker", context).attr("viewBox", "-5 -5 10 10").attr("markerWidth", 6.67).attr("markerHeight", 6.67).attr("fill", color).attr("stroke", "white").attr("stroke-width", 1.5).call(marker => marker.append("circle").attr("r", 3)).node();
17855
+ return create("svg:marker", context).attr("viewBox", "-5 -5 10 10").attr("markerWidth", 6.67).attr("markerHeight", 6.67).attr("fill", color).attr("stroke", "var(--plot-background)").attr("stroke-width", 1.5).call(marker => marker.append("circle").attr("r", 3)).node();
17834
17856
  }
17835
17857
  function markerCircleStroke(color, context) {
17836
- return create("svg:marker", context).attr("viewBox", "-5 -5 10 10").attr("markerWidth", 6.67).attr("markerHeight", 6.67).attr("fill", "white").attr("stroke", color).attr("stroke-width", 1.5).call(marker => marker.append("circle").attr("r", 3)).node();
17858
+ return create("svg:marker", context).attr("viewBox", "-5 -5 10 10").attr("markerWidth", 6.67).attr("markerHeight", 6.67).attr("fill", "var(--plot-background)").attr("stroke", color).attr("stroke-width", 1.5).call(marker => marker.append("circle").attr("r", 3)).node();
17859
+ }
17860
+ function markerTick(orient) {
17861
+ return (color, context) => create("svg:marker", context).attr("viewBox", "-3 -3 6 6").attr("markerWidth", 6).attr("markerHeight", 6).attr("orient", orient).attr("stroke", color).call(marker => marker.append("path").attr("d", "M0,-3v6")).node();
17837
17862
  }
17838
17863
  let nextMarkerId = 0;
17839
17864
  function applyMarkers(path, mark, {
@@ -17939,7 +17964,7 @@ function maybeIntervalK(k, maybeInsetK, options, trivial) {
17939
17964
  ...options,
17940
17965
  [k]: undefined,
17941
17966
  [`${k}1`]: v1 === undefined ? kv : v1,
17942
- [`${k}2`]: v2 === undefined ? kv : v2
17967
+ [`${k}2`]: v2 === undefined && !(v1 === v2 && trivial) ? kv : v2
17943
17968
  };
17944
17969
  }
17945
17970
  let D1, V1;
@@ -18577,7 +18602,7 @@ function defaultWidth(text, start = 0, end = text.length) {
18577
18602
  function monospaceWidth(text, start = 0, end = text.length) {
18578
18603
  let sum = 0;
18579
18604
  for (let i = start; i < end; i = readCharacter(text, i)) {
18580
- sum += isPictographic(text, i) ? 200 : 100;
18605
+ sum += isPictographic(text, i) ? 126 : 63;
18581
18606
  }
18582
18607
  return sum;
18583
18608
  }
@@ -19419,7 +19444,7 @@ function inferTextChannel(scale, data, ticks, tickFormat, anchor) {
19419
19444
  // possible, or the default ISO format (2014-01-26). TODO We need a better way
19420
19445
  // to infer whether the ordinal scale is UTC or local time.
19421
19446
  function inferTickFormat(scale, data, ticks, tickFormat, anchor) {
19422
- return typeof tickFormat === "function" ? tickFormat : tickFormat === undefined && data && isTemporal(data) ? inferTimeFormat(data, anchor) ?? formatDefault : scale.tickFormat ? scale.tickFormat(typeof ticks === "number" ? ticks : null, tickFormat) : tickFormat === undefined ? formatDefault : typeof tickFormat === "string" ? (isTemporal(scale.domain()) ? utcFormat : format$1)(tickFormat) : constant(tickFormat);
19447
+ return typeof tickFormat === "function" ? tickFormat : tickFormat === undefined && data && isTemporal(data) ? inferTimeFormat(scale.type, data, anchor) ?? formatDefault : scale.tickFormat ? scale.tickFormat(typeof ticks === "number" ? ticks : null, tickFormat) : tickFormat === undefined ? formatDefault : typeof tickFormat === "string" ? (isTemporal(scale.domain()) ? utcFormat : format$1)(tickFormat) : constant(tickFormat);
19423
19448
  }
19424
19449
  function inclusiveRange(interval, min, max) {
19425
19450
  return interval.range(min, interval.offset(interval.floor(max)));
@@ -19455,13 +19480,6 @@ function inferFontVariant(scale) {
19455
19480
  return scale.bandwidth && !scale.interval ? undefined : "tabular-nums";
19456
19481
  }
19457
19482
 
19458
- // Determines whether the scale points in the “positive” (right or down) or
19459
- // “negative” (left or up) direction; if the scale order cannot be determined,
19460
- // returns NaN; used to assign an appropriate label arrow.
19461
- function inferScaleOrder(scale) {
19462
- return Math.sign(orderof(scale.domain())) * Math.sign(orderof(scale.range()));
19463
- }
19464
-
19465
19483
  // Takes the scale label, and if this is not an ordinal scale and the label was
19466
19484
  // inferred from an associated channel, adds an orientation-appropriate arrow.
19467
19485
  function formatAxisLabel(k, scale, {
@@ -19553,29 +19571,29 @@ function legendItems(scale, options = {}, swatch) {
19553
19571
  const swatches = create("div", context).attr("class", `${className}-swatches ${className}-swatches-${columns != null ? "columns" : "wrap"}`);
19554
19572
  let extraStyle;
19555
19573
  if (columns != null) {
19556
- extraStyle = `.${className}-swatches-columns .${className}-swatch {
19574
+ extraStyle = `:where(.${className}-swatches-columns .${className}-swatch) {
19557
19575
  display: flex;
19558
19576
  align-items: center;
19559
19577
  break-inside: avoid;
19560
19578
  padding-bottom: 1px;
19561
19579
  }
19562
- .${className}-swatches-columns .${className}-swatch::before {
19580
+ :where(.${className}-swatches-columns .${className}-swatch::before) {
19563
19581
  flex-shrink: 0;
19564
19582
  }
19565
- .${className}-swatches-columns .${className}-swatch-label {
19583
+ :where(.${className}-swatches-columns .${className}-swatch-label) {
19566
19584
  white-space: nowrap;
19567
19585
  overflow: hidden;
19568
19586
  text-overflow: ellipsis;
19569
19587
  }`;
19570
19588
  swatches.style("columns", columns).selectAll().data(scale.domain).enter().append("div").attr("class", `${className}-swatch`).call(swatch, scale, swatchWidth, swatchHeight).call(item => item.append("div").attr("class", `${className}-swatch-label`).attr("title", tickFormat).text(tickFormat));
19571
19589
  } else {
19572
- extraStyle = `.${className}-swatches-wrap {
19590
+ extraStyle = `:where(.${className}-swatches-wrap) {
19573
19591
  display: flex;
19574
19592
  align-items: center;
19575
19593
  min-height: 33px;
19576
19594
  flex-wrap: wrap;
19577
19595
  }
19578
- .${className}-swatches-wrap .${className}-swatch {
19596
+ :where(.${className}-swatches-wrap .${className}-swatch) {
19579
19597
  display: inline-flex;
19580
19598
  align-items: center;
19581
19599
  margin-right: 1em;
@@ -19584,12 +19602,12 @@ function legendItems(scale, options = {}, swatch) {
19584
19602
  return this.ownerDocument.createTextNode(tickFormat.apply(this, arguments));
19585
19603
  });
19586
19604
  }
19587
- return swatches.call(div => div.insert("style", "*").text(`.${className}-swatches {
19605
+ return swatches.call(div => div.insert("style", "*").text(`:where(.${className}-swatches) {
19588
19606
  font-family: system-ui, sans-serif;
19589
19607
  font-size: 10px;
19590
19608
  margin-bottom: 0.5em;
19591
19609
  }
19592
- .${className}-swatch > svg {
19610
+ :where(.${className}-swatch > svg) {
19593
19611
  margin-right: 0.5em;
19594
19612
  overflow: visible;
19595
19613
  }
@@ -19742,7 +19760,7 @@ function frame(options) {
19742
19760
 
19743
19761
  const defaults$2 = {
19744
19762
  ariaLabel: "tip",
19745
- fill: "white",
19763
+ fill: "var(--plot-background)",
19746
19764
  stroke: "currentColor"
19747
19765
  };
19748
19766
 
@@ -19766,6 +19784,7 @@ class Tip extends Mark {
19766
19784
  y1,
19767
19785
  y2,
19768
19786
  anchor,
19787
+ preferredAnchor = "bottom",
19769
19788
  monospace,
19770
19789
  fontFamily = monospace ? "ui-monospace, monospace" : undefined,
19771
19790
  fontSize,
@@ -19822,7 +19841,7 @@ class Tip extends Mark {
19822
19841
  } // filter: defined
19823
19842
  }, options, defaults$2);
19824
19843
  this.anchor = maybeAnchor$1(anchor, "anchor");
19825
- this.previousAnchor = this.anchor ?? "top-left";
19844
+ this.preferredAnchor = maybeAnchor$1(preferredAnchor, "preferredAnchor");
19826
19845
  this.frameAnchor = maybeFrameAnchor(frameAnchor);
19827
19846
  this.textAnchor = impliedString(textAnchor, "middle");
19828
19847
  this.textPadding = +textPadding;
@@ -19970,8 +19989,8 @@ class Tip extends Mark {
19970
19989
  const [k] = cut(value, w - widthof(label), widthof, ee);
19971
19990
  if (k >= 0) {
19972
19991
  // value is truncated
19973
- value = value.slice(0, k).trimEnd() + ellipsis;
19974
19992
  title = value.trim();
19993
+ value = value.slice(0, k).trimEnd() + ellipsis;
19975
19994
  }
19976
19995
  }
19977
19996
  const line = selection.append("tspan").attr("x", 0).attr("dy", `${lineHeight}em`).text("\u200b"); // zwsp for double-click
@@ -19997,16 +20016,13 @@ class Tip extends Mark {
19997
20016
  w = Math.round(w), h = Math.round(h); // crisp edges
19998
20017
  let a = anchor; // use the specified anchor, if any
19999
20018
  if (a === undefined) {
20000
- a = mark.previousAnchor; // favor the previous anchor, if it fits
20001
20019
  const x = px(i) + ox;
20002
20020
  const y = py(i) + oy;
20003
- const fitLeft = x + w + r * 2 < width;
20004
- const fitRight = x - w - r * 2 > 0;
20005
- const fitTop = y + h + m + r * 2 + 7 < height;
20021
+ const fitLeft = x + w + m + r * 2 < width;
20022
+ const fitRight = x - w - m - r * 2 > 0;
20023
+ const fitTop = y + h + m + r * 2 < height;
20006
20024
  const fitBottom = y - h - m - r * 2 > 0;
20007
- const ax = (/-left$/.test(a) ? fitLeft || !fitRight : fitLeft && !fitRight) ? "left" : "right";
20008
- const ay = (/^top-/.test(a) ? fitTop || !fitBottom : fitTop && !fitBottom) ? "top" : "bottom";
20009
- a = mark.previousAnchor = `${ay}-${ax}`;
20025
+ a = fitLeft && fitRight ? fitTop && fitBottom ? mark.preferredAnchor : fitBottom ? "bottom" : "top" : fitTop && fitBottom ? fitLeft ? "left" : "right" : (fitLeft || fitRight) && (fitTop || fitBottom) ? `${fitBottom ? "bottom" : "top"}-${fitLeft ? "left" : "right"}` : mark.preferredAnchor;
20010
20026
  }
20011
20027
  const path = this.firstChild; // note: assumes exactly two children!
20012
20028
  const text = this.lastChild; // note: assumes exactly two children!
@@ -20481,15 +20497,15 @@ function plot(options = {}) {
20481
20497
  } = dimensions;
20482
20498
  select(svg).attr("class", className).attr("fill", "currentColor").attr("font-family", "system-ui, sans-serif").attr("font-size", 10).attr("text-anchor", "middle").attr("width", width).attr("height", height).attr("viewBox", `0 0 ${width} ${height}`).attr("aria-label", ariaLabel).attr("aria-description", ariaDescription).call(svg =>
20483
20499
  // Warning: if you edit this, change defaultClassName.
20484
- svg.append("style").text(`.${className} {
20500
+ svg.append("style").text(`:where(.${className}) {
20501
+ --plot-background: white;
20485
20502
  display: block;
20486
- background: white;
20487
20503
  height: auto;
20488
20504
  height: intrinsic;
20489
20505
  max-width: 100%;
20490
20506
  }
20491
- .${className} text,
20492
- .${className} tspan {
20507
+ :where(.${className} text),
20508
+ :where(.${className} tspan) {
20493
20509
  white-space: pre;
20494
20510
  }`)).call(applyInlineStyles, style);
20495
20511
 
@@ -20775,11 +20791,13 @@ function inferTips(marks) {
20775
20791
  pointer: tipOptions
20776
20792
  };
20777
20793
  let {
20778
- pointer: p
20794
+ pointer: p,
20795
+ preferredAnchor: a
20779
20796
  } = tipOptions;
20780
20797
  p = /^x$/i.test(p) ? pointerX : /^y$/i.test(p) ? pointerY : pointer; // TODO validate?
20781
20798
  tipOptions = p(derive(mark, tipOptions));
20782
20799
  tipOptions.title = null; // prevent implicit title for primitive data
20800
+ if (a === undefined) tipOptions.preferredAnchor = p === pointerY ? "left" : "bottom";
20783
20801
  const t = tip(mark.data, tipOptions);
20784
20802
  t.facet = mark.facet; // inherit facet settings
20785
20803
  t.facetAnchor = mark.facetAnchor; // inherit facet settings
@@ -21168,7 +21186,7 @@ gy,
21168
21186
  const BX2 = bx && setBX2([]);
21169
21187
  const BY1 = by && setBY1([]);
21170
21188
  const BY2 = by && setBY2([]);
21171
- const bin = bing(bx?.(data), by?.(data));
21189
+ const bin = bing(bx, by, data);
21172
21190
  let i = 0;
21173
21191
  for (const o of outputs) o.initialize(data);
21174
21192
  if (sort) sort.initialize(data);
@@ -21397,13 +21415,16 @@ function thresholdAuto(values, min, max) {
21397
21415
  function isTimeThresholds(t) {
21398
21416
  return isTimeInterval(t) || isIterable(t) && isTemporal(t);
21399
21417
  }
21400
- function bing(EX, EY) {
21418
+ function bing(bx, by, data) {
21419
+ const EX = bx?.(data);
21420
+ const EY = by?.(data);
21401
21421
  return EX && EY ? function* (I) {
21402
21422
  const X = EX.bin(I); // first bin on x
21403
21423
  for (const [ix, [x1, x2]] of EX.entries()) {
21404
21424
  const Y = EY.bin(X[ix]); // then bin on y
21405
21425
  for (const [iy, [y1, y2]] of EY.entries()) {
21406
21426
  yield [Y[iy], {
21427
+ data,
21407
21428
  x1,
21408
21429
  y1,
21409
21430
  x2,
@@ -21415,6 +21436,7 @@ function bing(EX, EY) {
21415
21436
  const X = EX.bin(I);
21416
21437
  for (const [i, [x1, x2]] of EX.entries()) {
21417
21438
  yield [X[i], {
21439
+ data,
21418
21440
  x1,
21419
21441
  x2
21420
21442
  }];
@@ -21423,6 +21445,7 @@ function bing(EX, EY) {
21423
21445
  const Y = EY.bin(I);
21424
21446
  for (const [i, [y1, y2]] of EY.entries()) {
21425
21447
  yield [Y[i], {
21448
+ data,
21426
21449
  y1,
21427
21450
  y2
21428
21451
  }];
@@ -21435,7 +21458,7 @@ function bin1(E, T, V) {
21435
21458
  T = coerceNumbers(T); // for faster bisection
21436
21459
  return I => {
21437
21460
  const B = E.map(() => []);
21438
- for (const i of I) B[bisect(T, V[i]) - 1]?.push(i); // TODO quantization?
21461
+ for (const i of I) B[bisectRight(T, V[i]) - 1]?.push(i); // TODO quantization?
21439
21462
  return B;
21440
21463
  };
21441
21464
  }
@@ -21984,11 +22007,13 @@ class Rect extends Mark {
21984
22007
  x1: {
21985
22008
  value: x1,
21986
22009
  scale: "x",
22010
+ type: x1 != null && x2 == null ? "band" : undefined,
21987
22011
  optional: true
21988
22012
  },
21989
22013
  y1: {
21990
22014
  value: y1,
21991
22015
  scale: "y",
22016
+ type: y1 != null && y2 == null ? "band" : undefined,
21992
22017
  optional: true
21993
22018
  },
21994
22019
  x2: {
@@ -22039,10 +22064,9 @@ class Rect extends Mark {
22039
22064
  rx,
22040
22065
  ry
22041
22066
  } = this;
22042
- return create("svg:g", context).call(applyIndirectStyles, this, dimensions, context).call(applyTransform, this, {
22043
- x: X1 && X2 && x,
22044
- y: Y1 && Y2 && y
22045
- }, 0, 0).call(g => g.selectAll().data(index).enter().append("rect").call(applyDirectStyles, this).attr("x", X1 && X2 && (projection || !isCollapsed(x)) ? i => Math.min(X1[i], X2[i]) + insetLeft : marginLeft + insetLeft).attr("y", Y1 && Y2 && (projection || !isCollapsed(y)) ? i => Math.min(Y1[i], Y2[i]) + insetTop : marginTop + insetTop).attr("width", X1 && X2 && (projection || !isCollapsed(x)) ? i => Math.max(0, Math.abs(X2[i] - X1[i]) - insetLeft - insetRight) : width - marginRight - marginLeft - insetRight - insetLeft).attr("height", Y1 && Y2 && (projection || !isCollapsed(y)) ? i => Math.max(0, Math.abs(Y1[i] - Y2[i]) - insetTop - insetBottom) : height - marginTop - marginBottom - insetTop - insetBottom).call(applyAttr, "rx", rx).call(applyAttr, "ry", ry).call(applyChannelStyles, this, channels)).node();
22067
+ const bx = (x?.bandwidth ? x.bandwidth() : 0) - insetLeft - insetRight;
22068
+ const by = (y?.bandwidth ? y.bandwidth() : 0) - insetTop - insetBottom;
22069
+ return create("svg:g", context).call(applyIndirectStyles, this, dimensions, context).call(applyTransform, this, {}, 0, 0).call(g => g.selectAll().data(index).enter().append("rect").call(applyDirectStyles, this).attr("x", X1 && (projection || !isCollapsed(x)) ? X2 ? i => Math.min(X1[i], X2[i]) + insetLeft : i => X1[i] + insetLeft : marginLeft + insetLeft).attr("y", Y1 && (projection || !isCollapsed(y)) ? Y2 ? i => Math.min(Y1[i], Y2[i]) + insetTop : i => Y1[i] + insetTop : marginTop + insetTop).attr("width", X1 && (projection || !isCollapsed(x)) ? X2 ? i => Math.max(0, Math.abs(X2[i] - X1[i]) + bx) : bx : width - marginRight - marginLeft - insetRight - insetLeft).attr("height", Y1 && (projection || !isCollapsed(y)) ? Y2 ? i => Math.max(0, Math.abs(Y1[i] - Y2[i]) + by) : by : height - marginTop - marginBottom - insetTop - insetBottom).call(applyAttr, "rx", rx).call(applyAttr, "ry", ry).call(applyChannelStyles, this, channels)).node();
22046
22070
  }
22047
22071
  }
22048
22072
  function rectY(data, options = {}) {