List item
Sessions: tab / click a row to select (one cyan indicator)
Settings: value rows, a disabled row, and a trailing control (toggle = its own target)
Messages: tap a row to expand (chevron rotates down, then up); tap again to collapse
Selected session: s2 · push notifications on · open message: m1. The island is live.
// Web: React, consuming @dizyx/nockerl-tokens. (Web is the laggard platform;// this is the canonical API the published @dizyx/nockerl-react package exposes.)import { NockerlListItem } from '@dizyx/nockerl-react';
export function SessionList({ sessions, activeId, onSelect }: SessionListProps) { return ( <div className="nk-card" role="listbox" aria-label="Sessions"> {sessions.map((s) => ( <NockerlListItem key={s.id} primary={s.name} secondary={s.statusLine} status={s.status} // 'success' | 'warning' | 'error' | 'info', never cyan value={s.timeAgo} chevron selected={s.id === activeId} onSelect={() => onSelect(s.id)} /> ))} </div> );}// Android (Jetpack Compose). PUBLISHED: the NockerlListItem grammar in// com.dizyx.nockerl.design.components (com.dizyx.nockerl.design on GitHub Packages Maven):// the row scaffold NockerlListItemRow + the unified leading NockerlLeadingStatusMark// (a status ICON at NockerlListItemDefaults.LeadingMarkSize, 18dp).import com.dizyx.nockerl.design.components.NockerlListItemRowimport com.dizyx.nockerl.design.components.NockerlLeadingStatusMark
// The row scaffold applies NO height/padding/background/click. The caller supplies// them via `modifier`, so the dense tree and the card body both keep their own anatomy.NockerlListItemRow( leadingMark = { NockerlLeadingStatusMark( icon = statusIcon(task.status), // shape + color, from a semantic mapping tint = statusColor(task.status), // status color, never the brand cyan contentDescription = task.status.displayName, ) }, modifier = Modifier .fillMaxWidth() .clickable(onClick = { onSelect(task) }) .padding(horizontal = 16.dp, vertical = 12.dp), trailing = { Icon(Icons.Default.ChevronRight, contentDescription = null) },) { // RowScope body: each list fills its own anatomy (ticket # + title + subtask badge). Text(task.ticket, style = MaterialTheme.typography.labelMedium) Spacer(Modifier.width(8.dp)) Text(task.title, style = MaterialTheme.typography.bodyMedium, modifier = Modifier.weight(1f))}
// A configuration row. The same scaffold fills its body with label + value; the// caller owns padding/click via `modifier`, and the trailing slot carries a chevron.NockerlListItemRow( leadingMark = { NockerlLeadingStatusMark( icon = Icons.Default.Palette, tint = LocalNockerlColors.current.onCardMuted, contentDescription = null, // the adjacent "Theme" label names it ) }, modifier = Modifier .fillMaxWidth() .clickable(onClick = ::openThemePicker) .padding(horizontal = 16.dp, vertical = 12.dp), trailing = { Icon(Icons.Default.ChevronRight, contentDescription = null) },) { Text("Theme", style = MaterialTheme.typography.bodyMedium, modifier = Modifier.weight(1f)) Text("System", style = MaterialTheme.typography.bodyMedium, color = LocalNockerlColors.current.onCardMuted)}// macOS SwiftUI (Voice). NockerlVoice/UI/HistoryView.swift// There is NO extracted list-item component on Swift yet; rows are built INLINE.// This is the shipped HistoryView row pattern (the page documents the intended grammar).private func row(_ record: TranscriptionRecord) -> some View { HStack(spacing: 10) { Button { toggle(record.id) } label: { // whole row = one tap target HStack(spacing: 8) { ProviderBadge(text: record.provider.badge) // leading mark (status-tinted) Text(record.createdAt, format: .dateTime.month().day().hour().minute()) .font(.system(size: 11)) .foregroundStyle(NockerlTheme.onSurfaceMuted) Text(oneLine(record.text)) // primary text .font(.system(size: 13)) .foregroundStyle(NockerlTheme.onSurface) .lineLimit(1) .frame(maxWidth: .infinity, alignment: .leading) } .contentShape(Rectangle()) } .buttonStyle(.plain)
NockerlIconButton(systemName: "doc.on.doc", tint: NockerlTheme.accent, help: "Copy") { copy(record) } NockerlIconButton(systemName: "trash", tint: NockerlTheme.error, help: "Delete") { delete(record) } } .padding(.horizontal, 14).padding(.vertical, 10) // Rows are FLAT: the wrapping ScrollView's card carries the elevation, and a // 1pt hairline (not a shadow) separates rows.}Parameters
Section titled “Parameters”| Prop | Type | Default | Description |
|---|---|---|---|
primary * | string | Primary text. Carries the row's accessible name (label.large role). | |
secondary | string | Optional supporting line under the primary text (body.small role). | |
status | NockerlListItemStatus | Optional leading status mark: renders the canonical B20 status ICON (shape + color dual-coding, never a bare dot) in the status color. Status colors only, never cyan. | |
leadingIcon | React.ReactNode | Optional leading ICON (any node) for action rows (share / rename / delete). Shown in the leading slot when the row is neither selected nor carrying a status mark. | |
danger | boolean | false | Destructive treatment. The primary text + leading icon go status-error (a delete row). |
value | string | Optional trailing value text (e.g. a count, a timestamp). | |
trailing | React.ReactNode | Optional trailing NODE (a NockerlBadge / NockerlChip / status pill) shown before the chevron. For rich rows: an accordion header's tone pill, a tool-card's state chip. Compose a real component (NockerlBadge / NockerlStatusDisc / NockerlChip), never a hand-rolled facsimile. | |
chevron | boolean | false | Show a trailing NAV chevron (right-pointing, for genuinely navigational rows). |
expandable | boolean | false | Make the row an accordion: trailing chevron points DOWN at rest, rotates UP when expanded; the row gets aria-expanded + aria-controls and reveals a body region below it. Mutually exclusive with the nav chevron. |
expanded | boolean | false | Expanded state for an expandable row; drives the chevron rotation + body reveal. |
onToggle | () => void | Toggle handler for an expandable row (whole-row tap). Ignored while disabled. | |
details | React.ReactNode | The body of an expandable row, revealed when the row expands. | |
selected | boolean | false | Selected state: soft cyan wash + a LEADING check. NOT a glow, not a left-rail. |
disabled | boolean | false | Inert + clearly-seen (never invisible) state. |
onSelect | () => void | Activate handler (whole-row tap). Ignored while disabled. |
Also accepts the native <button> attributes (e.g. onClick, disabled, id, aria-*, data-*), forwarded straight through, plus a forwarded ref.
NockerlListItemRow is the row scaffold; it applies no height, padding, background, or
click of its own. Callers supply those via modifier, so each list keeps its own anatomy.
The leading mark is the canonical NockerlLeadingStatusMark.
| Parameter | Type | Default | Description |
|---|---|---|---|
leadingMark * | @Composable -> Unit | The leading status mark slot, typically a NockerlLeadingStatusMark. | |
modifier | Modifier | Modifier | Outer modifier: the caller supplies height, padding, background, and click here (the row adds none). |
trailing | (@Composable -> Unit)? | null | Optional trailing content pinned after the body (e.g. a chevron). |
content * | RowScope.() -> Unit | The row body, laid out in a RowScope between the leading mark and any trailing content. | |
icon * | ImageVector | NockerlLeadingStatusMark: the status icon (from a semantic statusIcon mapping). | |
tint * | Color | NockerlLeadingStatusMark: the status color (a semantic statusColor token). Never a raw Color(0x…) or the brand cyan. | |
contentDescription * | String? | NockerlLeadingStatusMark: accessibility label for the status; null only when an adjacent label already names it. | |
size | Dp | LeadingMarkSize (18.dp) | NockerlLeadingStatusMark: mark size; defaults to the canonical shared 18dp. |
SwiftUI (Voice) has no extracted list-item component. Rows are composed inline from
an HStack whose label Button (.buttonStyle(.plain)) is the whole-row tap target, plus
trailing NockerlIconButtons. There is no parameterized API to table; these are the inline
building blocks the shipped HistoryView row uses. Tracked as a conformance item below.
| Style | Type | Default | Description |
|---|---|---|---|
Button(.plain) | ButtonStyle | Wraps the row content (leading badge + text) so the whole row is one tap target with one accessible name; .contentShape(Rectangle()) makes the full width tappable. | |
ProviderBadge | View | The leading mark, a small capsule tag tinted by NockerlTheme.accent / a status color (the inline stand-in for NockerlLeadingStatusMark). | |
NockerlIconButton | View | A trailing CONTROL (copy / delete) that is a separate focusable target from the row, with its own help / accessibility label. | |
Rectangle (hairline) | View | A 1pt NockerlTheme.hairline bottom overlay separates rows; depth is the wrapping card, not a per-row shadow. |