--- ## CitationChip Compact source marker rendered for a `[id]` citation. StreamingMarkdown wires it up automatically from its `sources` prop — each in-text marker becomes a CitationChip whose click opens a Popover with the source title, snippet, and a policy-checked outbound link. Also usable standalone for source footers / reference lists outside a streamed message. **Import:** `import { CitationChip } from '@urbicon-ui/blocks';` ### Variants - citationStyle: label, numeric (default: numeric) ### Api | Prop | Type | Required | Default | Description | | --- | --- | :---: | --- | --- | | source | `CitationSource` | yes | | The cited source. Required. | | ...HTMLButtonAttributes | `HTMLAttributes` | no | | HTML attributes (excluding: 'class' | 'children') | | citationStyle | `'numeric' | 'label'` | no | 'numeric' | What the chip shows: `numeric` renders `index` (or `source.id` as a fallback) as a compact numeric pill; `label` renders the (truncated) `source.title`. | | class | `string` | no | | Extra classes merged onto the trigger chip (the root slot). | | index | `number` | no | | 1-based ordinal shown as the chip label under `citationStyle="numeric"`. Falls back to `source.id` when omitted. | | label | `string` | no | | Override the trigger's `aria-label`. Defaults to `Source {index}: {title}` (or `Source: {title}` without an index). | | openLabel | `string` | no | 'Open source' | Text of the outbound link in the popover. | | preset | `string` | no | | Apply a named preset registered via ``. Prefer this over `class` overrides when the requested look falls outside the semantic intent palette. | | slotClasses | `Partial>` | no | | Per-slot class overrides. Slots: `trigger` (root chip), `popover` (content wrapper), `title`, `snippet`, `link`, `linkIcon`. | | unstyled | `boolean` | no | | Strip all default tv() classes; combine with `class` / `slotClasses` for a custom look. | | urlPolicy | `MarkdownUrlPolicy` | no | | URL policy applied to `source.url` before it becomes a link (same strict default as the streaming-markdown engine — untrusted LLM output). A blocked URL yields no link in the popover, only title/snippet. | Inherited from: - Omit (omit-pattern) ### Types ```ts interface CitationSource { /** Stable id — matches the `[id]` marker in the streamed markdown. */ id: string; /** Human-readable source title, always shown in the popover (and as the chip label under `citationStyle="label"`). */ title: string; /** Source URL. Rendered as an outbound link only when it passes the `urlPolicy`; a blocked or absent URL shows title/snippet with no link. */ url?: string; /** Short excerpt shown under the title, clamped to ~3 lines. */ snippet?: string; } ``` ```ts interface MarkdownUrlPolicy { /** * Allowed link protocols (with trailing colon). Relative URLs are always * allowed for links. @default ['http:', 'https:', 'mailto:', 'tel:'] */ allowedLinkProtocols?: string[]; /** * Prefix allowlist for image sources, matched against the normalized * absolute URL. Empty (the default) blocks every external image; relative * sources are allowed. Prefer deep, specific prefixes — broad ones are * open-redirect bait. `data:` images are blocked unless a `data:` prefix * is listed explicitly. * @default [] */ allowedImagePrefixes?: string[]; /** Observability hook — fires once per blocked URL occurrence. */ onBlocked?: (kind: 'link' | 'image', url: string) => void; } ``` ```ts type SlotNames = keyof ReturnType & string ``` ### Slots (slotClasses keys) `trigger`, `popover`, `title`, `snippet`, `link`, `linkIcon`