@umriss-ui/calculation 0.43.0 → 0.44.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -14,6 +14,17 @@ From 0.34.0 the packages share one number - five, and six from 0.40.0, when the
14
14
 
15
15
  ---
16
16
 
17
+ ## 0.44.0 – A calculation without a name says so (Oct. 2026)
18
+
19
+ ### Added
20
+
21
+ - **A `Calculation` with neither `aria-label` nor `aria-labelledby` (or an empty label) warns once in development.**
22
+
23
+ ### Changed
24
+
25
+ - **The peer range on core moves to `^0.44.0`.**
26
+ - Migration: install the 0.44 version of `@umriss-ui/core` beside it.
27
+
17
28
  ## 0.43.0 – Places that carry down, and a calculation's root (Oct. 2026)
18
29
 
19
30
  ### Added
@@ -1,36 +1,36 @@
1
1
  "use client";
2
2
  import "./calculation.css";
3
- import { jsx as c, jsxs as O } from "react/jsx-runtime";
4
- import { useId as Ce, useState as ae, useRef as ke, useCallback as me, useLayoutEffect as ye, useEffect as Ae } from "react";
5
- import { assess as Me, verdictWeight as X, useDensityFor as Be, useFormats as _e, useWording as be, VisuallyHidden as Te, AngleGlyph as Ee, Badge as se, useFreshness as Le, Tooltip as Re } from "@umriss-ui/core";
3
+ import { jsx as l, jsxs as O } from "react/jsx-runtime";
4
+ import { useId as ye, useState as ae, useRef as ke, useCallback as me, useLayoutEffect as Ae, useEffect as Ee } from "react";
5
+ import { assess as Me, verdictWeight as X, useDensityFor as Te, useFormats as be, useWording as Ne, VisuallyHidden as Be, AngleGlyph as De, Badge as se, useFreshness as Le, Tooltip as Re } from "@umriss-ui/core";
6
6
  import { p as We } from "./calculation.model-CZuohgrp.js";
