@toclocoinc/lattice-grid 1.57.0 → 1.59.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 +227 -17
- package/docs/api-detail.html +180 -4
- package/lattice-grid.d.ts +316 -13
- package/lattice-grid.esm.min.js +809 -128
- package/lattice-grid.min.cjs +809 -128
- package/lattice-grid.min.css +1 -1
- package/lattice-grid.min.js +809 -128
- package/modules/ai.esm.min.js +5 -4
- package/modules/ai.min.cjs +5 -4
- package/modules/ai.min.js +5 -4
- package/modules/angular.esm.min.js +3 -2
- package/modules/angular.min.cjs +3 -2
- package/modules/angular.min.js +3 -2
- 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 +109 -33
- package/modules/gantt.min.cjs +109 -33
- package/modules/gantt.min.js +109 -33
- package/modules/htmx.esm.min.js +809 -128
- package/modules/htmx.min.cjs +809 -128
- package/modules/htmx.min.js +809 -128
- package/modules/kanban.esm.min.js +5 -6
- package/modules/kanban.min.cjs +5 -6
- package/modules/kanban.min.js +5 -6
- 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 +59 -6
- package/modules/layout.min.cjs +59 -6
- package/modules/layout.min.js +59 -6
- 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 +3 -2
- package/modules/react.min.cjs +3 -2
- package/modules/react.min.js +3 -2
- package/modules/svelte.esm.min.js +3 -2
- package/modules/svelte.min.cjs +3 -2
- package/modules/svelte.min.js +3 -2
- package/modules/tabs.esm.min.js +411 -9
- package/modules/tabs.min.cjs +411 -9
- package/modules/tabs.min.js +411 -9
- package/modules/vue.esm.min.js +3 -2
- package/modules/vue.min.cjs +3 -2
- package/modules/vue.min.js +3 -2
- package/modules/webcomponent.esm.min.js +809 -128
- package/modules/webcomponent.min.cjs +809 -128
- package/modules/webcomponent.min.js +809 -128
- 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.59.0</p>
|
|
441
441
|
<nav>
|
|
442
442
|
<div class="rail__group">
|
|
443
443
|
<span class="rail__label">Start here</span>
|
|
@@ -553,7 +553,7 @@
|
|
|
553
553
|
<a href="API.html">reference tables</a> are the shorter version for when you already know.
|
|
554
554
|
</p>
|
|
555
555
|
<p class="chips">
|
|
556
|
-
<span class="chip">Version 1.
|
|
556
|
+
<span class="chip">Version 1.59.0</span>
|
|
557
557
|
<span class="chip">Zero dependencies</span>
|
|
558
558
|
<span class="chip">No build step</span>
|
|
559
559
|
</p>
|
|
@@ -1278,7 +1278,7 @@ off(); <span class="cmt">// every subscrip
|
|
|
1278
1278
|
</p>
|
|
1279
1279
|
<div class="example">
|
|
1280
1280
|
<p class="example__label">Which version am I running?</p>
|
|
1281
|
-
<pre><code>grid.getVersion(); <span class="cmt">// '1.
|
|
1281
|
+
<pre><code>grid.getVersion(); <span class="cmt">// '1.59.0'</span>
|
|
1282
1282
|
LatticeGrid.getVersion(); <span class="cmt">// the same, when you have no grid to hand</span></code></pre>
|
|
1283
1283
|
</div>
|
|
1284
1284
|
<p class="lead-in">
|
|
@@ -2684,6 +2684,131 @@ grid.setPinnedRows([], { edge: 'top' }); <span class="cmt">// clear</span
|
|
|
2684
2684
|
technology as one <code>role="columnheader"</code> cell with an <code>aria-colspan</code>.</p>
|
|
2685
2685
|
</div>
|
|
2686
2686
|
|
|
2687
|
+
<h2 id="group-row-renderer">Group rows you draw yourself</h2>
|
|
2688
|
+
<p class="lead-in">
|
|
2689
|
+
The grid's own group row is an expander, a label and a count. When the heading has to carry
|
|
2690
|
+
more than that — a sprint section with a chevron, the section name, the points summed
|
|
2691
|
+
across it, a done/total count and a progress bar — <code>groupRenderer</code> hands you
|
|
2692
|
+
the whole row. It is drawn as one band across every column, over the pinned regions, and no
|
|
2693
|
+
ordinary cells are mounted underneath it.
|
|
2694
|
+
</p>
|
|
2695
|
+
|
|
2696
|
+
<div class="example">
|
|
2697
|
+
<p class="example__label">A section header with a rollup the grid was never told to compute</p>
|
|
2698
|
+
<pre><code>createGrid(element, {
|
|
2699
|
+
columns,
|
|
2700
|
+
rows,
|
|
2701
|
+
groupRenderer: ({ value, leafCount, expanded, leaves }) => {
|
|
2702
|
+
<span class="cmt">// `leaves()` is the group's own rows. Roll up whatever you like.</span>
|
|
2703
|
+
<span class="kw">const</span> rows = leaves();
|
|
2704
|
+
<span class="kw">const</span> points = rows.reduce((sum, r) => sum + r.data.points, 0);
|
|
2705
|
+
<span class="kw">const</span> done = rows.filter((r) => r.data.done).length;
|
|
2706
|
+
<span class="kw">const</span> pct = Math.round((done / leafCount) * 100);
|
|
2707
|
+
<span class="kw">return</span> `<span data-lat-group-toggle>${expanded ? '▾' : '▸'}</span>
|
|
2708
|
+
<b>${value}</b> ${points} pts · ${done}/${leafCount}
|
|
2709
|
+
<progress value="${pct}" max="100"></progress>`;
|
|
2710
|
+
},
|
|
2711
|
+
});</code></pre>
|
|
2712
|
+
</div>
|
|
2713
|
+
|
|
2714
|
+
<h3 id="group-row-renderer-params">What the renderer is given</h3>
|
|
2715
|
+
<div class="table-wrap">
|
|
2716
|
+
<table>
|
|
2717
|
+
<thead><tr><th>Field</th><th>What it is</th></tr></thead>
|
|
2718
|
+
<tbody>
|
|
2719
|
+
<tr><td class="name">key</td><td class="desc">The group's key — the same string <code>rows.expand()</code> and <code>rows.collapse()</code> take, and the one <code>group:toggled</code> carries.</td></tr>
|
|
2720
|
+
<tr><td class="name">column</td><td class="desc">The id of the column <em>this level</em> groups on. It is stamped per rebuild from the grouping, not derived from the row's depth, so it stays correct when an outer grouping is removed and this level becomes the outermost.</td></tr>
|
|
2721
|
+
<tr><td class="name">value</td><td class="desc">The value this group stands for.</td></tr>
|
|
2722
|
+
<tr><td class="name">level</td><td class="desc">Depth of the group. Zero is the outermost.</td></tr>
|
|
2723
|
+
<tr><td class="name">expanded</td><td class="desc">Whether the group is open. Draw your chevron from this; the row is re-rendered when it changes.</td></tr>
|
|
2724
|
+
<tr><td class="name">leafCount</td><td class="desc">How many records sit beneath the heading, at any depth. Read this when the size is all you need.</td></tr>
|
|
2725
|
+
<tr><td class="name">totals</td><td class="desc">The group's own reductions by column id — whatever <code>total</code> asked for. Unaffected by drawing the row.</td></tr>
|
|
2726
|
+
<tr><td class="name">leaves()</td><td class="desc">The rows beneath the heading, computed <em>when you call it</em>. The members the filters left, in display order, so a rollup agrees with the rows drawn below. Also available on its own as <code>grid.rows.leavesOf(key)</code>.</td></tr>
|
|
2727
|
+
<tr><td class="name">toggle()</td><td class="desc">Expand the group if it is closed, collapse it if it is open.</td></tr>
|
|
2728
|
+
<tr><td class="name">grid, row, element</td><td class="desc">The grid, the group row model, and the element to fill if you would rather write into it than return anything.</td></tr>
|
|
2729
|
+
</tbody>
|
|
2730
|
+
</table>
|
|
2731
|
+
</div>
|
|
2732
|
+
|
|
2733
|
+
<div class="why">
|
|
2734
|
+
<p><strong>A string here is markup, and in <code>fullWidth.render</code> it is text.</strong>
|
|
2735
|
+
That difference is deliberate, and it is the difference between the two features. A
|
|
2736
|
+
<a href="#full-width-rows">full-width row</a> renders one of <em>your data</em> rows, and
|
|
2737
|
+
§8.9 keeps host markup behind <code>allowUnsafeTemplates</code> everywhere a data value
|
|
2738
|
+
reaches the page. A group heading has no data row at all — the grid synthesised it from
|
|
2739
|
+
the grouping — so its string can only be a template you wrote in your own source. That
|
|
2740
|
+
is the same footing the board's <code>cardRenderer</code> already stands on, and the header
|
|
2741
|
+
this exists for (a chevron, a bar) is unwritable without it. If you interpolate a value that
|
|
2742
|
+
came from outside your application, escape it yourself, or build a node and return that
|
|
2743
|
+
instead.</p>
|
|
2744
|
+
<p><strong>Your chevron is yours to wire.</strong> The grid's own expander binds a click
|
|
2745
|
+
handler to the button it built; a string cannot carry a handler, so that chevron would be
|
|
2746
|
+
dead. Any element in your markup carrying <code>data-lat-group-toggle</code> expands or
|
|
2747
|
+
collapses the group it sits in, and <code>toggle()</code> does the same from a node you built
|
|
2748
|
+
yourself.</p>
|
|
2749
|
+
<p><strong><code>leaves()</code> is a function on purpose.</strong> A group is unbounded and
|
|
2750
|
+
the renderer runs as rows are painted. Handing every group an array of its members would cost
|
|
2751
|
+
a hundred thousand rows on a heading nobody looked at. Call it when you need the rows; read
|
|
2752
|
+
<code>leafCount</code> when you need the size.</p>
|
|
2753
|
+
</div>
|
|
2754
|
+
|
|
2755
|
+
<h3 id="group-default-expanded">Which groups start open</h3>
|
|
2756
|
+
<p class="lead-in">
|
|
2757
|
+
<code>groupDefaultExpanded</code> decides the state of a group <em>before anyone has touched
|
|
2758
|
+
it</em>: <code>true</code> (the default) opens them all, <code>false</code> closes them all, a
|
|
2759
|
+
number opens the first N levels, and a predicate answers per group. Once the user or your own
|
|
2760
|
+
code expands or collapses a group, that decision stands — the default is not consulted
|
|
2761
|
+
for it again, so a group cannot spring shut under the user on the next rebuild.
|
|
2762
|
+
</p>
|
|
2763
|
+
|
|
2764
|
+
<div class="example">
|
|
2765
|
+
<p class="example__label">The current sprint open, everything else closed, executed</p>
|
|
2766
|
+
<pre data-run="js" data-expect="Backlog 0/1 8pts closed | Sprint 12 1/2 8pts open" data-covers="config:groupRenderer config:groupDefaultExpanded"><code><span class="kw">const</span> { createHeadlessGrid } = <span class="kw">await</span> import('../packages/core/src/index.js');
|
|
2767
|
+
|
|
2768
|
+
<span class="cmt">// The renderer the grid calls for each group row. Called here directly too,</span>
|
|
2769
|
+
<span class="cmt">// with the params the grid builds, so this block shows its actual output.</span>
|
|
2770
|
+
<span class="kw">const</span> groupRenderer = (p) => {
|
|
2771
|
+
<span class="kw">const</span> rows = p.leaves();
|
|
2772
|
+
<span class="kw">const</span> done = rows.filter((r) => r.data.done).length;
|
|
2773
|
+
<span class="kw">const</span> points = rows.reduce((sum, r) => sum + r.data.points, 0);
|
|
2774
|
+
<span class="kw">return</span> `${p.value} ${done}/${p.leafCount} ${points}pts ${p.expanded ? 'open' : 'closed'}`;
|
|
2775
|
+
};
|
|
2776
|
+
|
|
2777
|
+
<span class="kw">const</span> grid = createHeadlessGrid({
|
|
2778
|
+
rowKey: 'id',
|
|
2779
|
+
columns: [{ field: 'section' }, { field: 'points', type: 'number', total: 'sum' }, { field: 'done' }],
|
|
2780
|
+
rows: [
|
|
2781
|
+
{ id: 1, section: 'Sprint 12', points: 3, done: <span class="kw">true</span> },
|
|
2782
|
+
{ id: 2, section: 'Sprint 12', points: 5, done: <span class="kw">false</span> },
|
|
2783
|
+
{ id: 3, section: 'Backlog', points: 8, done: <span class="kw">false</span> },
|
|
2784
|
+
],
|
|
2785
|
+
groupRenderer,
|
|
2786
|
+
<span class="cmt">// Per group, not merely per depth: only the current sprint starts open.</span>
|
|
2787
|
+
groupDefaultExpanded: (group) => group.value === 'Sprint 12',
|
|
2788
|
+
});
|
|
2789
|
+
grid.columns.group(['section']);
|
|
2790
|
+
|
|
2791
|
+
<span class="kw">const</span> out = [];
|
|
2792
|
+
<span class="kw">for</span> (<span class="kw">let</span> i = 0; i < grid.rows.count(); i++) {
|
|
2793
|
+
<span class="kw">const</span> row = grid.rows.get(i);
|
|
2794
|
+
<span class="kw">if</span> (!row.group) <span class="kw">continue</span>;
|
|
2795
|
+
out.push(groupRenderer({
|
|
2796
|
+
row, key: row.key, column: row.groupColumn, value: row.groupValue,
|
|
2797
|
+
level: row.level, expanded: row.expanded, leafCount: row.leafCount,
|
|
2798
|
+
totals: row.totals, leaves: () => grid.rows.leavesOf(row.key),
|
|
2799
|
+
toggle: () => {}, grid, element: <span class="kw">null</span>,
|
|
2800
|
+
}));
|
|
2801
|
+
}
|
|
2802
|
+
grid.destroy();
|
|
2803
|
+
<span class="kw">return</span> out.join(' | ');</code></pre>
|
|
2804
|
+
</div>
|
|
2805
|
+
|
|
2806
|
+
<p class="lead-in">
|
|
2807
|
+
<code>grid.rows.leavesOf(key)</code> is the same reach on its own, for a breadcrumb, a
|
|
2808
|
+
side panel or a rollup computed away from the row: it returns the leaf rows beneath a group
|
|
2809
|
+
heading, which is what <code>leafCount</code> counts.
|
|
2810
|
+
</p>
|
|
2811
|
+
|
|
2687
2812
|
<h2 id="row-reorder">Row reorder</h2>
|
|
2688
2813
|
<p class="lead-in">
|
|
2689
2814
|
<code>rowReorder: true</code> puts a drag handle in the first visible column and lets a user
|
|
@@ -4094,6 +4219,55 @@ grid.destroy();
|
|
|
4094
4219
|
<span class="kw">return</span> `${a}, ${b}`;</code></pre>
|
|
4095
4220
|
</div>
|
|
4096
4221
|
|
|
4222
|
+
<h2 id="cell-tooltips">Rich cell tooltips</h2>
|
|
4223
|
+
<p class="lead-in">
|
|
4224
|
+
A <code>cell.tooltip</code> string becomes the browser's own <code>title</code>. That is one
|
|
4225
|
+
line of plain text, shown on the browser's schedule, styled by the browser, and unreachable
|
|
4226
|
+
with a keyboard — it cannot show a related record, a small chart, a list of validation
|
|
4227
|
+
errors or an edit history. The object form of <code>cell.tooltip</code> declares a tooltip the
|
|
4228
|
+
grid draws itself instead (BACKLOG-0001204): <code>{ render, mount, unmount }</code>. The
|
|
4229
|
+
plain-text form is unchanged and still produces a <code>title</code>.
|
|
4230
|
+
</p>
|
|
4231
|
+
<p class="lead-in">
|
|
4232
|
+
<code>render(params)</code> may return an element, a <code>{ title, rows, note }</code> spec the
|
|
4233
|
+
grid renders as text, a <code>{ html }</code> wrapper, or a string. <strong>A bare string is
|
|
4234
|
+
always text, never markup.</strong> That is deliberate and is not a style choice: the most
|
|
4235
|
+
natural tooltip anyone writes is <code>render: (p) => p.value</code>, and a value is row data
|
|
4236
|
+
— so if a bare string were markup, a field holding an <code>onerror</code> attribute would
|
|
4237
|
+
execute while the code that rendered it looked harmless. Markup has to be asked for explicitly,
|
|
4238
|
+
in the source, where review can see it; and what goes through <code>{ html }</code> is scrubbed
|
|
4239
|
+
of script the same way <code>allowUnsafeTemplates</code> output is.
|
|
4240
|
+
</p>
|
|
4241
|
+
<p class="lead-in">
|
|
4242
|
+
<code>mount(el, params)</code> and <code>unmount(el)</code> hold live content. The grid core
|
|
4243
|
+
never imports a module, so a sparkline or a KPI tile is mounted by <em>you</em>, inside
|
|
4244
|
+
<code>mount</code>, from a module bundle your page loaded. <code>unmount</code> runs on every
|
|
4245
|
+
close, so nothing is left running behind a hidden tooltip.
|
|
4246
|
+
</p>
|
|
4247
|
+
<p class="lead-in">
|
|
4248
|
+
<code>tooltip: { delay, maxWidth }</code> on the grid carries the defaults. <code>delay</code>
|
|
4249
|
+
is the rest before anything is built — 400ms by default, which is what stops a pointer
|
|
4250
|
+
sweeping across the grid from mounting a chart per cell — and <code>maxWidth</code> caps
|
|
4251
|
+
the width (a number is pixels, a string is used as written). Neither switches tooltips on: a
|
|
4252
|
+
column with no <code>cell.tooltip</code> has none.
|
|
4253
|
+
</p>
|
|
4254
|
+
<p class="lead-in">
|
|
4255
|
+
<strong>Keyboard and assistive technology.</strong> Focusing a cell shows the same tooltip after
|
|
4256
|
+
the same delay, and the cell carries <code>aria-describedby</code> pointing at it, so the
|
|
4257
|
+
content is announced rather than merely drawn. Any <code>aria-describedby</code> the cell
|
|
4258
|
+
already had — a validation message, for instance — is preserved and restored, not
|
|
4259
|
+
replaced. The tooltip is hoverable and stays open while the pointer rests on it, and Escape
|
|
4260
|
+
dismisses it without moving the pointer (WCAG 2.2 AA, 1.4.13). Escape is consumed only while a
|
|
4261
|
+
tooltip is open, so an editor, a menu or a maximised grid still sees it otherwise.
|
|
4262
|
+
</p>
|
|
4263
|
+
<p class="lead-in">
|
|
4264
|
+
<strong>Pooled rows.</strong> The tooltip closes on scroll, and its content is resolved from the
|
|
4265
|
+
DOM at the moment it opens rather than when the pointer arrived. Both follow from the same
|
|
4266
|
+
fact: rows and cells are recycled as the grid scrolls, so a bubble left open would be anchored
|
|
4267
|
+
to a node that has since been handed to a different row. It can therefore never show one row's
|
|
4268
|
+
content over another's.
|
|
4269
|
+
</p>
|
|
4270
|
+
|
|
4097
4271
|
<h2 id="scrollbars">Always-visible scrollbars</h2>
|
|
4098
4272
|
<p class="lead-in">
|
|
4099
4273
|
Native scrollbars are overlay bars on most platforms now: they fade away when the pointer is
|
|
@@ -7582,6 +7756,8 @@ el.grid.sort.set([{ col: 'charge', dir: 'desc' }]);</code></pre>
|
|
|
7582
7756
|
<tr><td class="name">cell:conflict</td><td class="desc">The write was accepted but the server row had moved underneath it. Last-write-wins with the divergence surfaced: your value stands and serverRow carries the server's truth.</td></tr>
|
|
7583
7757
|
<tr><td class="name">cell:contextmenu</td><td class="desc">Right-click on a cell.</td></tr>
|
|
7584
7758
|
<tr><td class="name">cell:dblclicked</td><td class="desc">A cell was double-clicked. Carries the row, column, value and text.</td></tr>
|
|
7759
|
+
<tr><td class="name">cell:mouseover</td><td class="desc">The pointer entered a cell. Fires once per cell, carries what cell:clicked carries plus the cell element as target, and is delegated on the viewport so it stays correct over pooled rows.</td></tr>
|
|
7760
|
+
<tr><td class="name">cell:mouseout</td><td class="desc">The pointer left a cell. Fires once per cell, including when the pointer left the grid; moving to the next cell fires this first, then cell:mouseover.</td></tr>
|
|
7585
7761
|
<tr><td class="name">cell:edit:end</td><td class="desc">It closed: committed or cancelled.</td></tr>
|
|
7586
7762
|
<tr><td class="name">cell:edit:start</td><td class="desc">An edit session opened.</td></tr>
|
|
7587
7763
|
<tr><td class="name">cell:pending</td><td class="desc">Applied optimistically, not yet durable. Only with edit.commit.</td></tr>
|
|
@@ -7901,7 +8077,7 @@ grid.licence.state(); <span class="cmt">// 'licensed' | 'localhost' | 'trial'<
|
|
|
7901
8077
|
|
|
7902
8078
|
<footer>
|
|
7903
8079
|
<p>
|
|
7904
|
-
Lattice Grid 1.
|
|
8080
|
+
Lattice Grid 1.59.0 · Copyright © 2026 TOCLOCO Inc. All rights reserved.
|
|
7905
8081
|
Written against the shipped source. Where this guide and the code disagree, the code wins,
|
|
7906
8082
|
please <a href="https://www.latticegrid.dev">tell us</a>.
|
|
7907
8083
|
</p>
|