File size: 42,552 Bytes
9375fc1
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
<!DOCTYPE html><html class="default" lang="en" data-base=".."><head><meta charset="utf-8"/><meta http-equiv="x-ua-compatible" content="IE=edge"/><title>docs/components/list | react-declarative</title><meta name="description" content="Documentation for react-declarative"/><meta name="viewport" content="width=device-width, initial-scale=1"/><link rel="stylesheet" href="../assets/style.css"/><link rel="stylesheet" href="../assets/highlight.css"/><script defer src="../assets/main.js"></script><script async src="../assets/icons.js" id="tsd-icons-script"></script><script async src="../assets/search.js" id="tsd-search-script"></script><script async src="../assets/navigation.js" id="tsd-nav-script"></script><script async src="../assets/hierarchy.js" id="tsd-hierarchy-script"></script></head><body><script>document.documentElement.dataset.theme = localStorage.getItem("tsd-theme") || "os";document.body.style.display="none";setTimeout(() => app?app.showPage():document.body.style.removeProperty("display"),500)</script><header class="tsd-page-toolbar"><div class="tsd-toolbar-contents container"><div class="table-cell" id="tsd-search"><div class="field"><label for="tsd-search-field" class="tsd-widget tsd-toolbar-icon search no-caption"><svg width="16" height="16" viewBox="0 0 16 16" fill="none" aria-hidden="true"><use href="../assets/icons.svg#icon-search"></use></svg></label><input type="text" id="tsd-search-field" aria-label="Search"/></div><div class="field"><div id="tsd-toolbar-links"></div></div><ul class="results"><li class="state loading">Preparing search index...</li><li class="state failure">The search index is not available</li></ul><a href="../index.html" class="title">react-declarative</a></div><div class="table-cell" id="tsd-widgets"><a href="#" class="tsd-widget tsd-toolbar-icon menu no-caption" data-toggle="menu" aria-label="Menu"><svg width="16" height="16" viewBox="0 0 16 16" fill="none" aria-hidden="true"><use href="../assets/icons.svg#icon-menu"></use></svg></a></div></div></header><div class="container container-main"><div class="col-content"><div class="tsd-page-title"><ul class="tsd-breadcrumb"><li><a href="../modules.html">react-declarative</a></li><li><a href="docs_components_list.html">docs/components/list</a></li></ul></div><div class="tsd-panel tsd-typography"><a id="list-component-paginated-and-filterable-data-grid" class="tsd-anchor"></a><h1 class="tsd-anchor-link">List component: paginated and filterable data grid<a href="#list-component-paginated-and-filterable-data-grid" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../assets/icons.svg#icon-anchor"></use></svg></a></h1><p><code>&lt;List /&gt;</code> (and its typed sibling <code>&lt;ListTyped /&gt;</code>) is react-declarative's data grid. You configure columns with <code>IColumn[]</code>, define filter fields with the same <code>TypedField[]</code> schema used by <code>&lt;One /&gt;</code>, attach bulk actions and per-row menus, and hand the component a <code>handler</code> function that fetches a page of rows. The grid handles pagination, sorting, chip filters, free-text search, and mobile layout adaptation automatically.</p>
<a id="installation" class="tsd-anchor"></a><h2 class="tsd-anchor-link">Installation<a href="#installation" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../assets/icons.svg#icon-anchor"></use></svg></a></h2><pre><code class="bash"><span class="hl-5">npm</span><span class="hl-1"> </span><span class="hl-3">install</span><span class="hl-1"> </span><span class="hl-4">--save</span><span class="hl-1"> </span><span class="hl-3">react-declarative</span><span class="hl-1"> </span><span class="hl-3">tss-react</span><span class="hl-1"> </span><span class="hl-3">@mui/material</span><span class="hl-1"> </span><span class="hl-3">@emotion/react</span><span class="hl-1"> </span><span class="hl-3">@emotion/styled</span>
</code><button type="button">Copy</button></pre>

