GrValue
A quantity with its affixes: prefix, value, suffix — and nothing else.
Machine-translated from the Russian original, not yet reviewed. Read the original
When to take it
- you are writing a component of your own with a quantity — a tile, a cell, a row of a report: the affixes will be styled the same way as in the rest of the package, with no copying of classes;
- the currency stands on the right —
100 ₽rather than$100: the side is set by which affix the symbol is put into; - the quantity is not a number — “2 h 15 min”, ”—”, “n/a” are printed as they are;
- markup of your own is needed around the value — the sign, an arrow, a hidden label go into the slots between the parts of the record.
When to take something else
| Need | Take |
|---|---|
| The sign and a tone by the sign inside a line of text | GrDelta |
| A large metric as a tile, with a label and a trend | GrStatistic |
| The value as a status or a label | GrBadge |
| A “property → value” pair | GrDescriptionList |
| Formatting a number by locale | formatStatisticValue from GrStatistic |
The quantity arrives ready
The primitive formats nothing: the digit groups, the precision and the separators are the concern of
whoever passes the value. That is not a saving but a boundary of responsibility: “2 h 15 min” and
”—” are quantities just as 1 284 500 is, and a component that tried to parse them would spoil
both.
Formatting by locale exists in the package — formatStatisticValue; it is available separately and
combines with the primitive in any way at all.
An affix is not necessarily a unit of measurement
The component does not decide what an affix is. That is its whole point: $, ₽, %, ms,
“per order” are different things, and one rule for all of them will lie one day.
The defaults are chosen by frequency rather than by truth:
| The prefix | The suffix | |
|---|---|---|
| the colour | as in the quantity | dimmed |
| the type size | as in the quantity | smaller |
| the spacing | none | there is some |
Behind them stands an observation: on the left people more often write the currency, and it is part
of the sum; on the right more often a unit, and it does not belong to the quantity. $14.99 and
42 % come out by themselves.
A currency on the right — remove the dimming
The rouble is written after the number, but it is as much part of the sum as the $ before it. The
default of the suffix therefore does not fit it, and it is changed with tokens:
<GrValue
:value="formatted"
suffix="₽"
style="--gr-value-suffix-color: currentColor; --gr-value-suffix-size: 1em"
/>
An application where it is always so finds it more convenient to declare that in a class once:
.amount { --gr-value-suffix-color: currentColor; --gr-value-suffix-size: 1em; }
Precisely currentColor and 1em rather than inherit. For a custom property inherit is the
keyword for inheriting the variable itself: it means “take its value from the parent”, and the
parent does not have it, so the token stays undefined. The fallback then fires as usual, and the
affix looks untouched — the edit silently gives nothing. currentColor and 1em are real values,
and they mean exactly what is needed: the colour and the type size of the quantity.
The component does not choose the side of the symbol. The temptation to infer it from the locale
is there, but Intl places the currency by locale rather than by currency: in ru-RU they all
end up on the right, the dollar included (1 284 500,50 $), and in en-US all on the left, the
rouble included (RUB 1,284,500.50). The familiar ”₽ on the right, $ and € on the left” is a mixed
product rule, and there is nowhere to infer it from. It is decided by the consumer, by choosing the
affix.
The tone reaches the affix by itself
The colour of the prefix is inherit by default rather than a copy of the tone role. The difference
is visible on a negative sum: the whole record turns red, not the number without the currency sign.
The tone is therefore set once on the parent — that is what GrStatistic does — and the primitive
does not need to know about it.
The type size is inherited the same way: the primitive has no size scale of its own, and the quantity is set in the type size of the place it stands in.
Limits
The positions of the affixes are fixed: the prefix on the left, the suffix on the right. The order is changed neither by a prop nor by the locale — a quantity whose affixes swap places is two different records, and only the author of the screen can choose between them.
Playground 2
Loading…
<GrValue />Install
npm i @feugene/granularityImport
import { GrValue } from '@feugene/granularity/components/GrValue'API
Props
| Prop | Type | default | Description |
|---|---|---|---|
value | string | number | null | undefined | — | A value ready for display. It is not formatted: "2 h 15 min" and "—" are quantities too. |
prefix | string | undefined | — | An addition before the value: a currency, a sign of approximation. |
suffix | string | undefined | — | An addition after the value: a unit of measurement, a currency on the right. |
Slots
| Slot | Type | Description |
|---|---|---|
default | any | The value instead of the prop. |
prefix | any | An addition before the value. |
suffix | any | An addition after the value. |
lead | any | Before the prefix: the sign of the quantity in `GrDelta`, an arrow of the direction. A slot rather than a prop — the markup there belongs to the consumer. |
trail | any | After the value: a hidden node for the screen reader in `GrStatistic`. |
Examples 1
Currency left, currency right, unit
<script setup lang="ts">
import { GrCard, GrValue } from '@feugene/granularity'
const amount = new Intl.NumberFormat('ru-RU', { maximumFractionDigits: 2 }).format(1284500.5)
</script>
<template>
<div class="grid gap-4 sm:grid-cols-3">
<GrCard variant="outlined" padding="md" body-class="grid gap-1">
<span class="text-[length:var(--gr-text-xs)] text-[var(--gr-muted-fg)]">Валюта слева</span>
<span class="text-[length:var(--gr-text-2xl)] font-semibold">
<GrValue :value="amount" prefix="$" />
</span>
<span class="text-[length:var(--gr-text-xs)] text-[var(--gr-muted-fg)]">
Дефолт: приписка слева набирается как число
</span>
</GrCard>
<!--
Рубль пишут справа, но он такая же часть суммы. Дефолт суффикса ему не
подходит, и его снимают токенами — компонент за потребителя не решает.
-->
<GrCard variant="outlined" padding="md" body-class="grid gap-1">
<span class="text-[length:var(--gr-text-xs)] text-[var(--gr-muted-fg)]">Валюта справа</span>
<span
class="text-[length:var(--gr-text-2xl)] font-semibold"
style="--gr-value-suffix-color: currentColor; --gr-value-suffix-size: 1em"
>
<GrValue :value="amount" suffix="₽" />
</span>
<span class="text-[length:var(--gr-text-xs)] text-[var(--gr-muted-fg)]">
Два токена — и приписка стала частью суммы
</span>
</GrCard>
<GrCard variant="outlined" padding="md" body-class="grid gap-1">
<span class="text-[length:var(--gr-text-xs)] text-[var(--gr-muted-fg)]">Единица измерения</span>
<span class="text-[length:var(--gr-text-2xl)] font-semibold">
<GrValue :value="42" suffix="%" />
</span>
<span class="text-[length:var(--gr-text-xs)] text-[var(--gr-muted-fg)]">
Дефолт: приписка справа приглушена и отбита
</span>
</GrCard>
</div>
</template>