Shared types + helpers for KPI hover detail popovers.
Mirrors kpi-detail.ts from @keenmate/svelte-pure-admin. Used by every
KPI tile / row module (kpi_tile/1, kpi_strip_row/1, kpi_sparkline_row/1,
kpi_bento_tile/1, kpi_hero_main/1, kpi_hero_side/1, kpi_gauge/1,
kpi_editorial_tile/1) to build the canonical popover body from typed
props — Current / Previous / Δ absolute / Δ percent / Target — without
forcing consumers to hand-author <dl> markup.
The detail popover itself is rendered by PureAdmin.Components.Kpi.kpi_detail/1.
This module supplies the row data + sentiment colour mapping.
Summary
Types
Delta / sentiment modifier names used across KPI components. Covers every
variant scale upstream emits: strip / editorial (up-strong / down-strong),
sparkline / terminal (very-positive / very-negative), gauge (warning).
A single popover row: dt/dd pair with optional sentiment colour on the
<dd>.
Sentiment class for a popover <dd>. Maps to the matching .pos / .neg /
.warn rule inside .pa-kpi-detail (upstream _kpi-base.scss).
Functions
Build the canonical detail-popover rows from a tile / row's typed props.
Convert an underscored sentiment / variant atom or string to the kebab-case
CSS modifier name upstream emits (very_positive → very-positive).
Map a delta variant modifier name onto the popover sentiment class.
CSS class for a <dd> cell given a sentiment.
Types
@type delta_variant() :: String.t()
Delta / sentiment modifier names used across KPI components. Covers every
variant scale upstream emits: strip / editorial (up-strong / down-strong),
sparkline / terminal (very-positive / very-negative), gauge (warning).
@type row() :: %{ :label_text => String.t(), :value_text => String.t(), optional(:sentiment) => sentiment() }
A single popover row: dt/dd pair with optional sentiment colour on the
<dd>.
@type sentiment() :: :pos | :neg | :warn | nil
Sentiment class for a popover <dd>. Maps to the matching .pos / .neg /
.warn rule inside .pa-kpi-detail (upstream _kpi-base.scss).
Functions
Build the canonical detail-popover rows from a tile / row's typed props.
Row order is Current → Previous → Δ absolute → Δ percent → Target. Each
row is skipped when its source field is nil.
Accepts a keyword list (or map) with optional fields:
:prefix_text— currency / scale prefix shown before the Current value:value_text— Current numeric value:unit_text— unit suffix shown after the Current value:previous_value_text— bare previous value (e.g."84.2%"):delta_absolute_text— absolute delta (e.g."+4.4pp"):delta_absolute_sentiment— sentiment override for the Δ absolute row:delta_text— Δ percent (e.g."+5.2%"):delta_sentiment— sentiment for the Δ percent row:target_text— target value (e.g."90.0%")
Examples
iex> KpiDetail.build_auto_rows(
...> value_text: "88.6",
...> unit_text: "%",
...> previous_value_text: "84.2%",
...> delta_text: "+5.2%",
...> delta_sentiment: :pos,
...> target_text: "90.0%"
...> )
[
%{label_text: "Current", value_text: "88.6%"},
%{label_text: "Previous", value_text: "84.2%"},
%{label_text: "Δ percent", value_text: "+5.2%", sentiment: :pos},
%{label_text: "Target", value_text: "90.0%"}
]
Convert an underscored sentiment / variant atom or string to the kebab-case
CSS modifier name upstream emits (very_positive → very-positive).
@spec delta_to_sentiment(delta_variant() | nil) :: sentiment()
Map a delta variant modifier name onto the popover sentiment class.
Returns nil when the variant has no sentiment mapping (e.g. "neutral").
Examples
iex> KpiDetail.delta_to_sentiment("positive")
:pos
iex> KpiDetail.delta_to_sentiment("very_negative")
:neg
iex> KpiDetail.delta_to_sentiment("warning")
:warn
iex> KpiDetail.delta_to_sentiment("neutral")
nil
CSS class for a <dd> cell given a sentiment.