@toclocoinc/lattice-grid 1.13.1 → 1.15.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.
@@ -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.13.0</p>
440
+ <p class="rail__sub">Developer guide · v1.15.0</p>
441
441
  <nav>
442
442
  <div class="rail__group">
443
443
  <span class="rail__label">Start here</span>
@@ -884,6 +884,14 @@ createGrid(element, { direction: 'rtl' }); <span class="cmt">// or say so out
884
884
  <code>.events</code> namespaces: sitting on top of a real Lattice grid underneath.
885
885
  Swap the import and, for the surface below, the calling code does not change.
886
886
  </p>
887
+ <p class="lead-in">
888
+ The wrapper shares the core the page already loads rather than carrying its own,
889
+ so load <code>@toclocoinc/lattice-grid</code> alongside it: a bundler wires the shared
890
+ import automatically (it dedupes against the core your app already imports), and a
891
+ plain <code>&lt;script src&gt;</code> page loads the global build first. The pay-off is
892
+ that a licence set on that one core applies to these grids too, and the module is a
893
+ few kilobytes of translation rather than a second copy of the grid.
894
+ </p>
887
895
 
888
896
  <div class="example">
889
897
  <p class="example__label">A drop-in constructor</p>
@@ -4813,12 +4821,22 @@ createStat({
4813
4821
  grid,
4814
4822
  container: tile,
4815
4823
  title: 'Total capacity',
4824
+ <span class="cmt">// A leading icon beside the title and value. Same three forms as a menu</span>
4825
+ <span class="cmt">// item: a sprite name, a character/emoji, or your own markup.</span>
4826
+ icon: '&lt;i class="fa-light fa-gauge-high"&gt;&lt;/i&gt;',
4816
4827
  value: { of: 'capacity', fn: 'sum' },
4817
4828
  baseline: (g) =&gt; lastMonth,
4818
4829
  bands: { good: 5000, warn: 3000, direction: 'up' },
4819
4830
  interval: (v, g) =&gt; g.statistics.interval('capacity'),
4820
4831
  });</code></pre>
4821
4832
  </div>
4833
+ <p class="lead-in">
4834
+ <code>icon</code> is optional and lays out to the side without disturbing the change indicator,
4835
+ threshold bands or confidence interval; omit it for the plain tile. It uses the same
4836
+ <a href="#custom-menu">icon contract</a> as a menu item — a sprite name, a single character or
4837
+ emoji, or author-supplied markup such as a Font Awesome glyph or an
4838
+ <code>&lt;img&gt;</code>.
4839
+ </p>
4822
4840
  <div class="why">
4823
4841
  <p><strong><code>bands</code> and <code>goodWhen</code> judge different things.</strong>
4824
4842
  <code>goodWhen</code> says whether a rise is good news, and colours the change indicator.
@@ -4919,6 +4937,33 @@ r.ok ? r.value : r.error; <span class="cmt">// 42</span></code></pre>
4919
4937
  <code>{ key, colId, value, row, data, column, index, grid }</code>. <code>data</code> is your
4920
4938
  original row object, so an item can reach fields the grid never displayed.
4921
4939
  </p>
4940
+ <div class="example">
4941
+ <p class="example__label">An item with your own icon</p>
4942
+ <pre><code>createGrid(el, {
4943
+ contextMenu: (params, defaults) =&gt; [
4944
+ ...defaults,
4945
+ { separator: <span class="kw">true</span> },
4946
+ <span class="cmt">// A registered sprite name — the built-in items use these.</span>
4947
+ { name: 'Download', icon: 'download', action: () =&gt; save(params.data) },
4948
+ <span class="cmt">// A single character or emoji, rendered as text.</span>
4949
+ { name: 'Star', icon: '★', action: () =&gt; star(params.data) },
4950
+ <span class="cmt">// Your own markup — a Font Awesome glyph, an inline SVG, an image.</span>
4951
+ <span class="cmt">// It is inserted into the icon slot as an element, at the same trust</span>
4952
+ <span class="cmt">// as the item's action, and never into the label.</span>
4953
+ { name: 'Export', icon: '&lt;i class="fa-light fa-file-export"&gt;&lt;/i&gt;', action: exportRow },
4954
+ ],
4955
+ });</code></pre>
4956
+ </div>
4957
+ <p class="lead-in">
4958
+ A <code>MenuItem</code>'s <code>icon</code> accepts three forms, told apart automatically so
4959
+ existing definitions keep working: a registered sprite <strong>name</strong>
4960
+ (<code>'download'</code>), a single <strong>character</strong> or emoji (<code>'↑'</code>),
4961
+ or author-supplied element <strong>markup</strong>
4962
+ (<code>'&lt;i class="fa-light fa-download"&gt;&lt;/i&gt;'</code>). Markup is rendered as an
4963
+ element rather than shown as text — the misbehaviour it replaces — and is written only into
4964
+ the icon slot, so a definition can never inject markup into the label. It is trusted like the
4965
+ item's <code>action</code>: a menu definition is code you wrote, not user data.
4966
+ </p>
4922
4967
  <div class="why">
