react-declarative-docs / documents /docs_components_kanban.html
tripolskypetr's picture
patch
9375fc1
<!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/kanban | 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_kanban.html">docs/components/kanban</a></li></ul></div><div class="tsd-panel tsd-typography"><a id="kanbanview-real-time-drag-and-drop-board-component" class="tsd-anchor"></a><h1 class="tsd-anchor-link">KanbanView: real-time drag-and-drop board component<a href="#kanbanview-real-time-drag-and-drop-board-component" 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;KanbanView /&gt;</code> turns a flat list of items and a column configuration into a full kanban board. Cards are draggable between columns; when a card moves, <code>onChangeColumn</code> fires so you can persist the change to your backend. The component supports real-time updates through a <code>reloadSubject</code> observable and can render arbitrary per-card detail rows defined in <code>IBoardRow[]</code>.</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="complete-example" class="tsd-anchor"></a><h2 class="tsd-anchor-link">Complete example<a href="#complete-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">KanbanView</span><span class="hl-1">,</span><br/><span class="hl-1"> </span><span class="hl-2">IBoardColumn</span><span class="hl-1">,</span><br/><span class="hl-1"> </span><span class="hl-2">IBoardRow</span><span class="hl-1">,</span><br/><span class="hl-1"> </span><span class="hl-2">IBoardItem</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-17">// Shape of each card&#39;s data</span><br/><span class="hl-4">interface</span><span class="hl-1"> </span><span class="hl-7">ILeadRow</span><span class="hl-1"> {</span><br/><span class="hl-1"> </span><span class="hl-2">first_name</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">last_name</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">email</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">phone</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">hire_date</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-17">// Column type — a union of valid column identifiers</span><br/><span class="hl-4">type</span><span class="hl-1"> </span><span class="hl-7">LeadColumn</span><span class="hl-1"> = </span><span class="hl-3">&#39;cold&#39;</span><span class="hl-1"> | </span><span class="hl-3">&#39;contact&#39;</span><span class="hl-1"> | </span><span class="hl-3">&#39;draft&#39;</span><span class="hl-1"> | </span><span class="hl-3">&#39;deal&#39;</span><span class="hl-1">;</span><br/><br/><span class="hl-17">// Rows define what to display inside each card</span><br/><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-7">IBoardRow</span><span class="hl-1">&lt;</span><span class="hl-7">ILeadRow</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;Display name&#39;</span><span class="hl-1">,</span><br/><span class="hl-1"> </span><span class="hl-5">value</span><span class="hl-2">:</span><span class="hl-1"> (</span><span class="hl-2">id</span><span class="hl-1">, </span><span class="hl-2">employee</span><span class="hl-1">) </span><span class="hl-4">=&gt;</span><br/><span class="hl-1"> [</span><span class="hl-2">employee</span><span class="hl-1">.</span><span class="hl-2">first_name</span><span class="hl-1">, </span><span class="hl-2">employee</span><span class="hl-1">.</span><span class="hl-2">last_name</span><span class="hl-1">].</span><span class="hl-5">join</span><span class="hl-1">(</span><span class="hl-3">&#39; &#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">label:</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-5">value</span><span class="hl-2">:</span><span class="hl-1"> (</span><span class="hl-2">id</span><span class="hl-1">, </span><span class="hl-2">employee</span><span class="hl-1">) </span><span class="hl-4">=&gt;</span><span class="hl-1"> </span><span class="hl-2">employee</span><span class="hl-1">.</span><span class="hl-2">email</span><span class="hl-1">,</span><br/><span class="hl-1"> </span><span class="hl-5">click</span><span class="hl-2">:</span><span class="hl-1"> (</span><span class="hl-2">id</span><span class="hl-1">, </span><span class="hl-2">data</span><span class="hl-1">, </span><span class="hl-2">payload</span><span class="hl-1">) </span><span class="hl-4">=&gt;</span><span class="hl-1"> </span><span class="hl-2">payload</span><span class="hl-1">.</span><span class="hl-5">openPreview</span><span class="hl-1">(</span><span class="hl-2">id</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">label:</span><span class="hl-1"> </span><span class="hl-3">&#39;Phone&#39;</span><span class="hl-1">,</span><br/><span class="hl-1"> </span><span class="hl-5">value</span><span class="hl-2">:</span><span class="hl-1"> (</span><span class="hl-2">id</span><span class="hl-1">, </span><span class="hl-2">employee</span><span class="hl-1">) </span><span class="hl-4">=&gt;</span><span class="hl-1"> </span><span class="hl-2">employee</span><span class="hl-1">.</span><span class="hl-2">phone</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">label:</span><span class="hl-1"> </span><span class="hl-3">&#39;Hire date&#39;</span><span class="hl-1">,</span><br/><span class="hl-1"> </span><span class="hl-5">value</span><span class="hl-2">:</span><span class="hl-1"> (</span><span class="hl-2">id</span><span class="hl-1">, </span><span class="hl-2">employee</span><span class="hl-1">) </span><span class="hl-4">=&gt;</span><span class="hl-1"> </span><span class="hl-2">employee</span><span class="hl-1">.</span><span class="hl-2">hire_date</span><span class="hl-1">,</span><br/><span class="hl-1"> },</span><br/><span class="hl-1">];</span><br/><br/><span class="hl-17">// Columns define the board lanes</span><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">IBoardColumn</span><span class="hl-1">&lt;</span><span class="hl-7">ILeadRow</span><span class="hl-1">, {}, </span><span class="hl-7">LeadColumn</span><span class="hl-1">&gt;[] = [</span><br/><span class="hl-1"> { </span><span class="hl-2">color:</span><span class="hl-1"> </span><span class="hl-3">&#39;#00ACC1&#39;</span><span class="hl-1">, </span><span class="hl-2">column:</span><span class="hl-1"> </span><span class="hl-3">&#39;cold&#39;</span><span class="hl-1">, </span><span class="hl-2">label:</span><span class="hl-1"> </span><span class="hl-3">&#39;Cold&#39;</span><span class="hl-1">, </span><span class="hl-2">rows</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;#9C27B0&#39;</span><span class="hl-1">, </span><span class="hl-2">column:</span><span class="hl-1"> </span><span class="hl-3">&#39;contact&#39;</span><span class="hl-1">, </span><span class="hl-2">label:</span><span class="hl-1"> </span><span class="hl-3">&#39;Contact&#39;</span><span class="hl-1">, </span><span class="hl-2">rows</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;#FFA000&#39;</span><span class="hl-1">, </span><span class="hl-2">column:</span><span class="hl-1"> </span><span class="hl-3">&#39;draft&#39;</span><span class="hl-1">, </span><span class="hl-2">label:</span><span class="hl-1"> </span><span class="hl-3">&#39;Draft&#39;</span><span class="hl-1">, </span><span class="hl-2">rows</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;#2E7D32&#39;</span><span class="hl-1">, </span><span class="hl-2">column:</span><span class="hl-1"> </span><span class="hl-3">&#39;deal&#39;</span><span class="hl-1">, </span><span class="hl-2">label:</span><span class="hl-1"> </span><span class="hl-3">&#39;In a deal&#39;</span><span class="hl-1">, </span><span class="hl-2">rows</span><span class="hl-1"> },</span><br/><span class="hl-1">];</span><br/><br/><span class="hl-17">// items is the flat list of cards</span><br/><span class="hl-4">const</span><span class="hl-1"> </span><span class="hl-10">items</span><span class="hl-1">: </span><span class="hl-7">IBoardItem</span><span class="hl-1">&lt;</span><span class="hl-7">ILeadRow</span><span class="hl-1">, {}, </span><span class="hl-7">LeadColumn</span><span class="hl-1">&gt;[] = [</span><br/><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;lead-1&#39;</span><span class="hl-1">,</span><br/><span class="hl-1"> </span><span class="hl-2">column:</span><span class="hl-1"> </span><span class="hl-3">&#39;cold&#39;</span><span class="hl-1">,</span><br/><span class="hl-1"> </span><span class="hl-2">data:</span><span class="hl-1"> {</span><br/><span class="hl-1"> </span><span class="hl-2">first_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">last_name:</span><span class="hl-1"> </span><span class="hl-3">&#39;Smith&#39;</span><span class="hl-1">,</span><br/><span class="hl-1"> </span><span class="hl-2">email:</span><span class="hl-1"> </span><span class="hl-3">&#39;alice@example.com&#39;</span><span class="hl-1">,</span><br/><span class="hl-1"> </span><span class="hl-2">phone:</span><span class="hl-1"> </span><span class="hl-3">&#39;+1 555 0100&#39;</span><span class="hl-1">,</span><br/><span class="hl-1"> </span><span class="hl-2">hire_date:</span><span class="hl-1"> </span><span class="hl-3">&#39;2024-01-15&#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><br/><span class="hl-1"> </span><span class="hl-2">id:</span><span class="hl-1"> </span><span class="hl-3">&#39;lead-2&#39;</span><span class="hl-1">,</span><br/><span class="hl-1"> </span><span class="hl-2">column:</span><span class="hl-1"> </span><span class="hl-3">&#39;contact&#39;</span><span class="hl-1">,</span><br/><span class="hl-1"> </span><span class="hl-2">data:</span><span class="hl-1"> {</span><br/><span class="hl-1"> </span><span class="hl-2">first_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><span class="hl-2">last_name:</span><span class="hl-1"> </span><span class="hl-3">&#39;Jones&#39;</span><span class="hl-1">,</span><br/><span class="hl-1"> </span><span class="hl-2">email:</span><span class="hl-1"> </span><span class="hl-3">&#39;bob@example.com&#39;</span><span class="hl-1">,</span><br/><span class="hl-1"> </span><span class="hl-2">phone:</span><span class="hl-1"> </span><span class="hl-3">&#39;+1 555 0101&#39;</span><span class="hl-1">,</span><br/><span class="hl-1"> </span><span class="hl-2">hire_date:</span><span class="hl-1"> </span><span class="hl-3">&#39;2024-02-20&#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><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">LeadsKanban</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-4">const</span><span class="hl-1"> </span><span class="hl-5">handleChangeColumn</span><span class="hl-1"> = </span><span class="hl-4">async</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">column</span><span class="hl-1">: </span><span class="hl-7">LeadColumn</span><span class="hl-1">,</span><br/><span class="hl-1"> </span><span class="hl-2">data</span><span class="hl-1">: </span><span class="hl-7">ILeadRow</span><span class="hl-1">,</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-17">// Persist the move to your backend</span><br/><span class="hl-1"> </span><span class="hl-0">await</span><span class="hl-1"> </span><span class="hl-5">fetch</span><span class="hl-1">(</span><span class="hl-3">`/api/leads/</span><span class="hl-4">${</span><span class="hl-2">id</span><span class="hl-4">}</span><span class="hl-3">`</span><span class="hl-1">, {</span><br/><span class="hl-1"> </span><span class="hl-2">method:</span><span class="hl-1"> </span><span class="hl-3">&#39;PATCH&#39;</span><span class="hl-1">,</span><br/><span class="hl-1"> </span><span class="hl-2">body:</span><span class="hl-1"> </span><span class="hl-10">JSON</span><span class="hl-1">.</span><span class="hl-5">stringify</span><span class="hl-1">({ </span><span class="hl-2">status:</span><span class="hl-1"> </span><span class="hl-2">column</span><span class="hl-1"> }),</span><br/><span class="hl-1"> });</span><br/><span class="hl-1"> };</span><br/><br/><span class="hl-1"> </span><span class="hl-0">return</span><span class="hl-1"> (</span><br/><span class="hl-1"> </span><span class="hl-6">&lt;</span><span class="hl-7">KanbanView</span><span class="hl-1">&lt;</span><span class="hl-7">ILeadRow</span><span class="hl-1">, {}, </span><span class="hl-7">LeadColumn</span><span class="hl-1">&gt;</span><br/><span class="hl-1"> </span><span class="hl-8">sx</span><span class="hl-1">=</span><span class="hl-4">{</span><span class="hl-9">{ </span><span class="hl-2">height:</span><span class="hl-9"> </span><span class="hl-3">&#39;calc(100vh - 145px)&#39;</span><span class="hl-9"> }</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">items</span><span class="hl-1">=</span><span class="hl-4">{</span><span class="hl-2">items</span><span class="hl-4">}</span><br/><span class="hl-1"> </span><span class="hl-8">onChangeColumn</span><span class="hl-1">=</span><span class="hl-4">{</span><span class="hl-2">handleChangeColumn</span><span class="hl-4">}</span><br/><span class="hl-1"> </span><span class="hl-6">/&gt;</span><br/><span class="hl-1"> );</span><br/><span class="hl-1">};</span>
</code><button type="button">Copy</button></pre>
<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>columns</code></strong><code>IBoardColumn&lt;Data, Payload, ColumnType&gt;[]</code> (required)</p>
<p>Defines the board lanes. Each column has a <code>column</code> identifier (the value stored on each item to indicate which lane it belongs to), an optional <code>label</code>, an optional <code>color</code> (used for the column header accent), and a <code>rows</code> array that controls which fields are shown inside every card in that lane.</p>
<p><strong><code>items</code></strong><code>IBoardItem&lt;Data, Payload, ColumnType&gt;[]</code> (required)</p>
<p>The flat list of cards to display. Each item has an <code>id</code>, a <code>column</code> value (must match one of the <code>column</code> identifiers in your <code>columns</code> array), and a <code>data</code> object of type <code>Data</code>.</p>
<p><strong><code>onChangeColumn</code></strong><code>(id: string, column: ColumnType, data: Data, payload: any) =&gt; void | Promise&lt;void&gt;</code></p>
<p>Called every time a card is dragged to a different column. <code>id</code> is the card's id, <code>column</code> is the destination column identifier. Use this callback to persist the move.</p>
<p><strong><code>payload</code></strong><code>Payload | (() =&gt; Payload)</code></p>
<p>Arbitrary data forwarded to every <code>IBoardRow.value</code>, <code>IBoardRow.click</code>, and <code>IBoardRow.visible</code> callback. Use it to carry service references or user context.</p>
<p><strong><code>reloadSubject</code></strong><code>TSubject&lt;void&gt;</code></p>
<p>An observable subject. Emit <code>void</code> on it to force the board to re-fetch and re-render all cards. Use this for real-time updates via WebSocket.</p>
<p><strong><code>onDataRequest</code></strong><code>(initial: boolean) =&gt; void</code></p>
<p>Called when the board mounts (<code>initial = true</code>) and whenever it needs fresh data. Pair with <code>reloadSubject</code> to implement a push-based real-time flow.</p>
<p><strong><code>cardLabel</code></strong><code>React.ReactNode | ((id, data, payload) =&gt; React.ReactNode | Promise&lt;React.ReactNode&gt;)</code></p>
<p>Custom label rendered at the top of each card. Falls back to the item's <code>id</code> when not provided.</p>
<p><strong><code>disabled</code></strong><code>boolean</code></p>
<p>Prevents all drag-and-drop interactions when <code>true</code>.</p>
<p><strong><code>sx</code></strong><code>SxProps</code></p>
<p>MUI system styles applied to the board root. Set a fixed height to enable scrolling within columns, e.g. <code>sx={{ height: 'calc(100vh - 64px)' }}</code>.</p>
<a id="card-row-definition-iboardrow" class="tsd-anchor"></a><h2 class="tsd-anchor-link">Card row definition (<code>IBoardRow</code>)<a href="#card-row-definition-iboardrow" 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>Each entry in the <code>rows</code> array of a column controls one line inside every card:</p>
<pre><code class="tsx"><span class="hl-0">import</span><span class="hl-1"> { </span><span class="hl-2">IBoardRow</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">interface</span><span class="hl-1"> </span><span class="hl-7">ILead</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-7">string</span><span class="hl-1">;</span><br/><span class="hl-1"> </span><span class="hl-2">priority</span><span class="hl-1">: </span><span class="hl-3">&#39;high&#39;</span><span class="hl-1"> | </span><span class="hl-3">&#39;low&#39;</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">rows</span><span class="hl-1">: </span><span class="hl-7">IBoardRow</span><span class="hl-1">&lt;</span><span class="hl-7">ILead</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;Name&#39;</span><span class="hl-1">,</span><br/><span class="hl-1"> </span><span class="hl-17">// value receives (cardId, data, payload) — can be async</span><br/><span class="hl-1"> </span><span class="hl-5">value</span><span class="hl-2">:</span><span class="hl-1"> (</span><span class="hl-2">id</span><span class="hl-1">, </span><span class="hl-2">lead</span><span class="hl-1">) </span><span class="hl-4">=&gt;</span><span class="hl-1"> </span><span class="hl-2">lead</span><span class="hl-1">.</span><span class="hl-2">name</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">label:</span><span class="hl-1"> </span><span class="hl-3">&#39;Priority&#39;</span><span class="hl-1">,</span><br/><span class="hl-1"> </span><span class="hl-5">value</span><span class="hl-2">:</span><span class="hl-1"> (</span><span class="hl-2">id</span><span class="hl-1">, </span><span class="hl-2">lead</span><span class="hl-1">) </span><span class="hl-4">=&gt;</span><span class="hl-1"> </span><span class="hl-2">lead</span><span class="hl-1">.</span><span class="hl-2">priority</span><span class="hl-1">.</span><span class="hl-5">toUpperCase</span><span class="hl-1">(),</span><br/><span class="hl-1"> </span><span class="hl-17">// visible controls whether this row renders at all</span><br/><span class="hl-1"> </span><span class="hl-5">visible</span><span class="hl-2">:</span><span class="hl-1"> (</span><span class="hl-2">id</span><span class="hl-1">, </span><span class="hl-2">lead</span><span class="hl-1">) </span><span class="hl-4">=&gt;</span><span class="hl-1"> </span><span class="hl-2">lead</span><span class="hl-1">.</span><span class="hl-2">priority</span><span class="hl-1"> === </span><span class="hl-3">&#39;high&#39;</span><span class="hl-1">,</span><br/><span class="hl-1"> </span><span class="hl-17">// click makes the row interactive</span><br/><span class="hl-1"> </span><span class="hl-5">click</span><span class="hl-2">:</span><span class="hl-1"> (</span><span class="hl-2">id</span><span class="hl-1">, </span><span class="hl-2">lead</span><span class="hl-1">, </span><span class="hl-2">payload</span><span class="hl-1">) </span><span class="hl-4">=&gt;</span><span class="hl-1"> </span><span class="hl-2">payload</span><span class="hl-1">.</span><span class="hl-5">openDetail</span><span class="hl-1">(</span><span class="hl-2">id</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="color-coding-per-column" class="tsd-anchor"></a><h2 class="tsd-anchor-link">Color coding per column<a href="#color-coding-per-column" 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>Set the <code>color</code> field on each column definition to apply a colored accent to the column header. Any valid CSS color string works:</p>
<pre><code class="tsx"><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">IBoardColumn</span><span class="hl-1">[] = [</span><br/><span class="hl-1"> { </span><span class="hl-2">column:</span><span class="hl-1"> </span><span class="hl-3">&#39;todo&#39;</span><span class="hl-1">, </span><span class="hl-2">label:</span><span class="hl-1"> </span><span class="hl-3">&#39;To Do&#39;</span><span class="hl-1">, </span><span class="hl-2">color:</span><span class="hl-1"> </span><span class="hl-3">&#39;#1976d2&#39;</span><span class="hl-1">, </span><span class="hl-2">rows</span><span class="hl-1"> },</span><br/><span class="hl-1"> { </span><span class="hl-2">column:</span><span class="hl-1"> </span><span class="hl-3">&#39;in_progress&#39;</span><span class="hl-1">, </span><span class="hl-2">label:</span><span class="hl-1"> </span><span class="hl-3">&#39;In Progress&#39;</span><span class="hl-1">, </span><span class="hl-2">color:</span><span class="hl-1"> </span><span class="hl-3">&#39;#f57c00&#39;</span><span class="hl-1">, </span><span class="hl-2">rows</span><span class="hl-1"> },</span><br/><span class="hl-1"> { </span><span class="hl-2">column:</span><span class="hl-1"> </span><span class="hl-3">&#39;done&#39;</span><span class="hl-1">, </span><span class="hl-2">label:</span><span class="hl-1"> </span><span class="hl-3">&#39;Done&#39;</span><span class="hl-1">, </span><span class="hl-2">color:</span><span class="hl-1"> </span><span class="hl-3">&#39;#388e3c&#39;</span><span class="hl-1">, </span><span class="hl-2">rows</span><span class="hl-1"> },</span><br/><span class="hl-1">];</span>
</code><button type="button">Copy</button></pre>
<a id="real-time-support" class="tsd-anchor"></a><h2 class="tsd-anchor-link">Real-time support<a href="#real-time-support" 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>Connect a WebSocket or server-sent events stream and call <code>reload()</code> whenever the backend pushes a change. Use <code>reloadSubject</code> to trigger a re-render from outside the component:</p>
<pre><code class="tsx"><span class="hl-0">import</span><span class="hl-1"> { </span><span class="hl-2">KanbanView</span><span class="hl-1">, </span><span class="hl-2">useSubject</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-0">export</span><span class="hl-1"> </span><span class="hl-4">const</span><span class="hl-1"> </span><span class="hl-5">RealtimeBoard</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-4">const</span><span class="hl-1"> </span><span class="hl-10">reloadSubject</span><span class="hl-1"> = </span><span class="hl-5">useSubject</span><span class="hl-1">&lt;</span><span class="hl-7">void</span><span class="hl-1">&gt;();</span><br/><br/><span class="hl-1"> </span><span class="hl-2">React</span><span class="hl-1">.</span><span class="hl-5">useEffect</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-4">const</span><span class="hl-1"> </span><span class="hl-10">ws</span><span class="hl-1"> = </span><span class="hl-4">new</span><span class="hl-1"> </span><span class="hl-5">WebSocket</span><span class="hl-1">(</span><span class="hl-3">&#39;wss://api.example.com/leads/stream&#39;</span><span class="hl-1">);</span><br/><span class="hl-1"> </span><span class="hl-2">ws</span><span class="hl-1">.</span><span class="hl-5">onmessage</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-17">// Trigger board refresh on any incoming message</span><br/><span class="hl-1"> </span><span class="hl-2">reloadSubject</span><span class="hl-1">.</span><span class="hl-5">next</span><span class="hl-1">();</span><br/><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-4">=&gt;</span><span class="hl-1"> </span><span class="hl-2">ws</span><span class="hl-1">.</span><span class="hl-5">close</span><span class="hl-1">();</span><br/><span class="hl-1"> }, []);</span><br/><br/><span class="hl-1"> </span><span class="hl-0">return</span><span class="hl-1"> (</span><br/><span class="hl-1"> </span><span class="hl-6">&lt;</span><span class="hl-7">KanbanView</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">items</span><span class="hl-1">=</span><span class="hl-4">{</span><span class="hl-2">items</span><span class="hl-4">}</span><br/><span class="hl-1"> </span><span class="hl-8">reloadSubject</span><span class="hl-1">=</span><span class="hl-4">{</span><span class="hl-2">reloadSubject</span><span class="hl-4">}</span><br/><span class="hl-1"> </span><span class="hl-8">onChangeColumn</span><span class="hl-1">=</span><span class="hl-4">{</span><span class="hl-2">handleChangeColumn</span><span class="hl-4">}</span><br/><span class="hl-1"> </span><span class="hl-6">/&gt;</span><br/><span class="hl-1"> );</span><br/><span class="hl-1">};</span>
</code><button type="button">Copy</button></pre>
<blockquote>
<p><strong>Tip:</strong> For high-frequency updates, debounce emissions on <code>reloadSubject</code> to avoid excessive re-renders. The <code>useQueuedAction</code> hook from react-declarative can help serialise incoming WebSocket messages before calling reload.</p>
</blockquote>
</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="#kanbanview-real-time-drag-and-drop-board-component"><span>Kanban<wbr/>View: real-<wbr/>time drag-<wbr/>and-<wbr/>drop board component</span></a><ul><li><a href="#installation"><span>Installation</span></a></li><li><a href="#complete-example"><span>Complete example</span></a></li><li><a href="#key-props"><span>Key props</span></a></li><li><a href="#card-row-definition-iboardrow"><span>Card row definition (IBoard<wbr/>Row)</span></a></li><li><a href="#color-coding-per-column"><span>Color coding per column</span></a></li><li><a href="#real-time-support"><span>Real-<wbr/>time support</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>