What can go wrong

A number not there yet, a division by zero, rounded figures that do not add up, and a limit crossed inside a folded line: what a calculation shows in each case.

import { Calculation } from "@umriss-ui/calculation";

An absent given is never zero: every quantity that depends on it is absent too, with the reason, up to the result. A quotient by zero is absent with its own reason.

Examples

A number that is not there yet

A given with value={null} shows as missing, and so does every figure that depends on it – never carried on as zero.

import { Calculation, Given, Quotient, Sum } from "@umriss-ui/calculation";

const BOOKED = [
  { name: "Luis Moreno", hours: 34 },
  { name: "Hana Sato", hours: 38 },
  { name: "Kofi Mensah", hours: null },
  { name: "Freya Olsen", hours: 36 },
  { name: "David Kowalski", hours: 17 },
];

export default function Missing() {
  return (
    <Calculation aria-label="Utilisation of the Apps team, week 11">
      <Quotient label="Utilisation, Apps team" format="percent" target={0.85}>
        <Sum label="Hours booked" unit="h">
          {BOOKED.map((person) => (
            <Given key={person.name} label={person.name} value={person.hours} unit="h" source="Timesheets" />
          ))}
        </Sum>
        <Given label="Capacity, Apps team" value={172} unit="h" />
      </Quotient>
    </Calculation>
  );
}

A division by zero

A tour that delivered nothing has no cost per parcel – not zero, not infinity; the quotient is absent with its own reason.

import { Calculation, Given, Product, Quotient, Sum } from "@umriss-ui/calculation";

export default function DivisionByZero() {
  return (
    <Calculation aria-label="Planned cost of tomorrow's parcels, tour T-07">
      <Product label="Cost of tomorrow's 80 parcels" unit="€" decimals={2}>
        <Quotient label="Cost per parcel, tour T-07" unit="€/parcel" decimals={2}>
          <Sum label="Cost of tour T-07" unit="€" decimals={2}>
            <Given label="Driver, standby" value={69} unit="€" decimals={2} />
            <Given label="E-van, one day" value={72} unit="€" decimals={2} />
          </Sum>
          <Given label="Parcels delivered" value={0} unit="parcels" />
        </Quotient>
        <Given label="Parcels planned for tomorrow" value={80} unit="parcels" />
      </Product>
    </Calculation>
  );
}

Rounded figures that do not add up

Operations use full values and only the screen rounds; where the rounded operands miss the rounded result, the line says so with ≈.

import { Calculation, Given, Quotient, Sum } from "@umriss-ui/calculation";

const PEOPLE = ["Arjun Mehta", "Chloe Durand", "Eva Novak"];

export default function Rounding() {
  return (
    <Calculation aria-label="Shares of the booking app release">
      <Sum label="All three" format="percent">
        {PEOPLE.map((person) => (
          <Quotient key={person} label={`Share, ${person}`} format="percent">
            <Given label={`Hours, ${person}`} value={12} unit="h" />
            <Given label="Hours on the release" value={36} unit="h" />
          </Quotient>
        ))}
      </Sum>
    </Calculation>
  );
}

A limit violated deep inside

A folded line holding a worse verdict says so quietly – without taking the colour itself, since its own number is not the one in alarm.

import { Calculation, Chain, Given, Interim, Plus, Product } from "@umriss-ui/calculation";

const ERROR_LIMITS = [
  { value: 0.01, side: "upper" as const, severity: "warning" as const },
  { value: 0.02, side: "upper" as const, severity: "alarm" as const },
];

export default function LimitInside() {
  return (
    <Calculation aria-label="Payments at risk, this morning">
      <Chain>
        <Product label="At risk, Billing" unit="€" decimals={2}>
          <Given label="Error rate, Billing" value={0.004} format="percent" limits={ERROR_LIMITS} />
          <Given label="Payments, Billing" value={24800} unit="€" decimals={2} />
        </Product>
        <Plus>
          <Product label="At risk, Checkout" unit="€" decimals={2}>
            <Given label="Error rate, Checkout" value={0.026} format="percent" limits={ERROR_LIMITS} />
            <Given label="Payments, Checkout" value={19650} unit="€" decimals={2} />
          </Product>
        </Plus>
        <Interim label="Payments at risk" unit="€" decimals={2} />
      </Chain>
    </Calculation>
  );
}

Keyboard

The keys of Calculation apply here.

Props on this page

From CalculationProps — the full table stands on Calculation.

