CngxTimelineMarker
projects/common/timeline/marker.component.ts
Import#
import { CngxTimelineMarker } from '@cngx/common/timeline'
Description#
The dot on the timeline rail - a status-coloured slot host for whatever the consumer projects into it (nothing, a glyph, an icon, an avatar).
Purely decorative and marked aria-hidden: the status it paints is
already carried semantically by the owning CngxTimelineItem, and
announcing it twice is worse than not announcing it here at all. That
also means colour is never this atom's only signal - the item's ARIA is.
Usable standalone. It ships its own token SET rules, so a marker
dropped into a hand-rolled layout renders at the right size and tracks
[data-density] with no timeline organism above it.
Bare dot
<cngx-timeline-marker status="done" />With a projected glyph
<cngx-timeline-marker status="rejected">!</cngx-timeline-marker>Pending
<cngx-timeline-marker status="active" busy />Metadata#
Host#
Relationships
Index#
HostBindings
Inputs#
Whether the marker pulses to signal work in flight - typically bound
from an item's own [state] being pending.
The pulse is a box-shadow animation rather than a transform or a
size change: the marker sits in a grid track the rail is aligned to,
so anything that altered its box would drag the rail with it every
frame. Suppressed under prefers-reduced-motion.
false, { transform: coerceBooleanProperty }Where the event sits in the history. Drives the dot colour and, for
upcoming, its hollow fill. Left unset the marker paints in the
neutral rail colour.
HostBindings#
| Binding | Expression |
|---|---|
[attr.data-status] | status() |
[class.cngx-timeline-marker--busy] | busy() |
The --cngx-timeline-* custom-property family, shared by every
artifact in @cngx/common/timeline and re-used by the <cngx-timeline>
organism in @cngx/ui/timeline. A pure token surface - registrations
plus :root chains, no structural rules and no @scope.
It lives with the atoms rather than with the organism on purpose: a
<cngx-timeline-item> dropped into a hand-rolled layout has to render
complete and density-correct on its own. A token family that only
resolved under a Level-4 host would make the molecule a fragment
instead of a terminal unit.
Where the spacing tokens are, and why not here
This file carries no -gap / -padding registration. A spacing token
is registered in the same stylesheet that SETs it from --cngx-space-*,
at that component's own host:
--cngx-timeline-gap,--cngx-timeline-row-gap,--cngx-timeline-content-padding-timeline-item.component.css--cngx-timeline-group-gap- the organism's stylesheet
Registering them here and SETting them there would put a registration
one file away from its derivation, where the two can drift silently: a
registered initial-value defeats every use-site var(token, fallback), so a token that loses its SET rule freezes at the literal
and a nested [data-density] never reaches it. Keeping the pair
together makes that failure impossible to introduce by accident, and is
what the repo's density guard checks per file.
The sizes that remain here are affordances, not compactness, and are
deliberately outside the density scale. --cngx-timeline-rail-inset in
particular derives from --cngx-timeline-marker-size: the rail has to
meet the marker's centre, and a density swap that moved one without the
other would detach the rail from the dot. That derivation is applied at
the row host (timeline-item.component.css), the nearest common ancestor
of the marker and the connector - custom properties inherit downwards
only, so deriving it on either sibling would never reach the other.
Colour and dark mode
Every colour chains to a --cngx-color-* foundation token, which
already carries its own light and dark values. Dark mode therefore
needs no per-token redefinition here - overriding
--cngx-color-primary or the active colour scheme re-themes the
timeline for free. The literal in each chain's tail is the leaf
default for consumers running without the foundation stylesheet.
--cngx-timeline-connector-color->--cngx-color-border--cngx-timeline-surface->--cngx-color-surface--cngx-timeline-text-color->--cngx-color-text--cngx-timeline-muted-color->--cngx-color-text-muted--cngx-timeline-done-color->--cngx-color-success--cngx-timeline-active-color->--cngx-color-primary--cngx-timeline-rejected-color->--cngx-color-danger--cngx-timeline-upcoming-color->--cngx-color-text-muted
Default visuals for CngxTimelineMarker - a round, status-coloured dot
that centres whatever is projected into it.
Status modifiers
Driven by [data-status], set from the status Input:
done- filled in the success toneactive- filled in the primary tone, with a soft halo ringupcoming- hollow, muted ring only, so the state reads without colourrejected- filled in the danger tone
Busy pulse
.cngx-timeline-marker--busy animates box-shadow only. The marker
shares a grid track with the connector rail, so animating size or
transform would shift the rail's anchor every frame. Fully suppressed
under prefers-reduced-motion.
Media
The dot clips to its circle, so a photo, a logo or a glyph can render inside it with no extra markup. The sizing contract has two halves and they are not the same:
- Bare media (
img/picture/svg) is sized here, as a percentage of the marker box, and therefore follows--cngx-timeline-marker-sizeon its own. Percentages rather thanem: the scope pinsfont-size: 0.625embelow, so anem-sized glyph would track that font-size and an enlarged marker would keep a 12px-era icon. Animgfills the dot; ansvginsets to--cngx-timeline-marker-glyph-size. - A projected
CngxAvatarorCngxIconsizes itself. Both pin--cngx-avatar-size/--cngx-icon-sizeon their own host from their size-variant classes, where nothing inherited from here can reach them, and a rule in this file naming.cngx-avatar--mdwould put a sibling atom's class in the marker's stylesheet at equal specificity - a source-order coin flip. So enlarging such a marker means setting--cngx-timeline-marker-sizeand the atom's own size.
--cngx-timeline-rail-inset derives from the marker size at the row host
either way, so the rail meets an enlarged marker's centre with no extra
wiring.
Density
--cngx-timeline-marker-size is a fixed affordance, not compactness, so it
is not SET from the scale. It is the anchor --cngx-timeline-rail-inset
derives from, but that derivation is applied at the row host in
timeline-item.component.css: the marker and the connector are siblings,
and a custom property set here would never reach the rail.
Index#
Layout
Typography
Variant / Done
Variant / Active
Variant / Upcoming
Variant / Rejected
Layout
<length>6pxDistance the rail is pulled back from the edge of the marker cell so
it meets the marker's centre. Affordance geometry, deliberately
outside the density scale - it tracks --cngx-timeline-marker-size
instead, and a density swap that moved it would detach the rail from
the dot.
<percentage>60%Size of a bare svg glyph projected into the marker, as a share of the
marker box. A percentage rather than a length so it tracks
--cngx-timeline-marker-size on its own: em would resolve against the
marker's pinned font-size, which is not the dot's size.
Photos are not covered by this - an img or picture fills the dot
edge to edge, because a cropped portrait wants no inset and a glyph does.
<length>192pxWidth of one row on the horizontal axis. Ignored in the vertical default, where a row takes the container's width.
An affordance, not compactness, so it is deliberately outside the density scale. It exists because a horizontal run has no sensible content-derived width: flex would size every card to its longest word and the axis would read as a ragged queue. Override per instance for denser or wider cards.
<length>3pxWidth of the halo ring drawn around a marker in the active status.
Surface
<color>oklch(0.88 0.005 250)Colour of the connector rail in its default (unstated) status.
See: [[--cngx-color-border]]
<color>oklch(1 0 0)Background the marker is punched out of, so a coloured rail passing behind the dot does not show through it.
See: [[--cngx-color-surface]]
Typography
<color>oklch(1 0 0)Foreground colour of a glyph projected into the marker.
*0.8125remFont size for secondary text across the family - timestamps, inline errors, date headers, the refreshing tail. Registered here rather than with either consumer, because the row and the organism both read it and a registration in one is out of scope for the other.
<color>oklch(0.2 0.01 250)Primary text colour inside an item.
See: [[--cngx-color-text]]
<color>oklch(0.5 0.01 250)Secondary text colour - timestamps, group headers, the refreshing tail.
See: [[--cngx-color-text-muted]]
Variant / Done
<color>oklch(0.6 0.15 145)Marker and rail colour for the done status.
See: [[--cngx-color-success]]
Variant / Active
<color>oklch(0.66 0.19 50)Marker and rail colour for the active status.
See: [[--cngx-color-primary]]
Variant / Upcoming
<color>oklch(0.5 0.01 250)Marker and rail colour for the upcoming status. Pairs with a dashed
rail, so the state survives a colour-blind reader.
See: [[--cngx-color-text-muted]]
Variant / Rejected
<color>oklch(0.6 0.18 25)Marker and rail colour for the rejected status, and for an item
whose own [state] failed.
See: [[--cngx-color-danger]]
Motion
<time>1.6sPeriod of the busy pulse on a marker. Set to 0s to stop it without
touching the rest of the family.