Detent web components
By Shane Logsdon

Data & tables

Activity Feed

Implemented

Real-time telemetry event stream with expandable audit payloads

detent-activity-feed

Port status
Catalog status
implemented
Origin
upstream
Phase
3
Wave
phase-3-data
Group
Data & tables

9.6 KB gzip for the class module · inlines the shared spring

Variants

A local sample telemetry feed. Search by title, description, trace id or actor; filter by category with the chips; open the JSON inspector with the chevron; copy a trace id with its chip. Start Live Stream is a local simulation: the element generates a fixed cycle of sample events every 3.5 seconds and shows a note saying so. Nothing is fetched and no network service is implied. A disabled feature is removed from the tree, not hidden — set feed.enableFilters = false, enableSearch or enableLiveSimulation.

No event has been replayed yet.

Recorded states

  • expanded recorded state; no setter
  • streaming recorded state; no setter

Usage

Import

import '/components/activity-feed/define.js';

// or register it yourself
import { DetentActivityFeed } from '/components/activity-feed/activity-feed.js';

Attributes

  • enable-filters
  • enable-live-simulation
  • enable-search
  • max-entries

Properties

  • events
  • onEventReplay

Slots

No slots are recorded for this component.

Events

  • detent-event-replay — {}

Example

Runnable example: site/examples/activity-feed.ts. The snippet below is generated from the catalogued attributes.

<detent-activity-feed
  enable-filters
  enable-live-simulation
  enable-search
  max-entries="20"
></detent-activity-feed>

Property-only values

const element = document.querySelector('detent-activity-feed');
if (element !== null) {
  // events: ActivityEvent[]
  element.events = [];
  // onEventReplay: (event: ActivityEvent) => void
  element.onEventReplay = () => {};
}

Source

The pinned upstream source for this row:

  • src/components/ui/ActivityFeed.tsx sha256 ad4b74e0c14e…

Native files

The native module and its artifacts:

  • src/components/activity-feed/activity-feed.ts
  • src/components/activity-feed/styles.css
  • src/components/activity-feed/define.ts
  • docs/components/activity-feed.md
  • site/examples/activity-feed.ts
  • tests/browser/activity-feed.spec.ts
  • evidence/components/activity-feed.md

API

Boolean attributes follow HTML presence semantics: present means true, absent means false, and disabled="false" still means disabled.

Attributes

Attributes
AttributePropertyTypeDefaultNotes
enable-filtersenableFiltersbooleantruePresence semantics: present means true, absent means false.
enable-live-simulationenableLiveSimulationbooleantruePresence semantics: present means true, absent means false.
enable-searchenableSearchbooleantruePresence semantics: present means true, absent means false.
max-entriesmaxEntriesnumber20Kebab-case attribute; camelCase property.

Properties

Properties
PropertyTypeDefaultNotes
eventsActivityEvent[][]Property-only: assign from script; not accepted as an attribute.
onEventReplay(event: ActivityEvent) => voidundefinedProperty-only: assign from script; not accepted as an attribute.

Events

Events
EventUpstream propPayload typeNotes
detent-event-replayonEventReplay(event: ActivityEvent) => voidComposed, bubbles; fires only for a user action.

Slots

No slots are recorded for this component.

