@bernierllc/content-flow-ui
v0.2.2
Published
Drop-in flow-board (kanban) view of the content pipeline for content-management-suite-client consumers — composes flow-board-ui with content-aware mapping, headless hooks + default components
Readme
@bernierllc/content-flow-ui
Drop-in flow-board (kanban) view of your content pipeline for consumers of @bernierllc/content-management-suite-client. Composes the generic @bernierllc/flow-board-ui with content-aware mapping: content items become cards, workflow stages become columns, and card moves call back into your content API.
Headless hooks + default components — use the batteries-included ContentFlowBoard, or build your own UI on useContentFlowBoard.
Install
npm install @bernierllc/content-flow-ui react react-dom@bernierllc/content-management-suite-client is an optional peer — only client mode needs it (and any object with the same method shapes works).
Props mode — you already have the data
import { ContentFlowBoard } from '@bernierllc/content-flow-ui';
<ContentFlowBoard
contents={contents} // ContentLike[] (client Content[] satisfies it)
workflow={workflow} // WorkflowLike (client Workflow satisfies it)
onStageChange={(contentId, stageId) => myApi.moveContent(contentId, stageId)}
/>No onStageChange → the board is read-only. Works without the suite client installed.
Client mode — hand it a client
import { ContentManagementClient } from '@bernierllc/content-management-suite-client';
import { ContentFlowBoard } from '@bernierllc/content-flow-ui';
const client = new ContentManagementClient({ baseUrl: '/api/content' });
<ContentFlowBoard client={client} workflowId="editorial" pollIntervalMs={30000} />The hook fetches the workflow + content, optionally polls, and applies board moves through the client's API. Note: the REST API is advance/reject based — moving a card one stage forward calls advanceWorkflowStage, moving it backward calls rejectWorkflowStage; arbitrary multi-stage jumps raise ADVANCE_FAILED.
Headless
import { useContentFlowBoard } from '@bernierllc/content-flow-ui';
import { KanbanBoard } from '@bernierllc/flow-board-ui';
const board = useContentFlowBoard({ client, workflowId: 'editorial' });
// board.boardProps → { flow, items, onTransition, onItemClick }
// board.selectedContent / selectedItem / clearSelection
// board.isLoading / error / refresh()
<KanbanBoard {...board.boardProps} />Pure mapping utilities are exported too: workflowToFlowDefinition, contentToFlowItems, resolveContentStage, itemIdToContentId.
Theming
Config-object pattern (same as content-workflow-ui):
<ContentFlowBoard
contents={contents}
workflow={workflow}
config={{
stageColors: { draft: '#94a3b8', review: '#f59e0b' },
showAssignee: true,
showContentType: true,
}}
/>Stage colors flow through the synthesized FlowDefinition into flow-board-ui columns.
Stage resolution
Cards are placed by content.workflowStage first, then content.status, then mapping.fallbackStageId, then the first stage. The synthesized flow is a view: the board allows any move and your content API stays the authority on which moves are legal.
Error Handling
All errors are ContentFlowUiError with ES2022 Error.cause chains, surfaced on the hook's error state (client fetch failures never throw into render).
| Class | Code | Description | Retryable |
|-------|------|-------------|-----------|
| ContentFlowUiError | CONTENT_FLOW_UI_ERROR | Generic | Depends on cause |
| ContentFlowUiError | FETCH_FAILED | Workflow/content fetch failed | Yes — refresh() |
| ContentFlowUiError | ADVANCE_FAILED | Board move rejected (API error or unsupported jump) | Sometimes — check cause |
| ContentFlowUiError | MAPPING_ERROR | Workflow has no stages | No — fix workflow |
| ContentFlowUiError | INVALID_OPTIONS | Neither props nor client mode satisfied | No |
Related
@bernierllc/flow-board-ui— the generic kanban this composes@bernierllc/content-flow-adapter— server-side companion mirroring content into real flow-engine flows@bernierllc/content-workflow-ui— editorial widgets (stepper, timeline)
License
SEE LICENSE IN LICENSE — Copyright (c) 2025 Bernier LLC. Limited-use license.
