| <!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><KanbanView /></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">'react-declarative'</span><span class="hl-1">;</span><br/><br/><span class="hl-17">// Shape of each card'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">'cold'</span><span class="hl-1"> | </span><span class="hl-3">'contact'</span><span class="hl-1"> | </span><span class="hl-3">'draft'</span><span class="hl-1"> | </span><span class="hl-3">'deal'</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"><</span><span class="hl-7">ILeadRow</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">'Display name'</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">=></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">' '</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">'Email'</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">=></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">=></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">'Phone'</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">=></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">'Hire date'</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">=></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"><</span><span class="hl-7">ILeadRow</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">color:</span><span class="hl-1"> </span><span class="hl-3">'#00ACC1'</span><span class="hl-1">, </span><span class="hl-2">column:</span><span class="hl-1"> </span><span class="hl-3">'cold'</span><span class="hl-1">, </span><span class="hl-2">label:</span><span class="hl-1"> </span><span class="hl-3">'Cold'</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">'#9C27B0'</span><span class="hl-1">, </span><span class="hl-2">column:</span><span class="hl-1"> </span><span class="hl-3">'contact'</span><span class="hl-1">, </span><span class="hl-2">label:</span><span class="hl-1"> </span><span class="hl-3">'Contact'</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">'#FFA000'</span><span class="hl-1">, </span><span class="hl-2">column:</span><span class="hl-1"> </span><span class="hl-3">'draft'</span><span class="hl-1">, </span><span class="hl-2">label:</span><span class="hl-1"> </span><span class="hl-3">'Draft'</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">'#2E7D32'</span><span class="hl-1">, </span><span class="hl-2">column:</span><span class="hl-1"> </span><span class="hl-3">'deal'</span><span class="hl-1">, </span><span class="hl-2">label:</span><span class="hl-1"> </span><span class="hl-3">'In a deal'</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"><</span><span class="hl-7">ILeadRow</span><span class="hl-1">, {}, </span><span class="hl-7">LeadColumn</span><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">'lead-1'</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">'cold'</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">'Alice'</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">'Smith'</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">'alice@example.com'</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">'+1 555 0100'</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">'2024-01-15'</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">'lead-2'</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">'contact'</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">'Bob'</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">'Jones'</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">'bob@example.com'</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">'+1 555 0101'</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">'2024-02-20'</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">=></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">=></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">'PATCH'</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"><</span><span class="hl-7">KanbanView</span><span class="hl-1"><</span><span class="hl-7">ILeadRow</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-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">'calc(100vh - 145px)'</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">/></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<Data, Payload, ColumnType>[]</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<Data, Payload, ColumnType>[]</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) => void | Promise<void></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 | (() => 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<void></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) => 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) => React.ReactNode | Promise<React.ReactNode>)</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">'react-declarative'</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">'high'</span><span class="hl-1"> | </span><span class="hl-3">'low'</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"><</span><span class="hl-7">ILead</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">'Name'</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">=></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">'Priority'</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">=></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">=></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">'high'</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">=></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">'todo'</span><span class="hl-1">, </span><span class="hl-2">label:</span><span class="hl-1"> </span><span class="hl-3">'To Do'</span><span class="hl-1">, </span><span class="hl-2">color:</span><span class="hl-1"> </span><span class="hl-3">'#1976d2'</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">'in_progress'</span><span class="hl-1">, </span><span class="hl-2">label:</span><span class="hl-1"> </span><span class="hl-3">'In Progress'</span><span class="hl-1">, </span><span class="hl-2">color:</span><span class="hl-1"> </span><span class="hl-3">'#f57c00'</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">'done'</span><span class="hl-1">, </span><span class="hl-2">label:</span><span class="hl-1"> </span><span class="hl-3">'Done'</span><span class="hl-1">, </span><span class="hl-2">color:</span><span class="hl-1"> </span><span class="hl-3">'#388e3c'</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">'react-declarative'</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">=></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"><</span><span class="hl-7">void</span><span class="hl-1">>();</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">=></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">'wss://api.example.com/leads/stream'</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">=></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">=></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"><</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">/></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> |
|
|