<a id="minimal-working-example" class="tsd-anchor"></a><h2 class="tsd-anchor-link">Minimal working example<a href="#minimal-working-example" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../assets/icons.svg#icon-anchor"></use></svg></a></h2><pre><code class="tsx"><span class="hl-0">import</span><span class="hl-1"> {</span><br/><span class="hl-1">  </span><span class="hl-2">ListTyped</span><span class="hl-1">,</span><br/><span class="hl-1">  </span><span class="hl-2">TypedField</span><span class="hl-1">,</span><br/><span class="hl-1">  </span><span class="hl-2">FieldType</span><span class="hl-1">,</span><br/><span class="hl-1">  </span><span class="hl-2">IColumn</span><span class="hl-1">,</span><br/><span class="hl-1">  </span><span class="hl-2">ColumnType</span><span class="hl-1">,</span><br/><span class="hl-1">  </span><span class="hl-2">IListAction</span><span class="hl-1">,</span><br/><span class="hl-1">  </span><span class="hl-2">ActionType</span><span class="hl-1">,</span><br/><span class="hl-1">  </span><span class="hl-2">IListChip</span><span class="hl-1">,</span><br/><span class="hl-1">  </span><span class="hl-2">IListRowAction</span><span class="hl-1">,</span><br/><span class="hl-1">} </span><span class="hl-0">from</span><span class="hl-1"> </span><span class="hl-3">&#39;react-declarative&#39;</span><span class="hl-1">;</span><br/><br/><span class="hl-4">interface</span><span class="hl-1"> </span><span class="hl-7">IFilterData</span><span class="hl-1"> {</span><br/><span class="hl-1">  </span><span class="hl-2">firstName</span><span class="hl-1">: </span><span class="hl-7">string</span><span class="hl-1">;</span><br/><span class="hl-1">  </span><span class="hl-2">lastName</span><span class="hl-1">: </span><span class="hl-7">string</span><span class="hl-1">;</span><br/><span class="hl-1">}</span><br/><br/><span class="hl-4">interface</span><span class="hl-1"> </span><span class="hl-7">IRowData</span><span class="hl-1"> {</span><br/><span class="hl-1">  </span><span class="hl-2">id</span><span class="hl-1">: </span><span class="hl-7">string</span><span class="hl-1">;</span><br/><span class="hl-1">  </span><span class="hl-2">firstName</span><span class="hl-1">: </span><span class="hl-7">string</span><span class="hl-1">;</span><br/><span class="hl-1">  </span><span class="hl-2">lastName</span><span class="hl-1">: </span><span class="hl-7">string</span><span class="hl-1">;</span><br/><span class="hl-1">  </span><span class="hl-2">chip1_enabled</span><span class="hl-1">: </span><span class="hl-7">boolean</span><span class="hl-1">;</span><br/><span class="hl-1">}</span><br/><br/><span class="hl-4">const</span><span class="hl-1"> </span><span class="hl-10">filters</span><span class="hl-1">: </span><span class="hl-7">TypedField</span><span class="hl-1">&lt;</span><span class="hl-7">IFilterData</span><span class="hl-1">&gt;[] = [</span><br/><span class="hl-1">  {</span><br/><span class="hl-1">    </span><span class="hl-2">type:</span><span class="hl-1"> </span><span class="hl-2">FieldType</span><span class="hl-1">.</span><span class="hl-2">Text</span><span class="hl-1">,</span><br/><span class="hl-1">    </span><span class="hl-2">name:</span><span class="hl-1"> </span><span class="hl-3">&#39;firstName&#39;</span><span class="hl-1">,</span><br/><span class="hl-1">    </span><span class="hl-2">title:</span><span class="hl-1"> </span><span class="hl-3">&#39;First name&#39;</span><span class="hl-1">,</span><br/><span class="hl-1">  },</span><br/><span class="hl-1">  {</span><br/><span class="hl-1">    </span><span class="hl-2">type:</span><span class="hl-1"> </span><span class="hl-2">FieldType</span><span class="hl-1">.</span><span class="hl-2">Text</span><span class="hl-1">,</span><br/><span class="hl-1">    </span><span class="hl-2">name:</span><span class="hl-1"> </span><span class="hl-3">&#39;lastName&#39;</span><span class="hl-1">,</span><br/><span class="hl-1">    </span><span class="hl-2">title:</span><span class="hl-1"> </span><span class="hl-3">&#39;Last name&#39;</span><span class="hl-1">,</span><br/><span class="hl-1">  },</span><br/><span class="hl-1">];</span><br/><br/><span class="hl-4">const</span><span class="hl-1"> </span><span class="hl-10">columns</span><span class="hl-1">: </span><span class="hl-7">IColumn</span><span class="hl-1">&lt;</span><span class="hl-7">IFilterData</span><span class="hl-1">, </span><span class="hl-7">IRowData</span><span class="hl-1">&gt;[] = [</span><br/><span class="hl-1">  {</span><br/><span class="hl-1">    </span><span class="hl-2">type:</span><span class="hl-1"> </span><span class="hl-2">ColumnType</span><span class="hl-1">.</span><span class="hl-2">Text</span><span class="hl-1">,</span><br/><span class="hl-1">    </span><span class="hl-2">field:</span><span class="hl-1"> </span><span class="hl-3">&#39;id&#39;</span><span class="hl-1">,</span><br/><span class="hl-1">    </span><span class="hl-2">headerName:</span><span class="hl-1"> </span><span class="hl-3">&#39;ID&#39;</span><span class="hl-1">,</span><br/><span class="hl-1">    </span><span class="hl-5">width</span><span class="hl-2">:</span><span class="hl-1"> (</span><span class="hl-2">fullWidth</span><span class="hl-1">) </span><span class="hl-4">=&gt;</span><span class="hl-1"> </span><span class="hl-2">Math</span><span class="hl-1">.</span><span class="hl-5">max</span><span class="hl-1">(</span><span class="hl-2">fullWidth</span><span class="hl-1"> - </span><span class="hl-16">650</span><span class="hl-1">, </span><span class="hl-16">200</span><span class="hl-1">),</span><br/><span class="hl-1">  },</span><br/><span class="hl-1">  {</span><br/><span class="hl-1">    </span><span class="hl-2">type:</span><span class="hl-1"> </span><span class="hl-2">ColumnType</span><span class="hl-1">.</span><span class="hl-2">Text</span><span class="hl-1">,</span><br/><span class="hl-1">    </span><span class="hl-2">field:</span><span class="hl-1"> </span><span class="hl-3">&#39;firstName&#39;</span><span class="hl-1">,</span><br/><span class="hl-1">    </span><span class="hl-2">headerName:</span><span class="hl-1"> </span><span class="hl-3">&#39;First name&#39;</span><span class="hl-1">,</span><br/><span class="hl-1">    </span><span class="hl-2">width:</span><span class="hl-1"> </span><span class="hl-3">&#39;200px&#39;</span><span class="hl-1">,</span><br/><span class="hl-1">    </span><span class="hl-2">sortable:</span><span class="hl-1"> </span><span class="hl-4">true</span><span class="hl-1">,</span><br/><span class="hl-1">  },</span><br/><span class="hl-1">  {</span><br/><span class="hl-1">    </span><span class="hl-2">type:</span><span class="hl-1"> </span><span class="hl-2">ColumnType</span><span class="hl-1">.</span><span class="hl-2">Text</span><span class="hl-1">,</span><br/><span class="hl-1">    </span><span class="hl-2">field:</span><span class="hl-1"> </span><span class="hl-3">&#39;lastName&#39;</span><span class="hl-1">,</span><br/><span class="hl-1">    </span><span class="hl-2">headerName:</span><span class="hl-1"> </span><span class="hl-3">&#39;Last name&#39;</span><span class="hl-1">,</span><br/><span class="hl-1">    </span><span class="hl-2">width:</span><span class="hl-1"> </span><span class="hl-3">&#39;200px&#39;</span><span class="hl-1">,</span><br/><span class="hl-1">    </span><span class="hl-2">sortable:</span><span class="hl-1"> </span><span class="hl-4">true</span><span class="hl-1">,</span><br/><span class="hl-1">  },</span><br/><span class="hl-1">];</span><br/><br/><span class="hl-4">const</span><span class="hl-1"> </span><span class="hl-10">actions</span><span class="hl-1">: </span><span class="hl-7">IListAction</span><span class="hl-1">&lt;</span><span class="hl-7">IRowData</span><span class="hl-1">&gt;[] = [</span><br/><span class="hl-1">  {</span><br/><span class="hl-1">    </span><span class="hl-2">type:</span><span class="hl-1"> </span><span class="hl-2">ActionType</span><span class="hl-1">.</span><span class="hl-2">Add</span><span class="hl-1">,</span><br/><span class="hl-1">    </span><span class="hl-2">label:</span><span class="hl-1"> </span><span class="hl-3">&#39;Create item&#39;</span><span class="hl-1">,</span><br/><span class="hl-1">  },</span><br/><span class="hl-1">];</span><br/><br/><span class="hl-4">const</span><span class="hl-1"> </span><span class="hl-10">chips</span><span class="hl-1">: </span><span class="hl-7">IListChip</span><span class="hl-1">&lt;</span><span class="hl-7">IRowData</span><span class="hl-1">&gt;[] = [</span><br/><span class="hl-1">  {</span><br/><span class="hl-1">    </span><span class="hl-2">label:</span><span class="hl-1"> </span><span class="hl-3">&#39;Chip 1 enabled&#39;</span><span class="hl-1">,</span><br/><span class="hl-1">    </span><span class="hl-2">name:</span><span class="hl-1"> </span><span class="hl-3">&#39;chip1_enabled&#39;</span><span class="hl-1">,</span><br/><span class="hl-1">    </span><span class="hl-2">color:</span><span class="hl-1"> </span><span class="hl-3">&#39;#4caf50&#39;</span><span class="hl-1">,</span><br/><span class="hl-1">  },</span><br/><span class="hl-1">];</span><br/><br/><span class="hl-4">const</span><span class="hl-1"> </span><span class="hl-10">rowActions</span><span class="hl-1">: </span><span class="hl-7">IListRowAction</span><span class="hl-1">[] = [</span><br/><span class="hl-1">  {</span><br/><span class="hl-1">    </span><span class="hl-2">label:</span><span class="hl-1"> </span><span class="hl-3">&#39;Edit&#39;</span><span class="hl-1">,</span><br/><span class="hl-1">    </span><span class="hl-2">action:</span><span class="hl-1"> </span><span class="hl-3">&#39;edit-action&#39;</span><span class="hl-1">,</span><br/><span class="hl-1">    </span><span class="hl-5">isVisible</span><span class="hl-2">:</span><span class="hl-1"> ({ </span><span class="hl-2">chip1_enabled</span><span class="hl-1"> }) </span><span class="hl-4">=&gt;</span><span class="hl-1"> </span><span class="hl-2">chip1_enabled</span><span class="hl-1">,</span><br/><span class="hl-1">  },</span><br/><span class="hl-1">];</span><br/><br/><span class="hl-0">export</span><span class="hl-1"> </span><span class="hl-4">const</span><span class="hl-1"> </span><span class="hl-5">PeoplePage</span><span class="hl-1"> = () </span><span class="hl-4">=&gt;</span><span class="hl-1"> (</span><br/><span class="hl-1">  </span><span class="hl-6">&lt;</span><span class="hl-7">ListTyped</span><span class="hl-1">&lt;</span><span class="hl-7">IFilterData</span><span class="hl-1">, </span><span class="hl-7">IRowData</span><span class="hl-1">&gt;</span><br/><span class="hl-1">    </span><span class="hl-8">withMobile</span><br/><span class="hl-1">    </span><span class="hl-8">withSearch</span><br/><span class="hl-1">    </span><span class="hl-8">withArrowPagination</span><br/><span class="hl-1">    </span><span class="hl-8">filters</span><span class="hl-1">=</span><span class="hl-4">{</span><span class="hl-2">filters</span><span class="hl-4">}</span><br/><span class="hl-1">    </span><span class="hl-8">columns</span><span class="hl-1">=</span><span class="hl-4">{</span><span class="hl-2">columns</span><span class="hl-4">}</span><br/><span class="hl-1">    </span><span class="hl-8">actions</span><span class="hl-1">=</span><span class="hl-4">{</span><span class="hl-2">actions</span><span class="hl-4">}</span><br/><span class="hl-1">    </span><span class="hl-8">chips</span><span class="hl-1">=</span><span class="hl-4">{</span><span class="hl-2">chips</span><span class="hl-4">}</span><br/><span class="hl-1">    </span><span class="hl-8">rowActions</span><span class="hl-1">=</span><span class="hl-4">{</span><span class="hl-2">rowActions</span><span class="hl-4">}</span><br/><span class="hl-1">    </span><span class="hl-8">handler</span><span class="hl-1">=</span><span class="hl-4">{async</span><span class="hl-9"> (</span><span class="hl-2">filterData</span><span class="hl-9">, </span><span class="hl-2">pagination</span><span class="hl-9">, </span><span class="hl-2">sort</span><span class="hl-9">, </span><span class="hl-2">chips</span><span class="hl-9">, </span><span class="hl-2">search</span><span class="hl-9">) </span><span class="hl-4">=&gt;</span><span class="hl-9"> {</span><br/><span class="hl-9">      </span><span class="hl-4">const</span><span class="hl-9"> </span><span class="hl-10">res</span><span class="hl-9"> </span><span class="hl-1">=</span><span class="hl-9"> </span><span class="hl-0">await</span><span class="hl-9"> </span><span class="hl-5">fetch</span><span class="hl-9">(</span><span class="hl-3">&#39;/api/people&#39;</span><span class="hl-9">, {</span><br/><span class="hl-9">        </span><span class="hl-2">method:</span><span class="hl-9"> </span><span class="hl-3">&#39;POST&#39;</span><span class="hl-9">,</span><br/><span class="hl-9">        </span><span class="hl-2">body:</span><span class="hl-9"> </span><span class="hl-10">JSON</span><span class="hl-9">.</span><span class="hl-5">stringify</span><span class="hl-9">({ </span><span class="hl-2">filterData</span><span class="hl-9">, </span><span class="hl-2">pagination</span><span class="hl-9">, </span><span class="hl-2">sort</span><span class="hl-9">, </span><span class="hl-2">chips</span><span class="hl-9">, </span><span class="hl-2">search</span><span class="hl-9"> }),</span><br/><span class="hl-9">      });</span><br/><span class="hl-9">      </span><span class="hl-4">const</span><span class="hl-9"> </span><span class="hl-10">json</span><span class="hl-9"> </span><span class="hl-1">=</span><span class="hl-9"> </span><span class="hl-0">await</span><span class="hl-9"> </span><span class="hl-2">res</span><span class="hl-9">.</span><span class="hl-5">json</span><span class="hl-9">();</span><br/><span class="hl-9">      </span><span class="hl-17">// return { rows, total } for server-side pagination</span><br/><span class="hl-9">      </span><span class="hl-0">return</span><span class="hl-9"> { </span><span class="hl-2">rows:</span><span class="hl-9"> </span><span class="hl-2">json</span><span class="hl-9">.</span><span class="hl-2">data</span><span class="hl-9">, </span><span class="hl-2">total:</span><span class="hl-9"> </span><span class="hl-2">json</span><span class="hl-9">.</span><span class="hl-2">total</span><span class="hl-9"> };</span><br/><span class="hl-9">    }</span><span class="hl-4">}</span><br/><span class="hl-1">    </span><span class="hl-8">onAction</span><span class="hl-1">=</span><span class="hl-4">{</span><span class="hl-9">(</span><span class="hl-2">action</span><span class="hl-9">, </span><span class="hl-2">selectedRows</span><span class="hl-9">, </span><span class="hl-2">reload</span><span class="hl-9">) </span><span class="hl-4">=&gt;</span><span class="hl-9"> {</span><br/><span class="hl-9">      </span><span class="hl-0">if</span><span class="hl-9"> (</span><span class="hl-2">action</span><span class="hl-9"> </span><span class="hl-1">===</span><span class="hl-9"> </span><span class="hl-3">&#39;add-action&#39;</span><span class="hl-9">) </span><span class="hl-5">openCreateDialog</span><span class="hl-9">().</span><span class="hl-5">then</span><span class="hl-9">(() </span><span class="hl-4">=&gt;</span><span class="hl-9"> </span><span class="hl-5">reload</span><span class="hl-9">());</span><br/><span class="hl-9">    }</span><span class="hl-4">}</span><br/><span class="hl-1">    </span><span class="hl-8">onRowAction</span><span class="hl-1">=</span><span class="hl-4">{</span><span class="hl-9">(</span><span class="hl-2">action</span><span class="hl-9">, </span><span class="hl-2">row</span><span class="hl-9">, </span><span class="hl-2">reload</span><span class="hl-9">) </span><span class="hl-4">=&gt;</span><span class="hl-9"> {</span><br/><span class="hl-9">      </span><span class="hl-0">if</span><span class="hl-9"> (</span><span class="hl-2">action</span><span class="hl-9"> </span><span class="hl-1">===</span><span class="hl-9"> </span><span class="hl-3">&#39;edit-action&#39;</span><span class="hl-9">) </span><span class="hl-5">openEditDialog</span><span class="hl-9">(</span><span class="hl-2">row</span><span class="hl-9">.</span><span class="hl-2">id</span><span class="hl-9">).</span><span class="hl-5">then</span><span class="hl-9">(() </span><span class="hl-4">=&gt;</span><span class="hl-9"> </span><span class="hl-5">reload</span><span class="hl-9">());</span><br/><span class="hl-9">    }</span><span class="hl-4">}</span><br/><span class="hl-1">    </span><span class="hl-8">onRowClick</span><span class="hl-1">=</span><span class="hl-4">{</span><span class="hl-9">(</span><span class="hl-2">row</span><span class="hl-9">) </span><span class="hl-4">=&gt;</span><span class="hl-9"> </span><span class="hl-2">console</span><span class="hl-9">.</span><span class="hl-5">log</span><span class="hl-9">(</span><span class="hl-3">&#39;clicked&#39;</span><span class="hl-9">, </span><span class="hl-2">row</span><span class="hl-9">.</span><span class="hl-2">id</span><span class="hl-9">)</span><span class="hl-4">}</span><br/><span class="hl-1">  </span><span class="hl-6">/&gt;</span><br/><span class="hl-1">);</span>
</code><button type="button">Copy</button></pre>