CSS customisation

  • `className` prop is replaced by documented CSS parts/custom properties; no Tailwind in consumers.
  • React callback props become typed composed CustomEvents; programmatic state assignment emits none.
  • Framer Motion springs/AnimatePresence ported to CSS transitions, WAAPI or the shared rAF spring helper.
  • React state/hooks replaced by element-owned state with pre-upgrade property preservation.
  • onEventReplay becomes the composed detent-event-replay { event } event with a plain snapshot; there is no callback property.
  • The live stream is a documented local simulation. Upstream built random Date.now()/Math.random() events inside the component with no label. This port cycles a fixed set of sample events (deterministic, testable), marks each with data-simulated="true", and shows a part="note" paragraph stating that the events are simulated locally and that nothing is fetched. No request is made and no service is implied.
  • The stream pauses while the document is hidden and stops on disconnect; upstream's setInterval kept running until unmount.
  • A disabled feature (enableFilters/enableSearch/enableLiveSimulation) is removed from the tree instead of being conditionally rendered by React, which is the same accessible result.
  • Category chips expose aria-pressed (upstream styled the active chip only) and carry the counts as text (Deploy (1)), so the state is not colour-only.
  • The status badge is text, not a bare colour dot.
  • lucide-react icons become local aria-hidden text glyphs. An event added after the feed first showed events enters on springSnappy (opacity, y -8 px, scale 0.98) through the shared spring helper, and the payload drawer opens and closes on springGentle height and opacity. The events a change displaces glide to their new place on springSnappy (Framer layout, vertical position only, through src/motion/layout-flip.ts); the exit animation is not carried over, so a removed event leaves at once and the rest glide up immediately. The live indicator's pulse is a CSS opacity animation; reduced motion removes it and jumps the entry and drawer.
  • Upstream's hard-coded dark palette and backdrop-style surfaces become theme tokens so both colour schemes meet AA.
  • The JSON inspector renders JSON.stringify(payload, null, 2) as text; a consumer string inside the payload is never markup.

What it does

A telemetry event stream with search, category filter chips and counts, a JSON payload inspector, trace-id copying and a labelled local live simulation.

Upstream behaviour
  • Real-time simulation toggle streaming live webhook/deploy events
  • Framer Motion layout and AnimatePresence entry transitions
  • Category filtering (Deploy, Security, API, System) with live count tags
  • Integrated JSON payload inspector with syntax highlighting and copy
  • One-click trace ID copying with animated validation feedback
Differences from upstream
  • `className` prop is replaced by documented CSS parts/custom properties; no Tailwind in consumers.
  • React callback props become typed composed CustomEvents; programmatic state assignment emits none.
  • Framer Motion springs/AnimatePresence ported to CSS transitions, WAAPI or the shared rAF spring helper.
  • React state/hooks replaced by element-owned state with pre-upgrade property preservation.
  • onEventReplay becomes the composed detent-event-replay { event } event with a plain snapshot; there is no callback property.
  • The live stream is a documented local simulation. Upstream built random Date.now()/Math.random() events inside the component with no label. This port cycles a fixed set of sample events (deterministic, testable), marks each with data-simulated="true", and shows a part="note" paragraph stating that the events are simulated locally and that nothing is fetched. No request is made and no service is implied.
  • The stream pauses while the document is hidden and stops on disconnect; upstream's setInterval kept running until unmount.
  • A disabled feature (enableFilters/enableSearch/enableLiveSimulation) is removed from the tree instead of being conditionally rendered by React, which is the same accessible result.
  • Category chips expose aria-pressed (upstream styled the active chip only) and carry the counts as text (Deploy (1)), so the state is not colour-only.
  • The status badge is text, not a bare colour dot.
  • lucide-react icons become local aria-hidden text glyphs. An event added after the feed first showed events enters on springSnappy (opacity, y -8 px, scale 0.98) through the shared spring helper, and the payload drawer opens and closes on springGentle height and opacity. The events a change displaces glide to their new place on springSnappy (Framer layout, vertical position only, through src/motion/layout-flip.ts); the exit animation is not carried over, so a removed event leaves at once and the rest glide up immediately. The live indicator's pulse is a CSS opacity animation; reduced motion removes it and jumps the entry and drawer.
  • Upstream's hard-coded dark palette and backdrop-style surfaces become theme tokens so both colour schemes meet AA.
  • The JSON inspector renders JSON.stringify(payload, null, 2) as text; a consumer string inside the payload is never markup.
Next: Activity Heatmap

Docs

Components

Project