{"$schema":"https://ui.shadcn.com/schema/registry-item.json","name":"marker","type":"registry:component","title":"Marker","description":"A labelled point in a stream: a status event with an icon between messages, or a label such as \"Today\" between two hairlines.","categories":["display"],"dependencies":["@radix-ui/react-direction@1.1.4","clsx@^2.1.1","tailwind-merge@^3.7.0"],"registryDependencies":["https://beamline.io/registry/look-prism.json"],"files":[{"path":"beamline/components/marker/defaults.ts","type":"registry:file","target":"src/ui/beamline/components/marker/defaults.ts","content":"/** Pure allowed presentation defaults for Marker; no component or runtime imports. */\nexport interface MarkerDefaults {\n  /** Shared variant setting; omit to inherit the surrounding scope or the component default. */\n  variant?: \"event\" | \"divider\";\n  /** Shared tone setting; omit to inherit the surrounding scope or the component default. */\n  tone?: \"danger\" | \"accent\" | \"success\" | \"warning\" | \"neutral\";\n}\n"},{"path":"beamline/components/marker/marker.module.css","type":"registry:file","target":"src/ui/beamline/components/marker/marker.module.css","content":"@layer properties, theme, base, components, utilities;\n@layer components {\n  /* The time stands at the end of the line it falls on, so a stream of markers reads its times as one column, and in\n     a narrow room it simply rides the last line of the words. No containment: a marker can sit in a row and keep its\n     own width. */\n  .root {\n    display: flex;\n    align-items: center;\n    gap: var(--pui-space-2);\n    min-width: 0;\n    color: var(--pui-ink-2);\n    font-size: var(--pui-text-sm);\n    line-height: 1.4;\n    list-style: none;\n  }\n  .icon {\n    display: grid;\n    place-items: center;\n    flex: none;\n    width: 16px;\n    height: 16px;\n    color: var(--pui-ink-3);\n    transition: color var(--pui-motion-out) var(--pui-ease-default);\n  }\n  .icon > svg {\n    width: 14px;\n    height: 14px;\n  }\n  .label {\n    min-width: 0;\n    flex: 1;\n  }\n  /* the time floats to the end of the line it falls on, so words (and links in them) flow as written */\n  .label :is(time, [data-slot=\"marker-meta\"]) {\n    float: inline-end;\n    margin-inline-start: var(--pui-space-3);\n    color: var(--pui-ink-3);\n    font-variant-numeric: tabular-nums;\n    /* a time keeps its own order inside a right-to-left line (O1 §13 D2) */\n    unicode-bidi: isolate;\n  }\n  .root[data-tone=\"accent\"] .icon {\n    color: var(--pui-accent-ink);\n  }\n  .root[data-tone=\"success\"] .icon {\n    color: var(--pui-green);\n  }\n  .root[data-tone=\"warning\"] .icon {\n    color: var(--pui-orange);\n  }\n  .root[data-tone=\"danger\"] .icon {\n    color: var(--pui-red);\n  }\n  /* Divider: a quiet label centred between two hairlines. */\n  .root[data-variant=\"divider\"] {\n    gap: var(--pui-space-3);\n    color: var(--pui-ink-3);\n    font-size: var(--pui-text-xs);\n    font-weight: var(--pui-weight-medium);\n  }\n  .root[data-variant=\"divider\"] .label {\n    flex: none;\n  }\n  .root[data-variant=\"divider\"]::before,\n  .root[data-variant=\"divider\"]::after {\n    content: \"\";\n    flex: 1;\n    height: 1px;\n    background: var(--pui-line-soft);\n  }\n}\n"},{"path":"beamline/components/marker/marker.tsx","type":"registry:file","target":"src/ui/beamline/components/marker/marker.tsx","content":"\"use client\";\n\nimport { useComponentDefaults } from \"../../runtime/appearance\";\nimport type { MarkerDefaults } from \"./defaults\";\nexport type { MarkerDefaults } from \"./defaults\";\n\nimport { type ComponentProps, type ComponentPropsWithoutRef, type ElementType, type Ref } from \"react\";\nimport { cn } from \"../../lib/utils\";\nimport styles from \"./marker.module.css\";\n\nexport type MarkerTone = \"neutral\" | \"accent\" | \"success\" | \"warning\" | \"danger\";\n\nexport interface MarkerProps extends ComponentPropsWithoutRef<\"div\"> {\n  /** `event`: an icon and a line of status in a timeline or thread. `divider`: a label between two hairlines (a day, a phase). */\n  variant?: \"event\" | \"divider\";\n  /** Colours the icon only; the words stay readable ink. */\n  tone?: MarkerTone;\n  /** The element to render: `li` inside a list, `div` elsewhere. */\n  as?: \"div\" | \"li\";\n  ref?: Ref<HTMLElement>;\n}\n\n/**\n * A labelled point in a stream: \"✓ Build passed in 42s\" between messages, or \"Today\" between two days. Compose\n * `Marker` › `MarkerIcon` (optional) › `MarkerLabel`; the label can hold a time or a link.\n */\nexport function Marker({\n  variant: variantProp,\n  tone: toneProp,\n  as = \"div\",\n  className,\n  children,\n  ...props\n}: MarkerProps) {\n  const scopeDefaults = useComponentDefaults<MarkerDefaults>(\"marker\", [\"variant\", \"tone\"]);\n  const variant = variantProp ?? scopeDefaults.variant ?? \"event\";\n  const tone = toneProp ?? scopeDefaults.tone ?? \"neutral\";\n\n  const Tag = as as ElementType;\n  return (\n    <Tag\n      role={variant === \"divider\" && as !== \"li\" ? \"separator\" : undefined}\n      data-slot=\"marker\"\n      data-variant={variant}\n      data-tone={tone}\n      className={cn(styles.root, className)}\n      {...props}\n    >\n      {children}\n    </Tag>\n  );\n}\n\nexport function MarkerIcon({ className, ...props }: ComponentProps<\"span\">) {\n  return <span data-slot=\"marker-icon\" aria-hidden className={cn(styles.icon, className)} {...props} />;\n}\n\nexport function MarkerLabel({ className, ...props }: ComponentProps<\"span\">) {\n  return <span data-slot=\"marker-label\" className={cn(styles.label, className)} {...props} />;\n}\n\nexport default Marker;\n"},{"path":"beamline/lib/utils.ts","type":"registry:file","target":"src/ui/beamline/lib/utils.ts","content":"import { clsx, type ClassValue } from \"clsx\";\nimport { extendTailwindMerge } from \"tailwind-merge\";\n\n/* The type roles (utilities.css) and the 2xs step are sizes, not text colours: without this, tailwind-merge reads\n   `text-overline` as a colour and drops it next to `text-ink-3`. A role and a size step still replace each other.\n   Likewise `font-title` is the look's title weight, not a family: read as a family it dropped `font-display` beside it,\n   and every merged page title lost the look's display face. */\nconst twMerge = extendTailwindMerge({\n  extend: {\n    classGroups: {\n      \"font-weight\": [{ font: [\"title\"] }],\n      \"font-family\": [{ font: [\"display\", \"numeric\", \"figure\"] }],\n      \"font-size\": [\n        {\n          text: [\n            \"2xs\",\n            \"display\",\n            \"title\",\n            \"heading\",\n            \"subheading\",\n            \"body\",\n            \"body-sm\",\n            \"reading\",\n            \"label\",\n            \"caption\",\n            \"overline\",\n            \"numeric\",\n            \"code\",\n          ],\n        },\n      ],\n    },\n  },\n});\n\n/** Merge class names, letting later Tailwind utilities win over earlier ones. */\nexport function cn(...inputs: ClassValue[]) {\n  return twMerge(clsx(inputs));\n}\n\n/** A small seeded random generator (LCG): the same seed gives the same sequence, for stable sample data and jitter. */\nexport function rng(seed = 1) {\n  let s = seed >>> 0 || 1;\n  return () => (s = (s * 1664525 + 1013904223) >>> 0) / 2 ** 32;\n}\n\nexport const clamp = (value: number, min: number, max: number) => Math.min(max, Math.max(min, value));\n"}],"docs":"Marker is in src/ui/beamline/components/marker/marker.tsx. The source is in src/ui/beamline (ui/beamline in a project without src/). After Tailwind, import its styles/beamline.css once, then styles/look-prism.css in your app stylesheet (use relative paths). Keep the shared base before all chosen looks. Wrap your app in <UIRoot preset={prism}> with UIRoot from its runtime/appearance and prism from its looks/prism.  shadcn replaces files when asked; use the Beamline managed-source CLI from the start for three-way upgrades that preserve edits.","meta":{"free":true,"version":"0.2.0-rc.42","library":"https://beamline.io/components/marker"}}