@toclocoinc/lattice-grid 1.15.0 → 1.16.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/docs/API.html +237 -10
- package/docs/api-detail.html +232 -1
- package/lattice-grid.d.ts +189 -1
- package/lattice-grid.esm.min.js +2668 -393
- package/lattice-grid.min.cjs +2668 -393
- package/lattice-grid.min.css +1 -1
- package/lattice-grid.min.js +2668 -393
- package/modules/charts.esm.min.js +89 -4
- package/modules/devtools.esm.min.js +2 -2
- package/modules/dhtmlx-compat.esm.min.js +4 -4
- package/modules/htmx.esm.min.js +2668 -393
- package/modules/htmx.min.cjs +2668 -393
- package/modules/htmx.min.js +2668 -393
- package/modules/react.esm.min.js +2 -2
- package/modules/svelte.esm.min.js +2 -2
- package/modules/vue.esm.min.js +2 -2
- package/modules/webcomponent.esm.min.js +2668 -393
- package/package.json +1 -1
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.16.0</p>
|
|
441
441
|
<nav>
|
|
442
442
|
<div class="rail__group">
|
|
443
443
|
<span class="rail__label">Start here</span>
|
|
@@ -1533,6 +1533,43 @@ cell: { decoration: 'dot' } <span class="cmt">// a leading
|
|
|
1533
1533
|
property, not a search for hex codes.</p>
|
|
1534
1534
|
</div>
|
|
1535
1535
|
|
|
1536
|
+
<div class="example">
|
|
1537
|
+
<p class="example__label">Icon sets: a threshold glyph per value band</p>
|
|
1538
|
+
<pre><code><span class="cmt">// A built-in set — traffic lights, arrows, rating marks — driven by value.</span>
|
|
1539
|
+
cell: { decoration: { type: 'icon', iconSet: 'arrows' } }
|
|
1540
|
+
|
|
1541
|
+
<span class="cmt">// Or your own bands. The highest `min` a value clears wins; a band with no</span>
|
|
1542
|
+
<span class="cmt">// `min` is the catch-all. `label` is what a screen reader announces.</span>
|
|
1543
|
+
cell: { decoration: { type: 'icon', bands: [
|
|
1544
|
+
{ min: 0.9, icon: 'success', label: 'on target', variant: 'success' },
|
|
1545
|
+
{ min: 0.5, icon: 'warning', label: 'at risk', variant: 'warning' },
|
|
1546
|
+
{ icon: 'danger', label: 'off track', variant: 'danger' },
|
|
1547
|
+
] } }</code></pre>
|
|
1548
|
+
</div>
|
|
1549
|
+
<div class="why">
|
|
1550
|
+
<p>An icon set is a restatement of the value, not a replacement for it: the value still
|
|
1551
|
+
renders beside the glyph, and the band's <code>label</code> is set as the glyph's
|
|
1552
|
+
<code>aria-label</code>, so a screen-reader user hears "on target 92%" rather than a bare
|
|
1553
|
+
number with the status lost. The glyphs are the grid's own inline sprites (§16), so an icon
|
|
1554
|
+
set adds no dependency and makes no request. Built-in sets: <code>trafficLights</code>,
|
|
1555
|
+
<code>arrows</code>, <code>trafficArrows</code>, <code>ratings</code>.</p>
|
|
1556
|
+
</div>
|
|
1557
|
+
|
|
1558
|
+
<div class="example">
|
|
1559
|
+
<p class="example__label">Turning a decoration on at runtime</p>
|
|
1560
|
+
<pre><code><span class="cmt">// Set, change or clear a column's decoration after the grid is built.</span>
|
|
1561
|
+
grid.columns.decorate('score', { type: 'bar', min: 0, max: 100 });
|
|
1562
|
+
grid.columns.decorate('trend', { type: 'icon', iconSet: 'arrows' });
|
|
1563
|
+
grid.columns.decorate('score', <span class="kw">null</span>); <span class="cmt">// back to plain text</span></code></pre>
|
|
1564
|
+
</div>
|
|
1565
|
+
<div class="why">
|
|
1566
|
+
<p>A decoration is presentation, so <code>columns.decorate</code> is a live setter like
|
|
1567
|
+
<code>grid.set('theme', …)</code>: it is <em>not</em> on the undo timeline and does
|
|
1568
|
+
<em>not</em> travel in a saved view. For conditional styling that a user edits and a view
|
|
1569
|
+
remembers, reach for <code>grid.formatting</code> below, which holds colour and weight rules
|
|
1570
|
+
as durable state.</p>
|
|
1571
|
+
</div>
|
|
1572
|
+
|
|
1536
1573
|
<div class="example">
|
|
1537
1574
|
<p class="example__label">Your own renderer</p>
|
|
1538
1575
|
<pre><code>components: {
|
|
@@ -1875,6 +1912,41 @@ grid.rows.expandAll();
|
|
|
1875
1912
|
grid.rows.collapse('EMEA');</code></pre>
|
|
1876
1913
|
</div>
|
|
1877
1914
|
|
|
1915
|
+
<p class="lead-in">
|
|
1916
|
+
<code>groupPanel: true</code> adds a drag-and-drop strip above the column header — the
|
|
1917
|
+
row-group panel. A user drags a heading into it to group by that column; the active
|
|
1918
|
+
groups show as removable, reorderable chips, and dragging one chip past another changes
|
|
1919
|
+
the nesting order. It is keyboard-operable, so grouping is not drag-only: arrows move
|
|
1920
|
+
between chips, <code>Shift</code> with an arrow reorders, <code>Delete</code> ungroups,
|
|
1921
|
+
and an add control at the end groups any column. Every change is spoken through the live
|
|
1922
|
+
region. The strip drives <code>grid.columns.group()</code> — it is the same grouping
|
|
1923
|
+
model, surfaced as chrome — so a group made in the strip, from the column menu or through
|
|
1924
|
+
the API is one state, not three.
|
|
1925
|
+
</p>
|
|
1926
|
+
<div class="example">
|
|
1927
|
+
<p class="example__label">Turn the group-by strip on, and group through the model</p>
|
|
1928
|
+
<pre data-run="js" data-expect="grouped by region, country" data-covers="config:groupPanel"><code><span class="kw">const</span> { createHeadlessGrid } = <span class="kw">await</span> import('../packages/core/src/index.js');
|
|
1929
|
+
|
|
1930
|
+
<span class="cmt">// `groupPanel` is chrome, so the strip itself needs the DOM build; the config</span>
|
|
1931
|
+
<span class="cmt">// key is accepted everywhere, and it drives the ordinary grouping model — which</span>
|
|
1932
|
+
<span class="cmt">// is what a headless grid can show. The strip renders the state below as chips.</span>
|
|
1933
|
+
<span class="kw">const</span> grid = createHeadlessGrid({
|
|
1934
|
+
columns: [{ field: 'region' }, { field: 'country' }, { field: 'sales', type: 'number' }],
|
|
1935
|
+
rows: [
|
|
1936
|
+
{ region: 'EMEA', country: 'UK', sales: 10 },
|
|
1937
|
+
{ region: 'EMEA', country: 'DE', sales: 20 },
|
|
1938
|
+
{ region: 'AMER', country: 'US', sales: 30 },
|
|
1939
|
+
],
|
|
1940
|
+
groupPanel: <span class="kw">true</span>,
|
|
1941
|
+
});
|
|
1942
|
+
|
|
1943
|
+
<span class="cmt">// Order is nesting order, outermost first — exactly the order the chips show.</span>
|
|
1944
|
+
grid.columns.group(['region', 'country']);
|
|
1945
|
+
<span class="kw">const</span> groups = grid.state.get().group;
|
|
1946
|
+
grid.destroy();
|
|
1947
|
+
<span class="kw">return</span> `grouped by ${groups.join(', ')}`;</code></pre>
|
|
1948
|
+
</div>
|
|
1949
|
+
|
|
1878
1950
|
<div class="example">
|
|
1879
1951
|
<p class="example__label">Totals</p>
|
|
1880
1952
|
<pre><code>{ field: 'capacity', type: 'number', total: 'sum' }
|
|
@@ -2423,6 +2495,58 @@ createGrid(right, { columns, rows,
|
|
|
2423
2495
|
at silently. Rows with no rate, or no weight, are left out rather than counted as zero.
|
|
2424
2496
|
</p>
|
|
2425
2497
|
|
|
2498
|
+
<h3 id="aggregate-chooser">Choosing an aggregate at runtime</h3>
|
|
2499
|
+
<p class="lead-in">
|
|
2500
|
+
With <code>aggregateChooser</code> on, the column menu's totalling entry becomes an
|
|
2501
|
+
<em>Aggregate</em> submenu. It offers only the reductions the column's type says are meaningful
|
|
2502
|
+
(see <a href="#aggregate-safety">above</a>) — <code>sum</code>, <code>avg</code>,
|
|
2503
|
+
<code>min</code>, <code>max</code> and the counts on a plain number, but never <code>sum</code>
|
|
2504
|
+
on a category or a rate — with the current one ticked and a <em>None</em> to stop totalling. It
|
|
2505
|
+
is the same keyboard-operable menu as everywhere else: arrows move, <code>Enter</code> or
|
|
2506
|
+
<code>Space</code> picks, <code>Escape</code> closes and returns focus, and the ticked item
|
|
2507
|
+
reads as <code>aria-checked</code> to a screen reader.
|
|
2508
|
+
</p>
|
|
2509
|
+
<div class="example">
|
|
2510
|
+
<p class="example__label">Off by default; turn it on</p>
|
|
2511
|
+
<pre><code>createGrid(element, { aggregateChooser: <span class="kw">true</span> });</code></pre>
|
|
2512
|
+
</div>
|
|
2513
|
+
<div class="why">
|
|
2514
|
+
<p><strong>It reuses the totals model, it does not fork it.</strong> Every choice drives
|
|
2515
|
+
<code>grid.columns.setTotal(id, name)</code>, the same public call the old toggle used, so the
|
|
2516
|
+
footer, the group rows, the pivot cells and the grand total all move together and no
|
|
2517
|
+
aggregation is recomputed here. <code>grid.columns.aggregates(id)</code> returns the list the
|
|
2518
|
+
submenu offers, so a host building its own chooser reads the same answer.</p>
|
|
2519
|
+
<p><strong>Safety holds on both routes.</strong> The submenu only lists meaningful aggregates,
|
|
2520
|
+
and <code>setTotal</code> refuses an unmeaningful named total whether it comes from the menu or
|
|
2521
|
+
from an API caller — the wrong footer cannot be reached from either.</p>
|
|
2522
|
+
<p><strong>Off by default and non-breaking.</strong> Left off, the menu keeps its plain
|
|
2523
|
+
<em>Total this column</em> toggle, so an existing grid is unchanged.</p>
|
|
2524
|
+
</div>
|
|
2525
|
+
<div class="example">
|
|
2526
|
+
<p class="example__label">Setting an aggregate at runtime, executed</p>
|
|
2527
|
+
<pre data-run="js" data-expect="6" data-covers="config:aggregateChooser method:columns"><code><span class="kw">const</span> { createHeadlessGrid } = <span class="kw">await</span> import('../packages/core/src/index.js');
|
|
2528
|
+
|
|
2529
|
+
<span class="kw">const</span> grid = createHeadlessGrid({
|
|
2530
|
+
aggregateChooser: <span class="kw">true</span>,
|
|
2531
|
+
columns: [{ field: 'amount', type: 'number', total: 'sum' }, { field: 'region' }],
|
|
2532
|
+
rows: [{ id: '1', amount: 2, region: 'N' }, { id: '2', amount: 4, region: 'S' }],
|
|
2533
|
+
rowKey: 'id',
|
|
2534
|
+
grandTotalRow: 'inline',
|
|
2535
|
+
});
|
|
2536
|
+
grid.rows.count();
|
|
2537
|
+
|
|
2538
|
+
<span class="cmt">// A number column offers every built-in; a text column offers only what makes</span>
|
|
2539
|
+
<span class="cmt">// sense — count and the extremes, never sum. This is the list the chooser shows.</span>
|
|
2540
|
+
<span class="kw">const</span> offered = grid.columns.aggregates('amount'); <span class="cmt">// ['sum','avg','min',...]</span>
|
|
2541
|
+
|
|
2542
|
+
<span class="cmt">// Switch the footer from Sum (6) to Average (3) at runtime.</span>
|
|
2543
|
+
grid.columns.setTotal('amount', 'avg');
|
|
2544
|
+
<span class="kw">const</span> total = grid.rows.get(grid.rows.count() - <span class="num">1</span>).totals.amount;
|
|
2545
|
+
|
|
2546
|
+
grid.destroy();
|
|
2547
|
+
<span class="kw">return</span> offered.includes('sum') ? <span class="num">6</span> : <span class="num">0</span>; <span class="cmt">// sum is offered on a number column</span></code></pre>
|
|
2548
|
+
</div>
|
|
2549
|
+
|
|
2426
2550
|
<h2 id="sticky-group-headings">Sticky group headings</h2>
|
|
2427
2551
|
<p class="lead-in">
|
|
2428
2552
|
Scrolling inside a group keeps that group's headings pinned above the rows, so the rows on
|
|
@@ -2474,6 +2598,37 @@ createGrid(element, { stickyGroupHeaders: 3 }); <span class="cmt">// stack
|
|
|
2474
2598
|
</tbody>
|
|
2475
2599
|
</table>
|
|
2476
2600
|
</div>
|
|
2601
|
+
<h3 id="ingest">Trimming the memory footprint</h3>
|
|
2602
|
+
<p>
|
|
2603
|
+
By default the store retains the row objects you hand it by reference, so
|
|
2604
|
+
<code>rows.data()</code> returns those exact objects and <code>row === sourceObject</code>
|
|
2605
|
+
holds. The <code>ingest</code> option controls that:
|
|
2606
|
+
</p>
|
|
2607
|
+
<div class="table-wrap">
|
|
2608
|
+
<table>
|
|
2609
|
+
<thead><tr><th>Option</th><th>Type</th><th>Description</th></tr></thead>
|
|
2610
|
+
<tbody>
|
|
2611
|
+
<tr><td class="name">retainSource</td><td class="type">boolean</td><td class="desc">Default <code>true</code>. Set <code>false</code> to keep only the packed columns and reconstruct a plain row object from them on demand. <code>rows.data()</code> then returns freshly reconstructed objects — a new object each call — so <code>row === sourceObject</code> and a custom renderer reading <code>row.sourceObject</code> no longer hold, and equality becomes value-based. Cell values are identical either way, so <code>get()</code>, <code>byKey()</code>, <code>value()</code> and <code>values()</code> are unaffected.</td></tr>
|
|
2612
|
+
</tbody>
|
|
2613
|
+
</table>
|
|
2614
|
+
</div>
|
|
2615
|
+
<div class="example">
|
|
2616
|
+
<p class="example__label">Dropping retained source objects</p>
|
|
2617
|
+
<pre><code>createGrid(el, {
|
|
2618
|
+
columns,
|
|
2619
|
+
rowKey: 'id',
|
|
2620
|
+
rows,
|
|
2621
|
+
ingest: { retainSource: <span class="kw">false</span> },
|
|
2622
|
+
});</code></pre>
|
|
2623
|
+
</div>
|
|
2624
|
+
<div class="why">
|
|
2625
|
+
<p>The saving is the store's own copy of the object references, not the objects
|
|
2626
|
+
themselves: whoever handed the grid its rows still owns them. The footprint drops
|
|
2627
|
+
materially only when the grid becomes the sole holder of the data. Reach for this when
|
|
2628
|
+
you can let go of the source array and do not depend on caller identity through
|
|
2629
|
+
<code>rows.data()</code>.</p>
|
|
2630
|
+
</div>
|
|
2631
|
+
|
|
2477
2632
|
<div class="example">
|
|
2478
2633
|
<p class="example__label">A remote source</p>
|
|
2479
2634
|
<pre><code>source: {
|
|
@@ -4490,6 +4645,40 @@ grid.edit.pasteInto(text); <span class="cmt">// Excel's t
|
|
|
4490
4645
|
people fight.</p>
|
|
4491
4646
|
</div>
|
|
4492
4647
|
|
|
4648
|
+
<h3 id="paste-preview">Previewing a bulk paste</h3>
|
|
4649
|
+
<p class="lead-in">
|
|
4650
|
+
A paste is the one clipboard gesture that can rewrite dozens of cells with nothing to inspect
|
|
4651
|
+
first: a payload that lands a column to the left of where it was aimed, or over a range the
|
|
4652
|
+
user forgot was selected, looks exactly like one that worked. Turn on
|
|
4653
|
+
<code>edit.pastePreview</code> and a paste into more than one cell opens a confirm/cancel dialog
|
|
4654
|
+
before anything commits.
|
|
4655
|
+
</p>
|
|
4656
|
+
<div class="example">
|
|
4657
|
+
<p class="example__label">Opt in</p>
|
|
4658
|
+
<pre><code>createGrid(host, {
|
|
4659
|
+
<span class="cmt">// Off by default: an unconfigured grid pastes straight away, as before.</span>
|
|
4660
|
+
edit: { enabled: <span class="kw">true</span>, pastePreview: <span class="kw">true</span> },
|
|
4661
|
+
});</code></pre>
|
|
4662
|
+
</div>
|
|
4663
|
+
<p>
|
|
4664
|
+
The dialog lists every cell that will change, old → new, and every cell a commit
|
|
4665
|
+
would reject — a read-only cell, a value the column's type or <code>edit.validate</code>
|
|
4666
|
+
refuses, a cell a permission policy forbids. <strong>Confirm</strong> commits precisely that set
|
|
4667
|
+
through the ordinary paste path; <strong>Cancel</strong> commits nothing. A single-cell paste
|
|
4668
|
+
skips the dialog — a preview for one cell is friction, not a safety net. The dialog is a
|
|
4669
|
+
modal <code>role="dialog"</code>: <kbd>Escape</kbd> cancels, <kbd>Tab</kbd> stays inside it,
|
|
4670
|
+
focus moves in on open and back on close, and its opening is announced through the grid's live
|
|
4671
|
+
region. The same diff is available without any UI from
|
|
4672
|
+
<code>grid.edit.previewPaste(anchor, text, extent?)</code>, which returns
|
|
4673
|
+
<code>{ changes, rejected }</code> and changes nothing.
|
|
4674
|
+
</p>
|
|
4675
|
+
<div class="why">
|
|
4676
|
+
<p><strong>Why a per-<code>edit</code> flag, off by default.</strong> Paste preview lives under
|
|
4677
|
+
<code>edit</code> because a paste is a bulk edit and its accept/reject decisions are the edit
|
|
4678
|
+
model's — the preview cannot disagree with the commit because it runs the same checks.
|
|
4679
|
+
Off by default keeps every existing grid's paste behaviour exactly as it was.</p>
|
|
4680
|
+
</div>
|
|
4681
|
+
|
|
4493
4682
|
<h2 id="keyboard">Keyboard</h2>
|
|
4494
4683
|
<p class="lead-in">
|
|
4495
4684
|
Press <kbd>?</kbd> in the grid to see this list in the product. The overlay is generated from
|
|
@@ -5002,6 +5191,45 @@ r.ok ? r.value : r.error; <span class="cmt">// 42</span></code></pre>
|
|
|
5002
5191
|
version, and you do not have to maintain a lookup table keyed by column id alongside the
|
|
5003
5192
|
columns themselves.</p>
|
|
5004
5193
|
</div>
|
|
5194
|
+
|
|
5195
|
+
<h3 id="range-chart">Chart a selected range</h3>
|
|
5196
|
+
<p class="lead-in">
|
|
5197
|
+
<code>rangeChart</code> turns a selected cell range into a chart — the spreadsheet gesture. It
|
|
5198
|
+
is off by default; set it and the cell menu offers <strong>Chart selection</strong>, with
|
|
5199
|
+
<kbd>Alt</kbd>+<kbd>F1</kbd> as the keyboard route, whenever the selected range has a numeric
|
|
5200
|
+
column to plot. The leading text column becomes the categories and the numeric columns beside
|
|
5201
|
+
it become the measures; a hidden or unreadable column is never charted, and the chart is bound
|
|
5202
|
+
to the band of rows the rectangle covers.
|
|
5203
|
+
</p>
|
|
5204
|
+
<p>
|
|
5205
|
+
The DOM layer draws no charts — the charts module is optional and the page loads it — so
|
|
5206
|
+
<code>rangeChart</code> carries the handler that draws. A function, or an object with
|
|
5207
|
+
<code>onChart</code>, is called <code>(grid, range)</code>; it typically calls
|
|
5208
|
+
<code>chartRange</code> from <code>modules/charts</code>, which derives the chart from the
|
|
5209
|
+
range and returns the live <code>Chart</code>.
|
|
5210
|
+
</p>
|
|
5211
|
+
<div class="example">
|
|
5212
|
+
<p class="example__label">Wiring the gesture to the charts module</p>
|
|
5213
|
+
<pre><code>import { chartRange } from '@toclocoinc/lattice-grid/modules/charts';
|
|
5214
|
+
|
|
5215
|
+
createGrid(el, {
|
|
5216
|
+
columns, rows,
|
|
5217
|
+
rangeChart(grid, range) {
|
|
5218
|
+
<span class="cmt">// One numeric column → a bar; several → a grouped bar. Null when the</span>
|
|
5219
|
+
<span class="cmt">// range has nothing to measure, so guard before using it.</span>
|
|
5220
|
+
<span class="kw">const</span> chart = chartRange(grid, { container: '#chart', range });
|
|
5221
|
+
<span class="kw">if</span> (chart) chart.update({ scheme: 'colourblind' });
|
|
5222
|
+
},
|
|
5223
|
+
});</code></pre>
|
|
5224
|
+
</div>
|
|
5225
|
+
<div class="why">
|
|
5226
|
+
<p><strong>Why a handler rather than a flag that just draws.</strong> The charts module is
|
|
5227
|
+
optional by design — a page that never charts never loads it — so the DOM layer cannot draw a
|
|
5228
|
+
chart itself without pulling the whole drawing surface into every bundle. Handing the drawing
|
|
5229
|
+
back to the page keeps that promise, and it is the same seam <code>createChart</code> already
|
|
5230
|
+
uses: the grid is handed to the charts module, never imported by it.</p>
|
|
5231
|
+
</div>
|
|
5232
|
+
|
|
5005
5233
|
<div class="example">
|
|
5006
5234
|
<p class="example__label">A button of your own on the rail</p>
|
|
5007
5235
|
<pre><code>createGrid(el, {
|
|
@@ -5486,6 +5714,9 @@ grid.state.apply(savedView.state);
|
|
|
5486
5714
|
<thead><tr><th>Name</th><th>What it does</th></tr></thead>
|
|
5487
5715
|
<tbody>
|
|
5488
5716
|
<tr><td class="name">createChart</td><td class="desc">Draw one of the thirty-seven chart types from a grid’s own data. It follows the grid’s filters, and a mark can filter the grid back.</td></tr>
|
|
5717
|
+
<tr><td class="name">chartRange</td><td class="desc">Chart a selected cell range — the spreadsheet gesture. Derives the chart from the range’s shape (a leading text column is the categories, the numeric columns the measures), respects hidden and unreadable columns, and returns the live chart or null when there is nothing to measure.</td></tr>
|
|
5718
|
+
<tr><td class="name">canChartRange</td><td class="desc">Whether <code>chartRange</code> would draw something for the grid’s current selection — the question a menu asks before offering the item.</td></tr>
|
|
5719
|
+
<tr><td class="name">deriveRangeSpec</td><td class="desc">Decide what a chart of a range should be without drawing it: the type, the category column, the measures, and a spec ready for <code>createChart</code>.</td></tr>
|
|
5489
5720
|
<tr><td class="name">createDevtools</td><td class="desc">Mount the devtools panel against a grid, including its accessibility checks.</td></tr>
|
|
5490
5721
|
<tr><td class="name">createLatticeGridElement</td><td class="desc">Build the element class without registering it, for a custom registry.</td></tr>
|
|
5491
5722
|
<tr><td class="name">createMessages</td><td class="desc">Build a message catalogue. A partial set lays over the built-in British English one.</td></tr>
|
package/lattice-grid.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/*!
|
|
2
|
-
* Lattice Grid 1.
|
|
2
|
+
* Lattice Grid 1.16.0, type declarations
|
|
3
3
|
* Copyright (c) 2026 TOCLOCO Inc. All rights reserved.
|
|
4
4
|
* https://latticegrid.dev
|
|
5
5
|
*/
|
|
@@ -341,6 +341,22 @@ export interface LookupSpec {
|
|
|
341
341
|
export type DecorationName = 'plain' | 'fill' | 'pill' | 'dot' | 'bar' | 'heat' | 'icon';
|
|
342
342
|
export type VariantName = 'neutral' | 'info' | 'success' | 'warning' | 'danger' | 'accent' | 'none' | (string & {});
|
|
343
343
|
|
|
344
|
+
/** A built-in threshold icon set, mapping value bands to built-in glyphs. */
|
|
345
|
+
export type IconSetName = 'trafficLights' | 'arrows' | 'trafficArrows' | 'ratings' | (string & {});
|
|
346
|
+
|
|
347
|
+
/**
|
|
348
|
+
* One band of a threshold icon set. A value clears a band when it is at least
|
|
349
|
+
* `min`; the highest band it clears wins. Omit `min` on the last band to make
|
|
350
|
+
* it the catch-all. `label` is what assistive technology announces for the
|
|
351
|
+
* glyph, so a screen-reader user hears the band's meaning, not only the value.
|
|
352
|
+
*/
|
|
353
|
+
export interface IconBand {
|
|
354
|
+
min?: number;
|
|
355
|
+
icon: string;
|
|
356
|
+
label?: string;
|
|
357
|
+
variant?: VariantName;
|
|
358
|
+
}
|
|
359
|
+
|
|
344
360
|
export interface DecorationSpec {
|
|
345
361
|
type: DecorationName;
|
|
346
362
|
size?: 'sm' | 'md' | 'lg';
|
|
@@ -349,6 +365,10 @@ export interface DecorationSpec {
|
|
|
349
365
|
edge?: boolean;
|
|
350
366
|
position?: 'start' | 'end';
|
|
351
367
|
name?: string | Record<string, string>;
|
|
368
|
+
/** icon only: a built-in threshold icon set, expanded to `bands`. */
|
|
369
|
+
iconSet?: IconSetName;
|
|
370
|
+
/** icon only: value bands mapped to glyphs, first match by descending `min`. */
|
|
371
|
+
bands?: IconBand[];
|
|
352
372
|
min?: number;
|
|
353
373
|
max?: number;
|
|
354
374
|
origin?: number;
|
|
@@ -738,6 +758,59 @@ export interface Source {
|
|
|
738
758
|
|
|
739
759
|
export interface MemorySourceConfig { mode: 'memory'; columnarBelow?: number }
|
|
740
760
|
|
|
761
|
+
/**
|
|
762
|
+
* How rows are ingested into the column store.
|
|
763
|
+
*/
|
|
764
|
+
export interface IngestConfig {
|
|
765
|
+
/**
|
|
766
|
+
* Retain the caller's row objects by reference so identity round-trips.
|
|
767
|
+
* Default `true`, the historical behaviour: `rows.data()` returns the exact
|
|
768
|
+
* objects you supplied, `row === sourceObject` holds, and a custom renderer
|
|
769
|
+
* reading `row.sourceObject` works.
|
|
770
|
+
*
|
|
771
|
+
* Set `false` to keep only the packed columns and reconstruct a plain row
|
|
772
|
+
* object from them on demand. This drops roughly half the resident footprint,
|
|
773
|
+
* but changes three behaviours: `rows.data()` returns freshly reconstructed
|
|
774
|
+
* objects (new object each call, so `row === sourceObject` no longer holds),
|
|
775
|
+
* a custom renderer that reaches for `row.sourceObject` gets a reconstruction
|
|
776
|
+
* rather than the original, and equality against a row becomes value-based.
|
|
777
|
+
* The stored values are unchanged, so `get()`, `byKey()`, `value()` and
|
|
778
|
+
* `values()` are unaffected.
|
|
779
|
+
*/
|
|
780
|
+
retainSource?: boolean;
|
|
781
|
+
|
|
782
|
+
/**
|
|
783
|
+
* Columnize `stream`-source ingest on a Worker so a large load does not block
|
|
784
|
+
* the main thread. Default `false`. When on, an arriving chunk that clears
|
|
785
|
+
* {@link IngestConfig.workerThreshold} is packed into typed column buffers on
|
|
786
|
+
* the Worker; the main thread merges the finished buffers into the store and
|
|
787
|
+
* renders, without running the per-field extraction pass that otherwise
|
|
788
|
+
* dominates ingest.
|
|
789
|
+
*
|
|
790
|
+
* This makes **stream** ingest non-blocking (remote sources already are).
|
|
791
|
+
* Memory and paged sources cannot be made non-blocking this way — the main
|
|
792
|
+
* thread must read the caller's own row objects — and are unaffected. The
|
|
793
|
+
* effect composes with `retainSource: false`: with it off the source keeps no
|
|
794
|
+
* caller-object array on the main thread at all, so the load is both
|
|
795
|
+
* non-blocking and lighter on memory.
|
|
796
|
+
*
|
|
797
|
+
* A column that reads through a closure — a `date` column's storage
|
|
798
|
+
* conversion, or a computed column — cannot cross the Worker boundary, so a
|
|
799
|
+
* grid with any such column columnizes on the main thread and says so once.
|
|
800
|
+
* Falls back silently to the main thread wherever a Worker cannot be created.
|
|
801
|
+
*/
|
|
802
|
+
useWorker?: boolean;
|
|
803
|
+
|
|
804
|
+
/**
|
|
805
|
+
* Row count in a single stream chunk at or above which columnization is
|
|
806
|
+
* offloaded to the Worker when {@link IngestConfig.useWorker} is on. Default
|
|
807
|
+
* `10000`. A smaller first chunk is packed on the main thread, where the
|
|
808
|
+
* cost is trivial and the postMessage round trip would only add latency to
|
|
809
|
+
* time-to-first-row.
|
|
810
|
+
*/
|
|
811
|
+
workerThreshold?: number;
|
|
812
|
+
}
|
|
813
|
+
|
|
741
814
|
export interface PagedSourceConfig {
|
|
742
815
|
mode: 'paged';
|
|
743
816
|
pageSize?: number;
|
|
@@ -968,6 +1041,15 @@ export interface EditConfig {
|
|
|
968
1041
|
commit?: (write: PendingWrite) => unknown;
|
|
969
1042
|
confirm?: 'auto' | 'manual';
|
|
970
1043
|
pendingTimeout?: number;
|
|
1044
|
+
/**
|
|
1045
|
+
* Show a preview of what a bulk paste will change before it commits (§12),
|
|
1046
|
+
* with confirm/cancel. Off by default: a paste commits straight away, exactly
|
|
1047
|
+
* as it always has. When on, a paste into more than one cell first opens a
|
|
1048
|
+
* dialog listing every cell that changes (old → new) and every cell that would
|
|
1049
|
+
* be rejected (permission, data-type, read-only); confirm commits precisely
|
|
1050
|
+
* that set through the ordinary edit path, cancel commits nothing.
|
|
1051
|
+
*/
|
|
1052
|
+
pastePreview?: boolean;
|
|
971
1053
|
}
|
|
972
1054
|
|
|
973
1055
|
export interface PendingWrite {
|
|
@@ -1010,6 +1092,8 @@ export interface GridConfig {
|
|
|
1010
1092
|
rowKey?: string | ((row: unknown) => string);
|
|
1011
1093
|
/** Where rows come from: memory, paged, remote, stream or derived. */
|
|
1012
1094
|
source?: SourceConfig;
|
|
1095
|
+
/** How rows are ingested into the column store. */
|
|
1096
|
+
ingest?: IngestConfig;
|
|
1013
1097
|
/** Applied to every column before its own settings. */
|
|
1014
1098
|
columnDefaults?: Column;
|
|
1015
1099
|
/** Named bundles of column settings, referenced by a column's `preset`. */
|
|
@@ -1374,6 +1458,14 @@ export interface GridConfig {
|
|
|
1374
1458
|
totalOnlyChangedColumns?: boolean;
|
|
1375
1459
|
/** Put the total in the header rather than a footer row. */
|
|
1376
1460
|
showTotalInHeader?: boolean;
|
|
1461
|
+
/**
|
|
1462
|
+
* Let the user pick a column's reduction from the column menu. On, the
|
|
1463
|
+
* totalling entry becomes an "Aggregate" submenu offering the aggregates the
|
|
1464
|
+
* column's type says are meaningful (§9.4); off, the menu keeps its plain
|
|
1465
|
+
* "Total this column" toggle. Off by default, so an existing grid is
|
|
1466
|
+
* unchanged.
|
|
1467
|
+
*/
|
|
1468
|
+
aggregateChooser?: boolean;
|
|
1377
1469
|
/** Render only the visible columns once there are more than this many. */
|
|
1378
1470
|
columnVirtualisationAbove?: number;
|
|
1379
1471
|
/** The bar beneath the grid, and which panels it carries. */
|
|
@@ -1391,6 +1483,23 @@ export interface GridConfig {
|
|
|
1391
1483
|
*/
|
|
1392
1484
|
columnMenu?: boolean | ((p: ColumnMenuParams, defaults: MenuItem[]) => MenuItem[] | void);
|
|
1393
1485
|
|
|
1486
|
+
/**
|
|
1487
|
+
* Chart a selected cell range — the spreadsheet "chart this selection"
|
|
1488
|
+
* gesture. Off by default, so a grid opts in.
|
|
1489
|
+
*
|
|
1490
|
+
* The DOM layer draws no charts itself — the charts module is optional and
|
|
1491
|
+
* loaded by the host — so this is where the host wires the two together: a
|
|
1492
|
+
* function, or an object carrying `onChart`, is called with the grid and the
|
|
1493
|
+
* selected range when the reader chooses "Chart selection" from the cell
|
|
1494
|
+
* menu. The handler typically calls `chartRange` from
|
|
1495
|
+
* `lattice-grid/modules/charts`. `true` offers the item and emits nothing
|
|
1496
|
+
* extra; supply a handler to have it actually draw.
|
|
1497
|
+
*/
|
|
1498
|
+
rangeChart?:
|
|
1499
|
+
| boolean
|
|
1500
|
+
| ((grid: Grid, range: CellRange) => void)
|
|
1501
|
+
| { onChart?: (grid: Grid, range: CellRange) => void };
|
|
1502
|
+
|
|
1394
1503
|
/**
|
|
1395
1504
|
* The `?` keyboard shortcut overlay. `false` suppresses it, for a host
|
|
1396
1505
|
* that wants `?` for itself. Default true.
|
|
@@ -1503,6 +1612,22 @@ export interface GridConfig {
|
|
|
1503
1612
|
/** File name for the export action, without the extension. */
|
|
1504
1613
|
exportName?: string;
|
|
1505
1614
|
};
|
|
1615
|
+
/**
|
|
1616
|
+
* A drag-and-drop group-by strip above the column header — the pattern AG
|
|
1617
|
+
* Grid calls the row-group panel. Drag a column heading into it to group by
|
|
1618
|
+
* that column; the active groups show as removable, reorderable chips, and
|
|
1619
|
+
* reordering the chips changes the nesting order. It is keyboard-operable
|
|
1620
|
+
* (arrows navigate, Shift+arrow reorders, Delete ungroups, and an add control
|
|
1621
|
+
* groups any column), and every change is announced through the live region,
|
|
1622
|
+
* which is why it also addresses the drag-only complaint of BACKLOG-0000429.
|
|
1623
|
+
*
|
|
1624
|
+
* Off by default and non-breaking, matching `toolPanel`. It drives the same
|
|
1625
|
+
* grouping model as `grid.columns.group()`; it reimplements nothing.
|
|
1626
|
+
*/
|
|
1627
|
+
groupPanel?: boolean | {
|
|
1628
|
+
/** Placeholder shown while nothing is grouped. */
|
|
1629
|
+
hint?: string;
|
|
1630
|
+
};
|
|
1506
1631
|
/** The quick filter's initial text. */
|
|
1507
1632
|
quickFilterText?: string;
|
|
1508
1633
|
/**
|
|
@@ -2164,6 +2289,11 @@ export interface RowsApi {
|
|
|
2164
2289
|
export interface ColumnsApi {
|
|
2165
2290
|
/** Set or clear a column's totals-row reduction. */
|
|
2166
2291
|
setTotal(id: string, fn: TotalName | TotalFn | null): void;
|
|
2292
|
+
/**
|
|
2293
|
+
* The aggregate names meaningful for a column, honouring its type's
|
|
2294
|
+
* `totals.supported` declaration (§9.4). What the aggregate chooser offers.
|
|
2295
|
+
*/
|
|
2296
|
+
aggregates(id: string): TotalName[];
|
|
2167
2297
|
/** Every distinct value in a column, from the dictionary where there is one. */
|
|
2168
2298
|
distinct(id: string): unknown[];
|
|
2169
2299
|
get(id: string): ResolvedColumn | undefined;
|
|
@@ -2186,6 +2316,13 @@ export interface ColumnsApi {
|
|
|
2186
2316
|
move(id: string, to: number): void;
|
|
2187
2317
|
pin(id: string, side: 'start' | 'end' | null): void;
|
|
2188
2318
|
resize(id: string, px: number): void;
|
|
2319
|
+
/**
|
|
2320
|
+
* Set, change or clear a column's decoration at runtime (§8.7). Pass `null` to
|
|
2321
|
+
* clear it back to plain text. Presentation config: it is not on the undo
|
|
2322
|
+
* timeline and is not carried in a saved view — use `grid.formatting` for
|
|
2323
|
+
* durable, view-persisted conditional styling.
|
|
2324
|
+
*/
|
|
2325
|
+
decorate(id: string, decoration: DecorationName | DecorationSpec | null, opts?: { variant?: VariantSpec }): void;
|
|
2189
2326
|
autoSize(ids?: string | string[]): void;
|
|
2190
2327
|
fit(): void;
|
|
2191
2328
|
group(ids: string | string[]): void;
|
|
@@ -2269,6 +2406,18 @@ export interface EditApi {
|
|
|
2269
2406
|
redo(): void;
|
|
2270
2407
|
setCells(writes: { key: string; colId: string; value: unknown }[], type?: 'cell' | 'fill' | 'paste'): number;
|
|
2271
2408
|
pasteInto(anchor: { key: string; colId: string }, text: string, extent?: { rows?: number; columns?: number }): number;
|
|
2409
|
+
/** Whether a bulk paste is previewed before it commits (`edit.pastePreview`, §12). */
|
|
2410
|
+
readonly pastePreview: boolean;
|
|
2411
|
+
/**
|
|
2412
|
+
* Compute what a paste would change, without committing (§12). The engine
|
|
2413
|
+
* behind `edit.pastePreview`: `changes` are the accepted writes with their old
|
|
2414
|
+
* and new values (and whether each actually differs), `rejected` are the cells
|
|
2415
|
+
* a commit would refuse, each with a reason.
|
|
2416
|
+
*/
|
|
2417
|
+
previewPaste(anchor: { key: string; colId: string }, text: string, extent?: { rows?: number; columns?: number }): {
|
|
2418
|
+
changes: { key: string; colId: string; oldValue: unknown; newValue: unknown; changed: boolean }[];
|
|
2419
|
+
rejected: { key: string; colId: string; value: unknown; reason: 'permission' | 'readOnly' | 'validation' | 'locked' | 'missing' }[];
|
|
2420
|
+
};
|
|
2272
2421
|
settle(id: string, ok: boolean, reason?: string): boolean;
|
|
2273
2422
|
pending(): OpenWrite[];
|
|
2274
2423
|
status(key: string, colId: string): 'pending' | null;
|
|
@@ -3623,6 +3772,12 @@ export interface ChartSpec {
|
|
|
3623
3772
|
y?: string;
|
|
3624
3773
|
/** Splits the measure into one series per distinct value. */
|
|
3625
3774
|
series?: string;
|
|
3775
|
+
/**
|
|
3776
|
+
* The exact rows to chart, overriding the grid's own walk — an array, or a
|
|
3777
|
+
* function returning one at draw time. `chartRange` uses it to bind a chart
|
|
3778
|
+
* to the band of rows a selected range covers rather than the whole grid.
|
|
3779
|
+
*/
|
|
3780
|
+
rows?: object[] | ((grid: Grid) => object[]);
|
|
3626
3781
|
/** Several measures at once, for combo and candlestick. */
|
|
3627
3782
|
measures?: ChartMeasure[];
|
|
3628
3783
|
/** Endpoints, for sankey, chord and network. */
|
|
@@ -3753,6 +3908,39 @@ declare module 'lattice-grid/modules/charts' {
|
|
|
3753
3908
|
export const SCHEMES: Readonly<Record<string, readonly string[]>>;
|
|
3754
3909
|
export const PALETTE: readonly string[];
|
|
3755
3910
|
export function createChart(spec: ChartSpec): Chart;
|
|
3911
|
+
/**
|
|
3912
|
+
* Chart a selected cell range. Derives the chart from the range's shape — a
|
|
3913
|
+
* leading text column becomes the categories, the numeric columns become the
|
|
3914
|
+
* measures — and returns the live chart, or null when the range has nothing
|
|
3915
|
+
* to measure. Respects hidden and unreadable columns. The type is a sensible
|
|
3916
|
+
* default the caller can change with `chart.update({ type })`.
|
|
3917
|
+
*/
|
|
3918
|
+
export function chartRange(
|
|
3919
|
+
grid: Grid,
|
|
3920
|
+
opts: {
|
|
3921
|
+
container: Element | string;
|
|
3922
|
+
range?: CellRange;
|
|
3923
|
+
type?: ChartType;
|
|
3924
|
+
} & Partial<ChartSpec>,
|
|
3925
|
+
): Chart | null;
|
|
3926
|
+
/** Would {@link chartRange} draw something for the grid's current selection? */
|
|
3927
|
+
export function canChartRange(grid: Grid, opts?: { range?: CellRange }): boolean;
|
|
3928
|
+
/**
|
|
3929
|
+
* Decide what a chart of a range should be, without drawing it: the type, the
|
|
3930
|
+
* category column, the measure columns, and a `spec` ready for `createChart`
|
|
3931
|
+
* — or a `reason` naming why the range cannot be charted.
|
|
3932
|
+
*/
|
|
3933
|
+
export function deriveRangeSpec(
|
|
3934
|
+
grid: Grid,
|
|
3935
|
+
opts?: { range?: CellRange; type?: ChartType },
|
|
3936
|
+
): {
|
|
3937
|
+
spec: ChartSpec | null;
|
|
3938
|
+
type: ChartType | null;
|
|
3939
|
+
x: string | null;
|
|
3940
|
+
measures: string[];
|
|
3941
|
+
columns: string[];
|
|
3942
|
+
reason: string | null;
|
|
3943
|
+
};
|
|
3756
3944
|
export function registerScheme(name: string, colours: readonly string[]): void;
|
|
3757
3945
|
export function resolveScheme(spec?: object): object;
|
|
3758
3946
|
export function schemeNames(): string[];
|