4923
4968
  <p><strong>Handed the defaults, rather than replacing them.</strong> A builder that had to
4924
4969
  return every item in order to append one would be written once as a copy of the built-ins and
@@ -5383,6 +5428,89 @@ grid.state.apply(savedView.state);
5383
5428
  to CSV takes about 100ms.</p>
5384
5429
  </div>
5385
5430
 
5431
+ <h2 id="less-common">Options and calls you may not have met</h2>
5432
+ <p class="lead-in">
5433
+ The rest of the surface, in one place. Each of these is documented in full in the
5434
+ <a href="API.html">reference</a>; this is here so that reading the guide end to end leaves
5435
+ nothing you have never heard of, which is the difference between a guide and a tour of the
5436
+ parts we found most interesting.
5437
+ </p>
5438
+ <h3>Configuration</h3>
5439
+ <div class="table-wrap">
5440
+ <table>
5441
+ <thead><tr><th>Name</th><th>What it does</th></tr></thead>
5442
+ <tbody>
5443
+ <tr><td class="name">autoHeight</td><td class="desc">autoHeight.</td></tr>
5444
+ <tr><td class="name">bucketFn</td><td class="desc">Replace the built-in bucketing entirely. (optional)</td></tr>
5445
+ <tr><td class="name">coalesceMs</td><td class="desc">(optional)</td></tr>
5446
+ <tr><td class="name">columnGroups</td><td class="desc">Header grouping declared separately from the columns.</td></tr>
5447
+ <tr><td class="name">columnPresets</td><td class="desc">Named bundles applied with preset: 'money'.</td></tr>
5448
+ <tr><td class="name">columnVirtualisationAbove</td><td class="desc">Column count above which columns virtualise too.</td></tr>
5449
+ <tr><td class="name">delimiter</td><td class="desc">(optional)</td></tr>
5450
+ <tr><td class="name">enterMovesDown</td><td class="desc">(optional)</td></tr>
5451
+ <tr><td class="name">fillHandle</td><td class="desc">(optional)</td></tr>
5452
+ <tr><td class="name">granularity</td><td class="desc">hour &amp;hellip; year. Chosen from the span when omitted.</td></tr>
5453
+ <tr><td class="name">groupFooter</td><td class="desc">A closing total row per group.</td></tr>
5454
+ <tr><td class="name">groupSelectsChildren</td><td class="desc">(optional)</td></tr>
5455
+ <tr><td class="name">groupSelectsFiltered</td><td class="desc">(optional)</td></tr>
5456
+ <tr><td class="name">headerHeight</td><td class="desc">Per header row.</td></tr>
5457
+ <tr><td class="name">historyBar</td><td class="desc">A standalone undo/redo toolbar with a timeline.</td></tr>
5458
+ <tr><td class="name">hostFilter</td><td class="desc">An application-level predicate composed with the grid's own filters.</td></tr>
5459
+ <tr><td class="name">idleMs</td><td class="desc">Silence after which a peer is shown idle. (optional)</td></tr>
5460
+ <tr><td class="name">indexLimit</td><td class="desc">Cell descriptors held before the oldest are dropped. (optional)</td></tr>
5461
+ <tr><td class="name">lineEnding</td><td class="desc">(optional)</td></tr>
5462
+ <tr><td class="name">lockMs</td><td class="desc">Silence after which a peer's edit claim is disregarded. (optional)</td></tr>
5463
+ <tr><td class="name">maxCachedPages</td><td class="desc">(optional)</td></tr>
5464
+ <tr><td class="name">maxDecimals</td><td class="desc">(optional)</td></tr>
5465
+ <tr><td class="name">me</td><td class="desc">(read-only)</td></tr>
5466
+ <tr><td class="name">minDecimals</td><td class="desc">(optional)</td></tr>
5467
+ <tr><td class="name">overscan</td><td class="desc">Rows rendered beyond the viewport.</td></tr>
5468
+ <tr><td class="name">pageSizes</td><td class="desc">(optional)</td></tr>
5469
+ <tr><td class="name">pinnedBottomRows</td><td class="desc">As pinnedTopRows, held below the body instead. Sits under the grand total when both are shown.</td></tr>
5470
+ <tr><td class="name">pipes</td><td class="desc">Template pipes for cell.template.</td></tr>
5471
+ <tr><td class="name">processCell</td><td class="desc">(optional)</td></tr>
5472
+ <tr><td class="name">promoteToMemoryBelow</td><td class="desc">(optional)</td></tr>
5473
+ <tr><td class="name">quickFilterText</td><td class="desc">Initial quick-filter term. Equivalent to grid.filters.quick(text).</td></tr>
5474
+ <tr><td class="name">quote</td><td class="desc">(optional)</td></tr>
5475
+ <tr><td class="name">removeMs</td><td class="desc">Silence after which a peer is dropped. (optional)</td></tr>
5476
+ <tr><td class="name">showHeader</td><td class="desc">Draw the column headings at all. false removes the row, and removes it from the accessibility tree rather than only from view. Distinct from showColumnFunctions, which keeps the headings and drops only their sort, filter and menu controls.</td></tr>
5477
+ <tr><td class="name">throttleMs</td><td class="desc">Milliseconds between published updates. Throttled, not debounced. (optional)</td></tr>
5478
+ <tr><td class="name">totalFns</td><td class="desc">Custom aggregations, addressable from column.total.</td></tr>
5479
+ <tr><td class="name">undoDepth</td><td class="desc">(optional)</td></tr>
5480
+ </tbody>
5481
+ </table>
5482
+ </div>
5483
+ <h3>Factories and registration</h3>
5484
+ <div class="table-wrap">
5485
+ <table>
5486
+ <thead><tr><th>Name</th><th>What it does</th></tr></thead>
5487
+ <tbody>
5488
+ <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>
5489
+ <tr><td class="name">createDevtools</td><td class="desc">Mount the devtools panel against a grid, including its accessibility checks.</td></tr>
5490
+ <tr><td class="name">createLatticeGridElement</td><td class="desc">Build the element class without registering it, for a custom registry.</td></tr>
5491
+ <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>
5492
+ <tr><td class="name">defineLatticeGrid</td><td class="desc">Register &amp;lt;lattice-grid&amp;gt;, or your own tag name.</td></tr>
5493
+ <tr><td class="name">defineUnit</td><td class="desc">Add one unit to a system, or override one of ours under the same name.</td></tr>
5494
+ <tr><td class="name">registerModules</td><td class="desc">Install optional modules once, for every grid on the page.</td></tr>
5495
+ <tr><td class="name">registerScheme</td><td class="desc">Add a colour scheme, or replace one of ours under the same name.</td></tr>
5496
+ <tr><td class="name">restoreStateWithin</td><td class="desc">Put it back afterwards.</td></tr>
5497
+ </tbody>
5498
+ </table>
5499
+ </div>
5500
+ <h3>Grid methods</h3>
5501
+ <div class="table-wrap">
5502
+ <table>
5503
+ <thead><tr><th>Name</th><th>What it does</th></tr></thead>
5504
+ <tbody>
5505
+ <tr><td class="name">attachRenderer</td><td class="desc">Bind a renderer to a headless grid.</td></tr>
5506
+ <tr><td class="name">emit</td><td class="desc">Emit on the grid's bus, for custom components.</td></tr>
5507
+ <tr><td class="name">getPinnedRows</td><td class="desc">The objects pinned at one edge, as a copy.</td></tr>
5508
+ <tr><td class="name">rendererHost</td><td class="desc">The host object a renderer reads: columns, rows, callbacks. Deliberately a plain bag rather than the grid itself, so a renderer cannot reach into core internals. You need this only when writing a renderer of your own.</td></tr>
5509
+ <tr><td class="name">setAll</td><td class="desc">Write several in one pass. Emits one config:changed for the batch, not one per key.</td></tr>
5510
+ </tbody>
5511
+ </table>
5512
+ </div>
5513
+
5386
5514
  <h2 id="webcomponent-guide">Web component</h2>
