@toclocoinc/lattice-grid 1.48.0 → 1.49.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (71) hide show
  1. package/README.md +1 -1
  2. package/docs/API.html +8 -2
  3. package/docs/api-detail.html +91 -1
  4. package/lattice-grid.d.ts +49 -1
  5. package/lattice-grid.esm.min.js +125 -19
  6. package/lattice-grid.min.cjs +125 -19
  7. package/lattice-grid.min.js +125 -19
  8. package/modules/ai.esm.min.js +4 -4
  9. package/modules/ai.min.cjs +4 -4
  10. package/modules/ai.min.js +4 -4
  11. package/modules/angular.esm.min.js +2 -2
  12. package/modules/angular.min.cjs +2 -2
  13. package/modules/angular.min.js +2 -2
  14. package/modules/chart-alluvial.esm.min.js +1 -1
  15. package/modules/chart-arc.esm.min.js +1 -1
  16. package/modules/chart-bubblemap.esm.min.js +1 -1
  17. package/modules/chart-bump.esm.min.js +1 -1
  18. package/modules/chart-calendar.esm.min.js +1 -1
  19. package/modules/chart-decomposition.esm.min.js +1 -1
  20. package/modules/chart-diverging.esm.min.js +1 -1
  21. package/modules/chart-dumbbell.esm.min.js +1 -1
  22. package/modules/chart-fan.esm.min.js +1 -1
  23. package/modules/chart-hexbin.esm.min.js +1 -1
  24. package/modules/chart-hexmap.esm.min.js +1 -1
  25. package/modules/chart-icicle.esm.min.js +1 -1
  26. package/modules/chart-parallel.esm.min.js +1 -1
  27. package/modules/chart-ridgeline.esm.min.js +1 -1
  28. package/modules/chart-roc.esm.min.js +1 -1
  29. package/modules/chart-slope.esm.min.js +1 -1
  30. package/modules/chart-splom.esm.min.js +1 -1
  31. package/modules/chart-waffle.esm.min.js +1 -1
  32. package/modules/charts.esm.min.js +1299 -1231
  33. package/modules/charts.min.cjs +1299 -1231
  34. package/modules/charts.min.js +1299 -1231
  35. package/modules/data-router.esm.min.js +4 -4
  36. package/modules/data-router.min.cjs +4 -4
  37. package/modules/data-router.min.js +4 -4
  38. package/modules/devtools.esm.min.js +2 -2
  39. package/modules/devtools.min.cjs +2 -2
  40. package/modules/devtools.min.js +2 -2
  41. package/modules/dhtmlx-compat.esm.min.js +4 -4
  42. package/modules/dhtmlx-compat.min.cjs +4 -4
  43. package/modules/dhtmlx-compat.min.js +4 -4
  44. package/modules/gantt.esm.min.js +4 -4
  45. package/modules/gantt.min.cjs +4 -4
  46. package/modules/gantt.min.js +4 -4
  47. package/modules/htmx.esm.min.js +125 -19
  48. package/modules/htmx.min.cjs +125 -19
  49. package/modules/htmx.min.js +125 -19
  50. package/modules/kanban.esm.min.js +4 -4
  51. package/modules/kanban.min.cjs +4 -4
  52. package/modules/kanban.min.js +4 -4
  53. package/modules/kpi.esm.min.js +4 -4
  54. package/modules/kpi.min.cjs +4 -4
  55. package/modules/kpi.min.js +4 -4
  56. package/modules/mock-socket.esm.min.js +2 -2
  57. package/modules/mock-socket.min.cjs +2 -2
  58. package/modules/mock-socket.min.js +2 -2
  59. package/modules/react.esm.min.js +2 -2
  60. package/modules/react.min.cjs +2 -2
  61. package/modules/react.min.js +2 -2
  62. package/modules/svelte.esm.min.js +2 -2
  63. package/modules/svelte.min.cjs +2 -2
  64. package/modules/svelte.min.js +2 -2
  65. package/modules/vue.esm.min.js +2 -2
  66. package/modules/vue.min.cjs +2 -2
  67. package/modules/vue.min.js +2 -2
  68. package/modules/webcomponent.esm.min.js +125 -19
  69. package/modules/webcomponent.min.cjs +125 -19
  70. package/modules/webcomponent.min.js +125 -19
  71. package/package.json +1 -1
package/README.md CHANGED
@@ -4,7 +4,7 @@
4
4
  dependencies, no build step required. Optional adapters for React, Vue, Svelte