<a id="the-handler-type" class="tsd-anchor"></a><h2 class="tsd-anchor-link">The <code>handler</code> type<a href="#the-handler-type" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../assets/icons.svg#icon-anchor"></use></svg></a></h2><p><code>ListHandler</code> is the central concept of the data grid. It can be a static
array (for client-side lists) or an async function for server-side pagination:</p>
<pre><code class="tsx"><span class="hl-0">import</span><span class="hl-1"> { </span><span class="hl-2">ListHandler</span><span class="hl-1"> } </span><span class="hl-0">from</span><span class="hl-1"> </span><span class="hl-3">&#39;react-declarative&#39;</span><span class="hl-1">;</span><br/><br/><span class="hl-17">// Static array — no server call, everything client-side</span><br/><span class="hl-4">const</span><span class="hl-1"> </span><span class="hl-10">staticHandler</span><span class="hl-1">: </span><span class="hl-7">ListHandler</span><span class="hl-1">&lt;{}, </span><span class="hl-7">IRowData</span><span class="hl-1">&gt; = [</span><br/><span class="hl-1">  { </span><span class="hl-2">id:</span><span class="hl-1"> </span><span class="hl-3">&#39;1&#39;</span><span class="hl-1">, </span><span class="hl-2">name:</span><span class="hl-1"> </span><span class="hl-3">&#39;Alice&#39;</span><span class="hl-1"> },</span><br/><span class="hl-1">  { </span><span class="hl-2">id:</span><span class="hl-1"> </span><span class="hl-3">&#39;2&#39;</span><span class="hl-1">, </span><span class="hl-2">name:</span><span class="hl-1"> </span><span class="hl-3">&#39;Bob&#39;</span><span class="hl-1"> },</span><br/><span class="hl-1">];</span><br/><br/><span class="hl-17">// Async function — full signature</span><br/><span class="hl-4">const</span><span class="hl-1"> </span><span class="hl-5">asyncHandler</span><span class="hl-1">: </span><span class="hl-7">ListHandler</span><span class="hl-1">&lt;</span><span class="hl-7">IFilterData</span><span class="hl-1">, </span><span class="hl-7">IRowData</span><span class="hl-1">&gt; = </span><span class="hl-4">async</span><span class="hl-1"> (</span><br/><span class="hl-1">  </span><span class="hl-2">filterData</span><span class="hl-1">,   </span><span class="hl-17">// current values from the filter &lt;One /&gt; form</span><br/><span class="hl-1">  </span><span class="hl-2">pagination</span><span class="hl-1">,   </span><span class="hl-17">// { limit: number; offset: number }</span><br/><span class="hl-1">  </span><span class="hl-2">sort</span><span class="hl-1">,         </span><span class="hl-17">// IListSortItem[] e.g. [{ field: &#39;name&#39;, sort: &#39;asc&#39; }]</span><br/><span class="hl-1">  </span><span class="hl-2">chips</span><span class="hl-1">,        </span><span class="hl-17">// Record&lt;keyof RowData, boolean&gt;</span><br/><span class="hl-1">  </span><span class="hl-2">search</span><span class="hl-1">,       </span><span class="hl-17">// free-text search string</span><br/><span class="hl-1">  </span><span class="hl-2">payload</span><span class="hl-1">,      </span><span class="hl-17">// arbitrary payload prop passed to &lt;List /&gt;</span><br/><span class="hl-1">) </span><span class="hl-4">=&gt;</span><span class="hl-1"> {</span><br/><span class="hl-1">  </span><span class="hl-4">const</span><span class="hl-1"> </span><span class="hl-10">rows</span><span class="hl-1"> = </span><span class="hl-0">await</span><span class="hl-1"> </span><span class="hl-5">fetchRows</span><span class="hl-1">({ </span><span class="hl-2">filterData</span><span class="hl-1">, </span><span class="hl-2">pagination</span><span class="hl-1">, </span><span class="hl-2">sort</span><span class="hl-1"> });</span><br/><span class="hl-1">  </span><span class="hl-0">return</span><span class="hl-1"> { </span><span class="hl-2">rows</span><span class="hl-1">, </span><span class="hl-2">total:</span><span class="hl-1"> </span><span class="hl-2">rows</span><span class="hl-1">.</span><span class="hl-2">length</span><span class="hl-1"> }; </span><span class="hl-17">// total drives pagination</span><br/><span class="hl-1">};</span>
</code><button type="button">Copy</button></pre>

