GrValue

Пакет: @feugene/granularityядроГруппа: Данные

Берут, когда пишете свой компонент с величиной.

Когда брать

  • пишете свой компонент с величиной — плитку, ячейку, строку отчёта: приписки оформятся так же, как в остальном пакете, без копирования классов;
  • валюта стоит справа100 ₽, а не $100: сторона задаётся тем, в какую приписку положить символ;
  • величина не число — «2 ч 15 мин», «—», «н/д» выводятся как есть;
  • нужна своя вёрстка вокруг значения — знак, стрелка, скрытая подпись ложатся в слоты между частями записи.

Когда взять другое

НужноБерите
Знак и тон по знаку внутри строки текстаGrDelta
Крупный показатель плиткой, с подписью и динамикойGrStatistic
Значение как статус или меткаGrBadge
Пара «характеристика → значение»GrDescriptionList
Форматирование числа по локалиformatStatisticValue из GrStatistic

Величина приходит готовой

Примитив ничего не форматирует: разряды, точность и разделители — забота того, кто передаёт значение. Это не экономия, а граница ответственности: «2 ч 15 мин» и «—» такие же величины, как 1 284 500, и компонент, который попытался бы их разобрать, испортил бы обе.

Форматирование по локали в пакете есть — formatStatisticValue; оно доступно отдельно и складывается с примитивом как угодно.

Приписка — не обязательно единица измерения

Компонент не решает, чем является приписка. Это и есть его смысл: $, , %, мс, «за заказ» — разные вещи, и одно правило на всех однажды соврёт.

Дефолты выбраны по частоте, а не по истине:

ПрефиксСуффикс
цветкак у величиныприглушённый
кеглькак у величинымельче
отбивканетесть

За ними стоит наблюдение: слева чаще пишут валюту, и она часть суммы; справа чаще единицу, и она величине не принадлежит. $14,99 и 42 % получаются сами.

Валюта справа — снимите приглушение

Рубль пишут после числа, но он такая же часть суммы, как $ перед ней. Поэтому дефолт суффикса ему не подходит, и его меняют токенами:

<GrValue
  :value="formatted"
  suffix="₽"
  style="--gr-value-suffix-color: currentColor; --gr-value-suffix-size: 1em"
/>

Приложению, где так всегда, удобнее объявить это классом один раз:

.amount { --gr-value-suffix-color: currentColor; --gr-value-suffix-size: 1em; }

Именно currentColor и 1em, а не inherit. У пользовательского свойства inherit — ключевое слово наследования самой переменной: оно означает «возьми её значение у родителя», а у родителя её нет, и токен остаётся неопределённым. Фолбэк тогда срабатывает как обычно, и приписка выглядит нетронутой — правка молча не даёт ничего. currentColor и 1em — настоящие значения, и они означают ровно то, что нужно: цвет и кегль величины.

Сторону символа компонент не выбирает. Соблазн вывести её из локали есть, но Intl расставляет валюту по локали, а не по валюте: в ru-RU справа оказываются все, включая доллар (1 284 500,50 $), в en-US слева все, включая рубль (RUB 1,284,500.50). Привычное «₽ справа, $ и € слева» — правило смешанное и продуктовое, вывести его неоткуда. Решает потребитель, выбирая приписку.

Тон доезжает до приписки сам

Цвет префикса по умолчанию — inherit, а не копия роли тона. Разница видна на отрицательной сумме: краснеет вся запись, а не число без символа валюты. Поэтому тон задаётся один раз на родителе — так делает GrStatistic, — и примитиву о нём знать не нужно.

Тем же способом наследуется кегль: своей шкалы размеров у примитива нет, величина набирается кеглем места, где стоит.

Границы

Позиции приписок фиксированы: префикс слева, суффикс справа. Порядок не меняется ни пропом, ни локалью — величина, у которой приписки переставляются местами, это две разные записи, и выбрать между ними может только автор экрана.

Playground 2

Загружается…

Код
<GrValue />

Установка

npm i @feugene/granularity

Импорт

import { GrValue } from '@feugene/granularity/components/GrValue'

API

Props

PropTypeпо умолчаниюОписание
valuestring | number | null | undefinedГотовое к показу значение. Не форматируется: «2 ч 15 мин» и «—» тоже величины.
prefixstring | undefinedПриписка перед значением: валюта, знак приближения.
suffixstring | undefinedПриписка после значения: единица измерения, валюта справа.

Slots

SlotTypeОписание
defaultanyЗначение вместо пропа.
prefixanyПриписка перед значением.
suffixanyПриписка после значения.
leadanyПеред префиксом: знак величины у `GrDelta`, стрелка направления. Слотом, а не пропом, — разметка там принадлежит потребителю.
trailanyПосле значения: скрытый узел для диктора у `GrStatistic`.

Примеры 1

Валюта слева, валюта справа, единица

Компонент не решает, чем является приписка. Дефолты выбраны по частоте: слева обычно валюта — она набирается как число; справа обычно единица измерения — она приглушается и отбивается. Рубль пишут справа, но он часть суммы, и дефолт ему не подходит: снимается двумя токенами --gr-value-suffix-color и --gr-value-suffix-size.

Валюта слева$1 284 500,5 Дефолт: приписка слева набирается как число
Валюта справа1 284 500,5 Два токена — и приписка стала частью суммы
Единица измерения42% Дефолт: приписка справа приглушена и отбита

Affixes
<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>

Сторону символа компонент не выбирает: Intl расставляет валюту по локали, а не по валюте — в ru-RU справа оказываются все, включая доллар. Привычное «₽ справа, $ слева» — правило продуктовое, и решает его потребитель, выбирая приписку.

Документация компонентаВсе компоненты