@toclocoinc/lattice-grid 1.67.0 → 1.68.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.
- package/README.md +1 -1
- package/angular/package.json +1 -1
- package/docs/API.html +21 -16
- package/docs/api-detail.html +40 -5
- package/lattice-grid.d.ts +12 -2
- package/lattice-grid.esm.min.js +27 -7
- package/lattice-grid.min.cjs +27 -7
- package/lattice-grid.min.js +27 -7
- package/modules/ai.d.ts +1 -1
- package/modules/ai.esm.min.js +3 -3
- package/modules/ai.min.cjs +3 -3
- package/modules/ai.min.js +3 -3
- package/modules/angular.d.ts +1 -1
- package/modules/angular.esm.min.js +3 -3
- package/modules/angular.min.cjs +3 -3
- package/modules/angular.min.js +3 -3
- package/modules/chart-alluvial.d.ts +1 -1
- package/modules/chart-alluvial.esm.min.js +1 -1
- package/modules/chart-alluvial.min.cjs +1 -1
- package/modules/chart-alluvial.min.js +1 -1
- package/modules/chart-arc.d.ts +1 -1
- package/modules/chart-arc.esm.min.js +1 -1
- package/modules/chart-arc.min.cjs +1 -1
- package/modules/chart-arc.min.js +1 -1
- package/modules/chart-bubblemap.d.ts +1 -1
- package/modules/chart-bubblemap.esm.min.js +1 -1
- package/modules/chart-bubblemap.min.cjs +1 -1
- package/modules/chart-bubblemap.min.js +1 -1
- package/modules/chart-bump.d.ts +1 -1
- package/modules/chart-bump.esm.min.js +1 -1
- package/modules/chart-bump.min.cjs +1 -1
- package/modules/chart-bump.min.js +1 -1
- package/modules/chart-calendar.d.ts +1 -1
- package/modules/chart-calendar.esm.min.js +1 -1
- package/modules/chart-calendar.min.cjs +1 -1
- package/modules/chart-calendar.min.js +1 -1
- package/modules/chart-decomposition.d.ts +1 -1
- package/modules/chart-decomposition.esm.min.js +1 -1
- package/modules/chart-decomposition.min.cjs +1 -1
- package/modules/chart-decomposition.min.js +1 -1
- package/modules/chart-diverging.d.ts +1 -1
- package/modules/chart-diverging.esm.min.js +1 -1
- package/modules/chart-diverging.min.cjs +1 -1
- package/modules/chart-diverging.min.js +1 -1
- package/modules/chart-dumbbell.d.ts +1 -1
- package/modules/chart-dumbbell.esm.min.js +1 -1
- package/modules/chart-dumbbell.min.cjs +1 -1
- package/modules/chart-dumbbell.min.js +1 -1
- package/modules/chart-fan.d.ts +1 -1
- package/modules/chart-fan.esm.min.js +1 -1
- package/modules/chart-fan.min.cjs +1 -1
- package/modules/chart-fan.min.js +1 -1
- package/modules/chart-hexbin.d.ts +1 -1
- package/modules/chart-hexbin.esm.min.js +1 -1
- package/modules/chart-hexbin.min.cjs +1 -1
- package/modules/chart-hexbin.min.js +1 -1
- package/modules/chart-hexmap.d.ts +1 -1
- package/modules/chart-hexmap.esm.min.js +1 -1
- package/modules/chart-hexmap.min.cjs +1 -1
- package/modules/chart-hexmap.min.js +1 -1
- package/modules/chart-icicle.d.ts +1 -1
- package/modules/chart-icicle.esm.min.js +1 -1
- package/modules/chart-icicle.min.cjs +1 -1
- package/modules/chart-icicle.min.js +1 -1
- package/modules/chart-markermap.d.ts +1 -1
- package/modules/chart-markermap.esm.min.js +1 -1
- package/modules/chart-markermap.min.cjs +1 -1
- package/modules/chart-markermap.min.js +1 -1
- package/modules/chart-parallel.d.ts +1 -1
- package/modules/chart-parallel.esm.min.js +1 -1
- package/modules/chart-parallel.min.cjs +1 -1
- package/modules/chart-parallel.min.js +1 -1
- package/modules/chart-ridgeline.d.ts +1 -1
- package/modules/chart-ridgeline.esm.min.js +1 -1
- package/modules/chart-ridgeline.min.cjs +1 -1
- package/modules/chart-ridgeline.min.js +1 -1
- package/modules/chart-roc.d.ts +1 -1
- package/modules/chart-roc.esm.min.js +1 -1
- package/modules/chart-roc.min.cjs +1 -1
- package/modules/chart-roc.min.js +1 -1
- package/modules/chart-slope.d.ts +1 -1
- package/modules/chart-slope.esm.min.js +1 -1
- package/modules/chart-slope.min.cjs +1 -1
- package/modules/chart-slope.min.js +1 -1
- package/modules/chart-splom.d.ts +1 -1
- package/modules/chart-splom.esm.min.js +1 -1
- package/modules/chart-splom.min.cjs +1 -1
- package/modules/chart-splom.min.js +1 -1
- package/modules/chart-waffle.d.ts +1 -1
- package/modules/chart-waffle.esm.min.js +1 -1
- package/modules/chart-waffle.min.cjs +1 -1
- package/modules/chart-waffle.min.js +1 -1
- package/modules/charts.d.ts +1 -1
- package/modules/charts.esm.min.js +1376 -1249
- package/modules/charts.min.cjs +1376 -1249
- package/modules/charts.min.js +1376 -1249
- package/modules/data-router.d.ts +1 -1
- package/modules/data-router.esm.min.js +204 -8
- package/modules/data-router.min.cjs +204 -8
- package/modules/data-router.min.js +204 -8
- package/modules/devtools.d.ts +1 -1
- package/modules/devtools.esm.min.js +1 -1
- package/modules/devtools.min.cjs +1 -1
- package/modules/devtools.min.js +1 -1
- package/modules/dhtmlx-compat.d.ts +1 -1
- package/modules/dhtmlx-compat.esm.min.js +3 -3
- package/modules/dhtmlx-compat.min.cjs +3 -3
- package/modules/dhtmlx-compat.min.js +3 -3
- package/modules/gantt.d.ts +1 -1
- package/modules/gantt.esm.min.js +32 -7
- package/modules/gantt.min.cjs +32 -7
- package/modules/gantt.min.js +32 -7
- package/modules/geo-europe-nuts.d.ts +1 -1
- package/modules/geo-europe-nuts.esm.min.js +1 -1
- package/modules/geo-uk.d.ts +1 -1
- package/modules/geo-uk.esm.min.js +1 -1
- package/modules/geo-us-states.d.ts +1 -1
- package/modules/geo-us-states.esm.min.js +1 -1
- package/modules/geo-world-110m.d.ts +1 -1
- package/modules/geo-world-110m.esm.min.js +1 -1
- package/modules/geo-world-50m.d.ts +1 -1
- package/modules/geo-world-50m.esm.min.js +1 -1
- package/modules/htmx.d.ts +1 -1
- package/modules/htmx.esm.min.js +27 -7
- package/modules/htmx.min.cjs +27 -7
- package/modules/htmx.min.js +27 -7
- package/modules/kanban.d.ts +1 -1
- package/modules/kanban.esm.min.js +3 -3
- package/modules/kanban.min.cjs +3 -3
- package/modules/kanban.min.js +3 -3
- package/modules/kpi.d.ts +26 -8
- package/modules/kpi.esm.min.js +31 -6
- package/modules/kpi.min.cjs +31 -6
- package/modules/kpi.min.js +31 -6
- package/modules/layout.d.ts +1 -1
- package/modules/layout.esm.min.js +3 -3
- package/modules/layout.min.cjs +3 -3
- package/modules/layout.min.js +3 -3
- package/modules/mock-socket.d.ts +1 -1
- package/modules/mock-socket.esm.min.js +1 -1
- package/modules/mock-socket.min.cjs +1 -1
- package/modules/mock-socket.min.js +1 -1
- package/modules/react.d.ts +1 -1
- package/modules/react.esm.min.js +3 -3
- package/modules/react.min.cjs +3 -3
- package/modules/react.min.js +3 -3
- package/modules/svelte.d.ts +1 -1
- package/modules/svelte.esm.min.js +3 -3
- package/modules/svelte.min.cjs +3 -3
- package/modules/svelte.min.js +3 -3
- package/modules/tabs.d.ts +1 -1
- package/modules/tabs.esm.min.js +13 -14
- package/modules/tabs.min.cjs +13 -14
- package/modules/tabs.min.js +13 -14
- package/modules/vue.d.ts +1 -1
- package/modules/vue.esm.min.js +3 -3
- package/modules/vue.min.cjs +3 -3
- package/modules/vue.min.js +3 -3
- package/modules/webcomponent.d.ts +1 -1
- package/modules/webcomponent.esm.min.js +27 -7
- package/modules/webcomponent.min.cjs +27 -7
- package/modules/webcomponent.min.js +27 -7
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -5,7 +5,7 @@ dependencies, no build step required. Optional adapters for React, Vue, Svelte
|
|
|
5
5
|
and Web Components ship alongside it, and Angular has compiled components of its
|
|
6
6
|
own at `@toclocoinc/lattice-grid/angular` — inside this package, not beside it.
|
|
7
7
|
|
|
8
|
-
Version 1.
|
|
8
|
+
Version 1.68.0 · [latticegrid.dev](https://www.latticegrid.dev) · TOCLOCO Inc
|
|
9
9
|
|
|
10
10
|
---
|
|
11
11
|
|
package/angular/package.json
CHANGED
package/docs/API.html
CHANGED
|
@@ -363,7 +363,7 @@
|
|
|
363
363
|
<div class="shell">
|
|
364
364
|
<aside class="rail">
|
|
365
365
|
<p class="rail__brand">Lattice Grid</p>
|
|
366
|
-
<p class="rail__sub">API reference · v1.
|
|
366
|
+
<p class="rail__sub">API reference · v1.68.0</p>
|
|
367
367
|
<nav>
|
|
368
368
|
<div class="rail__group">
|
|
369
369
|
<span class="rail__label">Start</span>
|
|
@@ -456,7 +456,7 @@
|
|
|
456
456
|
</header>
|
|
457
457
|
|
|
458
458
|
<p class="chips">
|
|
459
|
-
<span class="chip">Version 1.
|
|
459
|
+
<span class="chip">Version 1.68.0</span>
|
|
460
460
|
<span class="chip">Zero dependencies</span>
|
|
461
461
|
<span class="chip"><a href="api-detail.html">Developer guide →</a></span>
|
|
462
462
|
</p>
|
|
@@ -1960,7 +1960,7 @@ grid.destroy();
|
|
|
1960
1960
|
<table>
|
|
1961
1961
|
<thead><tr><th>Member</th><th>Returns</th><th>Description</th></tr></thead>
|
|
1962
1962
|
<tbody>
|
|
1963
|
-
<tr><td class="sig">getVersion()</td><td class="type">string</td><td class="desc">The version this grid came from, e.g. <code>'1.
|
|
1963
|
+
<tr><td class="sig">getVersion()</td><td class="type">string</td><td class="desc">The version this grid came from, e.g. <code>'1.68.0'</code>. Also on the module as <code>getVersion()</code>, for when you have no grid to hand.</td></tr>
|
|
1964
1964
|
<tr><td class="sig">get(key)</td><td class="type">unknown</td><td class="desc">Read any configuration key.</td></tr>
|
|
1965
1965
|
<tr><td class="sig">set(key, value)</td><td class="type">void</td><td class="desc">Write one key. Every key is live; nothing needs a rebuild.</td></tr>
|
|
1966
1966
|
<tr><td class="sig">setAll(values)</td><td class="type">void</td><td class="desc">Write several in one pass. Emits one <code>config:changed</code> for the batch, not one per key.</td></tr>
|
|
@@ -7366,7 +7366,7 @@ const kpi = createKPI(document.querySelector('#kpis'), {
|
|
|
7366
7366
|
],
|
|
7367
7367
|
onTileClick: ({ tile }) => drillInto(tile.id),
|
|
7368
7368
|
});</code></pre>
|
|
7369
|
-
<p>Each tile names an <strong>aggregation</strong> (<code>sum</code>, <code>avg</code>, <code>min</code>, <code>max</code>, <code>count</code>, <code>countDistinct</code>, or a <code>custom</code> reducer <code>(rows, tile) => value</code>), the <strong>field</strong> it reads, and an optional <strong>filter</strong> predicate. Formatting (<code>number</code>/<code>currency</code>/<code>percent</code>/<code>compact</code>, with decimals, currency and locale), a <strong>baseline</strong> for a delta, and semantic <strong>threshold bands</strong> (two cut points with a direction, or an explicit <code>bands</code> list) are all per tile; the band is a semantic name (<code>good</code>/<code>warn</code>/<code>critical</code>), separate from any accent colour. An optional <strong>sparkline</strong> plots a <code>{ x, y }</code> series in sequence order. Each tile is a labelled <code><figure></code>, focusable and keyboard-activatable, its value announced; the sparkline transition respects <code>prefers-reduced-motion</code>.</p>
|
|
7369
|
+
<p>Each tile names an <strong>aggregation</strong> (<code>sum</code>, <code>avg</code>, <code>min</code>, <code>max</code>, <code>count</code>, <code>countDistinct</code>, or a <code>custom</code> reducer <code>(rows, tile) => value</code>), the <strong>field</strong> it reads, and an optional <strong>filter</strong> predicate. Formatting (<code>number</code>/<code>currency</code>/<code>percent</code>/<code>compact</code>, with decimals, currency and locale), a <strong>baseline</strong> for a delta, and semantic <strong>threshold bands</strong> (two cut points with a direction, or an explicit <code>bands</code> list) are all per tile; the band is a semantic name (<code>good</code>/<code>warn</code>/<code>critical</code>), separate from any accent colour. <code>delta: 'absolute' | 'relative' | 'both'</code> (default <code>'both'</code>) chooses what the movement line prints against the baseline (BACKLOG-0001673) — the difference alone, the percentage alone, or both together, because the percentage of a rate series (4.10 vs a 4.30 baseline) is meaningless and a host needs to keep the line without it. An optional <strong>sparkline</strong> plots a <code>{ x, y }</code> series in sequence order. Each tile is a labelled <code><figure></code>, focusable and keyboard-activatable, its value announced; the sparkline transition respects <code>prefers-reduced-motion</code>.</p>
|
|
7370
7370
|
<p><strong>A panel with no data says so.</strong> A tile's status is <code>good</code>, <code>warn</code>, <code>critical</code>, <code>null</code> (no thresholds) — or <code>unknown</code>, which means the tile <em>measured nothing</em>. Two things cause that: the panel holds <em>no rows at all</em>, or the tile's <code>field</code> names no column on the bound grid, so it never read a cell to reduce over. That fourth status is decided from data presence <em>before</em> any threshold is consulted, because an aggregation over nothing returns the identity of its operation (<code>sum</code> and <code>count</code> return 0) and 0 is a number a threshold grades: under <code>lowerIsBetter</code> cut points it grades <code>good</code>, so an empty panel would otherwise read as a healthy one. An <code>unknown</code> tile reports a <code>null</code> value, renders the <code>nullText</code> placeholder rather than a zero, and is marked with a dashed edge and a visible “No data” caption that also forms part of its accessible name — the state is never carried by colour alone. Because <code>unknown</code> is an explicit status rather than a severity, anything rolling tiles up can surface “not measured” instead of inheriting a false green.</p>
|
|
7371
7371
|
<p><strong>A measured zero is still a measurement.</strong> A tile whose <code>filter</code> matches none of the rows the panel <em>does</em> hold is a different thing: no open incidents is genuinely good, so it reads <code>0</code> and is graded on its thresholds exactly as before. Only an empty panel is <code>unknown</code>.</p>
|
|
7372
7372
|
<p><strong>Staleness is a different question, and a time-bounded source answers it.</strong> <code>unknown</code> is about the absence of rows, not their staleness: a panel over an unbounded store keeps showing the last values it was given when its feed goes quiet, because those rows are still there. Give the underlying source a <a href="#sources">rolling time window</a> (<code>maxAge</code> with <code>ageBy</code>) and its rows age out while the feed is silent, so the panel drains and reports <code>unknown</code> the next time it reads them — a grid-bound panel as the grid announces the change (or when the host calls <code>refresh()</code>), a routed one as the removals reach <code>rows.apply</code>.</p>
|
|
@@ -7445,7 +7445,7 @@ const kpi = createKPI(document.querySelector('#kpis'), {
|
|
|
7445
7445
|
kpi.destroy();
|
|
7446
7446
|
<span class="kw">return</span> [shapes, shaped, ignoredAgg].join(' | ');</code></pre>
|
|
7447
7447
|
<h3 id="kpi-tree">The KPI tree: top-level items that expand to the indicators beneath them</h3>
|
|
7448
|
-
<p>Set <code>tree</code> and the panel becomes a <strong>rail</strong> instead of a grid of tiles: a small number of top-level items, each expanding to the indicators underneath it, with the parent telling you at a glance whether anything below needs attention. <code>Compute</code> expands to <code>psi</code> and <code>cpu</code>; collapsed, it still shows you that one of them is in breach.</p>
|
|
7448
|
+
<p>Set <code>tree</code> and the panel becomes a <strong>rail</strong> instead of a grid of tiles: a small number of top-level items, each expanding to the indicators underneath it, with the parent telling you at a glance whether anything below needs attention. <code>Compute</code> expands to <code>psi</code> and <code>cpu</code>; collapsed, it still shows you that one of them is in breach. <code>tree</code> is the opt-in (BACKLOG-0001673): a dotted tile id is not a hierarchy on its own — with <code>tree</code> unset, the ids you see below would stay plain, unsplit tile ids and the panel would render every tile flat, warning once that setting <code>tree</code> is how the hierarchy is reached.</p>
|
|
7449
7449
|
<pre><code>const kpi = createKPI(document.querySelector('#rail'), {
|
|
7450
7450
|
rows, rowKey: 'id',
|
|
7451
7451
|
tiles: [
|
|
@@ -7461,7 +7461,7 @@ kpi.destroy();
|
|
|
7461
7461
|
|
|
7462
7462
|
kpi.nodes()[0].rollup; <span class="cmt">// 'critical' — even with the branch shut</span>
|
|
7463
7463
|
kpi.expand(kpi.nodes()[0].key); <span class="cmt">// open it</span></code></pre>
|
|
7464
|
-
<p><strong>Where the shape comes from — two sources, in this order.</strong> <em>Declared:</em> <code>tree: { path }</code> or <code>tree: { parentKey }</code> over the <em>tile specs</em>, the same two shapes the grid's <a href="#tree-data">tree data</a> and the tree-select editor already take, so a hierarchy you have configured once needs no second vocabulary. A <code>path</code> is the tile's <em>own</em> place, its own segment last — <code>['System','Compute','cpu']</code>, exactly as <code>['EMEA','UK','Colchester']</code> is Colchester's path and not its parent's — and levels no tile represents are synthesised, so <code>System</code> and <code>Compute</code> appear without a tile of their own. <em>Derived:</em> with neither declared, the tile ids are split on <code>separator</code> (default <code>.</code>), so <code>system.compute.cpu</code> files itself. A panel whose ids carry no separator is flat and renders exactly as it always did; <code>tree: false</code
|
|
7464
|
+
<p><strong>Where the shape comes from — two sources, in this order, once <code>tree</code> is set.</strong> <em>Declared:</em> <code>tree: { path }</code> or <code>tree: { parentKey }</code> over the <em>tile specs</em>, the same two shapes the grid's <a href="#tree-data">tree data</a> and the tree-select editor already take, so a hierarchy you have configured once needs no second vocabulary. A <code>path</code> is the tile's <em>own</em> place, its own segment last — <code>['System','Compute','cpu']</code>, exactly as <code>['EMEA','UK','Colchester']</code> is Colchester's path and not its parent's — and levels no tile represents are synthesised, so <code>System</code> and <code>Compute</code> appear without a tile of their own. <em>Derived:</em> with neither declared, the tile ids are split on <code>separator</code> (default <code>.</code>), so <code>system.compute.cpu</code> files itself — but only once <code>tree</code> is given an object (<code>{}</code> included); unset, a dot in an id means nothing and the panel warns once rather than building a hierarchy you never asked for. A panel whose ids carry no separator is flat and renders exactly as it always did even with <code>tree</code> set; <code>tree: false</code>, same as leaving it unset, keeps it flat whatever the ids look like, silently. A tile's <code>field</code> is never a source — a dot there already means a nested object property, and overloading it would make <code>field: 'cpu.util'</code> ambiguous.</p>
|
|
7465
7465
|
<p><strong>No value rolls up; severity does.</strong> A parent shows no aggregated number. That is not a simplification: the running accumulators expose <code>add</code>/<code>remove</code>/<code>value</code> and no merge, so <code>avg</code>, <code>countDistinct</code> and a <code>custom</code> reducer cannot be composed from their children without rescanning, and a per-aggregation exception list would be a number that is right for a sum and wrong for an average. A parent that has a tile of its own still shows <em>that tile's</em> reading. What does roll up is the status: <code>rollup</code> is the worst severity at or below the node, across as many levels as you have, and it is what a collapsed branch reports.</p>
|
|
7466
7466
|
<p><strong>Nothing measured is not good news, and it does not win the roll-up either.</strong> A leaf that measured nothing is <code>unknown</code> (see above), and <code>unknown</code> is deliberately excluded from <code>rollup</code>: ranking “not measured” as the worst thing beneath a parent would hide a real warning under it. It is surfaced separately instead — <code>node.unknown</code> counts the descendants that measured nothing, and the node renders it in words (“2 unknown”) and puts it in its accessible name. So neither way of being wrong is available: silence cannot read as green, and it cannot bury an amber.</p>
|
|
7467
7467
|
<p><strong>Accessible by construction.</strong> The rail is a real <code>role="tree"</code> with the APG keyboard model — <kbd>→</kbd> opens a closed branch and otherwise steps into it, <kbd>←</kbd> closes an open one and otherwise steps out to its parent, <kbd>↑</kbd>/<kbd>↓</kbd> walk what is visible, <kbd>Home</kbd>/<kbd>End</kbd> jump to its ends, <kbd>Enter</kbd>/<kbd>Space</kbd> activate — with a roving tabindex, and <code>aria-level</code>, <code>aria-posinset</code> and <code>aria-setsize</code> on every node, because a reader cannot count what a collapsed branch has left out of the DOM. Status carries a <strong>shape</strong> as well as a colour (a filled circle, a triangle, a square, a hollow circle), not one dot in three colours, and a parent's rolled-up status is <em>in its accessible name</em>: “Compute, 6 items, worst status critical”, announced as one string. Every phrase is a catalogue key: pass <code>messages</code> (any <code>{ t(key, params) }</code>, including a grid's own) to translate the panel, and a key your catalogue lacks falls back to English rather than printing the key.</p>
|
|
@@ -7471,8 +7471,10 @@ kpi.expand(kpi.nodes()[0].key); <span class="cmt">// open it</span></code><
|
|
|
7471
7471
|
<p><strong>A collapsed branch costs data, not paint.</strong> Every node's status is computed whether or not you can see it — that is what makes the rail worth having — while a collapsed branch contributes no DOM at all. It is the same division the grid's grouping already makes between its totals walk and its display walk. Expansion is patched in place, keyed on the node, so a live routed feed does not throw a keyboard user off the node they are standing on.</p>
|
|
7472
7472
|
<h3 id="kpi-tree-example">A collapsed parent reports the red leaf underneath it, executed</h3>
|
|
7473
7473
|
<p class="section-note">Two subsystems from dotted tile ids, one of them in breach, with nothing expanded; then the same
|
|
7474
|
-
rail with no data at all.
|
|
7475
|
-
|
|
7474
|
+
rail with no data at all. <code>tree</code> is the opt-in (BACKLOG-0001673) — a dotted id alone does
|
|
7475
|
+
not build a hierarchy, so this example sets <code>tree: {}</code> deliberately, the way any host must. Run
|
|
7476
|
+
headless on every build.</p>
|
|
7477
|
+
<pre data-run="js" data-expect="compute false critical | cpu critical | null 2" data-covers="export:createKPI config:tree"><code><span class="kw">const</span> { createKPI } = <span class="kw">await</span> import('../packages/modules/kpi/index.js');
|
|
7476
7478
|
|
|
7477
7479
|
<span class="kw">const</span> fewerIsBetter = { warn: 70, critical: 90, direction: 'lowerIsBetter' };
|
|
7478
7480
|
<span class="kw">const</span> tiles = [
|
|
@@ -7482,8 +7484,9 @@ kpi.expand(kpi.nodes()[0].key); <span class="cmt">// open it</span></code><
|
|
|
7482
7484
|
thresholds: { warn: 100, critical: 300, direction: 'lowerIsBetter' } },
|
|
7483
7485
|
];
|
|
7484
7486
|
|
|
7485
|
-
<span class="cmt">//
|
|
7486
|
-
<span class="
|
|
7487
|
+
<span class="cmt">// `tree: {}` is the opt-in: without it, these dotted ids would stay flat tiles</span>
|
|
7488
|
+
<span class="cmt">// and the panel would warn once instead of building a hierarchy.</span>
|
|
7489
|
+
<span class="kw">const</span> kpi = createKPI(null, { rows: [{ id: 'h1', cpu: 94, mem: 40, latency: 12 }], rowKey: 'id', tree: {}, tiles });
|
|
7487
7490
|
|
|
7488
7491
|
<span class="kw">const</span> compute = kpi.nodes()[0];
|
|
7489
7492
|
<span class="cmt">// Nobody has opened it, and it reports the breach anyway.</span>
|
|
@@ -7491,7 +7494,7 @@ kpi.expand(kpi.nodes()[0].key); <span class="cmt">// open it</span></code><
|
|
|
7491
7494
|
<span class="kw">const</span> leaf = [compute.children[0].label, compute.children[0].status].join(' '); <span class="cmt">// cpu critical</span>
|
|
7492
7495
|
|
|
7493
7496
|
<span class="cmt">// Nothing delivered: the parent reports the silence rather than a false green.</span>
|
|
7494
|
-
<span class="kw">const</span> quiet = createKPI(null, { rows: [], rowKey: 'id', tiles });
|
|
7497
|
+
<span class="kw">const</span> quiet = createKPI(null, { rows: [], rowKey: 'id', tree: {}, tiles });
|
|
7495
7498
|
<span class="kw">const</span> silent = String(quiet.nodes()[0].rollup) + ' ' + quiet.nodes()[0].unknown; <span class="cmt">// null 2</span>
|
|
7496
7499
|
|
|
7497
7500
|
<span class="kw">return</span> [shut, leaf, silent].join(' | ');</code></pre>
|
|
@@ -9719,7 +9722,7 @@ return `next ${p.mean.toFixed(1)}; r2 ${f.r2.toFixed(1)}; band ${p.upper - p.low
|
|
|
9719
9722
|
</table>
|
|
9720
9723
|
</div>
|
|
9721
9724
|
<h3 id="type-ChartAnnotation">ChartAnnotation</h3>
|
|
9722
|
-
<p class="section-note">One declarative annotation (BACKLOG-0000744, extended by BACKLOG-0000953). A reference or target line, a shaded band, a callout, or an `event` marker. Its value is a constant `value` (or `from`/`to` for a band), or a `compute` reduction of the data it annotates — `mean`, `median`, `min`, `max`, or `p95` for a percentile — so it follows the data as the grid is filtered. A band with `orient: 'vertical'` shades an x-range instead — an event window, a maintenance period — and an `event` marker is a labelled vertical rule with a flag at a position on the x axis. Every annotation names the axis it reads, which on a dual-axis chart is what stops it being placed against the wrong scale, and is written into the accessible table as a sentence — a vertical marker and an event stating the position they sit at, because a screen-reader user needs where and when, not only that a marker exists.</p>
|
|
9725
|
+
<p class="section-note">One declarative annotation (BACKLOG-0000744, extended by BACKLOG-0000953). A reference or target line, a shaded band, a callout, or an `event` marker. Its value is a constant `value` (or `from`/`to` for a band), or a `compute` reduction of the data it annotates — `mean`, `median`, `min`, `max`, or `p95` for a percentile — so it follows the data as the grid is filtered. A band with `orient: 'vertical'` shades an x-range instead — an event window, a maintenance period — and an `event` marker is a labelled vertical rule with a flag at a position on the x axis. Every annotation names the axis it reads, which on a dual-axis chart is what stops it being placed against the wrong scale, and is written into the accessible table as a sentence — a vertical marker and an event stating the position they sit at, because a screen-reader user needs where and when, not only that a marker exists. An annotation the chart cannot place — an x value it cannot resolve on the axis, or a band whose edges are off-scale — is dropped with one console warning naming the annotation's kind, the axis and the reason, rather than vanishing without a trace (BACKLOG-0001672).</p>
|
|
9723
9726
|
<div class="table-wrap">
|
|
9724
9727
|
<table>
|
|
9725
9728
|
<thead><tr><th>Member</th><th>Type</th><th>Description</th></tr></thead>
|
|
@@ -9785,7 +9788,7 @@ return `next ${p.mean.toFixed(1)}; r2 ${f.r2.toFixed(1)}; band ${p.upper - p.low
|
|
|
9785
9788
|
<tr><td class="name">fn</td><td class="type">TotalName</td><td class="desc">A reduction name, as the totals row uses. <small>(optional)</small></td></tr>
|
|
9786
9789
|
<tr><td class="name">type</td><td class="type">'bar' | 'line' | 'area'</td><td class="desc">The mark this measure draws with, on a combo chart. <small>(optional)</small></td></tr>
|
|
9787
9790
|
<tr><td class="name">axis</td><td class="type">'left' | 'right'</td><td class="desc">Which axis it belongs to, on a combo chart. <small>(optional)</small></td></tr>
|
|
9788
|
-
<tr><td class="name">title</td><td class="type">string</td><td class="desc"
|
|
9791
|
+
<tr><td class="name">title</td><td class="type">string</td><td class="desc">The series label a combo's legend and axis titles use (BACKLOG-0001672). `label` is read too, as an undeclared alias, for a caller already using it; `title` wins when both are given. Falls back to the measure column's own `title`, then to `col`, when neither is set. <small>(optional)</small></td></tr>
|
|
9789
9792
|
</tbody>
|
|
9790
9793
|
</table>
|
|
9791
9794
|
</div>
|
|
@@ -12539,7 +12542,7 @@ return `next ${p.mean.toFixed(1)}; r2 ${f.r2.toFixed(1)}; band ${p.upper - p.low
|
|
|
12539
12542
|
<tr><td class="name">ariaLabel</td><td class="type">string</td><td class="desc"><small>(optional)</small></td></tr>
|
|
12540
12543
|
<tr><td class="name">nullText</td><td class="type">string</td><td class="desc"><small>(optional)</small></td></tr>
|
|
12541
12544
|
<tr><td class="name">locale</td><td class="type">string</td><td class="desc">The default locale a clock tile formats in when the tile itself declares none (BACKLOG-0001640); falls back to the browser's default. No effect on a stat tile, which takes its own `format.locale`. <small>(optional)</small></td></tr>
|
|
12542
|
-
<tr><td class="name">tree</td><td class="type">KPITreeConfig | false</td><td class="desc">Arrange the tiles as a hierarchy; `false` keeps the panel flat. <small>(optional)</small></td></tr>
|
|
12545
|
+
<tr><td class="name">tree</td><td class="type">KPITreeConfig | false</td><td class="desc">Arrange the tiles as a hierarchy; unset or `false` keeps the panel flat. Opt-in (BACKLOG-0001673): a dotted tile id is not a hierarchy until `tree` is set, and warns once while it is not. <small>(optional)</small></td></tr>
|
|
12543
12546
|
<tr><td class="name">messages</td><td class="type">{ t(key: string, params?: Record<string, unknown>): string }</td><td class="desc">The catalogue the panel's own text is read from. A panel routinely has no grid to borrow one off — two of its three input modes have none — so this is the first-class way to translate it. A grid's own `messages` satisfies the shape; a key it does not carry falls back to English. <small>(optional)</small></td></tr>
|
|
12544
12547
|
<tr><td class="name">onTileClick</td><td class="type">(event: KPIEvent) => void</td><td class="desc"><small>(optional)</small></td></tr>
|
|
12545
12548
|
<tr><td class="name">onTileDblClick</td><td class="type">(event: KPIEvent) => void</td><td class="desc"><small>(optional)</small></td></tr>
|
|
@@ -12625,6 +12628,7 @@ return `next ${p.mean.toFixed(1)}; r2 ${f.r2.toFixed(1)}; band ${p.upper - p.low
|
|
|
12625
12628
|
<tr><td class="name">format</td><td class="type">KPIFormat</td><td class="desc">Value formatting. <small>(optional)</small></td></tr>
|
|
12626
12629
|
<tr><td class="name">target</td><td class="type">number</td><td class="desc">A comparison target rendered alongside the value. <small>(optional)</small></td></tr>
|
|
12627
12630
|
<tr><td class="name">baseline</td><td class="type">number</td><td class="desc">A baseline the tile's delta is measured against. <small>(optional)</small></td></tr>
|
|
12631
|
+
<tr><td class="name">delta</td><td class="type">'absolute' | 'relative' | 'both'</td><td class="desc">What the movement line prints against `baseline` (BACKLOG-0001673, F-FRED-G): `'absolute'` the difference alone, `'relative'` the percentage alone, `'both'` (the default, unchanged) both together. A rate series (4.10 vs 4.30) makes the percentage a percent-of-a-percent and meaningless, so `'absolute'` is how a host keeps the line without it. The arrow and its colour follow the sign of the difference either way. <small>(optional)</small></td></tr>
|
|
12628
12632
|
<tr><td class="name">thresholds</td><td class="type">KPIThresholds</td><td class="desc">Threshold bands, either two cut points or an explicit band list. <small>(optional)</small></td></tr>
|
|
12629
12633
|
<tr><td class="name">bands</td><td class="type">KPIBand[]</td><td class="desc">Explicit status bands (an alternative to `thresholds`). <small>(optional)</small></td></tr>
|
|
12630
12634
|
<tr><td class="name">sparkline</td><td class="type">KPISparkline | string</td><td class="desc">A trend sparkline series. <small>(optional)</small></td></tr>
|
|
@@ -12663,13 +12667,14 @@ return `next ${p.mean.toFixed(1)}; r2 ${f.r2.toFixed(1)}; band ${p.upper - p.low
|
|
|
12663
12667
|
<tr><td class="name">delta</td><td class="type">number | null</td><td class="desc"></td></tr>
|
|
12664
12668
|
<tr><td class="name">deltaPercent</td><td class="type">number | null</td><td class="desc"></td></tr>
|
|
12665
12669
|
<tr><td class="name">deltaFormatted</td><td class="type">string</td><td class="desc"><small>(optional)</small></td></tr>
|
|
12670
|
+
<tr><td class="name">deltaMode</td><td class="type">'absolute' | 'relative' | 'both'</td><td class="desc">What the movement line prints; see `KPIStatTile.delta`. Always present once `baseline` is. <small>(optional)</small></td></tr>
|
|
12666
12671
|
<tr><td class="name">count</td><td class="type">number</td><td class="desc"></td></tr>
|
|
12667
12672
|
<tr><td class="name">sparkline</td><td class="type">number[] | null</td><td class="desc"></td></tr>
|
|
12668
12673
|
</tbody>
|
|
12669
12674
|
</table>
|
|
12670
12675
|
</div>
|
|
12671
12676
|
<h3 id="type-KPITreeConfig">KPITreeConfig</h3>
|
|
12672
|
-
<p class="section-note">The hierarchy a KPI panel arranges its tiles into (BACKLOG-0001059): a rail of top-level items that expand to the indicators beneath them, each parent highlighted with the worst status below it.
|
|
12677
|
+
<p class="section-note">The hierarchy a KPI panel arranges its tiles into (BACKLOG-0001059): a rail of top-level items that expand to the indicators beneath them, each parent highlighted with the worst status below it. `tree` is an opt-in (BACKLOG-0001673): omitted or `false`, the panel is flat whatever its tile ids look like, and a dotted id seen with `tree` unset is reported once rather than silently turned into a hierarchy. Given any object (`{}` included), the shape is declared with `path` or `parentKey` — the same two shapes the grid's tree data and the tree-select editor take — over the **tile specs**, not the rows. With neither declared, one is derived by splitting the tile ids on `separator`, so `system.compute.cpu` files itself under Compute under System. A panel whose ids carry no separator stays flat even with `tree` set. A tile's `field` is never a source: a dot there already means a nested object property.</p>
|
|
12673
12678
|
<div class="table-wrap">
|
|
12674
12679
|
<table>
|
|
12675
12680
|
<thead><tr><th>Member</th><th>Type</th><th>Description</th></tr></thead>
|
|
@@ -14901,7 +14906,7 @@ return `next ${p.mean.toFixed(1)}; r2 ${f.r2.toFixed(1)}; band ${p.upper - p.low
|
|
|
14901
14906
|
<!-- END GENERATED TYPE REFERENCE -->
|
|
14902
14907
|
|
|
14903
14908
|
<footer>
|
|
14904
|
-
Lattice Grid 1.
|
|
14909
|
+
Lattice Grid 1.68.0 · Copyright © 2026 TOCLOCO Inc. All rights reserved.
|
|
14905
14910
|
This document describes the behaviour of the shipped library. Where this guide and the code
|
|
14906
14911
|
disagree, the code wins: please <a href="https://www.latticegrid.dev">tell us</a>.
|
|
14907
14912
|
</footer>
|
package/docs/api-detail.html
CHANGED
|
@@ -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.
|
|
440
|
+
<p class="rail__sub">Developer guide · v1.68.0</p>
|
|
441
441
|
<nav>
|
|
442
442
|
<div class="rail__group">
|
|
443
443
|
<span class="rail__label">Start here</span>
|
|
@@ -554,7 +554,7 @@
|
|
|
554
554
|
<a href="API.html">reference tables</a> are the shorter version for when you already know.
|
|
555
555
|
</p>
|
|
556
556
|
<p class="chips">
|
|
557
|
-
<span class="chip">Version 1.
|
|
557
|
+
<span class="chip">Version 1.68.0</span>
|
|
558
558
|
<span class="chip">Zero dependencies</span>
|
|
559
559
|
<span class="chip">No build step</span>
|
|
560
560
|
</p>
|
|
@@ -1492,7 +1492,7 @@ off(); <span class="cmt">// every subscrip
|
|
|
1492
1492
|
</p>
|
|
1493
1493
|
<div class="example">
|
|
1494
1494
|
<p class="example__label">Which version am I running?</p>
|
|
1495
|
-
<pre><code>grid.getVersion(); <span class="cmt">// '1.
|
|
1495
|
+
<pre><code>grid.getVersion(); <span class="cmt">// '1.68.0'</span>
|
|
1496
1496
|
LatticeGrid.getVersion(); <span class="cmt">// the same, when you have no grid to hand</span></code></pre>
|
|
1497
1497
|
</div>
|
|
1498
1498
|
<p class="lead-in">
|
|
@@ -9035,7 +9035,7 @@ return (`proposals ${proposals.join(',')} | diff ${result.diff.map((d) => `ol
|
|
|
9035
9035
|
|
|
9036
9036
|
<h3 id="kpi-config-examples">KPI config keys, executed</h3>
|
|
9037
9037
|
<p class="lead-in">
|
|
9038
|
-
|
|
9038
|
+
Four examples covering the twelve KPI config keys not already demonstrated elsewhere in this
|
|
9039
9039
|
guide.
|
|
9040
9040
|
</p>
|
|
9041
9041
|
|
|
@@ -9145,6 +9145,41 @@ return (`${el.querySelectorAll('.lat-kpi__node')[0].getAttribute('aria-label')}
|
|
|
9145
9145
|
</p>
|
|
9146
9146
|
</div>
|
|
9147
9147
|
|
|
9148
|
+
<div class="example">
|
|
9149
|
+
<p class="example__label">What the movement line prints against a baseline: delta, executed</p>
|
|
9150
|
+
<pre data-run="js" data-expect="both:▼ -0.2 (-4.7%) | absolute:▼ -0.2 | relative:▼ -4.7%" data-covers="config:delta"><code>const { createTestDom } = await import('../packages/dom/src/renderer/testdom.js');
|
|
9151
|
+
const { createKPI } = await import('../packages/modules/kpi/index.js');
|
|
9152
|
+
|
|
9153
|
+
const dom = createTestDom({});
|
|
9154
|
+
const el = dom.document.createElement('div');
|
|
9155
|
+
// A rate series (4.10 vs a 4.30 baseline a year earlier): the percentage of a
|
|
9156
|
+
// rate is meaningless, so a host names 'absolute' to keep the line without it.
|
|
9157
|
+
const kpi = createKPI(el, {
|
|
9158
|
+
rows: [{ id: 1, rate: 4.10 }], rowKey: 'id',
|
|
9159
|
+
tiles: [
|
|
9160
|
+
{ id: 'both', label: 'Default', aggregation: 'max', field: 'rate',
|
|
9161
|
+
baseline: 4.30, format: { decimals: 1 } },
|
|
9162
|
+
{ id: 'absolute', label: 'Difference alone', aggregation: 'max', field: 'rate',
|
|
9163
|
+
baseline: 4.30, format: { decimals: 1 }, delta: 'absolute' },
|
|
9164
|
+
{ id: 'relative', label: 'Percentage alone', aggregation: 'max', field: 'rate',
|
|
9165
|
+
baseline: 4.30, format: { decimals: 1 }, delta: 'relative' },
|
|
9166
|
+
],
|
|
9167
|
+
});
|
|
9168
|
+
const lines = ['both', 'absolute', 'relative'].map((id) => {
|
|
9169
|
+
const fig = [...el.querySelectorAll('.lat-kpi__tile')].find((f) => f.getAttribute('aria-label').startsWith(
|
|
9170
|
+
id === 'both' ? 'Default' : (id === 'absolute' ? 'Difference' : 'Percentage')));
|
|
9171
|
+
return `${id}:${fig.querySelector('.lat-kpi__delta').textContent}`;
|
|
9172
|
+
});
|
|
9173
|
+
return lines.join(' | ');
|
|
9174
|
+
</code></pre>
|
|
9175
|
+
<p>
|
|
9176
|
+
<code>delta: 'absolute' | 'relative' | 'both'</code> (default <code>'both'</code>, unchanged)
|
|
9177
|
+
chooses what a tile's movement line prints against its <code>baseline</code> — the
|
|
9178
|
+
difference alone, the percentage alone, or both together, exactly as before this option
|
|
9179
|
+
existed. The arrow and its colour follow the sign of the difference in every mode.
|
|
9180
|
+
</p>
|
|
9181
|
+
</div>
|
|
9182
|
+
|
|
9148
9183
|
<h3 id="route-options-examples">Data Router route options, executed</h3>
|
|
9149
9184
|
<div class="example">
|
|
9150
9185
|
<p class="example__label">A per-route filter and transform, executed</p>
|
|
@@ -9651,7 +9686,7 @@ grid.licence.state(); <span class="cmt">// 'licensed' | 'localhost' | 'trial'<
|
|
|
9651
9686
|
|
|
9652
9687
|
<footer>
|
|
9653
9688
|
<p>
|
|
9654
|
-
Lattice Grid 1.
|
|
9689
|
+
Lattice Grid 1.68.0 · Copyright © 2026 TOCLOCO Inc. All rights reserved.
|
|
9655
9690
|
Written against the shipped source. Where this guide and the code disagree, the code wins,
|
|
9656
9691
|
please <a href="https://www.latticegrid.dev">tell us</a>.
|
|
9657
9692
|
</p>
|
package/lattice-grid.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/*!
|
|
2
|
-
* Lattice Grid 1.
|
|
2
|
+
* Lattice Grid 1.68.0, type declarations
|
|
3
3
|
* Copyright (c) 2026 TOCLOCO Inc. All rights reserved.
|
|
4
4
|
* https://latticegrid.dev
|
|
5
5
|
*/
|
|
@@ -7558,6 +7558,12 @@ export interface ChartMeasure {
|
|
|
7558
7558
|
type?: 'bar' | 'line' | 'area';
|
|
7559
7559
|
/** Which axis it belongs to, on a combo chart. */
|
|
7560
7560
|
axis?: 'left' | 'right';
|
|
7561
|
+
/**
|
|
7562
|
+
* The series label a combo's legend and axis titles use.
|
|
7563
|
+
* `label` is read too, as an undeclared alias, for a caller already using
|
|
7564
|
+
* it; `title` wins when both are given. Falls back to the measure column's
|
|
7565
|
+
* own `title`, then to `col`, when neither is set.
|
|
7566
|
+
*/
|
|
7561
7567
|
title?: string;
|
|
7562
7568
|
}
|
|
7563
7569
|
|
|
@@ -7670,7 +7676,11 @@ export interface ChartTrend {
|
|
|
7670
7676
|
* which on a dual-axis chart is what stops it being placed against the wrong
|
|
7671
7677
|
* scale, and is written into the accessible table as a sentence — a vertical
|
|
7672
7678
|
* marker and an event stating the position they sit at, because a screen-reader
|
|
7673
|
-
* user needs where and when, not only that a marker exists.
|
|
7679
|
+
* user needs where and when, not only that a marker exists. An annotation the
|
|
7680
|
+
* chart cannot place — an x value it cannot resolve on the axis, or a band
|
|
7681
|
+
* whose edges are off-scale — is dropped with one console warning naming the
|
|
7682
|
+
* annotation's kind, the axis and the reason, rather than vanishing without a
|
|
7683
|
+
* trace.
|
|
7674
7684
|
*/
|
|
7675
7685
|
export interface ChartAnnotation {
|
|
7676
7686
|
/**
|