<blockquote>
<p>Return <code>{ rows, total }</code> from your handler when you want accurate page
counts. Return <code>rows[]</code> directly for client-side data where the grid counts
locally.</p>
</blockquote>
<a id="key-props" class="tsd-anchor"></a><h2 class="tsd-anchor-link">Key props<a href="#key-props" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../assets/icons.svg#icon-anchor"></use></svg></a></h2><p><strong><code>handler</code></strong><code>ListHandler&lt;FilterData, RowData&gt;</code> (required)</p>
<p>Fetches rows. Called automatically on mount and whenever filters, pagination,
sort, chips, or search change.</p>
<hr>
<p><strong><code>columns</code></strong><code>IColumn&lt;FilterData, RowData&gt;[]</code> (required)</p>
<p>Defines the table columns. Each column has a <code>type</code> (from <code>ColumnType</code>), an
optional <code>field</code> key into <code>RowData</code>, a <code>headerName</code>, and a <code>width</code> (either
a CSS string or a function of the available pixel width).</p>
<hr>
<p><strong><code>filters</code></strong><code>TypedField[]</code></p>
<p>A field schema (same format as <code>&lt;One /&gt;</code>) rendered as a collapsible filter
panel above the grid. Filter values are passed as the first argument to
<code>handler</code>.</p>
<hr>
<p><strong><code>actions</code></strong><code>IListAction&lt;RowData&gt;[]</code></p>
<p>Buttons rendered in the grid toolbar. Each action has a <code>type</code>
(<code>ActionType.Add</code>, <code>ActionType.Menu</code>, etc.) and triggers <code>onAction</code> when
clicked.</p>
<hr>
<p><strong><code>operations</code></strong><code>IListOperation&lt;RowData&gt;[]</code></p>
<p>Bulk operations available when one or more rows are selected. Rendered as a
dropdown menu and trigger <code>onOperation</code> with the current selection.</p>
<hr>
<p><strong><code>chips</code></strong><code>IListChip&lt;RowData&gt;[]</code></p>
<p>Toggle chips rendered above the grid. Each chip maps to a boolean field in
<code>RowData</code> and its state is passed to <code>handler</code> in the <code>chips</code> argument.</p>
<hr>
<p><strong><code>rowActions</code></strong><code>IListRowAction[]</code></p>
<p>Per-row context menu items. Each action can have an <code>isVisible</code> callback
that receives the row data and returns whether to show it.</p>
<hr>
<p><strong><code>payload</code></strong><code>Payload | (() =&gt; Payload)</code></p>
<p>Arbitrary data forwarded to <code>handler</code>, <code>isVisible</code>/<code>isDisabled</code> callbacks on
actions, and filter field callbacks.</p>
<hr>
<p><strong><code>onAction</code></strong><code>(action: string, selectedRows: RowData[], reload: (keepPagination?) =&gt; Promise&lt;void&gt;) =&gt; void</code></p>
<p>Called when a toolbar action button is clicked. The third argument <code>reload</code>
refreshes the grid — call it after mutating data.</p>
<hr>
<p><strong><code>onRowAction</code></strong><code>(action: string, row: RowData, reload) =&gt; void</code></p>
<p>Called when a per-row action menu item is clicked.</p>
<hr>
<p><strong><code>onRowClick</code></strong><code>(row: RowData, reload) =&gt; void</code></p>
<p>Called when the user clicks anywhere on a row.</p>
<a id="column-definition" class="tsd-anchor"></a><h2 class="tsd-anchor-link">Column definition<a href="#column-definition" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../assets/icons.svg#icon-anchor"></use></svg></a></h2><pre><code class="tsx"><span class="hl-0">import</span><span class="hl-1"> { </span><span class="hl-2">IColumn</span><span class="hl-1">, </span><span class="hl-2">ColumnType</span><span class="hl-1"> } </span><span class="hl-0">from</span><span class="hl-1"> </span><span class="hl-3">&#39;react-declarative&#39;</span><span class="hl-1">;</span><br/><br/><span class="hl-4">const</span><span class="hl-1"> </span><span class="hl-10">columns</span><span class="hl-1">: </span><span class="hl-7">IColumn</span><span class="hl-1">&lt;{}, </span><span class="hl-7">IRowData</span><span class="hl-1">&gt;[] = [</span><br/><span class="hl-1">  {</span><br/><span class="hl-1">    </span><span class="hl-2">type:</span><span class="hl-1"> </span><span class="hl-2">ColumnType</span><span class="hl-1">.</span><span class="hl-2">Text</span><span class="hl-1">,</span><br/><span class="hl-1">    </span><span class="hl-2">field:</span><span class="hl-1"> </span><span class="hl-3">&#39;email&#39;</span><span class="hl-1">,</span><br/><span class="hl-1">    </span><span class="hl-2">headerName:</span><span class="hl-1"> </span><span class="hl-3">&#39;Email&#39;</span><span class="hl-1">,</span><br/><span class="hl-1">    </span><span class="hl-2">width:</span><span class="hl-1"> </span><span class="hl-3">&#39;250px&#39;</span><span class="hl-1">,</span><br/><span class="hl-1">    </span><span class="hl-2">sortable:</span><span class="hl-1"> </span><span class="hl-4">true</span><span class="hl-1">,</span><br/><span class="hl-1">    </span><span class="hl-17">// Computed value instead of direct field mapping</span><br/><span class="hl-1">    </span><span class="hl-5">compute</span><span class="hl-2">:</span><span class="hl-1"> (</span><span class="hl-2">row</span><span class="hl-1">) </span><span class="hl-4">=&gt;</span><span class="hl-1"> </span><span class="hl-2">row</span><span class="hl-1">.</span><span class="hl-2">email</span><span class="hl-1">.</span><span class="hl-5">toLowerCase</span><span class="hl-1">(),</span><br/><span class="hl-1">  },</span><br/><span class="hl-1">  {</span><br/><span class="hl-1">    </span><span class="hl-2">type:</span><span class="hl-1"> </span><span class="hl-2">ColumnType</span><span class="hl-1">.</span><span class="hl-2">Text</span><span class="hl-1">,</span><br/><span class="hl-1">    </span><span class="hl-2">field:</span><span class="hl-1"> </span><span class="hl-3">&#39;status&#39;</span><span class="hl-1">,</span><br/><span class="hl-1">    </span><span class="hl-2">headerName:</span><span class="hl-1"> </span><span class="hl-3">&#39;Status&#39;</span><span class="hl-1">,</span><br/><span class="hl-1">    </span><span class="hl-2">width:</span><span class="hl-1"> </span><span class="hl-3">&#39;120px&#39;</span><span class="hl-1">,</span><br/><span class="hl-1">    </span><span class="hl-17">// Custom React component rendered in the cell</span><br/><span class="hl-1">    </span><span class="hl-5">element</span><span class="hl-2">:</span><span class="hl-1"> ({ </span><span class="hl-2">status</span><span class="hl-1"> }) </span><span class="hl-4">=&gt;</span><span class="hl-1"> </span><span class="hl-6">&lt;</span><span class="hl-7">StatusBadge</span><span class="hl-1"> </span><span class="hl-8">value</span><span class="hl-1">=</span><span class="hl-4">{</span><span class="hl-2">status</span><span class="hl-4">}</span><span class="hl-1"> </span><span class="hl-6">/&gt;</span><span class="hl-1">,</span><br/><span class="hl-1">  },</span><br/><span class="hl-1">  {</span><br/><span class="hl-1">    </span><span class="hl-2">type:</span><span class="hl-1"> </span><span class="hl-2">ColumnType</span><span class="hl-1">.</span><span class="hl-2">Text</span><span class="hl-1">,</span><br/><span class="hl-1">    </span><span class="hl-2">field:</span><span class="hl-1"> </span><span class="hl-3">&#39;score&#39;</span><span class="hl-1">,</span><br/><span class="hl-1">    </span><span class="hl-2">headerName:</span><span class="hl-1"> </span><span class="hl-3">&#39;Score&#39;</span><span class="hl-1">,</span><br/><span class="hl-1">    </span><span class="hl-2">width:</span><span class="hl-1"> </span><span class="hl-3">&#39;80px&#39;</span><span class="hl-1">,</span><br/><span class="hl-1">    </span><span class="hl-2">phoneHidden:</span><span class="hl-1"> </span><span class="hl-4">true</span><span class="hl-1">,  </span><span class="hl-17">// hidden on phone breakpoint</span><br/><span class="hl-1">    </span><span class="hl-2">sortable:</span><span class="hl-1"> </span><span class="hl-4">true</span><span class="hl-1">,</span><br/><span class="hl-1">  },</span><br/><span class="hl-1">];</span>
</code><button type="button">Copy</button></pre>

