@toclocoinc/lattice-grid 1.56.0 → 1.58.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 +158 -17
- package/docs/api-detail.html +227 -7
- package/lattice-grid.d.ts +366 -15
- package/lattice-grid.esm.min.js +964 -545
- package/lattice-grid.min.cjs +963 -545
- package/lattice-grid.min.css +1 -1
- package/lattice-grid.min.js +963 -545
- package/modules/ai.esm.min.js +7 -4
- package/modules/ai.min.cjs +7 -4
- package/modules/ai.min.js +7 -4
- package/modules/angular.esm.min.js +7 -4
- package/modules/angular.min.cjs +7 -4
- package/modules/angular.min.js +7 -4
- package/modules/chart-alluvial.esm.min.js +1 -1
- package/modules/chart-arc.esm.min.js +1 -1
- package/modules/chart-bubblemap.esm.min.js +1 -1
- package/modules/chart-bump.esm.min.js +1 -1
- package/modules/chart-calendar.esm.min.js +1 -1
- package/modules/chart-decomposition.esm.min.js +1 -1
- package/modules/chart-diverging.esm.min.js +1 -1
- package/modules/chart-dumbbell.esm.min.js +1 -1
- package/modules/chart-fan.esm.min.js +1 -1
- package/modules/chart-hexbin.esm.min.js +1 -1
- package/modules/chart-hexmap.esm.min.js +1 -1
- package/modules/chart-icicle.esm.min.js +1 -1
- package/modules/chart-parallel.esm.min.js +1 -1
- package/modules/chart-ridgeline.esm.min.js +1 -1
- package/modules/chart-roc.esm.min.js +1 -1
- package/modules/chart-slope.esm.min.js +1 -1
- package/modules/chart-splom.esm.min.js +1 -1
- package/modules/chart-waffle.esm.min.js +1 -1
- package/modules/charts.esm.min.js +4 -4
- package/modules/charts.min.cjs +4 -4
- package/modules/charts.min.js +4 -4
- package/modules/data-router.esm.min.js +4 -4
- package/modules/data-router.min.cjs +4 -4
- package/modules/data-router.min.js +4 -4
- package/modules/devtools.esm.min.js +2 -2
- package/modules/devtools.min.cjs +2 -2
- package/modules/devtools.min.js +2 -2
- package/modules/dhtmlx-compat.esm.min.js +4 -4
- package/modules/dhtmlx-compat.min.cjs +4 -4
- package/modules/dhtmlx-compat.min.js +4 -4
- package/modules/gantt.esm.min.js +4 -4
- package/modules/gantt.min.cjs +4 -4
- package/modules/gantt.min.js +4 -4
- package/modules/htmx.esm.min.js +960 -545
- package/modules/htmx.min.cjs +960 -545
- package/modules/htmx.min.js +960 -545
- package/modules/kanban.esm.min.js +107 -27
- package/modules/kanban.min.cjs +107 -27
- package/modules/kanban.min.js +107 -27
- package/modules/kpi.esm.min.js +41 -8
- package/modules/kpi.min.cjs +41 -8
- package/modules/kpi.min.js +41 -8
- package/modules/layout.esm.min.js +4 -4
- package/modules/layout.min.cjs +4 -4
- package/modules/layout.min.js +4 -4
- package/modules/mock-socket.esm.min.js +2 -2
- package/modules/mock-socket.min.cjs +2 -2
- package/modules/mock-socket.min.js +2 -2
- package/modules/react.esm.min.js +7 -4
- package/modules/react.min.cjs +7 -4
- package/modules/react.min.js +7 -4
- package/modules/svelte.esm.min.js +7 -4
- package/modules/svelte.min.cjs +7 -4
- package/modules/svelte.min.js +7 -4
- package/modules/tabs.esm.min.js +4 -4
- package/modules/tabs.min.cjs +4 -4
- package/modules/tabs.min.js +4 -4
- package/modules/vue.esm.min.js +7 -4
- package/modules/vue.min.cjs +7 -4
- package/modules/vue.min.js +7 -4
- package/modules/webcomponent.esm.min.js +963 -545
- package/modules/webcomponent.min.cjs +963 -545
- package/modules/webcomponent.min.js +963 -545
- 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.
|
|
7
|
+
Version 1.58.0 · [latticegrid.dev](https://www.latticegrid.dev) · TOCLOCO Inc
|
|
8
8
|
|
|
9
9
|
---
|
|
10
10
|
|
package/docs/API.html
CHANGED
|
@@ -360,7 +360,7 @@
|
|
|
360
360
|
<div class="shell">
|
|
361
361
|
<aside class="rail">
|
|
362
362
|
<p class="rail__brand">Lattice Grid</p>
|
|
363
|
-
<p class="rail__sub">API reference · v1.
|
|
363
|
+
<p class="rail__sub">API reference · v1.58.0</p>
|
|
364
364
|
<nav>
|
|
365
365
|
<div class="rail__group">
|
|
366
366
|
<span class="rail__label">Start</span>
|
|
@@ -443,7 +443,7 @@
|
|
|
443
443
|
</header>
|
|
444
444
|
|
|
445
445
|
<p class="chips">
|
|
446
|
-
<span class="chip">Version 1.
|
|
446
|
+
<span class="chip">Version 1.58.0</span>
|
|
447
447
|
<span class="chip">Zero dependencies</span>
|
|
448
448
|
<span class="chip"><a href="api-detail.html">Developer guide →</a></span>
|
|
449
449
|
</p>
|
|
@@ -578,6 +578,11 @@
|
|
|
578
578
|
<td class="type">Grid</td>
|
|
579
579
|
<td class="desc">Core only. Everything below except <code>grid.element</code> and the DOM-only config keys works unchanged. What that does and doesn't reach is spelled out below.</td>
|
|
580
580
|
</tr>
|
|
581
|
+
<tr>
|
|
582
|
+
<td class="sig">defaults(config?)</td>
|
|
583
|
+
<td class="type">object</td>
|
|
584
|
+
<td class="desc">House-wide defaults, merged <em>beneath</em> the config of every grid built afterwards, through either factory. The per-grid value always wins. <code>defaults()</code> reads the current set; <code>defaults(null)</code> clears it. See the note below.</td>
|
|
585
|
+
</tr>
|
|
581
586
|
</tbody>
|
|
582
587
|
</table>
|
|
583
588
|
</div>
|
|
@@ -603,10 +608,51 @@
|
|
|
603
608
|
|
|
604
609
|
<span class="cmt">// everywhere else</span>
|
|
605
610
|
<span class="kw">import</span> { createGrid } <span class="kw">from</span> './your-lattice.js';</code></pre>
|
|
606
|
-
<p>
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
611
|
+
<p>The wrapping function above is still a good seam when the wrapper does more than supply
|
|
612
|
+
options. When all it does is supply options, use <code>defaults()</code> instead: it applies to
|
|
613
|
+
every grid built afterwards through <em>either</em> factory, including the ones built for you
|
|
614
|
+
inside a framework adapter or a module, which a wrapper in your own code never reaches.</p>
|
|
615
|
+
<ul>
|
|
616
|
+
<li><strong>The per-grid config always wins.</strong> Defaults sit beneath what the factory
|
|
617
|
+
is passed: a key the grid names keeps the grid's value, a key it omits takes the house one.
|
|
618
|
+
A key passed as <code>undefined</code> means "say nothing" — as it does everywhere else in
|
|
619
|
+
the config surface — and so takes the house value rather than blanking it.</li>
|
|
620
|
+
<li><strong>Plain objects deep-merge; arrays and everything else replace.</strong> A house
|
|
621
|
+
<code>views: { storage }</code> and a grid's <code>views: { local: true }</code> both
|
|
622
|
+
survive. A grid's <code>columns</code> array replaces the house one rather than extending
|
|
623
|
+
it. Which keys behave as option bags follows from the value at the key, not from a fixed
|
|
624
|
+
list.</li>
|
|
625
|
+
<li><strong>Calling it again replaces the set, it does not accumulate</strong>, so the
|
|
626
|
+
result never depends on the order your modules load. Extend explicitly with
|
|
627
|
+
<code>defaults({ ...defaults(), density: 'compact' })</code>.</li>
|
|
628
|
+
<li><strong>Never retroactive.</strong> The merge happens as a grid is built, so a grid that
|
|
629
|
+
already exists is never revisited. Nothing reached from the defaults is shared between two
|
|
630
|
+
grids: nested objects and arrays are copied per grid.</li>
|
|
631
|
+
</ul>
|
|
632
|
+
<pre data-run="js" data-expect="Ada; own-key true; cleared {}" data-covers="export:defaults"><code><span class="kw">const</span> { createHeadlessGrid, defaults } = <span class="kw">await</span> import('../packages/core/src/index.js');
|
|
633
|
+
|
|
634
|
+
<span class="cmt">// One place says what every grid in this application starts from.</span>
|
|
635
|
+
defaults({ rowKey: 'id', selection: 'multiple' });
|
|
636
|
+
|
|
637
|
+
<span class="cmt">// This grid says nothing about rowKey, so the house value applies.</span>
|
|
638
|
+
<span class="kw">const</span> a = createHeadlessGrid({
|
|
639
|
+
columns: [{ field: 'id' }, { field: 'name' }],
|
|
640
|
+
rows: [{ id: 'a1', name: 'Ada' }],
|
|
641
|
+
});
|
|
642
|
+
<span class="kw">const</span> house = a.rows.byKey('a1').data.name;
|
|
643
|
+
|
|
644
|
+
<span class="cmt">// This one names its own rowKey. The grid's own config always wins.</span>
|
|
645
|
+
<span class="kw">const</span> b = createHeadlessGrid({
|
|
646
|
+
rowKey: 'sku',
|
|
647
|
+
columns: [{ field: 'sku' }],
|
|
648
|
+
rows: [{ sku: 's9', id: 'ignored' }],
|
|
649
|
+
});
|
|
650
|
+
<span class="kw">const</span> own = b.rows.byKey('s9') !== <span class="kw">undefined</span> && b.rows.byKey('ignored') === <span class="kw">undefined</span>;
|
|
651
|
+
|
|
652
|
+
a.destroy();
|
|
653
|
+
b.destroy();
|
|
654
|
+
defaults(<span class="kw">null</span>); <span class="cmt">// clear: grids built after this are unaffected</span>
|
|
655
|
+
<span class="kw">return</span> `${house}; own-key ${own}; cleared ${JSON.stringify(defaults())}`;</code></pre>
|
|
610
656
|
</div>
|
|
611
657
|
|
|
612
658
|
<div class="note" id="headless-coverage">
|
|
@@ -843,6 +889,8 @@ autoInit(document); <span class="cmt">// builds every [data-lattice-grid] under
|
|
|
843
889
|
<tr><td class="name">pinnedTopRows</td><td class="type">object[]</td><td class="dflt">, </td><td class="desc">Rows held above the scrolling body. Rendered through the ordinary column pipeline, but not part of the data: not counted, sorted, filtered, grouped, selectable or exported. See <a href="api-detail.html#pinned-rows">Pinned rows</a>.</td></tr>
|
|
844
890
|
<tr><td class="name">pinnedBottomRows</td><td class="type">object[]</td><td class="dflt">, </td><td class="desc">As <code>pinnedTopRows</code>, held below the body instead. Sits under the grand total when both are shown.</td></tr>
|
|
845
891
|
<tr><td class="name">fullWidth</td><td class="type">{ when, render }</td><td class="dflt">, </td><td class="desc">Draw matching rows as one band across every column instead of dividing them into columns, a section banner, a note, a “load more” affordance. <code>when(row)</code> picks them, <code>render(params)</code> fills them. Still ordinary data rows in every other respect. See <a href="api-detail.html#full-width-rows">Full-width rows</a>.</td></tr>
|
|
892
|
+
<tr><td class="name">groupRenderer</td><td class="type">(params) => string | Node | void</td><td class="dflt">, </td><td class="desc">Draw the group row yourself — a section header with a chevron, a rollup, a count, a progress bar — instead of the grid's expander-and-label. The row is drawn as one band across every column and no ordinary cells are mounted underneath it. Return an HTML string, a node, or write into <code>params.element</code>. A string <strong>is</strong> inserted as markup here, unlike <code>fullWidth.render</code>, because a group heading is synthesised by the grid and has no data row: the string can only be your own template, the same contract the board's <code>cardRenderer</code> has. The renderer is handed the group key, the grouped column id, the value, the level, the expanded state, <code>leafCount</code>, the group's <code>totals</code> and <code>leaves()</code> for the rows themselves. Mark any element in your markup <code>data-lat-group-toggle</code> to make it expand and collapse the group. See <a href="api-detail.html#group-row-renderer">Group rows you draw yourself</a>.</td></tr>
|
|
893
|
+
<tr><td class="name">groupDefaultExpanded</td><td class="type">boolean | number | (group) => boolean</td><td class="dflt">, </td><td class="desc">Which groups start open before anyone has touched one. <code>true</code> (the default) opens every group, <code>false</code> closes every group, a number opens the first N levels (<code>0</code> closes everything, a negative opens every level), and a predicate answers per group — the current sprint open while the rest start closed. It is handed <code>{ key, column, value, level, path }</code>. Only ever consulted for a group nobody has expanded or collapsed: once the user or your code decides, that decision stands. See <a href="api-detail.html#group-row-renderer">Group rows you draw yourself</a>.</td></tr>
|
|
846
894
|
<tr><td class="name">groupFooter</td><td class="type">boolean</td><td class="dflt">false</td><td class="desc">A closing total row per group.</td></tr>
|
|
847
895
|
<tr><td class="name">totalFilteredOnly</td><td class="type">boolean</td><td class="dflt">true</td><td class="desc">Totals reduce the filtered set. <code>false</code> totals the whole dataset, group totals included. See <a href="api-detail.html#total-filtered-only">Grouping, totals and pivot</a>.</td></tr>
|
|
848
896
|
<tr><td class="name">totalOnlyChangedColumns</td><td class="type">boolean</td><td class="dflt">false</td><td class="desc">Reduce only the totalled columns an edit actually changed. Off by default, it asserts that each total depends on nothing but its own column. See <a href="api-detail.html#grouping">Grouping, totals and pivot</a>.</td></tr>
|
|
@@ -1084,7 +1132,7 @@ autoInit(document); <span class="cmt">// builds every [data-lattice-grid] under
|
|
|
1084
1132
|
<table>
|
|
1085
1133
|
<thead><tr><th>Member</th><th>Returns</th><th>Description</th></tr></thead>
|
|
1086
1134
|
<tbody>
|
|
1087
|
-
<tr><td class="sig">getVersion()</td><td class="type">string</td><td class="desc">The version this grid came from, e.g. <code>'1.
|
|
1135
|
+
<tr><td class="sig">getVersion()</td><td class="type">string</td><td class="desc">The version this grid came from, e.g. <code>'1.58.0'</code>. Also on the module as <code>getVersion()</code>, for when you have no grid to hand.</td></tr>
|
|
1088
1136
|
<tr><td class="sig">get(key)</td><td class="type">unknown</td><td class="desc">Read any configuration key.</td></tr>
|
|
1089
1137
|
<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>
|
|
1090
1138
|
<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>
|
|
@@ -1178,7 +1226,7 @@ grid.overlay.hide();</code></pre>
|
|
|
1178
1226
|
<tr><td class="sig">keys()</td><td class="type">string[]</td><td class="desc">Selected row keys.</td></tr>
|
|
1179
1227
|
<tr><td class="sig">rows()</td><td class="type">Row[]</td><td class="desc"></td></tr>
|
|
1180
1228
|
<tr><td class="sig">all()</td><td class="type">Row[]</td><td class="desc">Including rows selected but currently filtered out.</td></tr>
|
|
1181
|
-
<tr><td class="sig">set(keys)</td><td class="type">void</td><td class="desc">Replace the selection.</td></tr>
|
|
1229
|
+
<tr><td class="sig">set(keys)</td><td class="type">void</td><td class="desc">Replace the selection. In <code>mode: 'single'</code>, only the <em>first</em> key of the array is kept; the rest are dropped, they are not an error.</td></tr>
|
|
1182
1230
|
<tr><td class="sig">clear()</td><td class="type">void</td><td class="desc"></td></tr>
|
|
1183
1231
|
<tr><td class="sig">ranges()</td><td class="type">Range[]</td><td class="desc">Cell ranges, for spreadsheet-style selection.</td></tr>
|
|
1184
1232
|
<tr><td class="sig">setRange(range)</td><td class="type">void</td><td class="desc">Replace every range with one.</td></tr>
|
|
@@ -4290,6 +4338,10 @@ off(); <span class="cmt">// on() returns i
|
|
|
4290
4338
|
<tr><td class="name">row:sent</td><td class="desc">A row was written back to a source.</td></tr>
|
|
4291
4339
|
<tr><td class="name">row:copied</td><td class="desc">A row was duplicated.</td></tr>
|
|
4292
4340
|
<tr><td class="name">row:moved</td><td class="desc">A row was dragged to a new position.</td></tr>
|
|
4341
|
+
<tr><td class="name">rowDrag:started</td><td class="type">{ key, data, over, at, overKey }</td><td class="desc">A row drag passed the drag threshold and began (BACKLOG-0001224). Fires on the grid the drag started in, as do the other three, for a same-grid reorder and a cross-grid transfer alike. See <a href="#type-RowDragEvent">RowDragEvent</a>.</td></tr>
|
|
4342
|
+
<tr><td class="name">rowDrag:moved</td><td class="type">{ key, data, over, at, overKey }</td><td class="desc">The drag is over a candidate position. <strong>Coalesced to one event per animation frame</strong>, carrying that frame's latest pointer position, so a handler runs at the display's rate rather than the pointer's several hundred a second. <code>over</code> is the grid under the pointer (null over none), <code>at</code> and <code>overKey</code> where the row would land in it.</td></tr>
|
|
4343
|
+
<tr><td class="name">rowDrag:left</td><td class="type">{ key, data, over, at, overKey }</td><td class="desc">The pointer left a grid: <code>over</code> names the grid it left, <code>at</code> and <code>overKey</code> are null. Emitted on the transition rather than on a frame, so un-highlighting is never a frame behind the pointer.</td></tr>
|
|
4344
|
+
<tr><td class="name">rowDrag:ended</td><td class="type">{ key, data, over, at, overKey, dropped }</td><td class="desc">The gesture ended, whether or not a drop followed — including a release outside every grid, where <code>over</code> is null. <code>dropped</code> is whether the release is being acted on; the outcome is reported by <code>row:moved</code>, <code>row:sent</code>, <code>row:received</code> and <code>rowReceive:cancelled</code>. These four are notifications: none is cancellable, because the drop is already vetoable by <code>beforeRowMove</code> and <code>beforeRowReceive</code>.</td></tr>
|
|
4293
4345
|
<tr><td class="name">stream:evicted</td><td class="desc">A streaming source dropped rows to stay within its cap.</td></tr>
|
|
4294
4346
|
<tr><td class="name">header:contextmenu</td><td class="desc">A heading was right-clicked.</td></tr>
|
|
4295
4347
|
<tr><td class="name">timeline:attached</td><td class="desc">A time brush was connected to the grid.</td></tr>
|
|
@@ -4337,6 +4389,7 @@ off(); <span class="cmt">// on() returns i
|
|
|
4337
4389
|
<tr><td class="name">beforeDelete</td><td class="type">{ key, rows, origin }</td><td class="desc">An optimistic row delete is about to apply — the canonical confirm-before-delete hook.</td></tr>
|
|
4338
4390
|
<tr><td class="name">beforeRowMove</td><td class="type">{ key, from, to, origin }</td><td class="desc">A row reorder is about to apply.</td></tr>
|
|
4339
4391
|
<tr><td class="name">beforeGroup</td><td class="type">{ key, expanded, origin }</td><td class="desc">A group/tree expand or collapse is about to apply.</td></tr>
|
|
4392
|
+
<tr><td class="name">beforeRowReceive</td><td class="type">{ data, at, overKey, source, origin }</td><td class="desc">A row dragged from another grid is about to be inserted into this one; fires on the <strong>receiving</strong> grid (BACKLOG-0001225). <code>overKey</code> is the key of the row under the pointer — null past the last row, on empty space, on the header or on a pinned row — <code>at</code> the display index it would take, <code>source</code> the grid it came from. A veto leaves the source untouched: the row stays and neither <code>row:sent</code> nor <code>row:copied</code> fires. See <a href="#type-BeforeRowReceiveEvent">BeforeRowReceiveEvent</a>.</td></tr>
|
|
4340
4393
|
<tr><td class="name">edit:cancelled</td><td class="type">{ ...context, reason }</td><td class="desc">A <code>beforeEdit</code> was vetoed. <code>reason</code> is <code>'stale'</code> when a live delta moved the cell during an async gate.</td></tr>
|
|
4341
4394
|
<tr><td class="name">sort:cancelled</td><td class="type">{ ...context, reason }</td><td class="desc">A <code>beforeSort</code> was vetoed.</td></tr>
|
|
4342
4395
|
<tr><td class="name">filter:cancelled</td><td class="type">{ ...context, reason }</td><td class="desc">A <code>beforeFilter</code> was vetoed.</td></tr>
|
|
@@ -4348,6 +4401,7 @@ off(); <span class="cmt">// on() returns i
|
|
|
4348
4401
|
<tr><td class="name">delete:cancelled</td><td class="type">{ ...context, reason }</td><td class="desc">A <code>beforeDelete</code> was vetoed. <code>reason</code> is <code>'stale'</code> when the row was already gone.</td></tr>
|
|
4349
4402
|
<tr><td class="name">rowMove:cancelled</td><td class="type">{ ...context, reason }</td><td class="desc">A <code>beforeRowMove</code> was vetoed. <code>reason</code> is <code>'stale'</code> when the row had moved.</td></tr>
|
|
4350
4403
|
<tr><td class="name">group:cancelled</td><td class="type">{ ...context, reason }</td><td class="desc">A <code>beforeGroup</code> was vetoed.</td></tr>
|
|
4404
|
+
<tr><td class="name">rowReceive:cancelled</td><td class="type">{ ...context, reason }</td><td class="desc">A <code>beforeRowReceive</code> was vetoed; nothing was inserted and the source still holds the row. <code>reason</code> is <code>'stale'</code> when the row under the pointer had moved or was gone, or the source row was gone, by the time an async handler settled. See <a href="#type-RowReceiveCancelledEvent">RowReceiveCancelledEvent</a>.</td></tr>
|
|
4351
4405
|
</tbody>
|
|
4352
4406
|
</table>
|
|
4353
4407
|
</div>
|
|
@@ -4388,7 +4442,7 @@ grid.destroy();
|
|
|
4388
4442
|
settles, which is what makes a confirm dialog or a server check a genuine gate. On a veto the paired
|
|
4389
4443
|
<code><action>:cancelled</code> fires with the reason. Host/API writes and remote deltas do not
|
|
4390
4444
|
fire them. Run headless on every build.</p>
|
|
4391
|
-
<pre data-run="js" data-expect="0|Ann|sort,edit locked" data-covers="event:beforeEdit event:beforeSort event:beforeFilter event:beforeColumnMove event:beforeColumnResize event:beforeColumnHide event:beforeSelect event:beforeRowAdd event:beforeDelete event:beforeRowMove event:beforeGroup event:edit:cancelled event:sort:cancelled event:filter:cancelled event:columnMove:cancelled event:columnResize:cancelled event:columnHide:cancelled event:selection:cancelled event:rowAdd:cancelled event:delete:cancelled event:rowMove:cancelled event:group:cancelled event:print:before event:print:after event:export:request event:export:done event:shortcuts:opened event:shortcuts:closed"><code><span class="kw">const</span> { createHeadlessGrid } = <span class="kw">await</span> import('../packages/core/src/index.js');
|
|
4445
|
+
<pre data-run="js" data-expect="0|Ann|sort,edit locked" data-covers="event:beforeEdit event:beforeSort event:beforeFilter event:beforeColumnMove event:beforeColumnResize event:beforeColumnHide event:beforeSelect event:beforeRowAdd event:beforeDelete event:beforeRowMove event:beforeGroup event:edit:cancelled event:sort:cancelled event:filter:cancelled event:columnMove:cancelled event:columnResize:cancelled event:columnHide:cancelled event:selection:cancelled event:rowAdd:cancelled event:delete:cancelled event:rowMove:cancelled event:group:cancelled event:beforeRowReceive event:rowReceive:cancelled event:print:before event:print:after event:export:request event:export:done event:shortcuts:opened event:shortcuts:closed"><code><span class="kw">const</span> { createHeadlessGrid } = <span class="kw">await</span> import('../packages/core/src/index.js');
|
|
4392
4446
|
<span class="kw">const</span> grid = createHeadlessGrid({
|
|
4393
4447
|
rowKey: 'id',
|
|
4394
4448
|
columns: [{ field: 'id' }, { field: 'name', edit: { enabled: <span class="kw">true</span> } }, { field: 'v', type: 'number', edit: { enabled: <span class="kw">true</span> } }],
|
|
@@ -4419,6 +4473,10 @@ grid.on('beforeRowMove', (e) => e.preventDefault('ordered'));
|
|
|
4419
4473
|
grid.on('rowMove:cancelled', () => log.push('rowmove'));
|
|
4420
4474
|
grid.on('beforeRowAdd', (e) => e.preventDefault('quota'));
|
|
4421
4475
|
grid.on('rowAdd:cancelled', () => log.push('rowadd'));
|
|
4476
|
+
<span class="cmt">// A row dropped in from another grid: fires on the receiving grid, naming the</span>
|
|
4477
|
+
<span class="cmt">// row under the pointer, so "assign this to that" can veto the insert.</span>
|
|
4478
|
+
grid.on('beforeRowReceive', (e) => { <span class="kw">if</span> (e.overKey !== <span class="kw">null</span>) e.preventDefault('assigned'); });
|
|
4479
|
+
grid.on('rowReceive:cancelled', () => log.push('receive'));
|
|
4422
4480
|
grid.on('beforeSelect', () => {});
|
|
4423
4481
|
grid.on('selection:cancelled', () => log.push('sel'));
|
|
4424
4482
|
|
|
@@ -5609,7 +5667,9 @@ const board = createKanban(document.querySelector('#board'), {
|
|
|
5609
5667
|
<tr><td class="sig">select / selection / isSelected / clearSelection</td><td class="desc">Card selection: <code>select(keys, 'set'|'add'|'toggle'|'remove')</code>, the selected keys, a membership test, and a clear. Click selects; Ctrl/Cmd toggles; Shift extends within a column.</td></tr>
|
|
5610
5668
|
<tr><td class="sig">collapseColumn(id) / collapseLane(id)</td><td class="desc">Collapse, expand or toggle a column or swimlane; emits <code>column:collapse</code> / <code>swimlane:collapse</code>. State survives a keyed-diff update.</td></tr>
|
|
5611
5669
|
<tr><td class="sig">reorderColumns(order) / moveColumn(id, before)</td><td class="desc">Reorder the columns (also done by dragging a column header); emits <code>column:reorder</code>.</td></tr>
|
|
5670
|
+
<tr><td class="sig">setColumns(defs)</td><td class="desc">Replace the whole column set after construction — a tenant renaming, adding or removing a column, in one call, without rebuilding the board. Id-keyed like the grid's own <code>columns.apply(state)</code>: a column that keeps its id keeps its cards, its collapsed state and its place in a pinned <code>reorderColumns</code> order; the quick filter and the selection are untouched. A column dropped from <code>defs</code> is not specially handled — a card whose value has nowhere configured to go re-derives a plain, humanised ad hoc column rather than being dropped, the same rule an always-unconfigured value already gets.</td></tr>
|
|
5612
5671
|
<tr><td class="sig">setQuickFilter(text) / setFilter(fn) / facets(property)</td><td class="desc">Quick text search across card fields, a predicate filter, and distinct-value counts for a facet control.</td></tr>
|
|
5672
|
+
<tr><td class="sig">filters.where(name, fn) / filters.where(name, null) / filters.where() / filters.reapply(name?)</td><td class="desc">Named predicates, composed with AND (BACKLOG-0001229) — the grid's own <code>filters.where</code> convention. Register or replace one under <code>name</code>; <code>where(name, null)</code> removes only that one, leaving the others in force; <code>where()</code> lists the registered names; <code>reapply(name?)</code> re-runs and re-renders. The quick filter is untouched by any of this. <code>setFilter(fn)</code> is unchanged sugar for <code>where(filters.DEFAULT, fn)</code>, so it composes with any other named predicate instead of replacing it.</td></tr>
|
|
5613
5673
|
<tr><td class="sig">setSprint(id) / showBacklog() / sprints()</td><td class="desc">Sprint view and switcher: show one sprint, the backlog (<code>board.BACKLOG</code> — cards with no sprint), or all; and the distinct sprint values. Emits <code>sprint:changed</code>.</td></tr>
|
|
5614
5674
|
<tr><td class="sig">setEpic(id) / epics() / epicRollup() / rollup(property)</td><td class="desc">Epic view and rollup: filter to an epic, list epics, and roll rows up by epic (or any property) into count, points, and progress toward the <code>done</code> columns.</td></tr>
|
|
5615
5675
|
<tr><td class="sig">expand(key) / closeDetail() / canExpand(card)</td><td class="desc">Pop a card's children out as a nested child grid (or board) in a drawer/modal/inline container; emits <code>card:expand</code> and <code>card:drill</code>.</td></tr>
|
|
@@ -5627,7 +5687,7 @@ const board = createKanban(document.querySelector('#board'), {
|
|
|
5627
5687
|
</table>
|
|
5628
5688
|
</div>
|
|
5629
5689
|
<p><strong>Drag-and-drop and keyboard move (write-back).</strong> Cards drag between columns (writing <code>columnProperty</code>) and within a column into a position (writing <code>orderProperty</code> with fractional ranking, so only the moved cards' order is written). The same move is available from the keyboard: focus a card, press <kbd>Space</kbd> to grab it, use the arrows to choose a target column and position (announced on a live region), <kbd>Space</kbd>/<kbd>Enter</kbd> to drop, <kbd>Escape</kbd> to cancel. Multi-select drags every selected card. A move calls <code>onBeforeMove(card, from, to, index)</code> first — return <code>false</code> (or a promise of it) to veto — then persists: <strong>grid-bound</strong>, through <code>grid.edit.setCells</code> (the same public edit-commit path inline editing and the write-back adapter use, so the grid's own pipeline owns the optimistic apply, the confirm and the revert); <strong>standalone</strong>, optimistically with a revert when <code>onCardMove</code> returns <code>false</code>/rejects. A configurable per-card <code>contextMenu</code> (an array or <code>fn(card, selected)</code>) replaces the <code>card:contextmenu</code> event when present.</p>
|
|
5630
|
-
<p><strong>Swimlanes, collapse, reorder and search.</strong> Set <code>swimlanes: true</code> to render a 2D lane×column grid grouped by <code>swimlaneProperty</code>: one band per lane with its own count/points, columns aligned across every lane, the board scrolling vertically through lanes and horizontally through columns inside its own box. A drag across lanes writes the swimlane property too. Columns and lanes collapse (their state survives a keyed-diff update); columns reorder by dragging their header (<code>reorderColumns</code>/<code>moveColumn</code>). <code>setQuickFilter(text)</code> searches across card fields, <code>setFilter(fn)</code> applies a predicate, and <code>facets(property)</code> returns distinct-value counts to build a facet control. Naming the <code>swimlaneProperty</code> is separate from turning on the lane view, so a board can carry it for a cross-lane move without switching layout.</p>
|
|
5690
|
+
<p><strong>Swimlanes, collapse, reorder and search.</strong> Set <code>swimlanes: true</code> to render a 2D lane×column grid grouped by <code>swimlaneProperty</code>: one band per lane with its own count/points, columns aligned across every lane, the board scrolling vertically through lanes and horizontally through columns inside its own box. A drag across lanes writes the swimlane property too. Columns and lanes collapse (their state survives a keyed-diff update); columns reorder by dragging their header (<code>reorderColumns</code>/<code>moveColumn</code>). <code>setQuickFilter(text)</code> searches across card fields, <code>setFilter(fn)</code> applies a predicate (sugar for <code>filters.where(filters.DEFAULT, fn)</code> — <code>filters.where(name, fn)</code> registers any number of independent named predicates, ANDed together), and <code>facets(property)</code> returns distinct-value counts to build a facet control. Naming the <code>swimlaneProperty</code> is separate from turning on the lane view, so a board can carry it for a cross-lane move without switching layout.</p>
|
|
5631
5691
|
<p><strong>Sprint, epic and card pop-out.</strong> <code>setSprint(id)</code> shows one sprint, <code>showBacklog()</code> the cards with no sprint, and <code>sprints()</code> feeds a switcher; <code>setEpic(id)</code> narrows to an epic and <code>epicRollup()</code> (or <code>rollup(property)</code>) returns per-epic count, points and progress toward the <code>done</code> columns. A card can <strong>pop out a nested grid of its children</strong> — an epic's stories, a story's tasks, recursively. The child relationship is a <code>childrenProperty</code> (parent-id within the dataset) and/or a <code>loadChildren(card)</code> (per-card dataset or async fetch), and the child is a full composed <code>createGrid</code> (sort/filter/edit/write-back) — supplied as <code>children.factory</code> — opened in a <code>drawer</code> (default), <code>modal</code> or <code>inline</code>. With <code>children.asBoard</code> the child is itself a board, so it can pop its own children. This reuses the grid by composition and adds no grid-core coupling. <code>expand(key)</code> and the per-card drill affordance emit <code>card:expand</code>; a deeper open emits <code>card:drill</code>.</p>
|
|
5632
5692
|
<p><strong>Live updates.</strong> Because the board consumes data through the same keyed-diff contract a grid does, a <a href="#datarouter">Data Router</a> drives it directly — <code>router.attach(board, predicate)</code> — and one feed fans out to a grid, a kanban, a chart and a KPI tile at once. A live <code>rows.apply({ add, update, remove })</code> is applied as a keyed diff (an unchanged card keeps its model) and re-rendered <strong>preserving</strong> scroll, focus, selection, collapsed columns/lanes and any open pop-out, so a card can appear, move or update under the user without losing their place.</p>
|
|
5633
5693
|
<p><strong>Scale, state and accessibility.</strong> <code>virtualize</code> renders only a scroll window of a tall column (with true-height spacers so the scrollbar stays honest), for boards of thousands of cards. <code>getState()</code>/<code>setState()</code> (and <code>config.state</code>) save and restore the collapsed columns and lanes, the column order, the quick filter and the sprint/epic selection, so a reopened board comes back as it was; <code>setLoading</code>/<code>setError</code> add loading and error states. Accessibility runs throughout: the board is a labelled group of labelled column lists, cards are a roving-tabindex focus ring (arrows to move focus, Enter to activate), the move is fully keyboard-driven (<kbd>Space</kbd> grab, arrows for column/position, <kbd>Alt</kbd>+<kbd>↑/↓</kbd> across swimlanes, <kbd>Space</kbd>/<kbd>Enter</kbd> drop, <kbd>Escape</kbd> cancel) with live-region announcements, and every affordance carries a name.</p>
|
|
@@ -7119,7 +7179,7 @@ grid.destroy();
|
|
|
7119
7179
|
<p class="section-note">Each documented event is subscribed to and unsubscribed on every build. A consumer
|
|
7120
7180
|
wiring a handler to a renamed event gets silence, which is indistinguishable from an event that
|
|
7121
7181
|
has not fired yet — so the name is checked rather than left to be discovered.</p>
|
|
7122
|
-
<pre data-run="js" data-expect="
|
|
7182
|
+
<pre data-run="js" data-expect="112" data-covers="event:rowDrag:started event:rowDrag:moved event:rowDrag:left event:rowDrag:ended event:find:changed event:cell:changed event:cell:clicked event:cell:confirmed event:cell:conflict event:cell:contextmenu event:cell:dblclicked event:cell:edit:end event:cell:edit:start event:cell:pending event:cell:reverted event:clipboard:copy event:column:filter:open event:column:profile:open event:column:grouped event:column:menu:open event:column:pivoted event:column:resized event:columns:changed event:columns:tagged event:comment:added event:comment:deleted event:comment:edited event:comment:failed event:comment:indexLoaded event:comment:resolved event:comment:threadClosed event:comment:threadOpened event:comment:unresolved event:destroy event:detail:toggled event:diff:changed event:diff:swapped event:export:progress event:facet:computed event:facet:expanded event:facet:failed event:facet:filtered event:form:closed event:form:error event:form:opened event:form:saved event:formatting:changed event:group:toggled event:header:contextmenu event:highlight:changed event:history:applied event:history:changed event:licence:changed event:page:changed event:permissions:changed event:presence:failed event:presence:joined event:presence:left event:presence:lockRefused event:presence:published event:presence:updated event:presentation:captured event:presentation:changed event:presentation:ended event:presentation:scale event:presentation:spotlight event:presentation:started event:presentation:view event:range:changed event:ready event:redaction:changed event:render:done event:render:first event:row:clicked event:row:copied event:row:dblclicked event:row:edit:end event:row:edit:start event:row:moved event:row:received event:row:sent event:rows:deferred event:rows:paused event:rows:queued event:rows:resumed event:scroll event:scroll:end event:selection:changed event:size:changed event:source:error event:stream:chunk event:stream:end event:stream:evicted event:timeline:attached event:timeline:detached event:timeline:seek event:timeline:seeking event:toolpanel:focus event:tree:loadAborted event:tree:loadFailed event:tree:loaded event:tree:loading event:view:applied event:view:default event:view:removed event:view:renamed event:view:saved event:views:changed event:row:pending event:row:confirmed event:row:reverted event:row:conflict"><code><span class="kw">const</span> { createHeadlessGrid } = <span class="kw">await</span> import('../packages/core/src/index.js');
|
|
7123
7183
|
|
|
7124
7184
|
<span class="cmt">// Every documented event name, checked against the bus that would carry it.</span>
|
|
7125
7185
|
<span class="cmt">// Subscribing to a name the grid does not know is the failure this catches:</span>
|
|
@@ -7153,6 +7213,7 @@ grid.destroy();
|
|
|
7153
7213
|
'tree:loadFailed', 'tree:loaded', 'tree:loading', 'view:applied',
|
|
7154
7214
|
'view:default', 'view:removed', 'view:renamed', 'view:saved',
|
|
7155
7215
|
'views:changed',
|
|
7216
|
+
'rowDrag:started', 'rowDrag:moved', 'rowDrag:left', 'rowDrag:ended',
|
|
7156
7217
|
];
|
|
7157
7218
|
|
|
7158
7219
|
<span class="kw">const</span> grid = createHeadlessGrid({
|
|
@@ -7600,6 +7661,19 @@ return `next ${p.mean.toFixed(1)}; r2 ${f.r2.toFixed(1)}; band ${p.upper - p.low
|
|
|
7600
7661
|
</tbody>
|
|
7601
7662
|
</table>
|
|
7602
7663
|
</div>
|
|
7664
|
+
<h3 id="type-BeforeRowReceiveEvent">BeforeRowReceiveEvent</h3>
|
|
7665
|
+
<p class="section-note">The `beforeRowReceive` event (BACKLOG-0001225): a row dragged from another grid is about to be inserted into this one. Fires on the **receiving** grid, before the insert, with the row under the pointer named — so a drop that means "assign this to that" can be recorded by the host and the insert stopped with `preventDefault(reason)`. A veto leaves the source grid untouched: the row stays where it was, and neither `row:sent` nor `row:copied` fires there. The source removes its row only after the target has admitted it, and a veto is a refusal to admit. The paired `rowReceive:cancelled` carries the same context plus the reason. Like every {@link BeforeEvent}, the handler may be `async`; the insert is held until it settles, and is cancelled as `'stale'` (BACKLOG-0001242) if the source row is gone by then, or if the row under the pointer is gone or has moved to a different index — `at` names a slot as "before `overKey`", and once that is no longer where `overKey`'s row sits, `at` is a stale index into a list that changed while the handler was thinking, not the slot the drop meant. `overKey: null` (the drop landed on no row) has no row to drift against and is never stale on that account.</p>
|
|
7666
|
+
<div class="table-wrap">
|
|
7667
|
+
<table>
|
|
7668
|
+
<thead><tr><th>Member</th><th>Type</th><th>Description</th></tr></thead>
|
|
7669
|
+
<tbody>
|
|
7670
|
+
<tr><td class="name">data</td><td class="type">Record<string, unknown></td><td class="desc">The row about to be inserted: a shallow copy of the source row's data, and the very object that is inserted if no handler vetoes, so a change made to it here lands with the row.</td></tr>
|
|
7671
|
+
<tr><td class="name">at</td><td class="type">number</td><td class="desc">The display index the row would be inserted at: the index of the row under the pointer, or `rows.count()` when the drop landed on no row. When `overKey` names a row, this is guaranteed to still be that row's index at the moment the insert actually runs — an async handler that leaves the named row at a different index causes the drop to be cancelled as `'stale'` (BACKLOG-0001242) rather than inserted at this index regardless.</td></tr>
|
|
7672
|
+
<tr><td class="name">overKey</td><td class="type">string | null</td><td class="desc">The key of the row under the pointer when the drop happened — the row the user meant. Null when the drop landed past the last row, on empty space, on the header, or on a pinned row: there is no row to name, and a nearest guess would be wrong in a way that looks right.</td></tr>
|
|
7673
|
+
<tr><td class="name">source</td><td class="type">Grid</td><td class="desc">The grid the row is being dragged from.</td></tr>
|
|
7674
|
+
</tbody>
|
|
7675
|
+
</table>
|
|
7676
|
+
</div>
|
|
7603
7677
|
<h3 id="type-BooleanFormat">BooleanFormat</h3>
|
|
7604
7678
|
<div class="table-wrap">
|
|
7605
7679
|
<table>
|
|
@@ -8527,7 +8601,7 @@ return `next ${p.mean.toFixed(1)}; r2 ${f.r2.toFixed(1)}; band ${p.upper - p.low
|
|
|
8527
8601
|
<tr><td class="name">outline</td><td class="type">boolean</td><td class="desc"><small>(optional)</small></td></tr>
|
|
8528
8602
|
<tr><td class="name">edge</td><td class="type">boolean</td><td class="desc"><small>(optional)</small></td></tr>
|
|
8529
8603
|
<tr><td class="name">position</td><td class="type">'start' | 'end'</td><td class="desc"><small>(optional)</small></td></tr>
|
|
8530
|
-
<tr><td class="name">name</td><td class="type">
|
|
8604
|
+
<tr><td class="name">name</td><td class="type">IconName | Record<string, IconName></td><td class="desc">`icon` decoration only: either a single glyph name (see {@link IconName}) used for every value, or a value -> glyph name map for exact-value icons. Omit both `name` and `bands` to use `iconSet`/its default instead. <small>(optional)</small></td></tr>
|
|
8531
8605
|
<tr><td class="name">iconSet</td><td class="type">IconSetName</td><td class="desc">icon only: a built-in threshold icon set, expanded to `bands`. <small>(optional)</small></td></tr>
|
|
8532
8606
|
<tr><td class="name">bands</td><td class="type">IconBand[]</td><td class="desc">icon only: value bands mapped to glyphs, first match by descending `min`. <small>(optional)</small></td></tr>
|
|
8533
8607
|
<tr><td class="name">min</td><td class="type">number</td><td class="desc"><small>(optional)</small></td></tr>
|
|
@@ -9335,6 +9409,8 @@ return `next ${p.mean.toFixed(1)}; r2 ${f.r2.toFixed(1)}; band ${p.upper - p.low
|
|
|
9335
9409
|
<tr><td class="name">workerUrl</td><td class="type">string</td><td class="desc">Where to load the worker kernel from, when hosting it yourself. <small>(optional)</small></td></tr>
|
|
9336
9410
|
<tr><td class="name">sharedMemory</td><td class="type">boolean</td><td class="desc">Use a shared buffer for the worker, where the page's headers allow it. <small>(optional)</small></td></tr>
|
|
9337
9411
|
<tr><td class="name">groupFooter</td><td class="type">boolean</td><td class="desc">A totals line at the foot of each group as well as the grid. <small>(optional)</small></td></tr>
|
|
9412
|
+
<tr><td class="name">groupRenderer</td><td class="type">(params: GroupRowParams): string | Node | void</td><td class="desc">Draw the group row yourself. The grid's own group row is an expander, a label and a count. A host that needs more — a section header with a points rollup, a done/total count and a progress bar — supplies this instead, and owns the whole row: it is drawn as one band across every column, and no ordinary cells are mounted for it. Return an HTML string, or a node, or write into `params.element` and return nothing. Unlike `fullWidth.render`, a string here **is** inserted as markup, on the same footing as the board's `cardRenderer`: this is your own template for a row the grid synthesised, not a value out of your data. The chevron is yours to draw and yours to wire: give any element in your markup `data-lat-group-toggle` and a click on it expands or collapses the group, or call `params.toggle()` from a node you built yourself. <small>(optional)</small></td></tr>
|
|
9413
|
+
<tr><td class="name">groupDefaultExpanded</td><td class="type">boolean | number | ((group: GroupInfo) => boolean)</td><td class="desc">Which groups start expanded, before anyone has opened or closed one. `true` (the default) opens every group, `false` closes every group, a number opens the first N levels (`0` closes everything, a negative opens every level), and a predicate answers per group — the current sprint's section open while the rest start closed. Only ever consulted for a group nobody has touched: once the user or your code expands or collapses one, that decision stands. <small>(optional)</small></td></tr>
|
|
9338
9414
|
<tr><td class="name">grandTotalRow</td><td class="type">boolean | 'bottom'</td><td class="desc">Where the grand total goes. `true` adds it as the last display row, counted by `rows.count()` like any other. `'bottom'` pins it beneath the viewport instead, so it stays in view while the rows scroll and is *not* part of `rows.count()`. Omitted or `false` means no grand total row. <small>(optional)</small></td></tr>
|
|
9339
9415
|
<tr><td class="name">pinnedTopRows</td><td class="type">unknown[]</td><td class="desc">Rows pinned above the scrolling body. The objects are rendered through the ordinary column pipeline but are not part of the data: not counted by `rows.count()`, not sorted, filtered, grouped, selectable or exported. Use it for a totals line or a units row that must stay against the header. <small>(optional)</small></td></tr>
|
|
9340
9416
|
<tr><td class="name">pinnedBottomRows</td><td class="type">unknown[]</td><td class="desc">Rows pinned below the scrolling body. As `pinnedTopRows`, at the other edge. <small>(optional)</small></td></tr>
|
|
@@ -9470,6 +9546,41 @@ return `next ${p.mean.toFixed(1)}; r2 ${f.r2.toFixed(1)}; band ${p.upper - p.low
|
|
|
9470
9546
|
</tbody>
|
|
9471
9547
|
</table>
|
|
9472
9548
|
</div>
|
|
9549
|
+
<h3 id="type-GroupInfo">GroupInfo</h3>
|
|
9550
|
+
<p class="section-note">Which group `groupDefaultExpanded` is being asked about.</p>
|
|
9551
|
+
<div class="table-wrap">
|
|
9552
|
+
<table>
|
|
9553
|
+
<thead><tr><th>Member</th><th>Type</th><th>Description</th></tr></thead>
|
|
9554
|
+
<tbody>
|
|
9555
|
+
<tr><td class="name">key</td><td class="type">string</td><td class="desc">The group's key, the same string `Row.key` carries and `rows.expand` takes.</td></tr>
|
|
9556
|
+
<tr><td class="name">column</td><td class="type">string</td><td class="desc">The id of the column this level groups on. <small>(optional)</small></td></tr>
|
|
9557
|
+
<tr><td class="name">value</td><td class="type">unknown</td><td class="desc">The value this group stands for. <small>(optional)</small></td></tr>
|
|
9558
|
+
<tr><td class="name">level</td><td class="type">number</td><td class="desc">Depth of the group. Zero is the outermost level. <small>(optional)</small></td></tr>
|
|
9559
|
+
<tr><td class="name">path</td><td class="type">string[]</td><td class="desc">The group path from the root down to this group. <small>(optional)</small></td></tr>
|
|
9560
|
+
</tbody>
|
|
9561
|
+
</table>
|
|
9562
|
+
</div>
|
|
9563
|
+
<h3 id="type-GroupRowParams">GroupRowParams</h3>
|
|
9564
|
+
<p class="section-note">What `groupRenderer` is handed.</p>
|
|
9565
|
+
<div class="table-wrap">
|
|
9566
|
+
<table>
|
|
9567
|
+
<thead><tr><th>Member</th><th>Type</th><th>Description</th></tr></thead>
|
|
9568
|
+
<tbody>
|
|
9569
|
+
<tr><td class="name">row</td><td class="type">Row</td><td class="desc">The group row itself.</td></tr>
|
|
9570
|
+
<tr><td class="name">key</td><td class="type">string</td><td class="desc">The group's key, as `rows.expand`/`rows.collapse` take it.</td></tr>
|
|
9571
|
+
<tr><td class="name">column</td><td class="type">string</td><td class="desc">The id of the column this level groups on. <small>(optional)</small></td></tr>
|
|
9572
|
+
<tr><td class="name">value</td><td class="type">unknown</td><td class="desc">The value this group stands for.</td></tr>
|
|
9573
|
+
<tr><td class="name">level</td><td class="type">number</td><td class="desc">Depth of the group. Zero is the outermost level.</td></tr>
|
|
9574
|
+
<tr><td class="name">expanded</td><td class="type">boolean</td><td class="desc">Whether the group is currently open.</td></tr>
|
|
9575
|
+
<tr><td class="name">leafCount</td><td class="type">number</td><td class="desc">How many records sit beneath it, at any depth.</td></tr>
|
|
9576
|
+
<tr><td class="name">totals</td><td class="type">Record<string, unknown></td><td class="desc">The group's own reductions, by column id — whatever `total` asked for. <small>(optional)</small></td></tr>
|
|
9577
|
+
<tr><td class="name">leaves</td><td class="type">(): Row[]</td><td class="desc">The rows beneath this group, computed when you call it. A function rather than an array because a group is unbounded and this runs per paint: a host that only needs the count should read `leafCount` and never call this.</td></tr>
|
|
9578
|
+
<tr><td class="name">toggle</td><td class="type">(): void</td><td class="desc">Expand the group if it is closed, collapse it if it is open.</td></tr>
|
|
9579
|
+
<tr><td class="name">grid</td><td class="type">Grid</td><td class="desc"></td></tr>
|
|
9580
|
+
<tr><td class="name">element</td><td class="type">HTMLElement</td><td class="desc">The element to fill. Write into it directly, or return content instead.</td></tr>
|
|
9581
|
+
</tbody>
|
|
9582
|
+
</table>
|
|
9583
|
+
</div>
|
|
9473
9584
|
<h3 id="type-Heteroscedasticity">Heteroscedasticity</h3>
|
|
9474
9585
|
<p class="section-note">The Breusch–Pagan heteroscedasticity test result.</p>
|
|
9475
9586
|
<div class="table-wrap">
|
|
@@ -9543,7 +9654,7 @@ return `next ${p.mean.toFixed(1)}; r2 ${f.r2.toFixed(1)}; band ${p.upper - p.low
|
|
|
9543
9654
|
<thead><tr><th>Member</th><th>Type</th><th>Description</th></tr></thead>
|
|
9544
9655
|
<tbody>
|
|
9545
9656
|
<tr><td class="name">min</td><td class="type">number</td><td class="desc"><small>(optional)</small></td></tr>
|
|
9546
|
-
<tr><td class="name">icon</td><td class="type">
|
|
9657
|
+
<tr><td class="name">icon</td><td class="type">IconName</td><td class="desc">A glyph name from the icon registry (see {@link IconName}).</td></tr>
|
|
9547
9658
|
<tr><td class="name">label</td><td class="type">string</td><td class="desc"><small>(optional)</small></td></tr>
|
|
9548
9659
|
<tr><td class="name">variant</td><td class="type">VariantName</td><td class="desc"><small>(optional)</small></td></tr>
|
|
9549
9660
|
</tbody>
|
|
@@ -9877,7 +9988,7 @@ return `next ${p.mean.toFixed(1)}; r2 ${f.r2.toFixed(1)}; band ${p.upper - p.low
|
|
|
9877
9988
|
<tr><td class="name">label</td><td class="type">string</td><td class="desc"></td></tr>
|
|
9878
9989
|
<tr><td class="name">disabled</td><td class="type">boolean</td><td class="desc"><small>(optional)</small></td></tr>
|
|
9879
9990
|
<tr><td class="name">variant</td><td class="type">VariantName</td><td class="desc"><small>(optional)</small></td></tr>
|
|
9880
|
-
<tr><td class="name">icon</td><td class="type">
|
|
9991
|
+
<tr><td class="name">icon</td><td class="type">IconName</td><td class="desc">A glyph name from the icon registry (see {@link IconName}), shown before the label. <small>(optional)</small></td></tr>
|
|
9881
9992
|
<tr><td class="name">group</td><td class="type">string</td><td class="desc"><small>(optional)</small></td></tr>
|
|
9882
9993
|
</tbody>
|
|
9883
9994
|
</table>
|
|
@@ -10195,7 +10306,7 @@ return `next ${p.mean.toFixed(1)}; r2 ${f.r2.toFixed(1)}; band ${p.upper - p.low
|
|
|
10195
10306
|
<tbody>
|
|
10196
10307
|
<tr><td class="name">name</td><td class="type">string</td><td class="desc"></td></tr>
|
|
10197
10308
|
<tr><td class="name">title</td><td class="type">string | (() => string)</td><td class="desc"></td></tr>
|
|
10198
|
-
<tr><td class="name">icon</td><td class="type">
|
|
10309
|
+
<tr><td class="name">icon</td><td class="type">IconName | (() => IconName)</td><td class="desc">A glyph name from the icon registry (see {@link IconName}) — a built-in name, or one registered with `registerIcon`/`registerIcons`, `config.icons` or `grid.icons`. A function form is re-read on every repaint, the same as `title`, so a toggle can swap its glyph with its state. When omitted, the rail tries `name` as the icon name instead (so an action named after a built-in, e.g. `'undo'`, needs no separate `icon`); an unrecognised name — from either `icon` or the `name` fallback — draws a blank glyph, and only an explicitly-given unrecognised `icon` warns once in the console. <small>(optional)</small></td></tr>
|
|
10199
10310
|
<tr><td class="name">run</td><td class="type">(params: RailActionParams): void</td><td class="desc"></td></tr>
|
|
10200
10311
|
<tr><td class="name">enabled</td><td class="type">(): boolean</td><td class="desc"><small>(optional)</small></td></tr>
|
|
10201
10312
|
<tr><td class="name">active</td><td class="type">(): boolean</td><td class="desc">Marks the action as a toggle and reports whether it is currently on. When present the rail renders `aria-pressed` and a pressed style, re-read on every repaint; a one-shot action omits it and is unchanged. This is the hook the native annotation tools use, and it is available to a host button that is itself a toggle. <small>(optional)</small></td></tr>
|
|
@@ -10477,6 +10588,21 @@ return `next ${p.mean.toFixed(1)}; r2 ${f.r2.toFixed(1)}; band ${p.upper - p.low
|
|
|
10477
10588
|
</tbody>
|
|
10478
10589
|
</table>
|
|
10479
10590
|
</div>
|
|
10591
|
+
<h3 id="type-RowDragEvent">RowDragEvent</h3>
|
|
10592
|
+
<p class="section-note">The row-drag lifecycle events (BACKLOG-0001224): `rowDrag:started`, `rowDrag:moved`, `rowDrag:left` and `rowDrag:ended`, which report a row drag *as it happens* rather than once it has settled. Before them a host got the handle the grid draws and then one settled event, with nothing in between to highlight a candidate target, drive a custom drop indicator, or react when the pointer left the grid. **All four fire on the grid the drag started in**, whether the row is being reordered within that grid or dragged into another one. A drag is one gesture with one owner, and the source grid is the only grid present for the whole of it — the pointer may cross several others, or none. `over` names whichever grid the event is about, so a single subscription can drive decoration on any of them. **Notifications, not gates.** None of these is cancellable and none carries `preventDefault`. The drop is already vetoable twice over — `beforeRowMove` for a reorder, `beforeRowReceive` for a drop into another grid — and a third veto on the same gesture would be a third place to look when a drop does not happen. **What is safe to do in a handler.** Read, measure and draw: highlight a candidate row, move an indicator, update a side panel. Do not mutate rows, columns, sort, filters or grouping from one of these. The drag resolves where it would land against the display order, so changing that order mid-gesture moves the ground under the drop; and `data` is the source row's own object rather than a copy, so writing to it edits the row that is still in the grid without announcing it. Work that changes the grid belongs in `beforeRowReceive`, which is asked before the insert, or in the settled events afterwards. **`rowDrag:moved` is coalesced to one event per animation frame**, carrying the latest pointer position of that frame, so a handler runs at the display's rate rather than the pointer's several hundred events a second. The other three fire on the transition itself. The sequence for any gesture is `rowDrag:started`, then `rowDrag:moved` and `rowDrag:left` as the pointer travels, then exactly one `rowDrag:ended` — including when the pointer is released outside every grid. No `rowDrag:moved` is delivered after `rowDrag:ended`. A press that never passes the drag threshold is a click and raises none of them; a grid destroyed mid-drag raises no `rowDrag:ended`.</p>
|
|
10593
|
+
<div class="table-wrap">
|
|
10594
|
+
<table>
|
|
10595
|
+
<thead><tr><th>Member</th><th>Type</th><th>Description</th></tr></thead>
|
|
10596
|
+
<tbody>
|
|
10597
|
+
<tr><td class="name">key</td><td class="type">string</td><td class="desc">The key of the row being dragged.</td></tr>
|
|
10598
|
+
<tr><td class="name">data</td><td class="type">Record<string, unknown> | null</td><td class="desc">The dragged row's data as it stands in the source grid — that row's own object, not a copy. Null if the row has left the source during the drag.</td></tr>
|
|
10599
|
+
<tr><td class="name">over</td><td class="type">Grid | null</td><td class="desc">The grid the event is about: the grid under the pointer for `rowDrag:started`, `rowDrag:moved` and `rowDrag:ended`, and the grid just left for `rowDrag:left`. Null when the pointer is over no grid at all.</td></tr>
|
|
10600
|
+
<tr><td class="name">at</td><td class="type">number | null</td><td class="desc">Where the row would land in `over`: the display index it would take. Null when there is no candidate to report — the pointer is over no grid, over a grid that will refuse the row, or over a header; and on `rowDrag:left`, which is about a grid the pointer has already gone from.</td></tr>
|
|
10601
|
+
<tr><td class="name">overKey</td><td class="type">string | null</td><td class="desc">The key of the row under the pointer in `over`, or null where there is no row to name: past the last row, on empty space, on a header, on a pinned row, on a grid that will refuse the drop, or on `rowDrag:left`.</td></tr>
|
|
10602
|
+
<tr><td class="name">dropped</td><td class="type">boolean</td><td class="desc">`rowDrag:ended` only: whether the release is being acted on — a transfer the target accepts, or a same-grid reorder that is a real move and is not refused by a sort, filter or grouping. False when the row was released over no grid, over a grid that refuses it, or back where it started. What became of an acted-on drop is reported by `row:moved`, `row:sent`, `row:received` and `rowReceive:cancelled`. <small>(optional)</small></td></tr>
|
|
10603
|
+
</tbody>
|
|
10604
|
+
</table>
|
|
10605
|
+
</div>
|
|
10480
10606
|
<h3 id="type-RowFormApi">RowFormApi</h3>
|
|
10481
10607
|
<div class="table-wrap">
|
|
10482
10608
|
<table>
|
|
@@ -10489,6 +10615,20 @@ return `next ${p.mean.toFixed(1)}; r2 ${f.r2.toFixed(1)}; band ${p.upper - p.low
|
|
|
10489
10615
|
</tbody>
|
|
10490
10616
|
</table>
|
|
10491
10617
|
</div>
|
|
10618
|
+
<h3 id="type-RowReceiveCancelledEvent">RowReceiveCancelledEvent</h3>
|
|
10619
|
+
<p class="section-note">The `rowReceive:cancelled` event (BACKLOG-0001225): a `beforeRowReceive` was vetoed, or went stale during an async handler. Nothing was inserted and the source grid is untouched.</p>
|
|
10620
|
+
<div class="table-wrap">
|
|
10621
|
+
<table>
|
|
10622
|
+
<thead><tr><th>Member</th><th>Type</th><th>Description</th></tr></thead>
|
|
10623
|
+
<tbody>
|
|
10624
|
+
<tr><td class="name">data</td><td class="type">Record<string, unknown></td><td class="desc">The row that was not inserted, as the handler saw it.</td></tr>
|
|
10625
|
+
<tr><td class="name">at</td><td class="type">number</td><td class="desc">The display index it would have taken.</td></tr>
|
|
10626
|
+
<tr><td class="name">overKey</td><td class="type">string | null</td><td class="desc">The key of the row under the pointer, or null.</td></tr>
|
|
10627
|
+
<tr><td class="name">source</td><td class="type">Grid</td><td class="desc">The grid the row would have come from; it still holds the row.</td></tr>
|
|
10628
|
+
<tr><td class="name">reason</td><td class="type">string</td><td class="desc">The reason given to `preventDefault`, `'prevented'` when none was given, or `'stale'` when the row under the pointer or the source row was gone by the time an async handler settled.</td></tr>
|
|
10629
|
+
</tbody>
|
|
10630
|
+
</table>
|
|
10631
|
+
</div>
|
|
10492
10632
|
<h3 id="type-RowsApi">RowsApi</h3>
|
|
10493
10633
|
<div class="table-wrap">
|
|
10494
10634
|
<table>
|
|
@@ -10512,6 +10652,7 @@ return `next ${p.mean.toFixed(1)}; r2 ${f.r2.toFixed(1)}; band ${p.upper - p.low
|
|
|
10512
10652
|
<tr><td class="name">refresh</td><td class="type">(opts?: { rows?: string[]; columns?: string[]; force?: boolean }): void</td><td class="desc"></td></tr>
|
|
10513
10653
|
<tr><td class="name">move</td><td class="type">(key: string, to: number): { moved: boolean; from: number; to: number; reason?: string }</td><td class="desc">Move a row to another position in the data. Refuses, with a reason, while a sort, filter or grouping is active.</td></tr>
|
|
10514
10654
|
<tr><td class="name">groupHeadings</td><td class="type">(index: number): Row[]</td><td class="desc">The group headings enclosing a display row, outermost first. Empty when the grid is not grouped.</td></tr>
|
|
10655
|
+
<tr><td class="name">leavesOf</td><td class="type">(key: string): Row[]</td><td class="desc">The leaf rows beneath a group heading: the members it counts in `leafCount`, as rows, so you can roll up a field the grid was never told to total. Filtered members in display order. Computed per call, so call it when you draw a group row rather than in a loop over every row.</td></tr>
|
|
10515
10656
|
<tr><td class="name">expand</td><td class="type">(key: string, deep?: boolean): void</td><td class="desc"></td></tr>
|
|
10516
10657
|
<tr><td class="name">collapse</td><td class="type">(key: string): void</td><td class="desc"></td></tr>
|
|
10517
10658
|
<tr><td class="name">expandAll</td><td class="type">(): void</td><td class="desc"></td></tr>
|
|
@@ -10727,7 +10868,7 @@ return `next ${p.mean.toFixed(1)}; r2 ${f.r2.toFixed(1)}; band ${p.upper - p.low
|
|
|
10727
10868
|
</table>
|
|
10728
10869
|
</div>
|
|
10729
10870
|
<h3 id="type-StateChangedEvent">StateChangedEvent</h3>
|
|
10730
|
-
<p class="section-note">The `state:changed` event (BACKLOG-0001182). Fires once per logical state change, whether it began as a user gesture or as a programmatic call, so view persistence is built on this one event rather than on the ten individual ones — `reset()` raises those too, which made a debounced save write the reset arrangement back. **Exactly one event per change.** A change that internally routes through `state.apply()` — applying a saved view, an undo, a reset — announces itself once, carrying the outermost cause rather than the inner mechanism's.
|
|
10871
|
+
<p class="section-note">The `state:changed` event (BACKLOG-0001182). Fires once per logical state change, whether it began as a user gesture or as a programmatic call, so view persistence is built on this one event rather than on the ten individual ones — `reset()` raises those too, which made a debounced save write the reset arrangement back. **Exactly one event per change.** A change that internally routes through `state.apply()` — applying a saved view, an undo, a reset — announces itself once, carrying the outermost cause rather than the inner mechanism's. A host predicate registered, replaced or removed through `filters.where(name, fn)`, and a `filters.reapply()` that re-runs one, go through the same tracked door as `sort` and `filters`: each fires this event once, `cause: 'user'`, with `'where'` in `sections` (BACKLOG-0001235).</p>
|
|
10731
10872
|
<div class="table-wrap">
|
|
10732
10873
|
<table>
|
|
10733
10874
|
<thead><tr><th>Member</th><th>Type</th><th>Description</th></tr></thead>
|
|
@@ -11089,7 +11230,7 @@ return `next ${p.mean.toFixed(1)}; r2 ${f.r2.toFixed(1)}; band ${p.upper - p.low
|
|
|
11089
11230
|
<!-- END GENERATED TYPE REFERENCE -->
|
|
11090
11231
|
|
|
11091
11232
|
<footer>
|
|
11092
|
-
Lattice Grid 1.
|
|
11233
|
+
Lattice Grid 1.58.0 · Copyright © 2026 TOCLOCO Inc. All rights reserved.
|
|
11093
11234
|
This document describes the behaviour of the shipped library. Where this guide and the code
|
|
11094
11235
|
disagree, the code wins: please <a href="https://www.latticegrid.dev">tell us</a>.
|
|
11095
11236
|
</footer>
|