@open-kingdom/shared-frontend-ui-record-detail

v0.0.2-17

Published

A presentational React shell for showing the details of a single record (lead, opportunity, customer, project — anything with a title, an optional subtitle, optional status / next-action callouts, and one or more content tabs). Composes the `Card`, `Tabs`

Downloads

70

Readme

@open-kingdom/shared-frontend-ui-record-detail

A presentational React shell for showing the details of a single record (lead, opportunity, customer, project — anything with a title, an optional subtitle, optional status / next-action callouts, and one or more content tabs). Composes the Card, Tabs, and CardHeader/CardContent primitives from shared-frontend-ui-primitives into a consistent layout so detail pages across the app look the same.

The component is purely presentational — no data fetching, no Redux, no domain coupling. The host wires data into props.


Exports

| Export | Type | Description | | ------------------- | ----------- | --------------------------------------- | | RecordDetail | component | The detail-page shell. | | RecordDetailProps | interface | Props for RecordDetail. | | RecordDetailTab | interface | One tab descriptor in the tabs array. |


Layout

┌─────────────────────────────────────────────────────┐
│ <Card>                                              │
│   title              [actionsSlot]                  │
│   subtitle?                                         │
│   ──────────────────────────                        │
│   ┌──────────────┐  ┌────────────────┐              │
│   │ statusSlot?  │  │ nextActionSlot?│              │
│   └──────────────┘  └────────────────┘              │
│ </Card>                                             │
│                                                     │
│ ┌── Tabs ─────────────────────────────────┐         │
│ │ [tab 1] [tab 2] [tab 3]                 │         │
│ │ active tab content                      │         │
│ └─────────────────────────────────────────┘         │
└─────────────────────────────────────────────────────┘

The status and next-action callouts render in a 2-column grid on sm+ viewports and stack on mobile. The whole status / next-action CardContent block is omitted entirely when neither slot is provided.


Props

RecordDetailProps

| Prop | Type | Required | Default | Description | | ---------------- | ---------------------------- | -------- | ------------ | --------------------------------------------------------------------------------- | | title | ReactNode | Yes | — | Card title. Truncated with ellipsis on overflow. | | subtitle | ReactNode | No | — | Rendered as CardDescription below the title. | | statusSlot | ReactNode | No | — | Content shown in the "Status" callout. Useful for badges or short labels. | | nextActionSlot | ReactNode | No | — | Content shown in the "Next action" callout. Often a link or button. | | actionsSlot | ReactNode | No | — | Right-aligned action group in the card header. Typically a row of Buttons. | | tabs | readonly RecordDetailTab[] | Yes | — | At least one tab is required — passing an empty array throws. | | defaultTabId | string | No | tabs[0].id | Initial active tab when uncontrolled. | | value | string | No | — | Controlled active-tab id. When provided, onValueChange should also be provided. | | onValueChange | (value: string) => void | No | — | Fired when the active tab changes. | | className | string | No | — | Extra classes merged onto the outer wrapper. |

RecordDetailTab

| Property | Type | Required | Description | | ---------- | ----------- | -------- | ----------------------------------------------------------------------------- | | id | string | Yes | Stable tab identifier. Used as the <TabsTrigger> and <TabsContent> value. | | label | string | Yes | Trigger label. | | content | ReactNode | Yes | Body rendered inside <TabsContent> when this tab is active. | | disabled | boolean | No | Disables the trigger. |

Throwing on empty tabs is intentional — a record with no tabs is a usage error, not a runtime fallback condition.


Usage

import { RecordDetail, type RecordDetailTab } from '@open-kingdom/shared-frontend-ui-record-detail';
import { Button } from '@open-kingdom/shared-frontend-ui-primitives';

const tabs: RecordDetailTab[] = [
  { id: 'overview', label: 'Overview', content: <OverviewTab leadId={lead.id} /> },
  { id: 'activity', label: 'Activity', content: <ActivityTab leadId={lead.id} /> },
  { id: 'audit', label: 'Audit log', content: <AuditTab leadId={lead.id} />, disabled: !canSeeAudit },
];

<RecordDetail
  title={lead.name}
  subtitle={lead.companyName ?? undefined}
  statusSlot={<StatusBadge status={lead.status} />}
  nextActionSlot={lead.nextActivity ? <NextActionLink activity={lead.nextActivity} /> : 'No follow-up scheduled'}
  actionsSlot={
    <>
      <Button variant="outline" onClick={onEdit}>
        Edit
      </Button>
      <Button onClick={onConvert}>Convert</Button>
    </>
  }
  tabs={tabs}
/>;

Controlled tabs

const [tab, setTab] = useSearchParam('tab', 'overview');

<RecordDetail value={tab} onValueChange={setTab} tabs={tabs} title={…} />;

Tailwind classes

Uses semantic palette classes from shared-frontend-ui-theme (bg-muted/40, text-foreground, border-border, etc.). The host's Tailwind config must include this library's source files in its content glob.


Testing

nx test shared-frontend-ui-record-detail