<a id="behaviour-flags" class="tsd-anchor"></a><h2 class="tsd-anchor-link">Behaviour flags<a href="#behaviour-flags" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../assets/icons.svg#icon-anchor"></use></svg></a></h2><a id="withmobile" class="tsd-anchor"></a><h3 class="tsd-anchor-link">withMobile<a href="#withmobile" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../assets/icons.svg#icon-anchor"></use></svg></a></h3><p>Enables a mobile-friendly card layout on small screens. Columns can declare
<code>phoneOrder</code> and <code>phoneHidden</code> to control their appearance on phones.</p>
<pre><code class="tsx"><span class="hl-6">&lt;</span><span class="hl-7">ListTyped</span><span class="hl-1"> </span><span class="hl-8">withMobile</span><span class="hl-1"> </span><span class="hl-8">columns</span><span class="hl-1">=</span><span class="hl-4">{</span><span class="hl-2">columns</span><span class="hl-4">}</span><span class="hl-1"> </span><span class="hl-19">...</span><span class="hl-1"> </span><span class="hl-6">/&gt;</span>
</code><button type="button">Copy</button></pre>

<a id="withsearch" class="tsd-anchor"></a><h3 class="tsd-anchor-link">withSearch<a href="#withsearch" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../assets/icons.svg#icon-anchor"></use></svg></a></h3><p>Adds a search text box to the toolbar. The typed string is passed as the
<code>search</code> argument to your <code>handler</code>.</p>
<pre><code class="tsx"><span class="hl-6">&lt;</span><span class="hl-7">ListTyped</span><span class="hl-1"> </span><span class="hl-8">withSearch</span><span class="hl-1"> </span><span class="hl-19">...</span><span class="hl-1"> </span><span class="hl-6">/&gt;</span>
</code><button type="button">Copy</button></pre>

