2026-03-18 15:17:40 +01:00
import { useState } from 'react'
import styles from './CompositesSection.module.css'
import {
Accordion ,
AlertDialog ,
AreaChart ,
AvatarGroup ,
BarChart ,
Breadcrumb ,
CommandPalette ,
DataTable ,
DetailPanel ,
Dropdown ,
EventFeed ,
FilterBar ,
LineChart ,
MenuItem ,
Modal ,
Popover ,
ProcessorTimeline ,
ShortcutsBar ,
Tabs ,
ToastProvider ,
useToast ,
TreeView ,
} from '../../../design-system/composites'
import type { SearchResult } from '../../../design-system/composites'
import { Button } from '../../../design-system/primitives'
// ── DemoCard helper ──────────────────────────────────────────────────────────
interface DemoCardProps {
id : string
title : string
description : string
children : React.ReactNode
}
function DemoCard ( { id , title , description , children } : DemoCardProps ) {
return (
< div id = { id } className = { styles . componentCard } >
< h3 className = { styles . componentTitle } > { title } < / h3 >
< p className = { styles . componentDesc } > { description } < / p >
< div className = { styles . demoArea } > { children } < / div >
< / div >
)
}
// ── Toast demo inner component (must be inside ToastProvider) ─────────────────
function ToastDemo() {
const { toast } = useToast ( )
return (
< div className = { styles . demoAreaRow } >
< Button size = "sm" variant = "primary" onClick = { ( ) = > toast ( { title : 'Success!' , description : 'Operation completed.' , variant : 'success' } ) } >
Success toast
< / Button >
< Button size = "sm" variant = "secondary" onClick = { ( ) = > toast ( { title : 'Info' , description : 'Something to note.' , variant : 'info' } ) } >
Info toast
< / Button >
< Button size = "sm" variant = "danger" onClick = { ( ) = > toast ( { title : 'Error' , description : 'Something went wrong.' , variant : 'error' } ) } >
Error toast
< / Button >
< Button size = "sm" variant = "ghost" onClick = { ( ) = > toast ( { title : 'Warning' , description : 'Proceed with caution.' , variant : 'warning' } ) } >
Warning toast
< / Button >
< / div >
)
}
// ── Sample data ───────────────────────────────────────────────────────────────
const CHART_SERIES = [
{
label : 'Requests' ,
data : [
{ x : 0 , y : 120 } , { x : 1 , y : 180 } , { x : 2 , y : 150 } ,
{ x : 3 , y : 210 } , { x : 4 , y : 190 } , { x : 5 , y : 240 } ,
] ,
} ,
{
label : 'Errors' ,
data : [
{ x : 0 , y : 5 } , { x : 1 , y : 12 } , { x : 2 , y : 8 } ,
{ x : 3 , y : 15 } , { x : 4 , y : 7 } , { x : 5 , y : 10 } ,
] ,
color : 'var(--error)' ,
} ,
]
const BAR_SERIES = [
{
label : 'GET' ,
data : [
{ x : 'Mon' , y : 80 } , { x : 'Tue' , y : 95 } , { x : 'Wed' , y : 110 } ,
{ x : 'Thu' , y : 72 } , { x : 'Fri' , y : 130 } ,
] ,
} ,
{
label : 'POST' ,
data : [
{ x : 'Mon' , y : 40 } , { x : 'Tue' , y : 55 } , { x : 'Wed' , y : 60 } ,
{ x : 'Thu' , y : 38 } , { x : 'Fri' , y : 75 } ,
] ,
color : 'var(--success)' ,
} ,
]
const COMMAND_PALETTE_DATA : SearchResult [ ] = [
{ id : 'r1' , category : 'route' , title : 'order-ingest' , meta : 'POST /orders/ingest' } ,
{ id : 'r2' , category : 'route' , title : 'payment-validate' , meta : 'POST /payments/validate' } ,
2026-03-18 15:55:54 +01:00
{ id : 'e1' , category : 'exchange' , title : 'exch-001' , meta : 'Started 2m ago' } ,
{ id : 'e2' , category : 'exchange' , title : 'exch-002' , meta : 'Completed 5m ago' } ,
2026-03-18 15:17:40 +01:00
{ id : 'a1' , category : 'agent' , title : 'camel-agent-prod-1' , meta : 'live · 42 tps' } ,
{ id : 'x1' , category : 'exchange' , title : 'exch-aabb1122' , meta : 'route: order-ingest' } ,
]
interface TableRow {
id : string
name : string
method : string
status : string
exchanges : number
}
const TABLE_DATA : TableRow [ ] = [
{ id : '1' , name : 'order-ingest' , method : 'POST' , status : 'live' , exchanges : 1243 } ,
{ id : '2' , name : 'payment-validate' , method : 'POST' , status : 'live' , exchanges : 987 } ,
{ id : '3' , name : 'inventory-check' , method : 'GET' , status : 'stale' , exchanges : 432 } ,
{ id : '4' , name : 'notify-customer' , method : 'POST' , status : 'live' , exchanges : 876 } ,
{ id : '5' , name : 'archive-order' , method : 'PUT' , status : 'dead' , exchanges : 54 } ,
]
const NOW = new Date ( )
const minsAgo = ( n : number ) = > new Date ( NOW . getTime ( ) - n * 60 * 1000 )
const FEED_EVENTS = [
{ id : 'ev1' , severity : 'success' as const , message : 'Route order-ingest started successfully' , timestamp : minsAgo ( 1 ) } ,
{ id : 'ev2' , severity : 'warning' as const , message : 'Agent camel-agent-prod-2 response time elevated' , timestamp : minsAgo ( 3 ) } ,
{ id : 'ev3' , severity : 'error' as const , message : 'Exchange exch-aabb1122 failed: timeout' , timestamp : minsAgo ( 7 ) } ,
{ id : 'ev4' , severity : 'running' as const , message : 'Processor payment-validate processing batch' , timestamp : minsAgo ( 10 ) } ,
{ id : 'ev5' , severity : 'success' as const , message : 'Deployment v3.2.1 completed' , timestamp : minsAgo ( 15 ) } ,
]
const TREE_NODES = [
{
id : 'app1' ,
label : 'cameleer-prod' ,
icon : '⬡' ,
children : [
{
id : 'route1' ,
label : 'order-ingest' ,
icon : '→' ,
children : [
{ id : 'proc1' , label : 'ValidateOrder' , icon : '◈' , meta : '12ms' } ,
{ id : 'proc2' , label : 'EnrichPayload' , icon : '◈' , meta : '8ms' } ,
{ id : 'proc3' , label : 'RouteToQueue' , icon : '◈' , meta : '3ms' } ,
] ,
} ,
{
id : 'route2' ,
label : 'payment-validate' ,
icon : '→' ,
children : [
{ id : 'proc4' , label : 'TokenizeCard' , icon : '◈' , meta : '22ms' } ,
{ id : 'proc5' , label : 'AuthorizePayment' , icon : '◈' , meta : '45ms' } ,
] ,
} ,
] ,
} ,
]
// ── CompositesSection ─────────────────────────────────────────────────────────
export function CompositesSection() {
// 1. Accordion
const accordionItems = [
{ id : 'a1' , title : 'What is Apache Camel?' , content : 'Apache Camel is an open-source integration framework based on enterprise integration patterns.' } ,
{ id : 'a2' , title : 'How do routes work?' , content : 'Routes define the path a message takes through the system, from consumer to producer.' , defaultOpen : true } ,
{ id : 'a3' , title : 'What are processors?' , content : 'Processors transform, filter, enrich, or route messages as they flow through a route.' } ,
]
// 2. AlertDialog
const [ alertOpen , setAlertOpen ] = useState ( false )
const [ alertVariant , setAlertVariant ] = useState < 'danger' | 'warning' | 'info' > ( 'danger' )
// 7. CommandPalette
const [ cmdOpen , setCmdOpen ] = useState ( false )
// 8. DataTable
const tableColumns = [
{ key : 'name' , header : 'Route' , sortable : true } ,
{ key : 'method' , header : 'Method' , sortable : true } ,
{ key : 'status' , header : 'Status' , sortable : true } ,
{ key : 'exchanges' , header : 'Exchanges' , sortable : true } ,
]
// 9. DetailPanel
const [ panelOpen , setPanelOpen ] = useState ( false )
// 12. FilterBar
const filterOptions = [
{ label : 'Live' , value : 'live' , color : 'success' as const , count : 12 } ,
{ label : 'Stale' , value : 'stale' , count : 3 } ,
{ label : 'Dead' , value : 'dead' , color : 'error' as const , count : 1 } ,
]
const [ activeFilters , setActiveFilters ] = useState ( [ { label : 'Live' , value : 'live' } ] )
// 15. Modal
const [ modalOpen , setModalOpen ] = useState ( false )
// 19. Tabs
const tabItems = [
{ label : 'Overview' , value : 'overview' , count : undefined } ,
{ label : 'Routes' , value : 'routes' , count : 14 } ,
{ label : 'Agents' , value : 'agents' , count : 6 } ,
]
const [ activeTab , setActiveTab ] = useState ( 'overview' )
// 21. TreeView
const [ selectedNode , setSelectedNode ] = useState < string | undefined > ( 'proc1' )
return (
< ToastProvider >
< section id = "composites" className = { styles . section } >
< h2 className = { styles . sectionTitle } > Composites < / h2 >
{ /* 1. Accordion */ }
< DemoCard
id = "accordion"
title = "Accordion"
description = "Collapsible panels with single or multiple open mode."
>
< div className = { styles . demoAreaColumn } style = { { width : '100%' } } >
< span className = { styles . demoLabel } > Single mode ( default ) < / span >
< Accordion items = { accordionItems } / >
< span className = { styles . demoLabel } > Multiple mode < / span >
< Accordion
items = { [
{ id : 'm1' , title : 'Section A' , content : 'Content for section A.' } ,
{ id : 'm2' , title : 'Section B' , content : 'Content for section B.' , defaultOpen : true } ,
{ id : 'm3' , title : 'Section C' , content : 'Content for section C.' , defaultOpen : true } ,
] }
multiple
/ >
< / div >
< / DemoCard >
{ /* 2. AlertDialog */ }
< DemoCard
id = "alertdialog"
title = "AlertDialog"
description = "Modal confirmation dialog in danger, warning, and info variants."
>
< div className = { styles . demoAreaRow } >
< Button
size = "sm"
variant = "danger"
onClick = { ( ) = > { setAlertVariant ( 'danger' ) ; setAlertOpen ( true ) } }
>
Danger dialog
< / Button >
< Button
size = "sm"
variant = "secondary"
onClick = { ( ) = > { setAlertVariant ( 'warning' ) ; setAlertOpen ( true ) } }
>
Warning dialog
< / Button >
< Button
size = "sm"
variant = "ghost"
onClick = { ( ) = > { setAlertVariant ( 'info' ) ; setAlertOpen ( true ) } }
>
Info dialog
< / Button >
< / div >
< AlertDialog
open = { alertOpen }
onClose = { ( ) = > setAlertOpen ( false ) }
onConfirm = { ( ) = > setAlertOpen ( false ) }
title = { alertVariant === 'danger' ? 'Delete route?' : alertVariant === 'warning' ? 'Proceed with caution?' : 'Confirm action' }
description = {
alertVariant === 'danger'
? 'This will permanently delete the route and all its exchange history. This action cannot be undone.'
: alertVariant === 'warning'
? 'This operation will restart all active processors. Running exchanges may be interrupted.'
: 'This will update the route configuration and apply changes immediately.'
}
variant = { alertVariant }
confirmLabel = { alertVariant === 'danger' ? 'Delete' : 'Confirm' }
/ >
< / DemoCard >
{ /* 3. AreaChart */ }
< DemoCard
id = "areachart"
title = "AreaChart"
description = "SVG area chart with hover tooltip, threshold line, and legend."
>
< AreaChart series = { CHART_SERIES } xLabel = "Time (minutes)" yLabel = "Count" width = { 420 } height = { 180 } / >
< / DemoCard >
{ /* 4. AvatarGroup */ }
< DemoCard
id = "avatargroup"
title = "AvatarGroup"
description = "Stacked avatar group showing up to max avatars with an overflow count."
>
< div className = { styles . demoAreaColumn } >
< span className = { styles . demoLabel } > max = 3 , size = sm < / span >
< AvatarGroup names = { [ 'Alice Johnson' , 'Bob Smith' , 'Carol White' , 'David Lee' , 'Eve Brown' ] } max = { 3 } size = "sm" / >
< span className = { styles . demoLabel } > max = 4 , size = md < / span >
< AvatarGroup names = { [ 'Alice Johnson' , 'Bob Smith' , 'Carol White' , 'David Lee' , 'Eve Brown' ] } max = { 4 } size = "md" / >
< span className = { styles . demoLabel } > max = 2 , size = lg < / span >
< AvatarGroup names = { [ 'Alice Johnson' , 'Bob Smith' , 'Carol White' , 'David Lee' , 'Eve Brown' ] } max = { 2 } size = "lg" / >
< / div >
< / DemoCard >
{ /* 5. BarChart */ }
< DemoCard
id = "barchart"
title = "BarChart"
description = "Bar chart with grouped and stacked modes, hover tooltips, and legend."
>
< div className = { styles . demoAreaColumn } >
< span className = { styles . demoLabel } > Grouped < / span >
< BarChart series = { BAR_SERIES } width = { 420 } height = { 180 } xLabel = "Day" / >
< span className = { styles . demoLabel } > Stacked < / span >
< BarChart series = { BAR_SERIES } stacked width = { 420 } height = { 180 } xLabel = "Day" / >
< / div >
< / DemoCard >
{ /* 6. Breadcrumb */ }
< DemoCard
id = "breadcrumb"
title = "Breadcrumb"
description = "Slash-separated navigation breadcrumb with linked and plain segments."
>
< Breadcrumb
items = { [
{ label : 'Dashboard' , href : '#' } ,
{ label : 'Applications' , href : '#' } ,
{ label : 'order-ingest' } ,
] }
/ >
< / DemoCard >
{ /* 7. CommandPalette */ }
< DemoCard
id = "commandpalette"
title = "CommandPalette"
description = "Full-screen search palette with category tabs, keyboard navigation, and highlight."
>
< Button size = "sm" variant = "secondary" onClick = { ( ) = > setCmdOpen ( true ) } >
Open CommandPalette
< / Button >
< CommandPalette
open = { cmdOpen }
onClose = { ( ) = > setCmdOpen ( false ) }
onSelect = { ( ) = > setCmdOpen ( false ) }
data = { COMMAND_PALETTE_DATA }
/ >
< / DemoCard >
{ /* 8. DataTable */ }
< DemoCard
id = "datatable"
title = "DataTable"
description = "Sortable, paginated table with row click, accent rows, and page size selector."
>
< div style = { { width : '100%' } } >
< DataTable
columns = { tableColumns }
data = { TABLE_DATA }
sortable
pageSize = { 5 }
/ >
< / div >
< / DemoCard >
{ /* 9. DetailPanel */ }
< DemoCard
id = "detailpanel"
title = "DetailPanel"
description = "Slide-in side panel with tabbed content and close button."
>
< Button size = "sm" variant = "secondary" onClick = { ( ) = > setPanelOpen ( true ) } >
Open DetailPanel
< / Button >
< DetailPanel
open = { panelOpen }
onClose = { ( ) = > setPanelOpen ( false ) }
title = "Route: order-ingest"
tabs = { [
{ label : 'Overview' , value : 'overview' , content : < div style = { { padding : '12px 0' , fontSize : 13 } } > Route processes ~ 1 , 243 exchanges / day with avg latency 42 ms . < / div > } ,
{ label : 'Processors' , value : 'processors' , content : < div style = { { padding : '12px 0' , fontSize : 13 } } > ValidateOrder → EnrichPayload → RouteToQueue < / div > } ,
{ label : 'Errors' , value : 'errors' , content : < div style = { { padding : '12px 0' , fontSize : 13 } } > 3 errors in last 24 h . Last : timeout at EnrichPayload . < / div > } ,
] }
/ >
< / DemoCard >
{ /* 10. Dropdown */ }
< DemoCard
id = "dropdown"
title = "Dropdown"
description = "Click-triggered dropdown menu with icons, dividers, and disabled items."
>
< Dropdown
trigger = { < Button size = "sm" variant = "secondary" > Actions ▾ < / Button > }
items = { [
{ label : 'View details' , icon : '👁' , onClick : ( ) = > undefined } ,
{ label : 'Edit route' , icon : '✏' , onClick : ( ) = > undefined } ,
{ divider : true , label : '' } ,
{ label : 'Restart' , icon : '↺' , onClick : ( ) = > undefined } ,
{ label : 'Delete' , icon : '✕' , onClick : ( ) = > undefined , disabled : true } ,
] }
/ >
< / DemoCard >
{ /* 11. EventFeed */ }
< DemoCard
id = "eventfeed"
title = "EventFeed"
description = "Scrollable live event log with severity filters and auto-scroll."
>
< div style = { { width : '100%' } } >
< EventFeed events = { FEED_EVENTS } maxItems = { 10 } / >
< / div >
< / DemoCard >
{ /* 12. FilterBar */ }
< DemoCard
id = "filterbar"
title = "FilterBar"
description = "Search input combined with filter pills and active filter tag chips."
>
< div style = { { width : '100%' } } >
< FilterBar
filters = { filterOptions }
activeFilters = { activeFilters }
onFilterChange = { setActiveFilters }
searchPlaceholder = "Search routes..."
/ >
< / div >
< / DemoCard >
{ /* 13. LineChart */ }
< DemoCard
id = "linechart"
title = "LineChart"
description = "Multi-series SVG line chart with hover crosshair, tooltip, and legend."
>
< LineChart series = { CHART_SERIES } xLabel = "Time (minutes)" yLabel = "Count" width = { 420 } height = { 180 } / >
< / DemoCard >
{ /* 14. MenuItem */ }
< DemoCard
id = "menuitem"
title = "MenuItem"
description = "Navigation menu row with health dot, meta text, count badge, and active state."
>
< div className = { styles . demoAreaColumn } style = { { minWidth : 200 } } >
< MenuItem label = "order-ingest" meta = "POST route" count = { 1243 } health = "live" / >
< MenuItem label = "payment-validate" meta = "POST route" count = { 987 } health = "live" active / >
< MenuItem label = "inventory-check" meta = "GET route" count = { 432 } health = "stale" / >
< MenuItem label = "archive-order" meta = "PUT route" count = { 54 } health = "dead" indent = { 1 } / >
< / div >
< / DemoCard >
{ /* 15. Modal */ }
< DemoCard
id = "modal"
title = "Modal"
description = "Portal-rendered modal dialog in sm, md, and lg sizes with backdrop dismiss."
>
< Button size = "sm" variant = "secondary" onClick = { ( ) = > setModalOpen ( true ) } >
Open Modal
< / Button >
< Modal
open = { modalOpen }
onClose = { ( ) = > setModalOpen ( false ) }
title = "Configure Route"
size = "md"
>
< div style = { { fontSize : 13 , lineHeight : 1.6 } } >
< p style = { { margin : '0 0 12px' } } > Adjust the route settings below . Changes will take effect immediately after saving . < / p >
< p style = { { margin : 0 , color : 'var(--text-muted)' } } > Route : order - ingest · Processor chain : 3 steps · Avg latency : 42ms < / p >
< / div >
< / Modal >
< / DemoCard >
{ /* 16. Popover */ }
< DemoCard
id = "popover"
title = "Popover"
description = "Portal-positioned popover in all four positions with arrow indicator."
>
< div className = { styles . demoAreaRow } style = { { paddingTop : 8 , paddingBottom : 8 } } >
< Popover
position = "top"
trigger = { < Button size = "sm" variant = "secondary" > Top < / Button > }
content = { < div style = { { padding : '8px 12px' , fontSize : 12 } } > Popover on top < / div > }
/ >
< Popover
position = "bottom"
trigger = { < Button size = "sm" variant = "secondary" > Bottom < / Button > }
content = { < div style = { { padding : '8px 12px' , fontSize : 12 } } > Popover on bottom < / div > }
/ >
< Popover
position = "left"
trigger = { < Button size = "sm" variant = "secondary" > Left < / Button > }
content = { < div style = { { padding : '8px 12px' , fontSize : 12 } } > Popover on left < / div > }
/ >
< Popover
position = "right"
trigger = { < Button size = "sm" variant = "secondary" > Right < / Button > }
content = { < div style = { { padding : '8px 12px' , fontSize : 12 } } > Popover on right < / div > }
/ >
< / div >
< / DemoCard >
{ /* 17. ProcessorTimeline */ }
< DemoCard
id = "processortimeline"
title = "ProcessorTimeline"
description = "Horizontal Gantt-style timeline showing processor execution order, duration, and status."
>
< div style = { { width : '100%' } } >
< ProcessorTimeline
totalMs = { 120 }
processors = { [
{ name : 'ValidateOrder' , type : 'validator' , durationMs : 12 , status : 'ok' , startMs : 0 } ,
{ name : 'EnrichPayload' , type : 'enricher' , durationMs : 35 , status : 'slow' , startMs : 12 } ,
{ name : 'RouteToQueue' , type : 'router' , durationMs : 8 , status : 'ok' , startMs : 47 } ,
{ name : 'AuditLog' , type : 'logger' , durationMs : 65 , status : 'fail' , startMs : 55 } ,
] }
/ >
< / div >
< / DemoCard >
{ /* 18. ShortcutsBar */ }
< DemoCard
id = "shortcutsbar"
title = "ShortcutsBar"
description = "Row of keyboard shortcut hints, each pairing a key badge with a label."
>
< ShortcutsBar
shortcuts = { [
{ keys : 'Ctrl+K' , label : 'Search' } ,
{ keys : '↑↓' , label : 'Navigate' } ,
{ keys : 'Enter' , label : 'Open' } ,
{ keys : 'Esc' , label : 'Close' } ,
{ keys : '?' , label : 'Help' } ,
] }
/ >
< / DemoCard >
{ /* 19. Tabs */ }
< DemoCard
id = "tabs"
title = "Tabs"
description = "Tab bar with optional count badges and active indicator."
>
< div className = { styles . demoAreaColumn } style = { { width : '100%' } } >
< Tabs tabs = { tabItems } active = { activeTab } onChange = { setActiveTab } / >
< div style = { { fontSize : 13 , color : 'var(--text-muted)' } } >
Active tab : < strong > { activeTab } < / strong >
< / div >
< / div >
< / DemoCard >
{ /* 20. Toast */ }
< DemoCard
id = "toast"
title = "Toast"
description = "Stacked portal toast notifications in four variants with auto-dismiss and manual close."
>
< ToastDemo / >
< / DemoCard >
{ /* 21. TreeView */ }
< DemoCard
id = "treeview"
title = "TreeView"
description = "Keyboard-navigable tree showing App → Routes → Processors hierarchy."
>
< TreeView
nodes = { TREE_NODES }
selectedId = { selectedNode }
onSelect = { setSelectedNode }
/ >
< / DemoCard >
< / section >
< / ToastProvider >
)
}