Draggable and static board ticket card components for a kanban-style board view, providing both a card that registers its own drag and drop behaviour and a standalone presentational variant. ## Key Components | Export | Type | Description | |---|---|---| | `TicketCardBody` | Component | Pure presentational inner content — title, device/org row, priority flag, assignees, tags, timestamp, new message badge, and approval row | | `TicketCardView` | Component | Static, non-draggable card using the same shell and body as the board card; suitable for embeds, previews, and marketing | | `TicketCard` | Component | Full board card: registers itself as both draggable and drop target, fades in place while carried, draws the insertion line for the shared aim, and supports an optional `href` link plus drag/drop-disabled state | | `TicketCardBodyProps` | Interface | Props for the shared body: `ticket`, `columnColor`, `renderAssignSlot`, `onApprove`, `onReject` | | `TicketCardProps` | Interface | Extends body props with `columnId`, `href`, `dragDisabled`, `dropDisabled`, `allowedFromColumns`, and board-aware approve/reject signatures | **Nothing about the lane moves during a drag.** The card being carried stays exactly where it is, faded (0.4), and where it would land is drawn as a **line** on the nearest edge of the card it would displace — matched on the lane as well as the card id, because a ticket mid-status-change is briefly listed by two lanes at once. No room opens, no slot closes, so there is no layout to keep balanced and no lane height to wander. A no-op slot (the card's own place) draws nothing. That is a performance decision as much as a visual one. Opening a card's worth of room and drawing a copy of the card in it costs a lane relayout plus a whole card render — avatars, tags, tooltips, the host's assignee slot — on every edge flip, and the flips come as fast as the pointer moves. The line is one absolutely positioned span and says the same thing. The card under the pointer is the browser's **native drag image** — a DOM clone of the card, taken in `onGenerateDragPreview` (`setCustomNativeDragPreview` + `preserveOffsetOnSource`), at 0.9 opacity with a held shadow. A clone, not a second React tree: it is a photograph of exactly what is on screen, assignee slot included, with no providers to re-supply. Native, not a positioned element: an element in the page cannot leave the page, so a hand-drawn preview froze whenever the pointer crossed into the browser's own chrome. After the drop the board shows the move immediately (see `pending-move.ts`); the landed card is hidden under the portal copy gliding into its slot (`useIsLanding`) for the 160ms of that flight, and no longer than that. **Constants:** `MAX_VISIBLE_TAGS = 2`, `MAX_VISIBLE_ASSIGNEES = 3`, `PRIORITY_COLOR_CLASS` maps `low | medium | high | urgent` to ODS color tokens. ## Usage Example ```typescript // Draggable board card (inside a ) handleApprove(ticketId, requestId)} onReject={(ticketId, requestId) => handleReject(ticketId, requestId)} /> // Static preview card (renders anywhere, registers nothing) // Body only, composed into a custom shell } /> ``` **Source:** [`ticket-card.tsx`](https://github.com/flamingo-stack/openframe-oss-lib/blob/main/ticket-card.tsx)