<a id="witharrowpagination" class="tsd-anchor"></a><h3 class="tsd-anchor-link">withArrowPagination<a href="#witharrowpagination" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../assets/icons.svg#icon-anchor"></use></svg></a></h3><p>Replaces the default numbered page pagination with simple Prev / Next arrow
buttons. Useful for large datasets where you do not want to expose the total
number of pages.</p>
<pre><code class="tsx"><span class="hl-6">&lt;</span><span class="hl-7">ListTyped</span><span class="hl-1"> </span><span class="hl-8">withArrowPagination</span><span class="hl-1"> </span><span class="hl-19">...</span><span class="hl-1"> </span><span class="hl-6">/&gt;</span>
</code><button type="button">Copy</button></pre>

<a id="withtoggledfilters" class="tsd-anchor"></a><h3 class="tsd-anchor-link">withToggledFilters<a href="#withtoggledfilters" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../assets/icons.svg#icon-anchor"></use></svg></a></h3><p>Renders the filter panel collapsed by default. The user can expand it with
a toolbar button.</p>
<pre><code class="tsx"><span class="hl-6">&lt;</span><span class="hl-7">ListTyped</span><span class="hl-1"> </span><span class="hl-8">withToggledFilters</span><span class="hl-1"> </span><span class="hl-19">...</span><span class="hl-1"> </span><span class="hl-6">/&gt;</span>
</code><button type="button">Copy</button></pre>