5387
5515
  <p class="lead-in">
5388
5516
  <code>&lt;lattice-grid&gt;</code> is the grid as a custom element, shipped as a self-contained
@@ -5451,7 +5579,8 @@ el.grid.sort.set([{ col: 'charge', dir: 'desc' }]);</code></pre>
5451
5579
 
5452
5580
  <h2 id="events-guide">Events</h2>
5453
5581
  <p class="lead-in">
5454
- One bus, forty-odd events. These are the ones most applications actually use; the
5582
+ One bus, 111 events. The table below is the working set, the ones most applications
5583
+ actually reach for; a complete index by area follows it, and the
5455
5584
  <a href="API.html#events">reference</a> lists them all.
5456
5585
  </p>
5457
5586
  <div class="table-wrap">
@@ -5473,6 +5602,196 @@ el.grid.sort.set([{ col: 'charge', dir: 'desc' }]);</code></pre>
5473
5602
  </table>
5474
5603
  </div>
5475
5604
 
5605
+ <h3>Every event, by area</h3>
5606
+ <p class="lead-in">
5607
+ The table above is the working set. This is the whole list, grouped by what it is about,
5608
+ so a question like "can I hear about a column being pinned?" is answerable by scanning
5609
+ rather than by reading the reference end to end.
5610
+ </p>
5611
+ <h4>Lifecycle</h4>
5612
+ <div class="table-wrap">
5613
+ <table>
5614
+ <thead><tr><th>Event</th><th>Fires when</th></tr></thead>
5615
+ <tbody>
5616
+ <tr><td class="name">config:changed</td><td class="desc">A configuration key changed. Emitted after the grid has rebuilt, so a listener reading the grid back sees the change rather than what it replaced.</td></tr>
5617
+ <tr><td class="name">destroy</td><td class="desc">grid.destroy() has run.</td></tr>
5618
+ <tr><td class="name">licence:changed</td><td class="desc">A key was installed, and again when verification settles.</td></tr>
5619
+ <tr><td class="name">ready</td><td class="desc">First layout is complete and the API is safe to drive.</td></tr>
5620
+ <tr><td class="name">render:done</td><td class="desc">The cells are written and stable. Anything decorating them from outside must run after this, the cell layer rewrites each cell's className wholesale and would otherwise erase it.</td></tr>
5621
+ <tr><td class="name">render:first</td><td class="desc">First paint, the number to measure time-to-first-row against.</td></tr>
5622
+ </tbody>
5623
+ </table>
5624
+ </div>
5625
+ <h4>Data</h4>
5626
+ <div class="table-wrap">
5627
+ <table>
5628
+ <thead><tr><th>Event</th><th>Fires when</th></tr></thead>
5629
+ <tbody>
5630
+ <tr><td class="name">model:changed</td><td class="desc">Columns, grouping, pivot or another structural change.</td></tr>
5631
+ <tr><td class="name">row:clicked</td><td class="desc">Emitted alongside the cell event, cell first.</td></tr>
5632
+ <tr><td class="name">row:copied</td><td class="desc">A row was duplicated.</td></tr>
5633
+ <tr><td class="name">row:dblclicked</td><td class="desc">A row was double-clicked. Emitted alongside the cell event, cell first.</td></tr>
5634
+ <tr><td class="name">row:edit:end</td><td class="desc">In row mode an invalid cell blocks the whole commit and the session stays open.</td></tr>
5635
+ <tr><td class="name">row:edit:start</td><td class="desc">Replaces the cell pair when edit.mode is 'row'.</td></tr>
5636
+ <tr><td class="name">row:moved</td><td class="desc">A row was dragged to a new position.</td></tr>
5637
+ <tr><td class="name">row:received</td><td class="desc">A row arrived from a source.</td></tr>
5638
+ <tr><td class="name">row:sent</td><td class="desc">A row was written back to a source.</td></tr>
5639
+ <tr><td class="name">rows:changed</td><td class="desc">The row set changed. See what a change firing promises: identified means the three arrays name the rows that moved, companion marks a duplicate announcement of a change already made with identity, and a firing with neither is a real change of unknown extent.</td></tr>
5640
+ <tr><td class="name">rows:deferred</td><td class="desc">Updates were held rather than applied, because an edit is in flight.</td></tr>
5641
+ <tr><td class="name">rows:paused</td><td class="desc">A live feed was paused; updates queue from here.</td></tr>
5642
+ <tr><td class="name">rows:queued</td><td class="desc">A batched change is waiting for the next frame.</td></tr>
5643
+ <tr><td class="name">rows:resumed</td><td class="desc">The feed resumed and the queue drained.</td></tr>
5644
+ <tr><td class="name">source:error</td><td class="desc">A source or block load failed.</td></tr>
5645
+ <tr><td class="name">stream:chunk</td><td class="desc">A streamed chunk landed.</td></tr>
5646
+ <tr><td class="name">stream:end</td><td class="desc">Streaming finished; promoted means it switched to in-memory.</td></tr>
5647
+ <tr><td class="name">stream:evicted</td><td class="desc">A streaming source dropped rows to stay within its cap.</td></tr>
5648
+ </tbody>
5649
+ </table>
5650
+ </div>
5651
+ <h4>Cells and editing</h4>
5652
+ <div class="table-wrap">
5653
+ <table>
5654
+ <thead><tr><th>Event</th><th>Fires when</th></tr></thead>
5655
+ <tbody>
5656
+ <tr><td class="name">cell:changed</td><td class="desc">A committed edit reached the data. undo distinguishes a rollback.</td></tr>
5657
+ <tr><td class="name">cell:clicked</td><td class="desc">A cell was clicked. Announcement only: nothing is consumed, so editing and selection behave unchanged.</td></tr>
5658
+ <tr><td class="name">cell:confirmed</td><td class="desc">The write reached the server.</td></tr>
5659
+ <tr><td class="name">cell:contextmenu</td><td class="desc">Right-click on a cell.</td></tr>
5660
+ <tr><td class="name">cell:dblclicked</td><td class="desc">A cell was double-clicked. Carries the row, column, value and text.</td></tr>
5661
+ <tr><td class="name">cell:edit:end</td><td class="desc">It closed: committed or cancelled.</td></tr>
5662
+ <tr><td class="name">cell:edit:start</td><td class="desc">An edit session opened.</td></tr>
5663
+ <tr><td class="name">cell:pending</td><td class="desc">Applied optimistically, not yet durable. Only with edit.commit.</td></tr>
5664
+ <tr><td class="name">cell:reverted</td><td class="desc">The write failed. applied: false means a newer edit owned the cell, so nothing was written back.</td></tr>
5665
+ <tr><td class="name">form:closed</td><td class="desc">The row form closed without saving.</td></tr>
5666
+ <tr><td class="name">form:error</td><td class="desc">A commit from the form failed validation or was rejected.</td></tr>
5667
+ <tr><td class="name">form:opened</td><td class="desc">The row form opened.</td></tr>
5668
+ <tr><td class="name">form:saved</td><td class="desc">The row form committed.</td></tr>
5669
+ </tbody>
5670
+ </table>
5671
+ </div>
5672
+ <h4>Columns</h4>
5673
+ <div class="table-wrap">
5674
+ <table>
5675
+ <thead><tr><th>Event</th><th>Fires when</th></tr></thead>
5676
+ <tbody>
5677
+ <tr><td class="name">column:filter:open</td><td class="desc">Header filter popup opened.</td></tr>
5678
+ <tr><td class="name">column:grouped</td><td class="desc">The row-group column list changed.</td></tr>
5679
+ <tr><td class="name">column:menu:open</td><td class="desc">Header menu opened.</td></tr>
5680
+ <tr><td class="name">column:moved</td><td class="desc">Reordered by drag or by API.</td></tr>
5681
+ <tr><td class="name">column:pinned</td><td class="desc">side is 'start', 'end' or null.</td></tr>
5682
+ <tr><td class="name">column:pivoted</td><td class="desc">The pivot configuration changed.</td></tr>
5683
+ <tr><td class="name">column:resized</td><td class="desc">A column width settled after a drag or a keyboard resize.</td></tr>
5684
+ <tr><td class="name">column:visible</td><td class="desc">Columns shown or hidden.</td></tr>
5685
+ <tr><td class="name">columns:changed</td><td class="desc">The column set was replaced or reordered wholesale.</td></tr>
5686
+ <tr><td class="name">columns:tagged</td><td class="desc">A column's tags changed.</td></tr>
5687
+ </tbody>
5688
+ </table>
5689
+ </div>
5690
+ <h4>Query and view</h4>
5691
+ <div class="table-wrap">
5692
+ <table>
5693
+ <thead><tr><th>Event</th><th>Fires when</th></tr></thead>
5694
+ <tbody>
5695
+ <tr><td class="name">facet:computed</td><td class="desc">A header histogram finished counting. Carries the column and the buckets.</td></tr>
5696
+ <tr><td class="name">facet:expanded</td><td class="desc">The facet band was opened or collapsed.</td></tr>
5697
+ <tr><td class="name">facet:failed</td><td class="desc">A distribution could not be computed. Carries the reason.</td></tr>
5698
+ <tr><td class="name">facet:filtered</td><td class="desc">A bucket or a dragged range was applied as a filter.</td></tr>
5699
+ <tr><td class="name">filter:changed</td><td class="desc">The condition tree or the quick filter changed.</td></tr>
5700
+ <tr><td class="name">page:changed</td><td class="desc">Fired after the rows have moved, whether the page changed by API or by the pager control.</td></tr>
5701
+ <tr><td class="name">sort:changed</td><td class="desc">The full sort entry list.</td></tr>
5702
+ <tr><td class="name">state:changed</td><td class="desc">report lists anything a restore could not apply.</td></tr>
5703
+ <tr><td class="name">state:reset</td><td class="desc">The grid was returned to its baseline.</td></tr>
5704
+ <tr><td class="name">timeline:attached</td><td class="desc">A time brush was connected to the grid.</td></tr>
5705
+ <tr><td class="name">timeline:detached</td><td class="desc">The brush was removed.</td></tr>
5706
+ <tr><td class="name">timeline:seek</td><td class="desc">The brush settled on a range.</td></tr>
5707
+ <tr><td class="name">timeline:seeking</td><td class="desc">The brush is being dragged. Throttled.</td></tr>
5708
+ <tr><td class="name">view:applied</td><td class="desc">Emits no storage write: applying a view changes nothing to persist.</td></tr>
5709
+ <tr><td class="name">view:default</td><td class="desc">view is null when the default was cleared.</td></tr>
5710
+ <tr><td class="name">view:removed</td><td class="desc">A saved view was deleted.</td></tr>
5711
+ <tr><td class="name">view:renamed</td><td class="desc">A saved view was renamed.</td></tr>
5712
+ <tr><td class="name">view:saved</td><td class="desc">Carries the one view that moved: enough to POST a single record without diffing two lists.</td></tr>
5713
+ </tbody>
5714
+ </table>
5715
+ </div>
5716
+ <h4>Selection and interaction</h4>
5717
+ <div class="table-wrap">
5718
+ <table>
5719
+ <thead><tr><th>Event</th><th>Fires when</th></tr></thead>
5720
+ <tbody>
5721
+ <tr><td class="name">detail:toggled</td><td class="desc">A master-detail row opened or closed.</td></tr>
5722
+ <tr><td class="name">group:toggled</td><td class="desc">A group row opened or closed.</td></tr>
5723
+ <tr><td class="name">history:applied</td><td class="desc">An action was undone or redone. Distinct from history:changed, which also fires when a new action is pushed onto the stacks and so cannot tell you anything was reversed.</td></tr>
5724
+ <tr><td class="name">history:changed</td><td class="desc">Emitted after the entry is pushed, so a toolbar reading it names the right action. Repainting from sort:changed instead reads the timeline one action behind.</td></tr>
5725
+ <tr><td class="name">range:changed</td><td class="desc">Cell range selection changed.</td></tr>
5726
+ <tr><td class="name">scroll</td><td class="desc">Throttled to the frame.</td></tr>
5727
+ <tr><td class="name">scroll:end</td><td class="desc">Scrolling settled, the moment to trigger deferred work.</td></tr>
5728
+ <tr><td class="name">selection:changed</td><td class="desc">The selected rows changed. Carries the keys.</td></tr>
5729
+ <tr><td class="name">size:changed</td><td class="desc">The viewport resized.</td></tr>
5730
+ </tbody>
5731
+ </table>
5732
+ </div>
5733
+ <h4>Presentation and formatting</h4>
5734
+ <div class="table-wrap">
5735
+ <table>
5736
+ <thead><tr><th>Event</th><th>Fires when</th></tr></thead>
5737
+ <tbody>
5738
+ <tr><td class="name">formatting:changed</td><td class="desc">A conditional formatting rule was added, edited, reordered or restated.</td></tr>
5739
+ <tr><td class="name">highlight:changed</td><td class="desc">A highlight was added or cleared.</td></tr>
5740
+ <tr><td class="name">permissions:changed</td><td class="desc">The context moved and every column re-resolved.</td></tr>
5741
+ <tr><td class="name">presentation:captured</td><td class="desc">A PNG was taken.</td></tr>
5742
+ <tr><td class="name">presentation:changed</td><td class="desc">The options of a running presentation changed.</td></tr>
5743
+ <tr><td class="name">presentation:ended</td><td class="desc">Presentation mode ended. Annotations are cleared here.</td></tr>
5744
+ <tr><td class="name">presentation:scale</td><td class="desc">The presentation zoom changed.</td></tr>
5745
+ <tr><td class="name">presentation:spotlight</td><td class="desc">A region was spotlit or released.</td></tr>
5746
+ <tr><td class="name">presentation:started</td><td class="desc">Presentation mode began. Carries the scale, options, views and starting index. presentation:changed covers a later change to the same options, so a listener can tell entry from adjustment.</td></tr>
5747
+ <tr><td class="name">presentation:view</td><td class="desc">The presentation advanced to another saved view.</td></tr>
5748
+ <tr><td class="name">redaction:changed</td><td class="desc">A column was redacted or restored.</td></tr>
5749
+ </tbody>
5750
+ </table>
5751
+ </div>
5752
+ <h4>Collaboration</h4>
5753
+ <div class="table-wrap">
5754
+ <table>
5755
+ <thead><tr><th>Event</th><th>Fires when</th></tr></thead>
5756
+ <tbody>
5757
+ <tr><td class="name">comment:added</td><td class="desc">A comment was posted.</td></tr>
5758
+ <tr><td class="name">comment:deleted</td><td class="desc">A comment was removed.</td></tr>
5759
+ <tr><td class="name">comment:edited</td><td class="desc">A comment was changed.</td></tr>
5760
+ <tr><td class="name">comment:failed</td><td class="desc">A comment could not be saved. Carries the reason.</td></tr>
5761
+ <tr><td class="name">comment:indexLoaded</td><td class="desc">The comment index finished loading, so indicators can paint.</td></tr>
5762
+ <tr><td class="name">comment:resolved</td><td class="desc">A thread was marked resolved. Carries the cellKey.</td></tr>
5763
+ <tr><td class="name">comment:threadClosed</td><td class="desc">A thread was closed or resolved.</td></tr>
5764
+ <tr><td class="name">comment:threadOpened</td><td class="desc">A thread was opened in the panel.</td></tr>
5765
+ <tr><td class="name">comment:unresolved</td><td class="desc">A resolved thread was reopened. Carries the cellKey.</td></tr>
5766
+ <tr><td class="name">presence:failed</td><td class="desc">A presence transport error. Presence is lossy by design; this is informational.</td></tr>
5767
+ <tr><td class="name">presence:joined</td><td class="desc">A peer was seen for the first time. Carries the peer.</td></tr>
5768
+ <tr><td class="name">presence:left</td><td class="desc">A peer disconnected.</td></tr>
5769
+ <tr><td class="name">presence:lockRefused</td><td class="desc">An edit was refused because a peer holds the cell.</td></tr>
5770
+ <tr><td class="name">presence:published</td><td class="desc">This client's cursor or selection was broadcast.</td></tr>
5771
+ <tr><td class="name">presence:updated</td><td class="desc">A known peer moved or changed selection. Carries the peer.</td></tr>
5772
+ </tbody>
5773
+ </table>
5774
+ </div>
5775
+ <h4>Everything else</h4>
5776
+ <div class="table-wrap">
5777
+ <table>
5778
+ <thead><tr><th>Event</th><th>Fires when</th></tr></thead>
5779
+ <tbody>
5780
+ <tr><td class="name">clipboard:copy</td><td class="desc">A copy left the grid.</td></tr>
5781
+ <tr><td class="name">diff:changed</td><td class="desc">A snapshot was set or cleared.</td></tr>
5782
+ <tr><td class="name">diff:swapped</td><td class="desc">The baseline and the current rows were exchanged.</td></tr>
5783
+ <tr><td class="name">export:progress</td><td class="desc">Progress on a streamed export.</td></tr>
5784
+ <tr><td class="name">header:contextmenu</td><td class="desc">A column heading was right-clicked.</td></tr>
5785
+ <tr><td class="name">toolpanel:focus</td><td class="desc">The documented keyboard shortcut reached the tool panel.</td></tr>
5786
+ <tr><td class="name">tree:loadAborted</td><td class="desc">A child fetch was cancelled, usually because the node collapsed.</td></tr>
5787
+ <tr><td class="name">tree:loadFailed</td><td class="desc">A child fetch failed.</td></tr>
5788
+ <tr><td class="name">tree:loaded</td><td class="desc">Children arrived. Carries the key and the count.</td></tr>
5789
+ <tr><td class="name">tree:loading</td><td class="desc">Children are being fetched for a node.</td></tr>
5790
+ <tr><td class="name">views:changed</td><td class="desc">The whole list, plus what moved and why.</td></tr>
5791
+ </tbody>
5792
+ </table>
5793
+ </div>
5794
+
5476
5795
  <h2 id="licensing">Licensing</h2>