7
- function Ne(e, t) {
7
+ function we(e, t) {
8
8
  if (e.decimals !== void 0) return e.decimals;
9
9
  const m = e.format === "percent" ? 1 : e.given ? void 0 : 2;
10
10
  if (m === void 0) return;
11
11
  const i = e.format === "percent" ? t * 100 : t;
12
- return i !== 0 && we(i, m) === 0 ? void 0 : m;
12
+ return i !== 0 && $e(i, m) === 0 ? void 0 : m;
13
13
  }
14
14
  function pe(e, t) {
15
15
  const [m, i = "0"] = String(e).split("e");
16
16
  return +`${m}e${Number(i) + t}`;
17
17
  }
18
- function we(e, t) {
18
+ function $e(e, t) {
19
19
  return t === void 0 ? e : Math.sign(e) * pe(Math.round(pe(Math.abs(e), t)), -t) || 0;
20
20
  }
21
- function J(e, t, m = Ne(e, t)) {
22
- return we(e.format === "percent" ? t * 100 : t, m);
21
+ function J(e, t, m = we(e, t)) {
22
+ return $e(e.format === "percent" ? t * 100 : t, m);
23
23
  }
24
24
  const Fe = (e, t) => e.format === "percent" ? t / 100 : t;
25
25
  function fe(e, t, m) {
26
26
  const [i, ...d] = t;
27
27
  switch (e) {
28
28
  case "sum":
29
- return t.reduce((n, l, g) => m[g] ? n - l : n + l, 0);
29
+ return t.reduce((n, r, g) => m[g] ? n - r : n + r, 0);
30
30
  case "difference":
31
- return d.reduce((n, l) => n - l, i);
31
+ return d.reduce((n, r) => n - r, i);
32
32
  case "product":
33
- return d.reduce((n, l) => n * l, i);
33
+ return d.reduce((n, r) => n * r, i);
34
34
  case "quotient":
35
35
  return i / d[0];
36
36
  }
@@ -41,10 +41,10 @@ function qe(e) {
41
41
  const d = t.get(i);
42
42
  if (d) return d;
43
43
  const n = e.quantities.get(i);
44
- let l = null, g, p = !1, s;
44
+ let r = null, g, p = !1, s;
45
45
  if (n.given) {
46
46
  const N = n.given.value;
47
- typeof N == "number" && Number.isFinite(N) ? l = N : g = { kind: "missing", label: n.label };
47
+ typeof N == "number" && Number.isFinite(N) ? r = N : g = { kind: "missing", label: n.label };
48
48
  } else {
49
49
  const N = n.operands.map((w) => ({ operand: w, ...m(w.key) }));
50
50
  for (const { operand: w, verdict: S, worst: C } of N) {
@@ -55,44 +55,55 @@ function qe(e) {
55
55
  const I = N[1];
56
56
  if (!g && n.operator === "quotient" && I.value === 0 && (g = { kind: "zero", label: e.quantities.get(I.operand.key).label }), !g) {
57
57
  const w = n.operands.map(($) => $.negated === !0);
58
- l = fe(n.operator, N.map(($) => $.value), w);
58
+ r = fe(n.operator, N.map(($) => $.value), w);
59
59
  const S = fe(
60
60
  n.operator,
61
61
  N.map(($) => Fe(e.quantities.get($.operand.key), $.shown)),
62
62
  w
63
- ), C = Ne(n, l);
64
- p = J(n, S, C) !== J(n, l, C);
63
+ ), C = we(n, r);
64
+ p = J(n, S, C) !== J(n, r, C);
65
65
  }
66
66
  }
67
- const B = { target: n.target, limits: n.limits }, T = n.target !== void 0 || (n.limits?.length ?? 0) > 0 ? Me(l, B) : void 0, h = (n.limits?.length ?? 0) > 0 ? T.verdict : l === null ? "unknown" : void 0, j = {
68
- value: l,
67
+ const M = { target: n.target, limits: n.limits }, T = n.target !== void 0 || (n.limits?.length ?? 0) > 0 ? Me(r, M) : void 0, h = (n.limits?.length ?? 0) > 0 ? T.verdict : r === null ? "unknown" : void 0, q = {
68
+ value: r,
69
69
  absence: g,
70
- shown: l === null ? null : J(n, l),
70
+ shown: r === null ? null : J(n, r),
71
71
  approximate: p,
72
72
  assessment: T,
73
73
  verdict: h,
74
74
  worst: s
75
75
  };
76
- return t.set(i, j), j;
76
+ return t.set(i, q), q;
77
77
  };
78
78
  for (const i of e.quantities.keys()) m(i);
79
79
  return t;
80
80
  }
81
- const ve = 4;
82
- function je(e, t, m) {
81
+ function je() {
82
+ try {
83
+ return process.env.NODE_ENV !== "production";
84
+ } catch {
85
+ return !1;
86
+ }
87
+ }
88
+ const Pe = je(), ve = /* @__PURE__ */ new Set();
89
+ function Ue(e, t) {
90
+ !Pe || ve.has(e) || (ve.add(e), console.warn(`@umriss-ui/calculation: ${t}`));
91
+ }
92
+ const ge = 4;
93
+ function Ie(e, t, m) {
83
94
  const i = e.operands[t];
84
95
  if (i.previous) return;
85
96
  const d = e.operator, n = t === 0;
86
97
  if (d !== "sum" && d !== "difference") return n ? void 0 : { operator: d, negated: !1 };
87
- const l = d === "difference" ? !n : i.negated === !0, g = new Set(m.filter((s) => s !== null && s !== 0).map(Math.sign)), p = g.size === 1 ? { operator: "sum", negated: l !== g.has(-1), unsigned: !0 } : { operator: "sum", negated: l };
98
+ const r = d === "difference" ? !n : i.negated === !0, g = new Set(m.filter((s) => s !== null && s !== 0).map(Math.sign)), p = g.size === 1 ? { operator: "sum", negated: r !== g.has(-1), unsigned: !0 } : { operator: "sum", negated: r };
88
99
  return n && !p.negated ? void 0 : p;
89
100
  }
90
- const De = {
101
+ const Ve = {
91
102
  sum: "calculationSumSymbol",
92
103
  difference: "calculationDifferenceSymbol",
93
104
  product: "calculationProductSymbol",
94
105
  quotient: "calculationQuotientSymbol"
95
- }, Pe = {
106
+ }, ze = {
96
107
  sum: "calculationSumWord",
97
108
  difference: "calculationDifferenceWord",
98
109
  product: "calculationProductWord",
@@ -112,246 +123,247 @@ function K(e, t) {
112
123
  }
113
124
  function ee(e, t, m) {
114
125
  const i = e.negated ? "difference" : e.operator;
115
- return m[(t ? Pe : De)[i]];
126
+ return m[(t ? ze : Ve)[i]];
116
127
  }
117
- function Ue(e, t) {
128
+ function He(e, t) {
118
129
  return e.kind === "missing" ? t.calculationMissing(e.label) : t.calculationDivisionByZero(e.label);
119
130
  }
120
- function ge(e, t, m, i) {
131
+ function _e(e, t, m, i) {
121
132
  const d = e.format === "percent" ? i : e.unit, n = m.number(t, e.decimals);
122
133
  return d ? `${n} ${d}` : n;
123
134
  }
124
- function Ie(e, t, m, i, d, n, l, g = () => {
135
+ function Qe(e, t, m, i, d, n, r, g = () => {
125
136
  }) {
126
- const p = e.quantities.get(m), s = t.get(m), B = (v, y) => v.shown !== null && y?.unsigned ? Math.abs(v.shown) : v.shown, T = (v, y, _, F) => {
127
- const D = B(y, F);
128
- return D === null ? _ ? n.verdictUnknown : n.statAbsentValue : ge(v, D, d, _ ? n.calculationPercent : "%");
137
+ const p = e.quantities.get(m), s = t.get(m), M = (v, k) => v.shown !== null && k?.unsigned ? Math.abs(v.shown) : v.shown, T = (v, k, _, W) => {
138
+ const j = M(k, W);
139
+ return j === null ? _ ? n.verdictUnknown : n.statAbsentValue : _e(v, j, d, _ ? n.calculationPercent : "%");
129
140
  }, h = (v) => {
130
141
  if (i || !p.operator) return {};
131
142
  if (p.operands.length === 0) return { names: n.calculationNoOperands };
132
- if (!v && p.operands.length > ve)
143
+ if (!v && p.operands.length > ge)
133
144
  return { names: n.calculationOperandCount(p.operands.length) };
134
- const y = (_) => p.operands.map((F, D) => {
135
- const Y = e.quantities.get(F.key), q = g(D);
136
- return q ? `${ee(q, v, n)} ${_(Y, q)}` : _(Y);
145
+ const k = (_) => p.operands.map((W, j) => {
146
+ const Y = e.quantities.get(W.key), F = g(j);
147
+ return F ? `${ee(F, v, n)} ${_(Y, F)}` : _(Y);
137
148
  }).join(" ");
138
149
  return {
139
- names: y((_) => _.label),
140
- numbers: y((_, F) => T(_, t.get(_.key), v, F))
150
+ names: k((_) => _.label),
151
+ numbers: k((_, W) => T(_, t.get(_.key), v, W))
141
152
  };
142
- }, j = (v) => {
143
- const y = s.assessment?.deviation;
144
- if (y === void 0 || p.target === void 0) return;
145
- const _ = ge(p, J(p, p.target), d, v ? n.calculationPercent : "%");
146
- return y > 0 ? n.calculationAboveTarget(_) : y < 0 ? n.calculationBelowTarget(_) : n.calculationOnTarget(_);
147
- }, N = h(!1).names, I = N === void 0 || p.operands.length === 0 || p.operands.length > ve ? N : `= ${N}`, w = h(!0), S = s.absence ? Ue(s.absence, n) : void 0, C = ` ${n.calculationEquals} `, $ = s.approximate ? `${n.calculationApproximately} ${T(p, s, !0, l)}` : T(p, s, !0, l), te = [
148
- (l ? `${ee(l, !0, n)} ` : "") + p.label + C + [w.names, w.numbers, $].filter(Boolean).join(`,${C}`),
153
+ }, q = (v) => {
154
+ const k = s.assessment?.deviation;
155
+ if (k === void 0 || p.target === void 0) return;
156
+ const _ = _e(p, J(p, p.target), d, v ? n.calculationPercent : "%");
157
+ return k > 0 ? n.calculationAboveTarget(_) : k < 0 ? n.calculationBelowTarget(_) : n.calculationOnTarget(_);
158
+ }, N = h(!1).names, I = N === void 0 || p.operands.length === 0 || p.operands.length > ge ? N : `= ${N}`, w = h(!0), S = s.absence ? He(s.absence, n) : void 0, C = ` ${n.calculationEquals} `, $ = s.approximate ? `${n.calculationApproximately} ${T(p, s, !0, r)}` : T(p, s, !0, r), te = [
159
+ (r ? `${ee(r, !0, n)} ` : "") + p.label + C + [w.names, w.numbers, $].filter(Boolean).join(`,${C}`),
149
160
  s.verdict !== void 0 && s.verdict !== "unknown" ? K(s.verdict, n) : void 0,
150
- j(!0),
161
+ q(!0),
151
162
  S
152
- ].filter(Boolean).join(", "), G = s.shown === null ? void 0 : p.format === "percent" ? "%" : p.unit, k = (v) => v === null ? n.statAbsentValue : d.number(v, p.decimals);
153
- return { amount: k(B(s, l)), ownAmount: k(s.shown), unit: G, names: I, target: j(!1), reason: S, sentence: te, spokenNames: w.names, spokenNumber: $ };
163
+ ].filter(Boolean).join(", "), G = s.shown === null ? void 0 : p.format === "percent" ? "%" : p.unit, y = (v) => v === null ? n.statAbsentValue : d.number(v, p.decimals);
164
+ return { amount: y(M(s, r)), ownAmount: y(s.shown), unit: G, names: I, target: q(!1), reason: S, sentence: te, spokenNames: w.names, spokenNumber: $ };
154
165
  }
155
- function ze(e, t, m, i, d) {
156
- const n = d ? `${ee(d, !0, i)} ` : "", l = t[0].spokenNames, g = n + e + (l === void 0 ? "" : ` ${i.calculationEquals} ${l}`), p = m.map(
157
- (s, B) => [`${s.label} ${t[B].spokenNumber}`, t[B].reason].filter(Boolean).join(", ")
166
+ function Ge(e, t, m, i, d) {
167
+ const n = d ? `${ee(d, !0, i)} ` : "", r = t[0].spokenNames, g = n + e + (r === void 0 ? "" : ` ${i.calculationEquals} ${r}`), p = m.map(
168
+ (s, M) => [`${s.label} ${t[M].spokenNumber}`, t[M].reason].filter(Boolean).join(", ")
158
169
  );
159
170
  return `${g}: ${p.join("; ")}`;
160
171
  }
161
- const Ve = "_frame_10pic_24 _text_18806_22", He = "_calculation_10pic_51", Qe = "_line_10pic_86", Ge = "_assessment_10pic_98", Ye = "_disclosure_10pic_107", Ze = "_amount_10pic_90", Je = "_list_10pic_128", Ke = "_item_10pic_129", Xe = "_derivation_10pic_130", et = "_labelCell_10pic_90", tt = "_names_10pic_90", nt = "_operator_10pic_90", at = "_unit_10pic_90", st = "_label_10pic_90", ot = "_approximate_10pic_360", it = "_target_10pic_102", rt = "_worst_10pic_102", ct = "_head_10pic_512", lt = "_headCell_10pic_519", dt = "_headUnit_10pic_532", ut = "_notes_10pic_539", mt = "_freshness_10pic_553", pt = "_headLabel_10pic_583", o = {
162
- frame: Ve,
163
- calculation: He,
164
- line: Qe,
165
- assessment: Ge,
166
- disclosure: Ye,
167
- amount: Ze,
168
- list: Je,
169
- item: Ke,
170
- derivation: Xe,
171
- labelCell: et,
172
- names: tt,
173
- operator: nt,
174
- unit: at,
175
- label: st,
176
- approximate: ot,
177
- target: it,
178
- worst: rt,
179
- head: ct,
180
- headCell: lt,
181
- headUnit: dt,
182
- notes: ut,
183
- freshness: mt,
184
- headLabel: pt
185
- }, ft = 10, Q = (e) => 4 + 2 * e, ht = (e) => 5 + 2 * e, vt = { ok: "success", unknown: "neutral", warning: "warning", alarm: "danger" }, gt = (...e) => e.filter(Boolean).join(" ");
186
- function _t({ asOf: e, ages: t }) {
187
- const m = _e(), i = be(), d = Le(e, t), n = d.freshness === "lost" ? i.freshnessDisconnected : d.freshness === "stale" ? i.freshnessStale : i.freshnessFresh;
172
+ const Ye = "_frame_10pic_24 _text_18806_22", Ze = "_calculation_10pic_51", Je = "_line_10pic_86", Ke = "_assessment_10pic_98", Xe = "_disclosure_10pic_107", et = "_amount_10pic_90", tt = "_list_10pic_128", nt = "_item_10pic_129", at = "_derivation_10pic_130", st = "_labelCell_10pic_90", ot = "_names_10pic_90", it = "_operator_10pic_90", rt = "_unit_10pic_90", ct = "_label_10pic_90", lt = "_approximate_10pic_360", dt = "_target_10pic_102", ut = "_worst_10pic_102", mt = "_head_10pic_512", pt = "_headCell_10pic_519", ft = "_headUnit_10pic_532", ht = "_notes_10pic_539", vt = "_freshness_10pic_553", gt = "_headLabel_10pic_583", o = {
173
+ frame: Ye,
174
+ calculation: Ze,
175
+ line: Je,
176
+ assessment: Ke,
177
+ disclosure: Xe,
178
+ amount: et,
179
+ list: tt,
180
+ item: nt,
181
+ derivation: at,
182
+ labelCell: st,
183
+ names: ot,
184
+ operator: it,
185
+ unit: rt,
186
+ label: ct,
187
+ approximate: lt,
188
+ target: dt,
189
+ worst: ut,
190
+ head: mt,
191
+ headCell: pt,
192
+ headUnit: ft,
193
+ notes: ht,
194
+ freshness: vt,
195
+ headLabel: gt
196
+ }, _t = 10, Q = (e) => 4 + 2 * e, bt = (e) => 5 + 2 * e, Nt = { ok: "success", unknown: "neutral", warning: "warning", alarm: "danger" }, wt = (...e) => e.filter(Boolean).join(" ");
197
+ function $t({ asOf: e, ages: t }) {
198
+ const m = be(), i = Ne(), d = Le(e, t), n = d.freshness === "lost" ? i.freshnessDisconnected : d.freshness === "stale" ? i.freshnessStale : i.freshnessFresh;
188
199
  return /* @__PURE__ */ O("span", { className: o.freshness, "data-freshness": d.freshness, children: [
189
200
  n,
190
201
  d.age !== null && ` · ${m.relative(d.age)}`
191
202
  ] });
192
203
  }
193
- function xt({
204
+ function yt({
194
205
  model: e,
195
206
  ref: t,
196
207
  className: m,
197
208
  style: i,
198
209
  density: d,
199
210
  "aria-label": n,
200
- "aria-labelledby": l,
211
+ "aria-labelledby": r,
201
212
  "aria-describedby": g,
202
213
  ...p
203
214
  }) {
204
- const s = e.metrics, B = Be(d, "regular") === "compact", T = _e(), h = be(), j = Ce(), N = We(e).map((a) => ({ view: a, results: qe(a) })), [I, w] = ae(() => /* @__PURE__ */ new Set()), [S, C] = ae(null), $ = ke(null), oe = me(
215
+ !n && !r && Ue("no-name", "A Calculation has no accessible name: give it aria-label or aria-labelledby.");
216
+ const s = e.metrics, M = Te(d, "regular") === "compact", T = be(), h = Ne(), q = ye(), N = We(e).map((a) => ({ view: a, results: qe(a) })), [I, w] = ae(() => /* @__PURE__ */ new Set()), [S, C] = ae(null), $ = ke(null), oe = me(
205
217
  (a) => {
206
218
  $.current = a, typeof t == "function" ? t(a) : t && (t.current = a);
207
219
  },
208
220
  [t]
209
- ), [te, G] = ae(!1), k = s?.length ?? 0, v = me(() => {
210
- const a = $.current, u = a && k > 0 ? getComputedStyle(a.firstElementChild).gridTemplateColumns.split(" ").map(parseFloat) : [], f = Q(k) - 1;
221
+ ), [te, G] = ae(!1), y = s?.length ?? 0, v = me(() => {
222
+ const a = $.current, u = a && y > 0 ? getComputedStyle(a.firstElementChild).gridTemplateColumns.split(" ").map(parseFloat) : [], f = Q(y) - 1;
211
223
  if (!a || u.length <= f || u.some((x) => !Number.isFinite(x))) {
212
224
  G(!1);
213
225
  return;
214
226
  }
215
- const A = u.slice(2, f).reduce((x, M) => x + M, 0);
216
- let r = 0;
217
- const E = document.createRange();
227
+ const A = u.slice(2, f).reduce((x, E) => x + E, 0);
228
+ let c = 0;
229
+ const B = document.createRange();
218
230
  for (const x of a.querySelectorAll(`.${o.label}`)) {
219
- E.selectNodeContents(x);
220
- const M = [...E.getClientRects()].reduce((R, W) => R + W.width, 0);
221
- if (M === 0) continue;
222
- const V = x.parentElement, z = x.getBoundingClientRect().left - V.getBoundingClientRect().left;
223
- r = Math.max(r, z + M + parseFloat(getComputedStyle(V).paddingRight));
231
+ B.selectNodeContents(x);
232
+ const E = [...B.getClientRects()].reduce((L, R) => L + R.width, 0);
233
+ if (E === 0) continue;
234
+ const z = x.parentElement, V = x.getBoundingClientRect().left - z.getBoundingClientRect().left;
235
+ c = Math.max(c, V + E + parseFloat(getComputedStyle(z).paddingRight));
224
236
  }
225
- const L = parseFloat(getComputedStyle(document.documentElement).fontSize);
226
- G(a.clientWidth - A < Math.min(r, ft * L));
227
- }, [k]);
228
- ye(() => v()), Ae(() => {
237
+ const D = parseFloat(getComputedStyle(document.documentElement).fontSize);
238
+ G(a.clientWidth - A < Math.min(c, _t * D));
239
+ }, [y]);
240
+ Ae(() => v()), Ee(() => {
229
241
  const a = $.current;
230
- if (!a || k === 0) return;
242
+ if (!a || y === 0) return;
231
243
  const u = new ResizeObserver(() => v());
232
244
  return u.observe(a), () => u.disconnect();
233
- }, [v, k]);
234
- const y = (a) => w((u) => {
245
+ }, [v, y]);
246
+ const k = (a) => w((u) => {
235
247
  const f = new Set(u);
236
248
  return f.delete(a) || f.add(a), f;
237
- }), _ = (a, u) => je(
249
+ }), _ = (a, u) => Ie(
238
250
  a,
239
251
  u,
240
252
  N.map(({ results: f }) => f.get(a.operands[u].key).shown)
241
253
  );
242
- let F = !1;
243
- const D = (a, u) => a.map(({ own: f, text: A }, r) => [
254
+ let W = !1;
255
+ const j = (a, u) => a.map(({ own: f, text: A }, c) => [
244
256
  /* @__PURE__ */ O(
245
257
  "span",
246
258
  {
247
259
  className: o.amount,
248
260
  "aria-hidden": "true",
249
261
  "data-verdict": f.verdict,
250
- "data-later": r > 0 ? "" : void 0,
251
- style: s ? { "--_calculation-column": Q(r) } : void 0,
262
+ "data-later": c > 0 ? "" : void 0,
263
+ style: s ? { "--_calculation-column": Q(c) } : void 0,
252
264
  children: [
253
- f.approximate && /* @__PURE__ */ c(Re, { content: h.calculationApproximateNote, children: /* @__PURE__ */ c("span", { className: o.approximate, children: "≈" }) }),
265
+ f.approximate && /* @__PURE__ */ l(Re, { content: h.calculationApproximateNote, children: /* @__PURE__ */ l("span", { className: o.approximate, children: "≈" }) }),
254
266
  u ? A.ownAmount : A.amount
255
267
  ]
256
268
  },
257
- `amount-${r}`
269
+ `amount-${c}`
258
270
  ),
259
- /* @__PURE__ */ c(
271
+ /* @__PURE__ */ l(
260
272
  "span",
261
273
  {
262
274
  className: o.unit,
263
275
  "aria-hidden": "true",
264
- style: s ? { "--_calculation-column": ht(r) } : void 0,
265
- "data-last": s && r === a.length - 1 ? "" : void 0,
276
+ style: s ? { "--_calculation-column": bt(c) } : void 0,
277
+ "data-last": s && c === a.length - 1 ? "" : void 0,
266
278
  children: s && !u ? void 0 : A.unit
267
279
  },
268
- `unit-${r}`
280
+ `unit-${c}`
269
281
  )
270
- ]), Y = (a, u) => S === null ? void 0 : a === S ? "use" : u === S ? "operand" : void 0, q = (a, u, f, A) => {
271
- const r = e.quantities.get(a), E = N.map(({ view: b, results: U }) => ({
282
+ ]), Y = (a, u) => S === null ? void 0 : a === S ? "use" : u === S ? "operand" : void 0, F = (a, u, f, A) => {
283
+ const c = e.quantities.get(a), B = N.map(({ view: b, results: U }) => ({
272
284
  own: U.get(a),
273
- text: Ie(b, U, a, u, T, h, f.position, (Se) => _(r, Se))
274
- })), { own: L, text: x } = E[0], M = r.operator !== void 0 && !u, V = a === e.result && !u, z = M && r.operands.length > 0 && (r.interim ? f.flat : V), R = M && !z && r.operands.length > 0, W = R && I.has(a);
275
- F ||= R;
276
- const ie = `${j}-${a}`, ne = { depth: z ? f.depth : f.depth + 1, flat: !1, parent: a }, Z = M ? r.operands.find((b) => b.previous) : void 0, re = Z && f.flat ? q(Z.key, !1, { ...f, parent: a, position: void 0 }, `${A}-c`) : [], xe = Z && !f.flat ? q(Z.key, !1, { ...ne, flat: !0 }, `${A}-c`) : [], ce = M ? r.operands.map(
277
- (b, U) => b.previous ? null : q(b.key, b.reference, { ...ne, position: _(r, U) }, `${A}-${U}`)
278
- ) : [], H = R && !W && L.worst !== void 0 && X(L.worst) > X(L.verdict ?? "ok") ? L.worst : void 0, P = u ? void 0 : r.given, Oe = f.position ? ee(f.position, !1, h) : void 0, le = [
279
- !u && r.explanation !== void 0 && /* @__PURE__ */ c("span", { children: r.explanation }, "explanation"),
280
- P?.source !== void 0 && /* @__PURE__ */ c("span", { children: h.calculationSource(P.source) }, "source"),
281
- P?.asOf !== void 0 && (P.ages !== void 0 ? /* @__PURE__ */ c(_t, { asOf: P.asOf, ages: P.ages }, "asOf") : /* @__PURE__ */ c("span", { children: h.asOfAgo(T.dateTime(new Date(P.asOf), !1)) }, "asOf")),
282
- !u && r.aside !== void 0 && /* @__PURE__ */ c("span", { children: r.aside }, "aside")
283
- ].filter(Boolean), de = V ? "result" : r.interim && !u && f.flat ? "interim" : void 0, ue = /* @__PURE__ */ O(
285
+ text: Qe(b, U, a, u, T, h, f.position, (Ce) => _(c, Ce))
286
+ })), { own: D, text: x } = B[0], E = c.operator !== void 0 && !u, z = a === e.result && !u, V = E && c.operands.length > 0 && (c.interim ? f.flat : z), L = E && !V && c.operands.length > 0, R = L && I.has(a);
287
+ W ||= L;
288
+ const ie = `${q}-${a}`, ne = { depth: V ? f.depth : f.depth + 1, flat: !1, parent: a }, Z = E ? c.operands.find((b) => b.previous) : void 0, re = Z && f.flat ? F(Z.key, !1, { ...f, parent: a, position: void 0 }, `${A}-c`) : [], Oe = Z && !f.flat ? F(Z.key, !1, { ...ne, flat: !0 }, `${A}-c`) : [], ce = E ? c.operands.map(
289
+ (b, U) => b.previous ? null : F(b.key, b.reference, { ...ne, position: _(c, U) }, `${A}-${U}`)
290
+ ) : [], H = L && !R && D.worst !== void 0 && X(D.worst) > X(D.verdict ?? "ok") ? D.worst : void 0, P = u ? void 0 : c.given, Se = f.position ? ee(f.position, !1, h) : void 0, le = [
291
+ !u && c.explanation !== void 0 && /* @__PURE__ */ l("span", { children: c.explanation }, "explanation"),
292
+ P?.source !== void 0 && /* @__PURE__ */ l("span", { children: h.calculationSource(P.source) }, "source"),
293
+ P?.asOf !== void 0 && (P.ages !== void 0 ? /* @__PURE__ */ l($t, { asOf: P.asOf, ages: P.ages }, "asOf") : /* @__PURE__ */ l("span", { children: h.asOfAgo(T.dateTime(new Date(P.asOf), !1)) }, "asOf")),
294
+ !u && c.aside !== void 0 && /* @__PURE__ */ l("span", { children: c.aside }, "aside")
295
+ ].filter(Boolean), de = z ? "result" : c.interim && !u && f.flat ? "interim" : void 0, ue = /* @__PURE__ */ O(
284
296
  "div",
285
297
  {
286
298
  className: o.line,
287
299
  style: { "--_calculation-depth": f.depth },
288
300
  "data-inner": f.depth > 0 ? "" : void 0,
289
301
  "data-kind": de,
290
- "data-foldable": R ? "" : void 0,
302
+ "data-foldable": L ? "" : void 0,
291
303
  "data-reference": u ? "" : void 0,
292
- "data-emphasis": u ? void 0 : r.emphasis,
293
- "data-rule": !u && r.rule ? "" : void 0,
304
+ "data-emphasis": u ? void 0 : c.emphasis,
305
+ "data-rule": !u && c.rule ? "" : void 0,
294
306
  "data-mark": Y(a, f.parent),
295
307
  onPointerEnter: () => C(a),
296
308
  onPointerLeave: () => C(null),
297
309
  onFocus: () => C(a),
298
310
  onBlur: () => C(null),
299
- onClick: R ? () => {
300
- window.getSelection()?.toString() || y(a);
311
+ onClick: L ? () => {
312
+ window.getSelection()?.toString() || k(a);
301
313
  } : void 0,
302
314
  children: [
303
- /* @__PURE__ */ c(Te, { children: [
304
- s ? ze(r.label, E.map((b) => b.text), s, h, f.position) : x.sentence,
305
- E.some((b) => b.own.approximate) && h.calculationApproximateNote,
315
+ /* @__PURE__ */ l(Be, { children: [
316
+ s ? Ge(c.label, B.map((b) => b.text), s, h, f.position) : x.sentence,
317
+ B.some((b) => b.own.approximate) && h.calculationApproximateNote,
306
318
  H !== void 0 && h.calculationWorstInside(K(H, h))
307
319
  ].filter(Boolean).join(". ") }),
308
320
  /* @__PURE__ */ O("span", { className: o.labelCell, children: [
309
- R ? /* @__PURE__ */ c(
321
+ L ? /* @__PURE__ */ l(
310
322
  "button",
311
323
  {
312
324
  type: "button",
313
325
  className: o.disclosure,
314
- "aria-expanded": W,
326
+ "aria-expanded": R,
315
327
  "aria-controls": ie,
316
- "aria-label": (W ? h.calculationHideDerivation : h.calculationShowDerivation)(r.label),
317
- children: /* @__PURE__ */ c(Ee, { "data-open": W ? "" : void 0 })
328
+ "aria-label": (R ? h.calculationHideDerivation : h.calculationShowDerivation)(c.label),
329
+ children: /* @__PURE__ */ l(De, { "data-open": R ? "" : void 0 })
318
330
  }
319
- ) : /* @__PURE__ */ c("span", { className: o.disclosure, "aria-hidden": "true" }),
320
- /* @__PURE__ */ c("span", { className: o.label, "aria-hidden": "true", children: r.label })
331
+ ) : /* @__PURE__ */ l("span", { className: o.disclosure, "aria-hidden": "true" }),
332
+ /* @__PURE__ */ l("span", { className: o.label, "aria-hidden": "true", children: c.label })
321
333
  ] }),
322
- /* @__PURE__ */ c("span", { className: o.names, "aria-hidden": "true", children: M && !z && !W ? x.names : void 0 }),
323
- /* @__PURE__ */ c("span", { className: o.operator, "aria-hidden": "true", children: Oe }),
324
- D(E, de !== void 0),
334
+ /* @__PURE__ */ l("span", { className: o.names, "aria-hidden": "true", children: E && !V && !R ? x.names : void 0 }),
335
+ /* @__PURE__ */ l("span", { className: o.operator, "aria-hidden": "true", children: Se }),
336
+ j(B, de !== void 0),
325
337
  /* @__PURE__ */ O("span", { className: o.assessment, "aria-hidden": "true", children: [
326
338
  s ? (
327
339
  /* Short: which metric. The sentence carries the full reason. */
328
340
  s.map(
329
- (b, U) => E[U].own.absence && /* @__PURE__ */ c(se, { children: h.calculationMissing(b.unit ?? b.label) }, b.id)
341
+ (b, U) => B[U].own.absence && /* @__PURE__ */ l(se, { children: h.calculationMissing(b.unit ?? b.label) }, b.id)
330
342
  )
331
- ) : x.reason !== void 0 ? /* @__PURE__ */ c(se, { children: x.reason }) : L.verdict !== void 0 && /* @__PURE__ */ c(se, { tone: vt[L.verdict], children: K(L.verdict, h) }),
332
- x.target !== void 0 && /* @__PURE__ */ c("span", { className: o.target, children: x.target }),
333
- H !== void 0 && /* @__PURE__ */ c("span", { className: o.worst, "data-verdict": H, children: h.calculationWorstInside(K(H, h)) })
343
+ ) : x.reason !== void 0 ? /* @__PURE__ */ l(se, { children: x.reason }) : D.verdict !== void 0 && /* @__PURE__ */ l(se, { tone: Nt[D.verdict], children: K(D.verdict, h) }),
344
+ x.target !== void 0 && /* @__PURE__ */ l("span", { className: o.target, children: x.target }),
345
+ H !== void 0 && /* @__PURE__ */ l("span", { className: o.worst, "data-verdict": H, children: h.calculationWorstInside(K(H, h)) })
334
346
  ] }),
335
347
  le.length > 0 && /* A click here - on a link in the aside, on a sparkline - is the
336
348
  caller's, not a fold. */
337
- /* @__PURE__ */ c("span", { className: o.notes, onClick: (b) => b.stopPropagation(), children: le })
349
+ /* @__PURE__ */ l("span", { className: o.notes, onClick: (b) => b.stopPropagation(), children: le })
338
350
  ]
339
351
  }
340
352
  );
341
- return z ? [
353
+ return V ? [
342
354
  ...re,
343
355
  /* @__PURE__ */ O("li", { className: o.item, children: [
344
- /* @__PURE__ */ c("ul", { className: o.list, children: ce }),
356
+ /* @__PURE__ */ l("ul", { className: o.list, children: ce }),
345
357
  ue
346
358
  ] }, A)
347
359
  ] : [
348
360
  ...re,
349
- /* @__PURE__ */ O("li", { className: o.item, "data-open": W ? "" : void 0, style: { "--_calculation-depth": f.depth }, children: [
361
+ /* @__PURE__ */ O("li", { className: o.item, "data-open": R ? "" : void 0, style: { "--_calculation-depth": f.depth }, children: [
350
362
  ue,
351
- R && /* @__PURE__ */ O("ul", { id: ie, className: o.derivation, hidden: !W, children: [
352
- xe,
363
+ L && /* @__PURE__ */ O("ul", { id: ie, className: o.derivation, hidden: !R, children: [
364
+ Oe,
353
365
  ce,
354
- /* @__PURE__ */ c("li", { className: o.item, "aria-hidden": "true", children: /* @__PURE__ */ O(
366
+ /* @__PURE__ */ l("li", { className: o.item, "aria-hidden": "true", children: /* @__PURE__ */ O(
355
367
  "div",
356
368
  {
357
369
  className: o.line,
@@ -361,63 +373,63 @@ function xt({
361
373
  "data-mark": S === a ? "use" : void 0,
362
374
  children: [
363
375
  /* @__PURE__ */ O("span", { className: o.labelCell, children: [
364
- /* @__PURE__ */ c("span", { className: o.disclosure }),
376
+ /* @__PURE__ */ l("span", { className: o.disclosure }),
365
377
  /* @__PURE__ */ O("span", { className: o.label, children: [
366
378
  "= ",
367
- r.label
379
+ c.label
368
380
  ] })
369
381
  ] }),
370
- /* @__PURE__ */ c("span", { className: o.names }),
371
- /* @__PURE__ */ c("span", { className: o.operator }),
372
- D(E, !0)
382
+ /* @__PURE__ */ l("span", { className: o.names }),
383
+ /* @__PURE__ */ l("span", { className: o.operator }),
384
+ j(B, !0)
373
385
  ]
374
386
  }
375
387
  ) })
376
388
  ] })
377
389
  ] }, A)
378
390
  ];
379
- }, $e = q(e.result, !1, { depth: 0, flat: !0, parent: null }, "r");
391
+ }, xe = F(e.result, !1, { depth: 0, flat: !0, parent: null }, "r");
380
392
  return (
381
393
  /* The frame is the surface and the container the layout measures itself
382
394
  against; the list inside it is the statement. */
383
- /* @__PURE__ */ c(
395
+ /* @__PURE__ */ l(
384
396
  "div",
385
397
  {
386
398
  ...p,
387
399
  ref: oe,
388
- className: gt(o.frame, m),
400
+ className: wt(o.frame, m),
389
401
  style: s ? {
390
- "--_calculation-figure-tracks": Array(k * 2).fill("auto").join(" "),
391
- "--_calculation-figures-end": Q(k),
392
- "--_calculation-assessment-column": Q(k),
402
+ "--_calculation-figure-tracks": Array(y * 2).fill("auto").join(" "),
403
+ "--_calculation-figures-end": Q(y),
404
+ "--_calculation-assessment-column": Q(y),
393
405
  ...i
394
406
  } : i,
395
- "data-still": F ? void 0 : "",
396
- "data-metrics": s ? k : void 0,
407
+ "data-still": W ? void 0 : "",
408
+ "data-metrics": s ? y : void 0,
397
409
  "data-two-lines": te ? "" : void 0,
398
- "data-compact": B ? "" : void 0,
399
- children: /* @__PURE__ */ O("ul", { className: o.calculation, "aria-label": n, "aria-labelledby": l, "aria-describedby": g, children: [
410
+ "data-compact": M ? "" : void 0,
411
+ children: /* @__PURE__ */ O("ul", { className: o.calculation, "aria-label": n, "aria-labelledby": r, "aria-describedby": g, children: [
400
412
  s && /* The head names each metric and its unit above its column. Every
401
413
  row's sentence names them too, so the head is for the eye. */
402
- /* @__PURE__ */ c("li", { className: o.item, "aria-hidden": "true", children: /* @__PURE__ */ c("div", { className: o.head, children: s.map((a, u) => /* @__PURE__ */ O(
414
+ /* @__PURE__ */ l("li", { className: o.item, "aria-hidden": "true", children: /* @__PURE__ */ l("div", { className: o.head, children: s.map((a, u) => /* @__PURE__ */ O(
403
415
  "span",
404
416
  {
405
417
  className: o.headCell,
406
418
  "data-unit": a.unit === void 0 ? void 0 : "",
407
419
  style: { "--_calculation-column": Q(u) },
408
420
  children: [
409
- /* @__PURE__ */ c("span", { className: o.headLabel, children: a.label }),
410
- a.unit !== void 0 && /* @__PURE__ */ c("span", { className: o.headUnit, children: a.unit })
421
+ /* @__PURE__ */ l("span", { className: o.headLabel, children: a.label }),
422
+ a.unit !== void 0 && /* @__PURE__ */ l("span", { className: o.headUnit, children: a.unit })
411
423
  ]
412
424
  },
413
425
  a.id
414
426
  )) }) }),
415
- $e
427
+ xe
416
428
  ] })
417
429
  }
418
430
  )
419
431
  );
420
432
  }
421
433
  export {
422
- xt as CalculationView
434
+ yt as CalculationView
423
435
  };
package/docs/llms-full.md CHANGED
@@ -1,4 +1,4 @@
1
- # @umriss-ui/calculation 0.43.0
1
+ # @umriss-ui/calculation 0.44.0
2
2
 
3
3
  > React calculation view for data-dense applications - a derivation written as it is shown, evaluated by the library, folded and read line by line.
4
4
 
@@ -1568,7 +1568,7 @@ Also takes every attribute of `<div>` – without `children`.
1568
1568
  - No result, formula text or operator of your own: a written-out operation the library did not perform could say something the number does not ([ADR-0027](https://github.com/romanhaendler/umriss-ui/blob/main/docs/adr/0027-a-calculation-is-written-as-it-is-shown.md)).
1569
1569
  - No input: a calculation shows how a figure came about; changing a given is your application's form.
1570
1570
 
1571
- What umriss deliberately does not build, and why: [ADR-0032](https://github.com/romanhaendler/umriss-ui/blob/calculation-v0.43.0/docs/adr/0032-what-umriss-is-not.md).
1571
+ What umriss deliberately does not build, and why: [ADR-0032](https://github.com/romanhaendler/umriss-ui/blob/calculation-v0.44.0/docs/adr/0032-what-umriss-is-not.md).
1572
1572
 
1573
1573
  ### Tree
1574
1574
 
@@ -1849,7 +1849,7 @@ type Severity = "warning" | "alarm";
1849
1849
  - Four operators and nothing else – no powers, roots or functions; compute those before and hand them in as givens.
1850
1850
  - A unit is a label and is never converted or checked; the calculation does no unit algebra.
1851
1851
 
1852
- What umriss deliberately does not build, and why: [ADR-0032](https://github.com/romanhaendler/umriss-ui/blob/calculation-v0.43.0/docs/adr/0032-what-umriss-is-not.md).
1852
+ What umriss deliberately does not build, and why: [ADR-0032](https://github.com/romanhaendler/umriss-ui/blob/calculation-v0.44.0/docs/adr/0032-what-umriss-is-not.md).
1853
1853
 
1854
1854
  ### Chain
1855
1855
 
@@ -2197,7 +2197,7 @@ type Severity = "warning" | "alarm";
2197
2197
 
2198
2198
  - A chain in view does not fold; as an operand of a tree it folds to its last interim.
2199
2199
 
2200
- What umriss deliberately does not build, and why: [ADR-0032](https://github.com/romanhaendler/umriss-ui/blob/calculation-v0.43.0/docs/adr/0032-what-umriss-is-not.md).
2200
+ What umriss deliberately does not build, and why: [ADR-0032](https://github.com/romanhaendler/umriss-ui/blob/calculation-v0.44.0/docs/adr/0032-what-umriss-is-not.md).
2201
2201
 
2202
2202
  ### Rows from data
2203
2203
 
@@ -2637,7 +2637,7 @@ From `Metric` — the full table stands on [Metrics](#metrics).
2637
2637
 
2638
2638
  - Only a sum takes any count: an empty product, a difference of one and a quotient of anything but two still fail on the first render.
2639
2639
 
2640
- What umriss deliberately does not build, and why: [ADR-0032](https://github.com/romanhaendler/umriss-ui/blob/calculation-v0.43.0/docs/adr/0032-what-umriss-is-not.md).
2640
+ What umriss deliberately does not build, and why: [ADR-0032](https://github.com/romanhaendler/umriss-ui/blob/calculation-v0.44.0/docs/adr/0032-what-umriss-is-not.md).
2641
2641
 
2642
2642
  ### Given
2643
2643
 
@@ -3323,7 +3323,7 @@ The keys of [Calculation](#calculation) apply here.
3323
3323
  - Unit, format and places belong to the metric; on a quantity they fail on the first render, and so does a missing or unknown metric key in a `value`.
3324
3324
  - No target or limits with metrics: an assessment per cell is not there yet.
3325
3325
 
3326
- What umriss deliberately does not build, and why: [ADR-0032](https://github.com/romanhaendler/umriss-ui/blob/calculation-v0.43.0/docs/adr/0032-what-umriss-is-not.md).
3326
+ What umriss deliberately does not build, and why: [ADR-0032](https://github.com/romanhaendler/umriss-ui/blob/calculation-v0.44.0/docs/adr/0032-what-umriss-is-not.md).
3327
3327
 
3328
3328
  ## In practice
3329
3329
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@umriss-ui/calculation",
3
- "version": "0.43.0",
3
+ "version": "0.44.0",
4
4
  "description": "React calculation view for data-dense applications - a derivation written as it is shown, evaluated by the library, folded and read line by line.",
5
5
  "license": "MIT",
6
6
  "author": "Roman Händler",
@@ -56,7 +56,7 @@
56
56
  }
57
57
  },
58
58
  "peerDependencies": {
59
- "@umriss-ui/core": "^0.43.0",
59
+ "@umriss-ui/core": "^0.44.0",
60
60
  "react": ">=19",
61
61
  "react-dom": ">=19"
62
62
  },
@@ -72,7 +72,7 @@
72
72
  "typescript": "^5.6.3",
73
73
  "vite": "^6.0.0",
74
74
  "vite-plugin-dts": "^4.3.0",
75
- "@umriss-ui/core": "0.43.0",
75
+ "@umriss-ui/core": "0.44.0",
76
76
  "@umriss-ui/demo": "0.0.0"
77
77
  },
78
78
  "scripts": {