<a id="listtyped-vs-list" class="tsd-anchor"></a><h2 class="tsd-anchor-link"><code>ListTyped</code> vs <code>List</code><a href="#listtyped-vs-list" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../assets/icons.svg#icon-anchor"></use></svg></a></h2><p><code>ListTyped</code> is the recommended export. It enforces the <code>FilterData</code> and
<code>RowData</code> generics at the component level, so TypeScript will catch
mismatches between your handler return type, your columns, and your filter
fields:</p>
<pre><code class="tsx"><span class="hl-17">// Both are equivalent at runtime; ListTyped is stricter at compile time</span><br/><span class="hl-6">&lt;</span><span class="hl-7">List</span><span class="hl-1">&lt;</span><span class="hl-7">IFilterData</span><span class="hl-1">, </span><span class="hl-7">IRowData</span><span class="hl-1">&gt; </span><span class="hl-19">...</span><span class="hl-1"> </span><span class="hl-6">/&gt;</span><br/><span class="hl-6">&lt;</span><span class="hl-7">ListTyped</span><span class="hl-1">&lt;</span><span class="hl-7">IFilterData</span><span class="hl-1">, </span><span class="hl-7">IRowData</span><span class="hl-1">&gt; </span><span class="hl-19">...</span><span class="hl-1"> </span><span class="hl-6">/&gt;</span>
</code><button type="button">Copy</button></pre>