5477
5796
  <p class="lead-in">
5478
5797
  <strong>There is one Lattice Grid and every copy is feature-identical.</strong> No community
package/lattice-grid.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * Lattice Grid 1.13.1, type declarations
2
+ * Lattice Grid 1.15.0, type declarations
3
3
  * Copyright (c) 2026 TOCLOCO Inc. All rights reserved.
4
4
  * https://latticegrid.dev
5
5
  */
@@ -1592,6 +1592,14 @@ export type PermissionPolicy =
1592
1592
 
1593
1593
  export interface MenuItem {
1594
1594
  name?: string;
1595
+ /**
1596
+ * An icon shown in the slot before the label. Three forms, told apart without
1597
+ * a second option so existing definitions keep working: a registered sprite
1598
+ * name (`'download'`), a single character or emoji (`'↑'`), or author-trusted
1599
+ * element markup (`'<i class="fa-light fa-download"></i>'`), which is rendered
1600
+ * as an element rather than shown as text. Markup is inserted into the icon
1601
+ * slot only — never the label — at the same trust as `action`.
1602
+ */
1595
1603
  icon?: string;
1596
1604
  shortcut?: string;
1597
1605
  action?: () => void;
@@ -1987,7 +1995,7 @@ export interface ColumnDistribution {
1987
1995
  export type EventName =
1988
1996
  /* Lifecycle */
1989
1997
  | 'ready' | 'destroy' | 'render:first' | 'render:done' | 'config:changed'
1990
- | 'licence:changed' | 'environment:changed'
1998
+ | 'licence:changed'
1991
1999
  /* Data */
1992
2000
  | 'model:changed' | 'rows:changed' | 'rows:queued' | 'rows:deferred'
1993
2001
  | 'rows:paused' | 'rows:resumed' | 'row:received' | 'row:sent' | 'row:copied'
@@ -2017,12 +2025,15 @@ export type EventName =
2017
2025
  | 'view:renamed' | 'view:default'
2018
2026
  /* Formatting and presentation */
2019
2027
  | 'formatting:changed' | 'redaction:changed' | 'permissions:changed'
2020
- | 'presentation:changed' | 'presentation:ended' | 'presentation:view'
2028
+ | 'presentation:changed' | 'presentation:started' | 'presentation:ended'
2029
+ | 'presentation:view'
2021
2030
  | 'presentation:scale' | 'presentation:spotlight' | 'presentation:captured'
2022
2031
  /* Collaboration */
2023
2032
  | 'comment:added' | 'comment:edited' | 'comment:deleted' | 'comment:failed'
2033
+ | 'comment:resolved' | 'comment:unresolved'
2024
2034
  | 'comment:threadOpened' | 'comment:threadClosed' | 'comment:indexLoaded'
2025
- | 'presence:published' | 'presence:left' | 'presence:failed' | 'presence:lockRefused'
2035
+ | 'presence:published' | 'presence:joined' | 'presence:updated' | 'presence:left'
2036
+ | 'presence:failed' | 'presence:lockRefused'
2026
2037
  /* Comparison and time */
2027
2038
  | 'diff:changed' | 'diff:swapped'
2028
2039
  | 'timeline:attached' | 'timeline:detached' | 'timeline:seek' | 'timeline:seeking'
@@ -3190,6 +3201,15 @@ export interface StatConfig extends StatValueSpec {
3190
3201
  /** An element, or a CSS selector resolved against the grid's document. */
3191
3202
  container: HTMLElement | string;
3192
3203
  title?: string;
3204
+ /**
3205
+ * An optional leading icon beside the title and value, using the same value
3206
+ * contract as a menu item: a registered sprite name, a single character or
3207
+ * emoji, or author-trusted element markup (`'<i class="fa-light fa-bolt">
3208
+ * </i>'`, an `<img>`). It lays out to the side without disturbing the change
3209
+ * indicator, threshold bands or confidence interval; omit it for the plain
3210
+ * tile layout.
3211
+ */
3212
+ icon?: string;
3193
3213
  /** A literal value, a spec to reduce, or a function of the grid. */
3194
3214
  value?: unknown | StatValueSpec | ((grid: Grid) => unknown);
3195
3215
  /** Text under the value, or a function of it. */
@@ -3257,7 +3277,18 @@ export const NO_CAPABILITIES: Readonly<Required<PushdownCapabilities>>;
3257
3277
  * Resolve what an adapter says it can do against the defaults, giving a
3258
3278
  * complete capability set with no absent keys to test for.
3259
3279
  */
3260
- export function capabilitiesOf(declared?: PushdownCapabilities): Required<PushdownCapabilities>;
3280
+ /**
3281
+ * A capability set with every key present, as `capabilitiesOf` returns it.
3282
+ *
3283
+ * `operators` becomes a `Set` rather than staying an array: it is tested once
3284
+ * per condition per query, and membership on an array is a scan. The declared
3285
+ * form and the resolved form differ, which is why this is its own type.
3286
+ */
3287
+ export type ResolvedCapabilities = Omit<Required<PushdownCapabilities>, 'operators'> & {
3288
+ operators: ReadonlySet<string>;
3289
+ };
3290
+
3291
+ export function capabilitiesOf(declared?: PushdownCapabilities): ResolvedCapabilities;
3261
3292
 
3262
3293
  /**
3263
3294
  * Split a filter tree into the half the engine takes and the half left over.
@@ -3271,7 +3302,7 @@ export function capabilitiesOf(declared?: PushdownCapabilities): Required<Pushdo
3271
3302
  */
3272
3303
  export function splitFilters(
3273
3304
  filters: object | null,
3274
- caps: Required<PushdownCapabilities>,
3305
+ caps: ResolvedCapabilities,
3275
3306
  ): { pushed: object | null; residual: object | null };
3276
3307
 
3277
3308
  /**
@@ -3286,7 +3317,7 @@ export function splitFilters(
3286
3317
  */
3287
3318
  export function planQuery(
3288
3319
  request: RemoteRequest,
3289
- caps: Required<PushdownCapabilities>,
3320
+ caps: ResolvedCapabilities,
3290
3321
  ): PushdownPlan;
3291
3322
 
3292
3323
  /**
@@ -3371,6 +3402,15 @@ export function dfqlAdapter(options: {
3371
3402
 
3372
3403
  export function createGrid(element: HTMLElement, config?: GridConfig): Grid;
3373
3404
  export function createHeadlessGrid(config?: GridConfig): Grid;
3405
+
3406
+ /**
3407
+ * The library version, e.g. `'1.13.1'`.
3408
+ *
3409
+ * The same value `grid.getVersion()` returns, available without a grid. The
3410
+ * method was declared and the module-level function was not, though the
3411
+ * reference documents both.
3412
+ */
3413
+ export function getVersion(): string;
3374
3414
  export function registerModules(modules: GridModule[], opts?: { licence?: string }): void;
3375
3415
  export function setLicence(licence: string): LicenceInfo;
3376
3416
 
@@ -3801,7 +3841,16 @@ declare module 'lattice-grid/modules/htmx' {
3801
3841
  }
3802
3842
 
3803
3843
  declare module 'lattice-grid/modules/dhtmlx-compat' {
3804
- /** A dhtmlx Grid-shaped API over Lattice, for migrating a piece at a time. */
3844
+ /**
3845
+ * A dhtmlx Grid-shaped API over Lattice, for migrating a piece at a time.
3846
+ *
3847
+ * The module shares the page's one core rather than bundling its own: the
3848
+ * grid it builds comes from the `lattice-grid` package the app already loads
3849
+ * (or the `LatticeGrid` global a script tag publishes), so a licence set on
3850
+ * that core applies to these grids too. Load the core alongside this module —
3851
+ * a bundler wires the peer import for you; a `<script src>` page loads the
3852
+ * global build first.
3853
+ */
3805
3854
  export class Grid {
3806
3855
  constructor(container: Element | string, config?: object);
3807
3856
  }