5
5
  and Web Components ship alongside it.
6
6
 
7
- Version 1.48.0 · [latticegrid.dev](https://www.latticegrid.dev) · TOCLOCO Inc
7
+ Version 1.49.0 · [latticegrid.dev](https://www.latticegrid.dev) · TOCLOCO Inc
8
8
 
9
9
  ---
10
10
 
package/docs/API.html CHANGED
@@ -6168,7 +6168,7 @@ spans.addSpan('R0', 'name', 3, 2); <span class="cmt">// rowspan 3, colspan 2</sp
6168
6168
  <h3 id="nested-config-example">Nested configuration, executed</h3>
6169
6169
  <p class="section-note">Thirteen option blocks, each key written where it belongs. Parsed and evaluated on
6170
6170
  every build, so a key that was renamed or moved shows up here.</p>
6171
- <pre data-run="js" data-expect="14" data-covers="config:aboveLimit config:adapter config:binary config:bucket config:bucketFn config:buckets config:cacheLimit config:cardinalityLimit config:checkbox config:coalesceMs config:commit config:confirm config:cumulative config:debounce config:decimals config:delimiter config:display config:download config:enabled config:enterMovesDown config:fetch config:fileName config:fill config:fillHandle config:follow config:format config:from config:granularity config:groupBy config:hasChildren config:headerCheckbox config:headers config:hint config:idleMs config:indexLimit config:isMaster config:join config:label config:limit config:limitPer config:lineEnding config:loadChildren config:lock config:lockMs config:markdown config:maxCachedPages config:maxDecimals config:maxRows config:me config:minDecimals config:mode config:onCreate config:open config:orient config:orphans config:pageSize config:palette config:parentKey config:path config:pendingTimeout config:placement config:processCell config:profile config:promoteToMemoryBelow config:provider config:quote config:ranges config:removeMs config:retainSource config:roster config:scale config:select config:space config:start config:strategy config:system config:target config:throttleMs config:undoDepth config:unit config:unnest config:where"><code><span class="cmt">// Placeholders for the things a real page supplies. The point of this block is</span>
6171
+ <pre data-run="js" data-expect="14" data-covers="config:aboveLimit config:adapter config:ageBy config:binary config:bucket config:bucketFn config:buckets config:cacheLimit config:cardinalityLimit config:checkbox config:coalesceMs config:commit config:confirm config:cumulative config:debounce config:decimals config:delimiter config:display config:download config:enabled config:enterMovesDown config:fetch config:fileName config:fill config:fillHandle config:follow config:format config:from config:granularity config:groupBy config:hasChildren config:headerCheckbox config:headers config:hint config:idleMs config:indexLimit config:isMaster config:join config:label config:limit config:limitPer config:lineEnding config:loadChildren config:lock config:lockMs config:markdown config:maxCachedPages config:maxAge config:maxDecimals config:maxRows config:me config:minDecimals config:mode config:onCreate config:open config:orient config:orphans config:pageSize config:palette config:parentKey config:path config:pendingTimeout config:placement config:processCell config:profile config:promoteToMemoryBelow config:provider config:quote config:ranges config:removeMs config:retainSource config:roster config:scale config:select config:space config:start config:strategy config:system config:target config:throttleMs config:undoDepth config:unit config:unnest config:where"><code><span class="cmt">// Placeholders for the things a real page supplies. The point of this block is</span>
6172
6172
  <span class="cmt">// the option names: each one below is a documented key, written where it</span>
6173
6173
  <span class="cmt">// belongs, so a key that was renamed or moved stops matching its interface.</span>
6174
6174
  <span class="kw">const</span> source = {}, other = {}, provider = {}, compute = {}, adapter = {};
@@ -6209,7 +6209,10 @@ spans.addSpan('R0', 'name', 3, 2); <span class="cmt">// rowspan 3, colspan 2</sp
6209
6209
  <span class="kw">const</span> pagedSourceConfig = { mode: 'paged', pageSize: 100, maxCachedPages: 5, fetch };
6210
6210
 
6211
6211
  <span class="cmt">// A streaming source — StreamSourceConfig</span>
6212
- <span class="kw">const</span> streamSourceConfig = { mode: 'stream', open, coalesceMs: 16, maxRows: 1e6, promoteToMemoryBelow: 5e5 };
6212
+ <span class="kw">const</span> streamSourceConfig = { mode: 'stream', open, coalesceMs: 16, maxRows: 1e6, promoteToMemoryBelow: 5e5,
6213
+ <span class="cmt">// A rolling *time* window beside the count one: keep five minutes, aged by the</span>
6214
+ <span class="cmt">// row's own clock. Omit ageBy and rows age from when they arrived instead.</span>
6215
+ maxAge: 5 * 60 * 1000, ageBy: 'ts' };
6213
6216
 
6214
6217
  <span class="cmt">// A pushdown source — PushdownSourceConfig</span>
6215
6218
  <span class="kw">const</span> pushdownSourceConfig = { adapter, compute, pageSize: 200 };
@@ -6916,6 +6919,7 @@ return `next ${p.mean.toFixed(1)}; r2 ${f.r2.toFixed(1)}; band ${p.upper - p.low
6916
6919
  <tr><td class="name">labels</td><td class="type">boolean</td><td class="desc">Draw the tick labels. <small>(optional)</small></td></tr>
6917
6920
  <tr><td class="name">every</td><td class="type">number</td><td class="desc">Show every nth category label, on a crowded category axis. <small>(optional)</small></td></tr>
6918
6921
  <tr><td class="name">rotate</td><td class="type">boolean | 'auto'</td><td class="desc">Force the category labels' rotation rather than deciding it. <small>(optional)</small></td></tr>
6922
+ <tr><td class="name">window</td><td class="type">Pick&lt;WindowSpec, 'kind' | 'span'&gt;</td><td class="desc">A rolling window for the axis domain (BACKLOG-0001036), in the shipped `WindowSpec` vocabulary that rolling statistics already use. Only `{ kind: 'time', span }` applies to an axis: the domain becomes the last `span` milliseconds ending **now**, so the chart keeps scrolling left while the feed is silent — the thing a count window cannot do, because with no rows arriving nothing changes. Advanced on a low-frequency clock (a quarter of the window, between 50 ms and 1 s), never per frame, and stopped when the chart is destroyed or its document is hidden. Needs a continuous x axis carrying wall-clock times; `{ kind: 'count' }` is the source's `maxRows` and is refused here rather than given a second meaning. <small>(optional)</small></td></tr>
6919
6923
  </tbody>
6920
6924
  </table>
6921
6925
  </div>
@@ -9900,6 +9904,8 @@ return `next ${p.mean.toFixed(1)}; r2 ${f.r2.toFixed(1)}; band ${p.upper - p.low
9900
9904
  <tr><td class="name">mode</td><td class="type">'stream'</td><td class="desc"></td></tr>
9901
9905
  <tr><td class="name">open</td><td class="type">(req: {</td><td class="desc"></td></tr>
9902
9906
  <tr><td class="name">maxRows</td><td class="type">number</td><td class="desc">The most rows to keep. A stream has no end, so an unbounded grid dies overnight; this makes it a sliding window and the oldest rows are dropped. Omit for no limit. Set on the source, not passed to `open`, it bounds what the grid retains rather than what the producer sends. <small>(optional)</small></td></tr>
9907
+ <tr><td class="name">maxAge</td><td class="type">number</td><td class="desc">The longest a row is kept, in milliseconds — a rolling *time* window, sitting beside `maxRows` as a second, independent bound (BACKLOG-0001036). Rows older than the span are evicted through the same path, the same `evicted` counters and the same `stream:evicted` event as the count bound, so an existing readout keeps working. Set both and whichever bites first applies. Eviction continues on a low-frequency timer while the feed is idle, so "the last five minutes" keeps shrinking through a silent period rather than freezing — which is the thing `maxRows` cannot do. Retention is a *bound, not a guillotine*: rows live a little past the span before a block is dropped. Two things add to it. First the eviction slack, ten per cent of the span, exactly as `maxRows` overshoots its count, so the row permutation is rebuilt once per block rather than once per row. Second, when the feed is idle, up to one tick of the eviction timer, which runs at a quarter of the span clamped to between 50 ms and one second. So the real ceiling is roughly `span * 1.1 + tick`, and because the tick has a floor it is proportionally larger the shorter the window: negligible at a five-minute window (about 10%), around 1.25x at ten seconds, and as much as ~1.35x at three. That is the deliberate trade for an idle grid that costs no CPU. Omit for no age limit. <small>(optional)</small></td></tr>
9908
+ <tr><td class="name">ageBy</td><td class="type">string | ((row: unknown) =&gt; unknown)</td><td class="desc">Which clock `maxAge` reads: a column id (or dotted path), or a function of the row returning a `Date`, epoch milliseconds, or an ISO string (BACKLOG-0001036). Given, the window follows the **data's own** clock, so it means what the producer means — and inherits the producer's clock skew. Omitted, `maxAge` falls back to **arrival time**: when the row reached this source. Arrival time needs no timestamp column and cannot be skewed, but it is not event time — a row delayed in transit counts as young. A row whose time value cannot be read is never aged out. <small>(optional)</small></td></tr>
9903
9909
  <tr><td class="name">promoteToMemoryBelow</td><td class="type">number</td><td class="desc"><small>(optional)</small></td></tr>
9904
9910
  <tr><td class="name">coalesceMs</td><td class="type">number</td><td class="desc"><small>(optional)</small></td></tr>
9905
9911
  </tbody>
@@ -437,7 +437,7 @@
437
437
  <div class="shell">
438
438
  <aside class="rail">
439
439
  <p class="rail__brand">Lattice Grid</p>
440
- <p class="rail__sub">Developer guide · v1.48.0</p>
440
+ <p class="rail__sub">Developer guide · v1.49.0</p>
441
441
  <nav>
442
442
  <div class="rail__group">
443
443
  <span class="rail__label">Start here</span>
@@ -4470,6 +4470,96 @@ grid.updates.log({ since: Date.now() - 60000 }); <span class="cmt">// what arr
4470
4470
  left up overnight holds every row it was ever sent. Set <code>source.maxRows</code> and the
4471
4471
  stream becomes a sliding window, dropping the oldest as new ones arrive and reporting how
4472
4472
  many it let go through <code>evicted</code> on the progress report.</p>
4473
+ </div>
4474
+
4475
+ <h3 id="time-window-guide">A time window, not just a row count</h3>
4476
+ <p class="lead-in">
4477
+ <code>maxRows</code> is a <em>count</em> window. <code>maxAge</code> is a <em>time</em>
4478
+ window. They are different promises, and a live feed usually wants the second one.
4479
+ </p>
4480
+ <div class="example">
4481
+ <p class="example__label">Keep the last five minutes, and show the last five minutes</p>
4482
+ <pre><code>const grid = createGrid(el, {
4483
+ columns,
4484
+ source: {
4485
+ mode: 'stream',
4486
+ open,
4487
+ maxAge: 5 * 60 * 1000, <span class="cmt">// keep five minutes of rows</span>
4488
+ ageBy: 'ts', <span class="cmt">// ...aged by this column; omit for arrival time</span>
4489
+ maxRows: 20000, <span class="cmt">// ...and never more than this many, whichever bites first</span>
4490
+ },
4491
+ });
4492
+
4493
+ createChart({
4494
+ grid, container, type: 'line', x: 'ts', y: { col: 'value', fn: 'avg' },
4495
+ <span class="cmt">// The x domain is the last five minutes ending *now*, so the chart</span>
4496
+ <span class="cmt">// keeps scrolling left even while the feed is silent.</span>
4497
+ axis: { x: { window: { kind: 'time', span: 5 * 60 * 1000 } } },
4498
+ });</code></pre>
4499
+ </div>
4500
+ <div class="why">
4501
+ <p><strong>A count window drifts, and it freezes.</strong> <code>maxRows</code> equals
4502
+ &ldquo;the last five minutes&rdquo; only while the feed rate is steady: a burst silently
4503
+ shrinks the window to two minutes, a quiet spell stretches it to twenty, and the x axis
4504
+ changes span under the reader. Worse, when the feed goes quiet nothing is evicted and the
4505
+ chart stops moving, even though time is still passing &mdash; and the silence is usually the
4506
+ thing worth seeing. <code>maxAge</code> is a span of wall clock, so it means the same thing
4507
+ whatever the feed is doing.</p>
4508
+ <p><strong>Two bounds, one eviction path.</strong> <code>maxAge</code> and
4509
+ <code>maxRows</code> are independent and compose: both are applied on the same pass and
4510
+ whichever bites first is simply the one that drops rows. Neither is silently ignored.
4511
+ Age eviction reuses the count bound&rsquo;s machinery outright, so <code>evicted</code> on
4512
+ the progress report and the <code>stream:evicted</code> event carry age evictions exactly as
4513
+ they always carried count evictions &mdash; an existing &ldquo;dropped off the back of the
4514
+ window&rdquo; readout keeps working with nothing changed.</p>
4515
+ <p><strong>The span is a bound, not a guillotine.</strong> A row lives a little past the span
4516
+ before it goes, and two things add to that. First the eviction slack, ten per cent of the
4517
+ span &mdash; exactly the overshoot <code>maxRows</code> already allows on its count &mdash; so
4518
+ the row permutation is rebuilt once per block rather than once per arriving row. Second, when
4519
+ the feed is idle, up to one tick of the eviction timer, which runs at a quarter of the span
4520
+ clamped to between 50&nbsp;ms and one second. The real ceiling is therefore about
4521
+ <code>span &times; 1.1 + tick</code>, and because the tick has a floor it is
4522
+ <em>proportionally larger the shorter the window</em>: about 10% over at a five-minute
4523
+ window, around 1.25&times; at ten seconds, and as much as ~1.35&times; at three. That is the
4524
+ deliberate price of an idle grid that costs no CPU, and it is why the number to reach for is
4525
+ the window you want the reader to see rather than a hard retention limit. The chart&rsquo;s
4526
+ domain is exact either way &mdash; it ends at <em>now</em> &mdash; so the extra rows sit off
4527
+ the left edge rather than being drawn.</p>
4528
+ <p><strong>Which clock: <code>ageBy</code>, or arrival.</strong> Given
4529
+ <code>ageBy</code> &mdash; a column id, a dotted path, or a function of the row returning a
4530
+ <code>Date</code>, epoch milliseconds or an ISO string &mdash; the window follows the
4531
+ <em>data&rsquo;s own</em> clock, so it means what the producer means. That also inherits the
4532
+ producer&rsquo;s clock skew: if their clock runs five minutes fast, their rows live five
4533
+ minutes longer than yours. Omit <code>ageBy</code> and rows age from <strong>arrival
4534
+ time</strong>, when the row reached the source. Arrival time needs no timestamp column and
4535
+ cannot be skewed, but it is not event time &mdash; a row delayed in transit is treated as
4536
+ young. A synthetic or metric feed usually wants arrival; a log or event feed usually wants
4537
+ <code>ageBy</code>. A row whose time value cannot be read is never aged out: dropping data
4538
+ because a timestamp was malformed is the worse failure.</p>
4539
+ <p><strong>Out of order is handled, not reordered.</strong> With <code>ageBy</code> the
4540
+ row&rsquo;s clock need not be monotonic in arrival order, so eviction scans the window rather
4541
+ than walking the head; a late row that is already older than the span is dropped on the same
4542
+ pass it arrived on and counted as evicted, rather than being painted and then withdrawn a
4543
+ moment later. Nothing is re-sorted: a row&rsquo;s <em>position</em> is still arrival order,
4544
+ only its <em>retention</em> is decided by its time.</p>
4545
+ <p><strong>The chart axis rolls independently.</strong> The axis takes the same
4546
+ <code>WindowSpec</code> vocabulary rolling statistics use &mdash;
4547
+ <code>window: { kind: 'time', span }</code> &mdash; and its domain ends at <em>now</em>
4548
+ rather than at the newest point, which is what makes the chart keep scrolling with zero new
4549
+ rows. It works with or without <code>maxAge</code> on the source; set both to the same span
4550
+ and the retained data and the drawn domain agree. Only <code>kind: 'time'</code> applies to
4551
+ an axis: a count window over a chart is the source&rsquo;s <code>maxRows</code>, and
4552
+ <code>kind: 'count'</code> is refused with a warning rather than quietly given a second
4553
+ meaning. The x column has to be continuous and carry wall-clock times &mdash; a banded or
4554
+ categorical axis has no domain to roll.</p>
4555
+ <p><strong>Idle costs nothing.</strong> Both halves advance on a plain interval &mdash; a
4556
+ quarter of the window, clamped to between 50&nbsp;ms and one second &mdash; and never on an
4557
+ animation frame. The source&rsquo;s wake returns after a single number comparison unless a
4558
+ row is actually due, and the chart&rsquo;s wake does nothing at all when the document is
4559
+ hidden or the chart is detached. Both timers are cleared on destroy. Measured over a
4560
+ five-minute window holding 50,000 rows with no feed at all, the window&rsquo;s CPU cost is
4561
+ inside the run-to-run noise of the same source with no bound set: under 0.04% of one core
4562
+ (<code>bench/idle-window.mjs</code>).</p>
4473
4563
  <p><strong>The log keeps the raw sequence, not the merged one.</strong> Merging is right for
4474
4564
  applying a backlog quickly and wrong for looking at what happened, because the intermediate
4475
4565
  states are exactly what a time scrubber would move between. It survives the flush,
package/lattice-grid.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * Lattice Grid 1.48.0, type declarations
2
+ * Lattice Grid 1.49.0, type declarations
3
3
  * Copyright (c) 2026 TOCLOCO Inc. All rights reserved.
4
4
  * https://latticegrid.dev
5
5
  */
@@ -1145,6 +1145,41 @@ export interface StreamSourceConfig {
1145
1145
  * rather than what the producer sends.
1146
1146
  */
1147
1147
  maxRows?: number;
1148
+ /**
1149
+ * The longest a row is kept, in milliseconds — a rolling *time* window, sitting
1150
+ * beside `maxRows` as a second, independent bound (BACKLOG-0001036). Rows older
1151
+ * than the span are evicted through the same path, the same `evicted` counters
1152
+ * and the same `stream:evicted` event as the count bound, so an existing
1153
+ * readout keeps working. Set both and whichever bites first applies. Eviction
1154
+ * continues on a low-frequency timer while the feed is idle, so "the last five
1155
+ * minutes" keeps shrinking through a silent period rather than freezing —
1156
+ * which is the thing `maxRows` cannot do.
1157
+ *
1158
+ * Retention is a *bound, not a guillotine*: rows live a little past the span
1159
+ * before a block is dropped. Two things add to it. First the eviction slack,
1160
+ * ten per cent of the span, exactly as `maxRows` overshoots its count, so the
1161
+ * row permutation is rebuilt once per block rather than once per row. Second,
1162
+ * when the feed is idle, up to one tick of the eviction timer, which runs at a
1163
+ * quarter of the span clamped to between 50 ms and one second. So the real
1164
+ * ceiling is roughly `span * 1.1 + tick`, and because the tick has a floor it
1165
+ * is proportionally larger the shorter the window: negligible at a five-minute
1166
+ * window (about 10%), around 1.25x at ten seconds, and as much as ~1.35x at
1167
+ * three. That is the deliberate trade for an idle grid that costs no CPU.
1168
+ *
1169
+ * Omit for no age limit.
1170
+ */
1171
+ maxAge?: number;
1172
+ /**
1173
+ * Which clock `maxAge` reads: a column id (or dotted path), or a function of
1174
+ * the row returning a `Date`, epoch milliseconds, or an ISO string
1175
+ * (BACKLOG-0001036). Given, the window follows the **data's own** clock, so it
1176
+ * means what the producer means — and inherits the producer's clock skew.
1177
+ * Omitted, `maxAge` falls back to **arrival time**: when the row reached this
1178
+ * source. Arrival time needs no timestamp column and cannot be skewed, but it
1179
+ * is not event time — a row delayed in transit counts as young. A row whose
1180
+ * time value cannot be read is never aged out.
1181
+ */
1182
+ ageBy?: string | ((row: unknown) => unknown);
1148
1183
  promoteToMemoryBelow?: number;
1149
1184
  coalesceMs?: number;
1150
1185
  }
@@ -6238,6 +6273,19 @@ export interface ChartAxis {
6238
6273
  every?: number;
6239
6274
  /** Force the category labels' rotation rather than deciding it. */
6240
6275
  rotate?: boolean | 'auto';
6276
+ /**
6277
+ * A rolling window for the axis domain (BACKLOG-0001036), in the shipped
6278
+ * `WindowSpec` vocabulary that rolling statistics already use. Only
6279
+ * `{ kind: 'time', span }` applies to an axis: the domain becomes the last
6280
+ * `span` milliseconds ending **now**, so the chart keeps scrolling left while
6281
+ * the feed is silent — the thing a count window cannot do, because with no
6282
+ * rows arriving nothing changes. Advanced on a low-frequency clock (a quarter
6283
+ * of the window, between 50 ms and 1 s), never per frame, and stopped when the
6284
+ * chart is destroyed or its document is hidden. Needs a continuous x axis
6285
+ * carrying wall-clock times; `{ kind: 'count' }` is the source's `maxRows` and
6286
+ * is refused here rather than given a second meaning.
6287
+ */
6288
+ window?: Pick<WindowSpec, 'kind' | 'span'>;
6241
6289
  }
6242
6290
 
6243
6291
  /**