</div></div><div class="col-sidebar"><div class="page-menu"><div class="tsd-navigation settings"><details class="tsd-accordion"><summary class="tsd-accordion-summary"><h3><svg width="20" height="20" viewBox="0 0 24 24" fill="none" aria-hidden="true"><use href="../assets/icons.svg#icon-chevronDown"></use></svg>Settings</h3></summary><div class="tsd-accordion-details"><div class="tsd-filter-visibility"><span class="settings-label">Member Visibility</span><ul id="tsd-filter-options"><li class="tsd-filter-item"><label class="tsd-filter-input"><input type="checkbox" id="tsd-filter-protected" name="protected"/><svg width="32" height="32" viewBox="0 0 32 32" aria-hidden="true"><rect class="tsd-checkbox-background" width="30" height="30" x="1" y="1" rx="6" fill="none"></rect><path class="tsd-checkbox-checkmark" d="M8.35422 16.8214L13.2143 21.75L24.6458 10.25" stroke="none" stroke-width="3.5" stroke-linejoin="round" fill="none"></path></svg><span>Protected</span></label></li><li class="tsd-filter-item"><label class="tsd-filter-input"><input type="checkbox" id="tsd-filter-inherited" name="inherited" checked/><svg width="32" height="32" viewBox="0 0 32 32" aria-hidden="true"><rect class="tsd-checkbox-background" width="30" height="30" x="1" y="1" rx="6" fill="none"></rect><path class="tsd-checkbox-checkmark" d="M8.35422 16.8214L13.2143 21.75L24.6458 10.25" stroke="none" stroke-width="3.5" stroke-linejoin="round" fill="none"></path></svg><span>Inherited</span></label></li><li class="tsd-filter-item"><label class="tsd-filter-input"><input type="checkbox" id="tsd-filter-external" name="external"/><svg width="32" height="32" viewBox="0 0 32 32" aria-hidden="true"><rect class="tsd-checkbox-background" width="30" height="30" x="1" y="1" rx="6" fill="none"></rect><path class="tsd-checkbox-checkmark" d="M8.35422 16.8214L13.2143 21.75L24.6458 10.25" stroke="none" stroke-width="3.5" stroke-linejoin="round" fill="none"></path></svg><span>External</span></label></li></ul></div><div class="tsd-theme-toggle"><label class="settings-label" for="tsd-theme">Theme</label><select id="tsd-theme"><option value="os">OS</option><option value="light">Light</option><option value="dark">Dark</option></select></div></div></details></div><details open class="tsd-accordion tsd-page-navigation"><summary class="tsd-accordion-summary"><h3><svg width="20" height="20" viewBox="0 0 24 24" fill="none" aria-hidden="true"><use href="../assets/icons.svg#icon-chevronDown"></use></svg>On This Page</h3></summary><div class="tsd-accordion-details"><a href="#list-component-paginated-and-filterable-data-grid"><span>List component: paginated and filterable data grid</span></a><ul><li><a href="#installation"><span>Installation</span></a></li><li><a href="#minimal-working-example"><span>Minimal working example</span></a></li><li><a href="#the-handler-type"><span>The handler type</span></a></li><li><a href="#key-props"><span>Key props</span></a></li><li><a href="#column-definition"><span>Column definition</span></a></li><li><a href="#behaviour-flags"><span>Behaviour flags</span></a></li><li><ul><li><a href="#withmobile"><span>with<wbr/>Mobile</span></a></li><li><a href="#withsearch"><span>with<wbr/>Search</span></a></li><li><a href="#witharrowpagination"><span>with<wbr/>Arrow<wbr/>Pagination</span></a></li><li><a href="#withtoggledfilters"><span>with<wbr/>Toggled<wbr/>Filters</span></a></li></ul></li><li><a href="#listtyped-vs-list"><span>List<wbr/>Typed vs <wbr/>List</span></a></li></ul></div></details></div><div class="site-menu"><nav class="tsd-navigation"><a href="../modules.html">react-declarative</a><ul class="tsd-small-nested-navigation" id="tsd-nav-container"><li>Loading...</li></ul></nav></div></div></div><footer><p class="tsd-generator">Generated using <a href="https://typedoc.org/" target="_blank">TypeDoc</a></p></footer><div class="overlay"></div></body></html>