KanbanView
Esta página aún no está disponible en tu idioma.
import { KanbanView } from "@rebasepro/ui";| Prop | Type | Required | Description |
|---|---|---|---|
data |
{ id: string; data: T }[] |
yes | Drag-and-drop board. T = card payload, COLUMN = the column key union. |
columns |
COLUMN[] |
yes | |
assignColumn |
(item: { id: string; data: T }) => COLUMN |
yes | |
ItemComponent |
React.ComponentType<{ item: { id: string; data: T }; isDragging: boolean; isClone?: boolean; isGroupedOver?: boolean; style?: React.CSSProperties; index?: number }> |
yes | |
columnLabels |
Record<COLUMN, string> |
— | |
columnColors |
Record<COLUMN, unknown> |
— | |
allowColumnReorder |
boolean |
— | |
onColumnReorder |
(columns: COLUMN[]) => void |
— | |
onItemsReorder |
(items: { id: string; data: T }[], moveInfo?: { itemId: string; sourceColumn: COLUMN; targetColumn: COLUMN }) => void |
— | |
columnLoadingState |
{ [columnKey: string]: { loading: boolean; hasMore: boolean; itemCount: number; totalCount?: number } } |
— | |
onLoadMoreColumn |
(column: COLUMN) => void |
— | |
onAddItemToColumn |
(column: COLUMN) => void |
— | |
AddColumnComponent |
React.ReactNode |
— | |
className |
string |
— |
Example
Section titled “Example”This is the example the design-system sync renders and verifies for this component.
import { useState, useCallback, useMemo } from "react";import { Typography, Chip, cls, KanbanView, FolderKanbanIcon } from "@rebasepro/ui";import type { BoardItem, BoardItemViewProps, ChipHue } from "@rebasepro/ui";
type ProjectStatus = "backlog" | "in_progress" | "in_review" | "done";
type ProjectPriority = "low" | "medium" | "high" | "critical";
interface SampleProject { id: string; name: string; description: string; status: ProjectStatus; priority: ProjectPriority; assignee: string; tags: string[]; dueDate: string;}
const PRIORITY_CONFIG: Record<ProjectPriority, { label: string; color: ChipHue }> = { low: { label: "Low", color: "gray" }, medium: { label: "Medium", color: "yellow" }, high: { label: "High", color: "orange" }, critical: { label: "Critical", color: "red" }};
const STATUS_COLUMNS: ProjectStatus[] = ["backlog", "in_progress", "in_review", "done"];
const COLUMN_LABELS: Record<ProjectStatus, string> = { backlog: "Backlog", in_progress: "In Progress", in_review: "In Review", done: "Done" };
const COLUMN_COLORS: Record<ProjectStatus, string> = { backlog: "#6b7280", in_progress: "#3b82f6", in_review: "#8b5cf6", done: "#22c55e" };
const SAMPLE_PROJECTS: SampleProject[] = [ { id: "proj-1", name: "Website Redesign", description: "Complete overhaul of the marketing website with new brand guidelines", status: "in_progress", priority: "high", assignee: "Alice Johnson", tags: ["frontend", "design"], dueDate: "2026-08-07" }, { id: "proj-2", name: "API Rate Limiting", description: "Implement token-bucket rate limiting across all public endpoints", status: "in_review", priority: "critical", assignee: "Bob Smith", tags: ["backend", "security"], dueDate: "2026-08-02" }, { id: "proj-3", name: "Mobile Push Notifications", description: "Add support for push notifications on iOS and Android clients", status: "backlog", priority: "medium", assignee: "Carol White", tags: ["mobile", "backend"], dueDate: "2026-08-21" }, { id: "proj-4", name: "Dashboard Analytics", description: "Build real-time analytics dashboard with charts and KPI widgets", status: "in_progress", priority: "high", assignee: "David Brown", tags: ["frontend", "data"], dueDate: "2026-08-05" }, { id: "proj-5", name: "User Onboarding Flow", description: "Multi-step onboarding wizard with progress tracking and email triggers", status: "done", priority: "medium", assignee: "Eva Green", tags: ["frontend", "ux"], dueDate: "2026-07-29" }, { id: "proj-6", name: "Database Migration v3", description: "Migrate from PostgreSQL 14 to 16 with zero-downtime strategy", status: "backlog", priority: "low", assignee: "Frank Miller", tags: ["backend", "infrastructure"], dueDate: "2026-08-30" }, { id: "proj-7", name: "SSO Integration", description: "SAML 2.0 and OIDC single sign-on for enterprise customers", status: "in_progress", priority: "critical", assignee: "Alice Johnson", tags: ["backend", "security", "enterprise"], dueDate: "2026-08-03" }, { id: "proj-8", name: "E2E Test Suite", description: "Playwright-based end-to-end tests covering critical user journeys", status: "in_review", priority: "medium", assignee: "Bob Smith", tags: ["testing", "devops"], dueDate: "2026-08-01" }, { id: "proj-9", name: "Billing System Upgrade", description: "Stripe integration upgrade with metered billing and invoice PDF generation", status: "done", priority: "high", assignee: "Carol White", tags: ["backend", "payments"], dueDate: "2026-07-26" }, { id: "proj-10", name: "Dark Mode Polish", description: "Audit and fix all remaining dark mode inconsistencies across the app", status: "backlog", priority: "low", assignee: "David Brown", tags: ["frontend", "design"], dueDate: "2026-08-14" }];
function KanbanProjectCard({ item, isDragging, isGroupedOver, style }: BoardItemViewProps<SampleProject>) { const project = item.data; const priorityCfg = PRIORITY_CONFIG[project.priority];
const backgroundColor = isDragging ? "bg-surface-100 dark:bg-surface-800" : isGroupedOver ? "bg-surface-200 dark:bg-surface-700" : "bg-white dark:bg-surface-800";
return ( <div style={style} className="py-1"> <div className={cls("p-2 flex items-start border rounded-lg border-surface-200 dark:border-surface-800", backgroundColor, isDragging && "ring-2 ring-primary")}> <div className="w-10 h-10 rounded-md shrink-0 mr-2 bg-surface-100 dark:bg-surface-900 flex items-center justify-center"> <FolderKanbanIcon size={16} className="text-surface-400" /> </div> <div className="flex-1 min-w-0"> <Typography variant="body2" className="font-medium line-clamp-2">{project.name}</Typography> <Typography variant="caption" color="secondary" className="line-clamp-2">{project.description}</Typography> <div className="flex items-center gap-1 mt-1 flex-wrap"> <Chip colorScheme={priorityCfg.color} size="smallest" outlined>{priorityCfg.label}</Chip> {project.tags.slice(0, 1).map(tag => ( <Chip key={tag} size="smallest" colorScheme="cyan">{tag}</Chip> ))} </div> <div className="flex items-center justify-between mt-1"> <Typography variant="caption" color="secondary">{project.assignee}</Typography> <Typography variant="caption" color="secondary" className="font-mono">{project.dueDate}</Typography> </div> </div> </div> </div> );}
export function ProjectBoard() { const [boardData, setBoardData] = useState<BoardItem<SampleProject>[]>(() => SAMPLE_PROJECTS.map(p => ({ id: p.id, data: p }))); const [columns, setColumns] = useState<ProjectStatus[]>(STATUS_COLUMNS);
const assignColumn = useCallback((item: BoardItem<SampleProject>): ProjectStatus => item.data.status, []);
const handleItemsReorder = useCallback((items: BoardItem<SampleProject>[], moveInfo?: { itemId: string; sourceColumn: ProjectStatus; targetColumn: ProjectStatus }) => { const updatedItems = items.map(item => { if (moveInfo && item.id === moveInfo.itemId && moveInfo.sourceColumn !== moveInfo.targetColumn) { return { ...item, data: { ...item.data, status: moveInfo.targetColumn } }; } return item; }); setBoardData(updatedItems); }, []);
const handleColumnReorder = useCallback((reordered: ProjectStatus[]) => setColumns(reordered), []);
const columnLoadingState = useMemo(() => { const state: Record<string, { loading: boolean; hasMore: boolean; itemCount: number; totalCount: number }> = {}; for (const col of columns) { const count = boardData.filter(item => item.data.status === col).length; state[col] = { loading: false, hasMore: false, itemCount: count, totalCount: count }; } return state; }, [boardData, columns]);
return ( <div style={{ height: 480 }} className="w-full rounded-lg border border-surface-200 dark:border-surface-800 overflow-hidden"> <KanbanView<SampleProject, ProjectStatus> data={boardData} columns={columns} columnLabels={COLUMN_LABELS} columnColors={COLUMN_COLORS} assignColumn={assignColumn} allowColumnReorder={true} onColumnReorder={handleColumnReorder} onItemsReorder={handleItemsReorder} ItemComponent={KanbanProjectCard} columnLoadingState={columnLoadingState} /> </div> );}