MetricRing
A ring for any single value-vs-goal metric (calories, protein, steps, water, ...). CalorieRing is exported as a semantic alias of the same component for the calorie call site.
Playground
1.400of 2.200 kcal
Try: drag value past goal with status set to onTrack to see the goal-reached glow pulse; switch status to see the ring both change color and (with badge filled in) recolor the pill to match.
vue
<script setup>
import { MetricRing } from 'yemek'
</script>
<template>
<MetricRing :value="1800" :goal="2200" status="onTrack" unit-label="kcal" goal-prefix="of" badge="Balanced" />
</template>Props
| Prop | Type | Default | Description |
|---|---|---|---|
value | number | — | Current value. |
goal | number | — | Target value. |
status | 'under' | 'onTrack' | 'over' | undefined | Zone coloring. Omit for a neutral Apple-Watch-style ring that only cares about filled vs. not filled — not every metric has a meaningful "over" direction (e.g. protein is a floor, not a cut/bulk-relative target). Whether over-goal is good or bad is the consumer's domain judgment; the component never infers it. |
size | number | 220 | Ring diameter in px. |
unitLabel | string | '' | Appended after the goal number, e.g. "kcal". |
goalPrefix | string | 'of' | Text before the goal number (e.g. "of 2200 kcal"). A prop, not hardcoded — the component must not decide the consuming app's language. A German consumer passes goal-prefix="von". |
badge | string | undefined | Optional status pill anchored to the ring's bottom edge (e.g. "-320 kcal deficit"). Text only — the consumer still owns the wording; the ring only places and colors it, reusing the same status zone color so the two never disagree. |
editable | boolean | false | Shows a small pencil affordance attached to the ring instead of the consumer building a separate "edit goal" button below it. The kit still owns no editing UI/dialog — this only renders the affordance and emits edit; the consumer opens whatever dialog it already has. |
Events
| Event | Payload | Fired when |
|---|---|---|
edit | — | The pencil affordance is clicked (only rendered when editable is true, toggle it on in the playground above). |
Behavior notes
- Goal reached (
value >= goal && goal > 0) triggers a soft glow-pulse animation on the fill, looping until the value drops back below goal. - The displayed number animates with a subtle pop transition whenever
valuechanges. - Track color derives from
--yemek-color-textviacolor-mix(), not a fixed surface-relative token — this guarantees contrast against an arbitrary host background regardless of the host app's exact surface color (see Design tokens).
See the live Histoire stories (npm run dev in the yemek repo) for every status/size/badge combination.