NameTypeDefaultDescription
childrenrequiredReactNode—The result: exactly one quantity - a tree (<Sum>, <Difference>, <Product>, <Quotient> with their operands, <Given> as leaves) or a <Chain>, the two mixing freely; <Ref> for a quantity defined elsewhere.

From OperatorProps — the full table stands on Tree.

NameTypeDefaultDescription
childrenReactNode—The operands, in order: quantities, givens and references.
labelrequiredstring—What the quantity is called. It stands on its line, wherever it is an operand, and in the accessible sentence. from QuantityProps
unitstring—A label written after the number - "min", "pcs", "€". Never converted and never checked; the calculation does no unit algebra. from QuantityProps
format"percent"—percent presents a plain ratio as per cent: 0.916 is shown as 91.6 %. The quantity stays a ratio in every operation. from QuantityProps
decimalsnumberone digit for a percentage, at most two for a derived number, a given as it was givenFixed number of fraction digits as shown. Rounding happens only in presentation; every operation uses the full value. from QuantityProps
targetnumber—The value this quantity is meant to reach - missed, never violated. from QuantityProps
limitsreadonly Limit[]—Bounds the quantity is assessed against, through core's assess(). from QuantityProps

From ChainProps — the full table stands on Chain.

NameTypeDefaultDescription
childrenReactNode—The operands, top to bottom: a first quantity with no operator, then Plus, Minus, Times and DividedBy with their operands and Interims naming the value where they stand. The last line is an Interim; a Times or DividedBy stands alone between two named values.

From ChainOperandProps — the full table stands on Chain.

NameTypeDefaultDescription
childrenReactNode—Instead of label and value: exactly one quantity - a tree, a <Ref> or a <Chain>.
sourcestring—Where the number came from: a system, a report, a person. from GivenProps
unitstring—A label written after the number - "min", "pcs", "€". Never converted and never checked; the calculation does no unit algebra. from QuantityProps
format"percent"—percent presents a plain ratio as per cent: 0.916 is shown as 91.6 %. The quantity stays a ratio in every operation. from QuantityProps
decimalsnumberone digit for a percentage, at most two for a derived number, a given as it was givenFixed number of fraction digits as shown. Rounding happens only in presentation; every operation uses the full value. from QuantityProps
targetnumber—The value this quantity is meant to reach - missed, never violated. from QuantityProps
limitsreadonly Limit[]—Bounds the quantity is assessed against, through core's assess(). from QuantityProps

From QuantityProps — the full table stands on Chain.

NameTypeDefaultDescription
labelrequiredstring—What the quantity is called. It stands on its line, wherever it is an operand, and in the accessible sentence.
unitstring—A label written after the number - "min", "pcs", "€". Never converted and never checked; the calculation does no unit algebra.
format"percent"—percent presents a plain ratio as per cent: 0.916 is shown as 91.6 %. The quantity stays a ratio in every operation.
decimalsnumberone digit for a percentage, at most two for a derived number, a given as it was givenFixed number of fraction digits as shown. Rounding happens only in presentation; every operation uses the full value.
targetnumber—The value this quantity is meant to reach - missed, never violated.
limitsreadonly Limit[]—Bounds the quantity is assessed against, through core's assess().

From GivenProps — the full table stands on Given.

NameTypeDefaultDescription
valuerequired| number
| null
| undefined
| MetricValues
—The number the calculation starts from. Absent (null, undefined, not finite) makes every quantity that depends on it absent, with the reason - never zero. Where the calculation has metrics, an object with a number for each metric id instead; absence then stays in its metric.
sourcestring—Where the number came from: a system, a report, a person.
labelrequiredstring—What the quantity is called. It stands on its line, wherever it is an operand, and in the accessible sentence. from QuantityProps
unitstring—A label written after the number - "min", "pcs", "€". Never converted and never checked; the calculation does no unit algebra. from QuantityProps
format"percent"—percent presents a plain ratio as per cent: 0.916 is shown as 91.6 %. The quantity stays a ratio in every operation. from QuantityProps
decimalsnumberone digit for a percentage, at most two for a derived number, a given as it was givenFixed number of fraction digits as shown. Rounding happens only in presentation; every operation uses the full value. from QuantityProps
targetnumber—The value this quantity is meant to reach - missed, never violated. from QuantityProps
limitsreadonly Limit[]—Bounds the quantity is assessed against, through core's assess(). from QuantityProps

Every page of @umriss-ui/calculation

Getting started

Writing a calculation

In practice

API index