@robosystems/report-components 0.2.0 → 0.2.2
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/dist/adapters/index.d.ts +1 -1
- package/dist/adapters/index.js +1 -1
- package/dist/{chunk-POSLHOTN.js → chunk-RQXAMFTZ.js} +201 -31
- package/dist/chunk-RQXAMFTZ.js.map +1 -0
- package/dist/{index-D6FzPTm5.d.ts → index-BS6_6h3l.d.ts} +162 -1
- package/dist/index.d.ts +92 -29
- package/dist/index.js +701 -182
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/dist/chunk-POSLHOTN.js.map +0 -1
package/dist/index.js
CHANGED
|
@@ -1,34 +1,8 @@
|
|
|
1
|
-
import { isExternalFactUrl, BLOCK_ORDER,
|
|
2
|
-
export { BLOCK_ORDER, BLOCK_TITLES, NS, cypherAdapter, fetchSecReportShell, fetchSecSection, humanize, isExternalFactUrl, jsonldFileAdapter, mergeSecSections, parseJsonld, parseStore, parseStructureDefinition, qname } from './chunk-
|
|
1
|
+
import { formatDate, BLOCK_TITLES, numericKindOf, humanizeDuration, formatValue, formatPeriod, isExternalFactUrl, BLOCK_ORDER, humanize, qname, currencySymbolFor } from './chunk-RQXAMFTZ.js';
|
|
2
|
+
export { BLOCK_ORDER, BLOCK_TITLES, NS, currencySymbolFor, cypherAdapter, fetchSecReportShell, fetchSecSection, formatDate, formatMoney, formatPeriod, formatValue, humanize, humanizeDuration, isExternalFactUrl, jsonldFileAdapter, mergeSecSections, numericKindOf, parseJsonld, parseStore, parseStructureDefinition, qname } from './chunk-RQXAMFTZ.js';
|
|
3
3
|
import { useState, useEffect, useMemo, useRef } from 'react';
|
|
4
4
|
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
5
5
|
|
|
6
|
-
// src/format.ts
|
|
7
|
-
function formatMoney(value, opts = {}) {
|
|
8
|
-
if (value === null || value === void 0 || Number.isNaN(value)) return "\u2014";
|
|
9
|
-
const symbol = opts.currencySymbol ?? "$";
|
|
10
|
-
const abs = Math.abs(value).toLocaleString("en-US", {
|
|
11
|
-
minimumFractionDigits: 2,
|
|
12
|
-
maximumFractionDigits: 2
|
|
13
|
-
});
|
|
14
|
-
return value < 0 ? `${symbol}(${abs})` : `${symbol}${abs}`;
|
|
15
|
-
}
|
|
16
|
-
var MONTHS = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"];
|
|
17
|
-
function formatDate(iso) {
|
|
18
|
-
if (!iso) return "";
|
|
19
|
-
const m = /^(\d{4})-(\d{2})-(\d{2})/.exec(iso);
|
|
20
|
-
if (!m) return iso;
|
|
21
|
-
const [, year, month, day] = m;
|
|
22
|
-
const idx = Number(month) - 1;
|
|
23
|
-
return `${MONTHS[idx] ?? month} ${Number(day)}, ${year}`;
|
|
24
|
-
}
|
|
25
|
-
function formatPeriod(period) {
|
|
26
|
-
if (period.type === "instant") {
|
|
27
|
-
return `As of ${formatDate(period.instant ?? period.end)}`;
|
|
28
|
-
}
|
|
29
|
-
return `${formatDate(period.startDate)} \u2013 ${formatDate(period.endDate ?? period.end)}`;
|
|
30
|
-
}
|
|
31
|
-
|
|
32
6
|
// src/project.ts
|
|
33
7
|
function fallbackElement(id) {
|
|
34
8
|
return {
|
|
@@ -81,6 +55,121 @@ function calcSubtotals(model) {
|
|
|
81
55
|
for (const assoc of model.calcAssociations) out.add(assoc.parent);
|
|
82
56
|
return out;
|
|
83
57
|
}
|
|
58
|
+
function sliceReportSection(model, informationBlockId) {
|
|
59
|
+
const ib = model.informationBlocks.find((b) => b.id === informationBlockId);
|
|
60
|
+
return { ...model, informationBlocks: ib ? [ib] : [] };
|
|
61
|
+
}
|
|
62
|
+
function footCheck(model, table, elementId, columnIndex) {
|
|
63
|
+
const kids = model.calcAssociations.filter((a) => a.parent === elementId);
|
|
64
|
+
if (!kids.length) return null;
|
|
65
|
+
const valueOf = (id) => {
|
|
66
|
+
const row = table.rows.find((r) => r.element.id === id && r.members.length === 0);
|
|
67
|
+
return row ? row.cells[columnIndex]?.value ?? null : null;
|
|
68
|
+
};
|
|
69
|
+
const terms = kids.slice().sort((a, b) => a.order - b.order).map((a) => ({
|
|
70
|
+
element: model.elements[a.child] ?? fallbackElement(a.child),
|
|
71
|
+
weight: a.weight,
|
|
72
|
+
value: valueOf(a.child)
|
|
73
|
+
}));
|
|
74
|
+
const present = terms.filter((t) => t.value !== null);
|
|
75
|
+
const expected = present.length ? present.reduce((sum, t) => sum + t.value * t.weight, 0) : null;
|
|
76
|
+
const actual = valueOf(elementId);
|
|
77
|
+
const ok = expected !== null && actual !== null && Math.abs(expected - actual) < 5e-3;
|
|
78
|
+
return {
|
|
79
|
+
element: model.elements[elementId] ?? fallbackElement(elementId),
|
|
80
|
+
columnIndex,
|
|
81
|
+
terms,
|
|
82
|
+
expected,
|
|
83
|
+
actual,
|
|
84
|
+
ok
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
// src/pivot.ts
|
|
89
|
+
var DOMAIN = "\u2205";
|
|
90
|
+
function dimKey(axis) {
|
|
91
|
+
return `dim:${axis}`;
|
|
92
|
+
}
|
|
93
|
+
function axisOf(key) {
|
|
94
|
+
return key.startsWith("dim:") ? key.slice(4) : null;
|
|
95
|
+
}
|
|
96
|
+
function dimAxes(keys) {
|
|
97
|
+
return keys.map(axisOf).filter((a) => a !== null);
|
|
98
|
+
}
|
|
99
|
+
function memberByAxis(fact) {
|
|
100
|
+
const m = /* @__PURE__ */ new Map();
|
|
101
|
+
for (const d of fact.dimensions ?? []) m.set(d.axis, d);
|
|
102
|
+
return m;
|
|
103
|
+
}
|
|
104
|
+
function coordinate(byAxis, axes) {
|
|
105
|
+
return axes.map((a) => `${a}=${byAxis.get(a)?.member ?? byAxis.get(a)?.typedValue ?? DOMAIN}`).join("|");
|
|
106
|
+
}
|
|
107
|
+
function sectionFacts(model, ib) {
|
|
108
|
+
return model.facts.filter((f) => f.factSet !== null && f.factSet === ib.factSet);
|
|
109
|
+
}
|
|
110
|
+
function localName(qname2) {
|
|
111
|
+
return qname2.includes(":") ? qname2.split(":").pop() : qname2;
|
|
112
|
+
}
|
|
113
|
+
function presentationNodeLocals(model, structureId) {
|
|
114
|
+
const out = /* @__PURE__ */ new Set();
|
|
115
|
+
for (const a of model.presAssociations) {
|
|
116
|
+
if (a.structure !== structureId) continue;
|
|
117
|
+
out.add(localName(a.parent));
|
|
118
|
+
out.add(localName(a.child));
|
|
119
|
+
}
|
|
120
|
+
return out;
|
|
121
|
+
}
|
|
122
|
+
function presentationScope(model, structureId) {
|
|
123
|
+
const declared = presentationNodeLocals(model, structureId);
|
|
124
|
+
let listsMembers = false;
|
|
125
|
+
for (const l of declared) {
|
|
126
|
+
if (l.endsWith("Member")) {
|
|
127
|
+
listsMembers = true;
|
|
128
|
+
break;
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
return { declared, listsMembers };
|
|
132
|
+
}
|
|
133
|
+
function dimensionInScope(scope, d) {
|
|
134
|
+
if (!scope.declared.has(localName(d.axis))) return false;
|
|
135
|
+
return !scope.listsMembers || d.member === null || scope.declared.has(localName(d.member));
|
|
136
|
+
}
|
|
137
|
+
function presentationTree(model, structureId) {
|
|
138
|
+
const children = /* @__PURE__ */ new Map();
|
|
139
|
+
const froms = /* @__PURE__ */ new Set();
|
|
140
|
+
const tos = /* @__PURE__ */ new Set();
|
|
141
|
+
for (const assoc of model.presAssociations) {
|
|
142
|
+
if (assoc.structure !== structureId) continue;
|
|
143
|
+
const kids = children.get(assoc.parent) ?? [];
|
|
144
|
+
kids.push([assoc.order, assoc.child]);
|
|
145
|
+
children.set(assoc.parent, kids);
|
|
146
|
+
froms.add(assoc.parent);
|
|
147
|
+
tos.add(assoc.child);
|
|
148
|
+
}
|
|
149
|
+
const childrenOf = /* @__PURE__ */ new Map();
|
|
150
|
+
for (const [parent, kids] of children) {
|
|
151
|
+
childrenOf.set(
|
|
152
|
+
parent,
|
|
153
|
+
kids.sort((a, b) => a[0] - b[0]).map(([, child]) => child)
|
|
154
|
+
);
|
|
155
|
+
}
|
|
156
|
+
const rootKey = (root) => {
|
|
157
|
+
const kids = children.get(root);
|
|
158
|
+
return kids && kids.length ? kids[0][0] : 0;
|
|
159
|
+
};
|
|
160
|
+
const roots = [...froms].filter((f) => !tos.has(f)).sort((a, b) => rootKey(a) - rootKey(b));
|
|
161
|
+
const indexOf = /* @__PURE__ */ new Map();
|
|
162
|
+
const seen = /* @__PURE__ */ new Set();
|
|
163
|
+
const pre = (node) => {
|
|
164
|
+
if (seen.has(node)) return;
|
|
165
|
+
seen.add(node);
|
|
166
|
+
const ln = localName(node);
|
|
167
|
+
if (!indexOf.has(ln)) indexOf.set(ln, indexOf.size);
|
|
168
|
+
for (const child of childrenOf.get(node) ?? []) pre(child);
|
|
169
|
+
};
|
|
170
|
+
for (const root of roots) pre(root);
|
|
171
|
+
return { childrenOf, roots, indexOf };
|
|
172
|
+
}
|
|
84
173
|
function structureForBlock(model, ib) {
|
|
85
174
|
if (ib.structureId) {
|
|
86
175
|
const byId = model.structures.find((s) => s.id === ib.structureId);
|
|
@@ -88,17 +177,68 @@ function structureForBlock(model, ib) {
|
|
|
88
177
|
}
|
|
89
178
|
return model.structures.find((s) => s.blockType === ib.blockType) ?? null;
|
|
90
179
|
}
|
|
91
|
-
function
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
180
|
+
function fallbackElement2(id) {
|
|
181
|
+
return {
|
|
182
|
+
id,
|
|
183
|
+
qname: qname(id),
|
|
184
|
+
label: humanize(id),
|
|
185
|
+
balance: null,
|
|
186
|
+
periodType: null,
|
|
187
|
+
abstract: false,
|
|
188
|
+
monetary: false
|
|
189
|
+
};
|
|
190
|
+
}
|
|
191
|
+
var elementOf = (model, id) => model.elements[id] ?? fallbackElement2(id);
|
|
192
|
+
function defaultPivotConfig(model, ib) {
|
|
193
|
+
const facts = sectionFacts(model, ib);
|
|
194
|
+
const structure = structureForBlock(model, ib);
|
|
195
|
+
const scope = structure ? presentationScope(model, structure.id) : { declared: /* @__PURE__ */ new Set(), listsMembers: false };
|
|
196
|
+
const membersByAxis = /* @__PURE__ */ new Map();
|
|
197
|
+
let hasEntity = false;
|
|
198
|
+
for (const f of facts) {
|
|
199
|
+
if (f.entity) hasEntity = true;
|
|
200
|
+
for (const d of f.dimensions ?? []) {
|
|
201
|
+
if (!dimensionInScope(scope, d)) continue;
|
|
202
|
+
const set = membersByAxis.get(d.axis) ?? /* @__PURE__ */ new Set();
|
|
203
|
+
set.add(d.member ?? d.typedValue ?? DOMAIN);
|
|
204
|
+
membersByAxis.set(d.axis, set);
|
|
205
|
+
}
|
|
95
206
|
}
|
|
96
|
-
|
|
207
|
+
const axes = [...membersByAxis.keys()].sort();
|
|
208
|
+
const memberAxes = axes.filter((a) => (membersByAxis.get(a)?.size ?? 0) > 1);
|
|
209
|
+
const slicerAxes = axes.filter((a) => (membersByAxis.get(a)?.size ?? 0) <= 1);
|
|
210
|
+
return {
|
|
211
|
+
rows: ["concept", ...memberAxes.map(dimKey)],
|
|
212
|
+
columns: ["period"],
|
|
213
|
+
slicers: [...hasEntity ? ["entity"] : [], ...slicerAxes.map(dimKey)],
|
|
214
|
+
scale: "auto",
|
|
215
|
+
showAbstracts: true,
|
|
216
|
+
dropSparsePeriods: true
|
|
217
|
+
};
|
|
218
|
+
}
|
|
219
|
+
function pivotDimensionsOn(config, placement) {
|
|
220
|
+
const isDim = (k) => k.startsWith("dim:");
|
|
221
|
+
const dims = [...config.rows, ...config.columns].filter(isDim);
|
|
222
|
+
const rows = config.rows.filter((k) => !isDim(k));
|
|
223
|
+
const columns = config.columns.filter((k) => !isDim(k));
|
|
224
|
+
if (placement === "rows") rows.push(...dims);
|
|
225
|
+
else columns.push(...dims);
|
|
226
|
+
return { ...config, rows, columns };
|
|
97
227
|
}
|
|
98
|
-
|
|
99
|
-
|
|
228
|
+
var PERIOD_DENSITY_FRACTION = 0.2;
|
|
229
|
+
function pruneSparsePeriods(model, facts, periods) {
|
|
230
|
+
const count = /* @__PURE__ */ new Map();
|
|
231
|
+
for (const f of facts) {
|
|
232
|
+
const populated = f.value !== null || f.textValue != null && f.textValue !== "";
|
|
233
|
+
const end = model.periods[f.period]?.end;
|
|
234
|
+
if (end && populated) count.set(end, (count.get(end) ?? 0) + 1);
|
|
235
|
+
}
|
|
236
|
+
const max = Math.max(0, ...count.values());
|
|
237
|
+
if (max < 5) return periods;
|
|
238
|
+
const threshold = Math.max(2, max * PERIOD_DENSITY_FRACTION);
|
|
239
|
+
return periods.filter((p) => (count.get(p.end) ?? 0) >= threshold);
|
|
100
240
|
}
|
|
101
|
-
function
|
|
241
|
+
function derivePeriods(model, facts) {
|
|
102
242
|
const byEnd = /* @__PURE__ */ new Map();
|
|
103
243
|
for (const fact of facts) {
|
|
104
244
|
const period = model.periods[fact.period];
|
|
@@ -112,87 +252,307 @@ function deriveColumns(model, facts) {
|
|
|
112
252
|
const aStart = a.startDate ?? a.end;
|
|
113
253
|
const bStart = b.startDate ?? b.end;
|
|
114
254
|
return aStart.localeCompare(bStart) || a.end.localeCompare(b.end);
|
|
115
|
-
})
|
|
255
|
+
});
|
|
256
|
+
}
|
|
257
|
+
function memberCombos(facts, axes, order, domainLast) {
|
|
258
|
+
if (axes.length === 0) return [{ sig: "", members: [], labels: [] }];
|
|
259
|
+
const perAxis = axes.map((axis) => {
|
|
260
|
+
const byMember = /* @__PURE__ */ new Map();
|
|
261
|
+
let hasDomain = false;
|
|
262
|
+
for (const f of facts) {
|
|
263
|
+
const d = (f.dimensions ?? []).find((x) => x.axis === axis);
|
|
264
|
+
if (d) byMember.set(d.member ?? d.typedValue ?? DOMAIN, d);
|
|
265
|
+
else hasDomain = true;
|
|
266
|
+
}
|
|
267
|
+
const members = [...byMember.entries()].map(([key, qual]) => ({ key, qual })).sort((a, b) => {
|
|
268
|
+
const ao = a.qual?.member ? order.get(localName(a.qual.member)) ?? Infinity : Infinity;
|
|
269
|
+
const bo = b.qual?.member ? order.get(localName(b.qual.member)) ?? Infinity : Infinity;
|
|
270
|
+
return ao - bo || (a.qual?.memberLabel ?? a.key).localeCompare(b.qual?.memberLabel ?? b.key);
|
|
271
|
+
});
|
|
272
|
+
if (hasDomain) {
|
|
273
|
+
const domain = { key: DOMAIN, qual: null };
|
|
274
|
+
members.push(domain);
|
|
275
|
+
}
|
|
276
|
+
return { axis, members };
|
|
277
|
+
});
|
|
278
|
+
let combos = [{ sig: "", members: [], labels: [] }];
|
|
279
|
+
for (const { axis, members } of perAxis) {
|
|
280
|
+
const next = [];
|
|
281
|
+
for (const combo of combos) {
|
|
282
|
+
for (const { key, qual } of members) {
|
|
283
|
+
next.push({
|
|
284
|
+
sig: combo.sig ? `${combo.sig}|${axis}=${key}` : `${axis}=${key}`,
|
|
285
|
+
members: [...combo.members, ...qual ? [qual] : []],
|
|
286
|
+
labels: [...combo.labels, qual ? qual.memberLabel : "Total"]
|
|
287
|
+
});
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
combos = next;
|
|
291
|
+
}
|
|
292
|
+
return combos;
|
|
293
|
+
}
|
|
294
|
+
function headerLevels(segsPerColumn) {
|
|
295
|
+
const levels = segsPerColumn[0]?.length ?? 0;
|
|
296
|
+
const out = [];
|
|
297
|
+
for (let level = 0; level < levels; level++) {
|
|
298
|
+
const row = [];
|
|
299
|
+
let i = 0;
|
|
300
|
+
while (i < segsPerColumn.length) {
|
|
301
|
+
let span = 1;
|
|
302
|
+
while (i + span < segsPerColumn.length && segsPerColumn[i + span][level] === segsPerColumn[i][level] && Array.from({ length: level + 1 }, (_, l) => l).every(
|
|
303
|
+
(l) => segsPerColumn[i + span][l] === segsPerColumn[i][l]
|
|
304
|
+
)) {
|
|
305
|
+
span++;
|
|
306
|
+
}
|
|
307
|
+
row.push({ label: segsPerColumn[i][level], span });
|
|
308
|
+
i += span;
|
|
309
|
+
}
|
|
310
|
+
out.push(row);
|
|
311
|
+
}
|
|
312
|
+
return out;
|
|
313
|
+
}
|
|
314
|
+
var SCALE_FACTOR = {
|
|
315
|
+
ones: { factor: 1, label: "" },
|
|
316
|
+
thousands: { factor: 1e3, label: "thousands" },
|
|
317
|
+
millions: { factor: 1e6, label: "millions" },
|
|
318
|
+
billions: { factor: 1e9, label: "billions" }
|
|
319
|
+
};
|
|
320
|
+
function resolveScale(facts, model, requested) {
|
|
321
|
+
const kindOf = (id) => numericKindOf(elementOf(model, id));
|
|
322
|
+
let factor = 1;
|
|
323
|
+
let label = "";
|
|
324
|
+
if (requested !== "auto") {
|
|
325
|
+
({ factor, label } = SCALE_FACTOR[requested]);
|
|
326
|
+
} else {
|
|
327
|
+
const decimalsCount = /* @__PURE__ */ new Map();
|
|
328
|
+
for (const f of facts) {
|
|
329
|
+
if (f.value === null || kindOf(f.element) !== "monetary") continue;
|
|
330
|
+
const d = f.decimals === null || f.decimals === "INF" ? NaN : Number(f.decimals);
|
|
331
|
+
if (Number.isNaN(d) || d >= 0) continue;
|
|
332
|
+
decimalsCount.set(d, (decimalsCount.get(d) ?? 0) + 1);
|
|
333
|
+
}
|
|
334
|
+
let dominant = 0;
|
|
335
|
+
let best = 0;
|
|
336
|
+
for (const [d, count] of decimalsCount) {
|
|
337
|
+
if (count > best) {
|
|
338
|
+
best = count;
|
|
339
|
+
dominant = d;
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
if (dominant <= -9) ({ factor, label } = SCALE_FACTOR.billions);
|
|
343
|
+
else if (dominant <= -6) ({ factor, label } = SCALE_FACTOR.millions);
|
|
344
|
+
else if (dominant <= -3) ({ factor, label } = SCALE_FACTOR.thousands);
|
|
345
|
+
}
|
|
346
|
+
let caption = null;
|
|
347
|
+
if (factor > 1) {
|
|
348
|
+
const hasPerShare = facts.some((f) => {
|
|
349
|
+
const k = kindOf(f.element);
|
|
350
|
+
return f.value !== null && (k === "perShare" || k === "shares");
|
|
351
|
+
});
|
|
352
|
+
caption = hasPerShare ? `In ${label}, except per-share amounts` : `In ${label}`;
|
|
353
|
+
}
|
|
354
|
+
return { factor, label, caption };
|
|
355
|
+
}
|
|
356
|
+
function buildSlicers(model, facts, config) {
|
|
357
|
+
const slicers = [];
|
|
358
|
+
for (const key of config.slicers) {
|
|
359
|
+
if (key === "entity") {
|
|
360
|
+
if (model.entity) {
|
|
361
|
+
slicers.push({
|
|
362
|
+
aspect: "entity",
|
|
363
|
+
label: "Reporting Entity",
|
|
364
|
+
valueLabel: model.entity.name
|
|
365
|
+
});
|
|
366
|
+
}
|
|
367
|
+
continue;
|
|
368
|
+
}
|
|
369
|
+
const axis = axisOf(key);
|
|
370
|
+
if (!axis) continue;
|
|
371
|
+
let qual = null;
|
|
372
|
+
for (const f of facts) {
|
|
373
|
+
const d = (f.dimensions ?? []).find((x) => x.axis === axis);
|
|
374
|
+
if (d) {
|
|
375
|
+
qual = d;
|
|
376
|
+
break;
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
const axisLabel = qual?.axisLabel ?? humanize(axis);
|
|
380
|
+
slicers.push({
|
|
381
|
+
aspect: key,
|
|
382
|
+
label: `${axisLabel} [Axis]`,
|
|
383
|
+
valueLabel: qual ? qual.memberLabel : "Consolidated"
|
|
384
|
+
});
|
|
385
|
+
}
|
|
386
|
+
return slicers;
|
|
116
387
|
}
|
|
117
|
-
function
|
|
388
|
+
function buildPivot(model, ib, config = defaultPivotConfig(model, ib)) {
|
|
118
389
|
const structure = structureForBlock(model, ib);
|
|
119
|
-
const
|
|
120
|
-
const
|
|
121
|
-
const
|
|
122
|
-
const
|
|
123
|
-
const
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
390
|
+
const tree = structure ? presentationTree(model, structure.id) : { childrenOf: /* @__PURE__ */ new Map(), roots: [], indexOf: /* @__PURE__ */ new Map() };
|
|
391
|
+
const rowDimAxes = dimAxes(config.rows);
|
|
392
|
+
const colDimAxes = dimAxes(config.columns);
|
|
393
|
+
const allowedAxes = /* @__PURE__ */ new Set([...rowDimAxes, ...colDimAxes, ...dimAxes(config.slicers)]);
|
|
394
|
+
const scope = structure ? presentationScope(model, structure.id) : { declared: /* @__PURE__ */ new Set(), listsMembers: false };
|
|
395
|
+
const facts = sectionFacts(model, ib).filter(
|
|
396
|
+
(f) => (f.dimensions ?? []).every((d) => allowedAxes.has(d.axis) && dimensionInScope(scope, d))
|
|
397
|
+
);
|
|
398
|
+
const periodOnColumns = config.columns.includes("period");
|
|
399
|
+
let periods = periodOnColumns ? derivePeriods(model, facts) : [];
|
|
400
|
+
if (periodOnColumns && config.dropSparsePeriods !== false) {
|
|
401
|
+
periods = pruneSparsePeriods(model, facts, periods);
|
|
402
|
+
}
|
|
403
|
+
const colCombos = memberCombos(facts, colDimAxes, tree.indexOf);
|
|
404
|
+
const occupiedCols = /* @__PURE__ */ new Set();
|
|
405
|
+
for (const f of facts) {
|
|
406
|
+
const end = model.periods[f.period]?.end ?? "";
|
|
407
|
+
occupiedCols.add(`${end}#${coordinate(memberByAxis(f), colDimAxes)}`);
|
|
408
|
+
}
|
|
409
|
+
const columns = [];
|
|
410
|
+
const columnSegs = [];
|
|
411
|
+
const periodList = periodOnColumns ? periods : [null];
|
|
412
|
+
for (const period of periodList) {
|
|
413
|
+
for (const combo of colCombos) {
|
|
414
|
+
const end = period?.end ?? "";
|
|
415
|
+
if (!occupiedCols.has(`${end}#${combo.sig}`)) continue;
|
|
416
|
+
const periodLabel = period ? formatDate(period.end) : "";
|
|
417
|
+
columns.push({
|
|
418
|
+
key: `${end}#${combo.sig}`,
|
|
419
|
+
period,
|
|
420
|
+
members: combo.members,
|
|
421
|
+
label: combo.labels.length ? combo.labels[combo.labels.length - 1] : periodLabel
|
|
422
|
+
});
|
|
423
|
+
columnSegs.push([...periodOnColumns ? [periodLabel] : [], ...combo.labels]);
|
|
133
424
|
}
|
|
134
|
-
cells[idx] = { value: fact.value, fact, textValue: fact.textValue ?? null };
|
|
135
425
|
}
|
|
136
|
-
const
|
|
137
|
-
|
|
426
|
+
const columnHeaders = headerLevels(columnSegs);
|
|
427
|
+
const factIndex = /* @__PURE__ */ new Map();
|
|
428
|
+
for (const f of facts) {
|
|
429
|
+
const byAxis = memberByAxis(f);
|
|
430
|
+
const end = model.periods[f.period]?.end ?? "";
|
|
431
|
+
const rowSig = coordinate(byAxis, rowDimAxes);
|
|
432
|
+
const colSig = coordinate(byAxis, colDimAxes);
|
|
433
|
+
factIndex.set(`${f.element}\u241F${rowSig}\u241F${end}\u241F${colSig}`, f);
|
|
434
|
+
}
|
|
435
|
+
const factfulConcepts = new Set(facts.map((f) => f.element));
|
|
436
|
+
const rowCombos = memberCombos(facts, rowDimAxes, tree.indexOf);
|
|
437
|
+
const combosForConcept = (element) => {
|
|
438
|
+
if (rowDimAxes.length === 0) return rowCombos;
|
|
439
|
+
return rowCombos.filter(
|
|
440
|
+
(combo) => columns.some(
|
|
441
|
+
(col) => factIndex.has(
|
|
442
|
+
`${element}\u241F${combo.sig}\u241F${col.period?.end ?? ""}\u241F${coordinate(
|
|
443
|
+
new Map(col.members.map((m) => [m.axis, m])),
|
|
444
|
+
colDimAxes
|
|
445
|
+
)}`
|
|
446
|
+
)
|
|
447
|
+
)
|
|
448
|
+
);
|
|
449
|
+
};
|
|
450
|
+
const cellsFor = (element, rowSig) => columns.map((col) => {
|
|
451
|
+
const colSig = coordinate(new Map(col.members.map((m) => [m.axis, m])), colDimAxes);
|
|
452
|
+
const fact = factIndex.get(`${element}\u241F${rowSig}\u241F${col.period?.end ?? ""}\u241F${colSig}`);
|
|
138
453
|
return {
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
454
|
+
value: fact?.value ?? null,
|
|
455
|
+
fact: fact ?? null,
|
|
456
|
+
textValue: fact && fact.value === null ? fact.textValue ?? null : null
|
|
142
457
|
};
|
|
143
|
-
})
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
458
|
+
});
|
|
459
|
+
const subtotals = calcSubtotals(model);
|
|
460
|
+
const hasFactMemo = /* @__PURE__ */ new Map();
|
|
461
|
+
const subtreeHasFact = (id) => {
|
|
462
|
+
const cached = hasFactMemo.get(id);
|
|
463
|
+
if (cached !== void 0) return cached;
|
|
464
|
+
hasFactMemo.set(id, false);
|
|
465
|
+
let has = factfulConcepts.has(id);
|
|
466
|
+
for (const child of tree.childrenOf.get(id) ?? []) {
|
|
467
|
+
if (subtreeHasFact(child)) has = true;
|
|
468
|
+
}
|
|
469
|
+
hasFactMemo.set(id, has);
|
|
470
|
+
return has;
|
|
471
|
+
};
|
|
472
|
+
const rows = [];
|
|
473
|
+
const emitConcept = (id, depth) => {
|
|
474
|
+
const el = elementOf(model, id);
|
|
475
|
+
const combos = combosForConcept(id);
|
|
476
|
+
if (!combos.length) return;
|
|
477
|
+
if (combos.every((c) => c.members.length > 0)) {
|
|
478
|
+
rows.push({
|
|
479
|
+
key: id,
|
|
480
|
+
element: el,
|
|
481
|
+
depth,
|
|
482
|
+
header: false,
|
|
483
|
+
isSubtotal: subtotals.has(id),
|
|
484
|
+
members: [],
|
|
485
|
+
cells: columns.map(() => ({ value: null, fact: null, textValue: null }))
|
|
486
|
+
});
|
|
487
|
+
}
|
|
488
|
+
for (const combo of combos) {
|
|
489
|
+
rows.push({
|
|
490
|
+
key: combo.members.length ? `${id}\u241F${combo.sig}` : id,
|
|
491
|
+
element: el,
|
|
492
|
+
depth: depth + (combo.members.length ? 1 : 0),
|
|
493
|
+
header: false,
|
|
494
|
+
isSubtotal: subtotals.has(id),
|
|
495
|
+
members: combo.members,
|
|
496
|
+
cells: cellsFor(id, combo.sig)
|
|
497
|
+
});
|
|
498
|
+
}
|
|
499
|
+
};
|
|
500
|
+
const seenInTree = /* @__PURE__ */ new Set();
|
|
501
|
+
const walk = (id, depth) => {
|
|
502
|
+
if (seenInTree.has(id) || !subtreeHasFact(id)) return;
|
|
503
|
+
seenInTree.add(id);
|
|
504
|
+
const el = elementOf(model, id);
|
|
505
|
+
if (el.abstract) {
|
|
506
|
+
if (config.showAbstracts) {
|
|
507
|
+
rows.push({
|
|
508
|
+
key: id,
|
|
509
|
+
element: el,
|
|
510
|
+
depth,
|
|
511
|
+
header: true,
|
|
512
|
+
isSubtotal: false,
|
|
513
|
+
members: [],
|
|
514
|
+
cells: []
|
|
515
|
+
});
|
|
516
|
+
}
|
|
517
|
+
for (const child of tree.childrenOf.get(id) ?? []) walk(child, depth + 1);
|
|
518
|
+
} else {
|
|
519
|
+
for (const child of tree.childrenOf.get(id) ?? []) walk(child, depth + 1);
|
|
520
|
+
emitConcept(id, depth);
|
|
521
|
+
}
|
|
522
|
+
};
|
|
523
|
+
for (const root of tree.roots) walk(root, 0);
|
|
524
|
+
for (const id of factfulConcepts) {
|
|
525
|
+
if (seenInTree.has(id) || elementOf(model, id).abstract) continue;
|
|
526
|
+
emitConcept(id, 0);
|
|
527
|
+
}
|
|
149
528
|
const title = ib.structureId ? structure?.structureName ?? ib.label ?? BLOCK_TITLES[ib.blockType] ?? ib.blockType : BLOCK_TITLES[ib.blockType] ?? ib.label ?? ib.blockType;
|
|
150
529
|
return {
|
|
151
530
|
ib,
|
|
152
531
|
blockType: ib.blockType,
|
|
153
532
|
title,
|
|
154
533
|
structureName: ib.structureId ? null : structure?.structureName ?? ib.label ?? null,
|
|
534
|
+
slicers: buildSlicers(model, facts, config),
|
|
535
|
+
columnHeaders,
|
|
155
536
|
columns,
|
|
156
|
-
rows
|
|
537
|
+
rows,
|
|
538
|
+
scale: resolveScale(facts, model, config.scale),
|
|
539
|
+
config
|
|
157
540
|
};
|
|
158
541
|
}
|
|
159
542
|
function reportSections(model) {
|
|
160
|
-
return
|
|
161
|
-
}
|
|
162
|
-
function sliceReportSection(model, informationBlockId) {
|
|
163
|
-
const ib = model.informationBlocks.find((b) => b.id === informationBlockId);
|
|
164
|
-
return { ...model, informationBlocks: ib ? [ib] : [] };
|
|
543
|
+
return buildPivots(model).map((p) => ({ id: p.ib.id, title: p.title }));
|
|
165
544
|
}
|
|
166
|
-
function
|
|
167
|
-
const
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
const kids = model.calcAssociations.filter((a) => a.parent === elementId);
|
|
174
|
-
if (!kids.length) return null;
|
|
175
|
-
const valueOf = (id) => {
|
|
176
|
-
const row = statement.rows.find((r) => r.element.id === id);
|
|
177
|
-
return row ? row.cells[columnIndex]?.value ?? null : null;
|
|
178
|
-
};
|
|
179
|
-
const terms = kids.slice().sort((a, b) => a.order - b.order).map((a) => ({
|
|
180
|
-
element: model.elements[a.child] ?? fallbackElement(a.child),
|
|
181
|
-
weight: a.weight,
|
|
182
|
-
value: valueOf(a.child)
|
|
183
|
-
}));
|
|
184
|
-
const present = terms.filter((t) => t.value !== null);
|
|
185
|
-
const expected = present.length ? present.reduce((sum, t) => sum + t.value * t.weight, 0) : null;
|
|
186
|
-
const actual = valueOf(elementId);
|
|
187
|
-
const ok = expected !== null && actual !== null && Math.abs(expected - actual) < 5e-3;
|
|
188
|
-
return {
|
|
189
|
-
element: model.elements[elementId] ?? fallbackElement(elementId),
|
|
190
|
-
columnIndex,
|
|
191
|
-
terms,
|
|
192
|
-
expected,
|
|
193
|
-
actual,
|
|
194
|
-
ok
|
|
545
|
+
function buildPivots(model, configFor) {
|
|
546
|
+
const order = (ib) => {
|
|
547
|
+
if (ib.structureId) {
|
|
548
|
+
const s = model.structures.find((x) => x.id === ib.structureId);
|
|
549
|
+
if (s?.order !== void 0) return s.order;
|
|
550
|
+
}
|
|
551
|
+
return BLOCK_ORDER[ib.blockType] ?? 99;
|
|
195
552
|
};
|
|
553
|
+
return [...model.informationBlocks].sort((a, b) => order(a) - order(b) || a.blockType.localeCompare(b.blockType)).map(
|
|
554
|
+
(ib) => configFor ? buildPivot(model, ib, configFor(ib, defaultPivotConfig(model, ib))) : buildPivot(model, ib)
|
|
555
|
+
);
|
|
196
556
|
}
|
|
197
557
|
var styles = {
|
|
198
558
|
status: {
|
|
@@ -223,6 +583,9 @@ function wrapHtml(body) {
|
|
|
223
583
|
a { color: #1d4ed8; }
|
|
224
584
|
</style></head><body>${body}</body></html>`;
|
|
225
585
|
}
|
|
586
|
+
function InlineTextBlock({ html }) {
|
|
587
|
+
return /* @__PURE__ */ jsx(SandboxedHtml, { html });
|
|
588
|
+
}
|
|
226
589
|
function SandboxedHtml({ html }) {
|
|
227
590
|
const ref = useRef(null);
|
|
228
591
|
const fit = () => {
|
|
@@ -298,8 +661,6 @@ var styles2 = {
|
|
|
298
661
|
gap: "1rem",
|
|
299
662
|
marginBottom: "0.75rem"
|
|
300
663
|
},
|
|
301
|
-
// `minWidth: 0` lets this flex child shrink below its content so the long
|
|
302
|
-
// label / qname wrap inside the panel instead of overflowing it.
|
|
303
664
|
headerText: { minWidth: 0 },
|
|
304
665
|
label: { fontSize: "1rem", fontWeight: 700, margin: 0, overflowWrap: "anywhere" },
|
|
305
666
|
qname: {
|
|
@@ -307,7 +668,6 @@ var styles2 = {
|
|
|
307
668
|
fontFamily: "var(--rs-font-mono, ui-monospace, monospace)",
|
|
308
669
|
fontSize: "0.8rem",
|
|
309
670
|
color: "var(--rs-primary-700, #1d4ed8)",
|
|
310
|
-
// qnames are single unbroken tokens — break anywhere so they don't overflow.
|
|
311
671
|
overflowWrap: "anywhere"
|
|
312
672
|
},
|
|
313
673
|
close: {
|
|
@@ -327,6 +687,7 @@ var styles2 = {
|
|
|
327
687
|
},
|
|
328
688
|
key: { color: "var(--rs-muted, #6b7280)" },
|
|
329
689
|
mono: { fontFamily: "var(--rs-font-mono, ui-monospace, monospace)" },
|
|
690
|
+
dims: { display: "grid", gap: "0.15rem" },
|
|
330
691
|
footing: {
|
|
331
692
|
marginTop: "0.85rem",
|
|
332
693
|
paddingTop: "0.75rem",
|
|
@@ -351,20 +712,19 @@ function Field({ k, children }) {
|
|
|
351
712
|
/* @__PURE__ */ jsx("span", { children })
|
|
352
713
|
] });
|
|
353
714
|
}
|
|
354
|
-
function
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
columnIndex,
|
|
359
|
-
onClose,
|
|
360
|
-
currencySymbol = "$"
|
|
361
|
-
}) {
|
|
715
|
+
function symbolFor(unit) {
|
|
716
|
+
return unit?.symbol ?? currencySymbolFor(unit?.measure) ?? "$";
|
|
717
|
+
}
|
|
718
|
+
function FactInspector({ report, table, row, columnIndex, onClose }) {
|
|
362
719
|
const { element } = row;
|
|
363
720
|
const cell = row.cells[columnIndex];
|
|
364
|
-
const
|
|
365
|
-
const
|
|
366
|
-
const
|
|
367
|
-
const
|
|
721
|
+
const fact = cell?.fact ?? null;
|
|
722
|
+
const period = fact ? report.periods[fact.period] : null;
|
|
723
|
+
const unit = fact?.unit ? report.units[fact.unit] : void 0;
|
|
724
|
+
const kind = numericKindOf(element);
|
|
725
|
+
const dims = fact?.dimensions ?? row.members;
|
|
726
|
+
const foot = footCheck(report, table, element.id, columnIndex);
|
|
727
|
+
const sym = symbolFor(unit);
|
|
368
728
|
return /* @__PURE__ */ jsxs("div", { style: styles2.panel, children: [
|
|
369
729
|
/* @__PURE__ */ jsxs("div", { style: styles2.header, children: [
|
|
370
730
|
/* @__PURE__ */ jsxs("div", { style: styles2.headerText, children: [
|
|
@@ -374,19 +734,28 @@ function FactInspector({
|
|
|
374
734
|
onClose ? /* @__PURE__ */ jsx("button", { style: styles2.close, onClick: onClose, "aria-label": "Close", children: "\xD7" }) : null
|
|
375
735
|
] }),
|
|
376
736
|
/* @__PURE__ */ jsxs("div", { style: styles2.grid, children: [
|
|
377
|
-
/* @__PURE__ */ jsx(Field, { k: "Value", children: cell
|
|
378
|
-
/* @__PURE__ */ jsxs(Field, { k: "Period", children: [
|
|
379
|
-
formatPeriod(
|
|
737
|
+
/* @__PURE__ */ jsx(Field, { k: "Value", children: cell?.value === null && cell?.textValue ? /* @__PURE__ */ jsx("span", { children: humanizeDuration(cell.textValue) ?? cell.textValue }) : /* @__PURE__ */ jsx("span", { style: styles2.mono, children: formatValue(cell?.value ?? null, { numericKind: kind, symbol: sym }) }) }),
|
|
738
|
+
period ? /* @__PURE__ */ jsxs(Field, { k: "Period", children: [
|
|
739
|
+
formatPeriod(period),
|
|
380
740
|
" ",
|
|
381
741
|
/* @__PURE__ */ jsxs("span", { style: styles2.key, children: [
|
|
382
742
|
"(",
|
|
383
|
-
|
|
743
|
+
period.type,
|
|
384
744
|
")"
|
|
385
745
|
] })
|
|
386
|
-
] }),
|
|
746
|
+
] }) : null,
|
|
747
|
+
report.entity ? /* @__PURE__ */ jsx(Field, { k: "Entity", children: report.entity.name }) : null,
|
|
748
|
+
dims.length ? /* @__PURE__ */ jsx(Field, { k: "Dimensions", children: /* @__PURE__ */ jsx("span", { style: styles2.dims, children: dims.map((d) => /* @__PURE__ */ jsxs("span", { children: [
|
|
749
|
+
/* @__PURE__ */ jsxs("span", { style: styles2.key, children: [
|
|
750
|
+
d.axisLabel,
|
|
751
|
+
":"
|
|
752
|
+
] }),
|
|
753
|
+
" ",
|
|
754
|
+
d.explicit ? d.memberLabel : d.typedValue ?? d.memberLabel
|
|
755
|
+
] }, d.axis)) }) }) : null,
|
|
387
756
|
/* @__PURE__ */ jsx(Field, { k: "Unit", children: unit ? unit.label : "\u2014" }),
|
|
388
757
|
element.balance ? /* @__PURE__ */ jsx(Field, { k: "Balance", children: element.balance }) : null,
|
|
389
|
-
|
|
758
|
+
fact?.decimals ? /* @__PURE__ */ jsx(Field, { k: "Decimals", children: fact.decimals }) : null
|
|
390
759
|
] }),
|
|
391
760
|
foot ? /* @__PURE__ */ jsxs("div", { style: styles2.footing, children: [
|
|
392
761
|
/* @__PURE__ */ jsxs("div", { style: styles2.footTitle, children: [
|
|
@@ -398,17 +767,18 @@ function FactInspector({
|
|
|
398
767
|
const op = i === 0 ? term.weight < 0 ? "\u2212" : "" : term.weight < 0 ? " \u2212 " : " + ";
|
|
399
768
|
return /* @__PURE__ */ jsxs("span", { title: term.element.qname, children: [
|
|
400
769
|
op,
|
|
401
|
-
|
|
402
|
-
|
|
770
|
+
formatValue(term.value === null ? 0 : Math.abs(term.value), {
|
|
771
|
+
numericKind: "monetary",
|
|
772
|
+
symbol: sym
|
|
403
773
|
})
|
|
404
774
|
] }, term.element.id);
|
|
405
775
|
}),
|
|
406
776
|
" = ",
|
|
407
|
-
/* @__PURE__ */ jsx("strong", { children:
|
|
777
|
+
/* @__PURE__ */ jsx("strong", { children: formatValue(foot.expected, { numericKind: "monetary", symbol: sym }) }),
|
|
408
778
|
" ",
|
|
409
779
|
foot.ok ? /* @__PURE__ */ jsx("span", { style: { color: "var(--rs-success, #00875a)" }, children: "\u2713" }) : /* @__PURE__ */ jsxs("span", { style: { color: "var(--rs-error, #dc2626)" }, children: [
|
|
410
780
|
"\u2717 (reported ",
|
|
411
|
-
|
|
781
|
+
formatValue(foot.actual, { numericKind: "monetary", symbol: sym }),
|
|
412
782
|
")"
|
|
413
783
|
] })
|
|
414
784
|
] })
|
|
@@ -421,10 +791,7 @@ var styles3 = {
|
|
|
421
791
|
color: "var(--rs-text, #111827)",
|
|
422
792
|
marginBottom: "2.5rem"
|
|
423
793
|
},
|
|
424
|
-
heading: {
|
|
425
|
-
textAlign: "center",
|
|
426
|
-
marginBottom: "1rem"
|
|
427
|
-
},
|
|
794
|
+
heading: { textAlign: "center", marginBottom: "0.75rem" },
|
|
428
795
|
title: {
|
|
429
796
|
fontFamily: "var(--rs-font-heading, var(--rs-font-sans, sans-serif))",
|
|
430
797
|
fontSize: "1.15rem",
|
|
@@ -432,28 +799,92 @@ var styles3 = {
|
|
|
432
799
|
letterSpacing: "0.02em",
|
|
433
800
|
margin: 0
|
|
434
801
|
},
|
|
435
|
-
subtitle: {
|
|
436
|
-
|
|
802
|
+
subtitle: { fontSize: "0.85rem", color: "var(--rs-muted, #6b7280)", marginTop: "0.25rem" },
|
|
803
|
+
scaleCaption: {
|
|
804
|
+
fontSize: "0.8rem",
|
|
805
|
+
fontStyle: "italic",
|
|
437
806
|
color: "var(--rs-muted, #6b7280)",
|
|
438
807
|
marginTop: "0.25rem"
|
|
439
808
|
},
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
809
|
+
slicers: {
|
|
810
|
+
display: "flex",
|
|
811
|
+
flexWrap: "wrap",
|
|
812
|
+
gap: "0.5rem",
|
|
813
|
+
margin: "0 0 0.75rem"
|
|
814
|
+
},
|
|
815
|
+
slicer: {
|
|
816
|
+
display: "inline-flex",
|
|
817
|
+
gap: "0.4rem",
|
|
818
|
+
alignItems: "baseline",
|
|
819
|
+
border: "1px solid var(--rs-border, #e5e7eb)",
|
|
820
|
+
borderRadius: "6px",
|
|
821
|
+
padding: "0.2rem 0.55rem",
|
|
822
|
+
fontSize: "0.78rem",
|
|
823
|
+
background: "var(--rs-slicer-bg, #f9fafb)"
|
|
824
|
+
},
|
|
825
|
+
slicerLabel: {
|
|
826
|
+
color: "var(--rs-muted, #6b7280)",
|
|
827
|
+
textTransform: "uppercase",
|
|
828
|
+
letterSpacing: "0.03em",
|
|
829
|
+
fontSize: "0.68rem"
|
|
830
|
+
},
|
|
831
|
+
slicerValue: { fontWeight: 600 },
|
|
832
|
+
controls: {
|
|
833
|
+
display: "flex",
|
|
834
|
+
alignItems: "center",
|
|
835
|
+
gap: "0.5rem",
|
|
836
|
+
margin: "0 0 0.9rem",
|
|
837
|
+
fontSize: "0.8rem"
|
|
838
|
+
},
|
|
839
|
+
controlLabel: { color: "var(--rs-muted, #6b7280)" },
|
|
840
|
+
segmented: {
|
|
841
|
+
display: "inline-flex",
|
|
842
|
+
border: "1px solid var(--rs-border, #e5e7eb)",
|
|
843
|
+
borderRadius: "7px",
|
|
844
|
+
overflow: "hidden"
|
|
845
|
+
},
|
|
846
|
+
segment: {
|
|
847
|
+
border: "none",
|
|
848
|
+
padding: "0.25rem 0.7rem",
|
|
849
|
+
fontSize: "0.78rem",
|
|
850
|
+
cursor: "pointer",
|
|
851
|
+
background: "transparent",
|
|
852
|
+
color: "var(--rs-text, #111827)"
|
|
853
|
+
},
|
|
854
|
+
segmentActive: {
|
|
855
|
+
background: "var(--rs-primary-600, #2563eb)",
|
|
856
|
+
color: "#ffffff",
|
|
857
|
+
fontWeight: 600
|
|
444
858
|
},
|
|
859
|
+
scroll: { overflowX: "auto" },
|
|
860
|
+
table: { width: "100%", borderCollapse: "collapse", fontSize: "0.875rem" },
|
|
445
861
|
th: {
|
|
446
862
|
borderBottom: "2px solid var(--rs-border-strong, #9ca3af)",
|
|
447
|
-
padding: "0.
|
|
863
|
+
padding: "0.4rem 0.75rem",
|
|
448
864
|
fontWeight: 600,
|
|
449
865
|
color: "var(--rs-muted, #6b7280)",
|
|
450
866
|
fontSize: "0.8rem"
|
|
451
867
|
},
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
labelCell: {
|
|
868
|
+
thGroup: {
|
|
869
|
+
borderBottom: "1px solid var(--rs-border, #e5e7eb)",
|
|
455
870
|
padding: "0.3rem 0.75rem",
|
|
456
|
-
|
|
871
|
+
fontWeight: 600,
|
|
872
|
+
color: "var(--rs-muted, #6b7280)",
|
|
873
|
+
fontSize: "0.8rem",
|
|
874
|
+
textAlign: "center"
|
|
875
|
+
},
|
|
876
|
+
// A floor on the concept column so a wide table (many member/period columns)
|
|
877
|
+
// scrolls horizontally rather than squeezing labels down to vertical text.
|
|
878
|
+
thConcept: { textAlign: "left", verticalAlign: "bottom", minWidth: "18rem" },
|
|
879
|
+
thNum: { textAlign: "right", whiteSpace: "nowrap" },
|
|
880
|
+
labelCell: { padding: "0.3rem 0.75rem", whiteSpace: "normal", minWidth: "18rem" },
|
|
881
|
+
headerRowLabel: {
|
|
882
|
+
padding: "0.4rem 0.75rem",
|
|
883
|
+
fontWeight: 700,
|
|
884
|
+
fontSize: "0.8rem",
|
|
885
|
+
textTransform: "uppercase",
|
|
886
|
+
letterSpacing: "0.02em",
|
|
887
|
+
color: "var(--rs-muted, #6b7280)"
|
|
457
888
|
},
|
|
458
889
|
numCell: {
|
|
459
890
|
padding: "0.3rem 0.75rem",
|
|
@@ -462,10 +893,7 @@ var styles3 = {
|
|
|
462
893
|
fontFamily: "var(--rs-font-mono, ui-monospace, SFMono-Regular, monospace)",
|
|
463
894
|
fontVariantNumeric: "tabular-nums"
|
|
464
895
|
},
|
|
465
|
-
textBlockCell: {
|
|
466
|
-
padding: "0.75rem",
|
|
467
|
-
borderTop: "1px solid var(--rs-border, #e5e7eb)"
|
|
468
|
-
},
|
|
896
|
+
textBlockCell: { padding: "0.75rem", borderTop: "1px solid var(--rs-border, #e5e7eb)" },
|
|
469
897
|
textBlockLabel: {
|
|
470
898
|
fontSize: "0.7rem",
|
|
471
899
|
textTransform: "uppercase",
|
|
@@ -475,35 +903,112 @@ var styles3 = {
|
|
|
475
903
|
marginBottom: "0.5rem"
|
|
476
904
|
}
|
|
477
905
|
};
|
|
906
|
+
function cellSymbol(unit) {
|
|
907
|
+
return unit?.symbol ?? currencySymbolFor(unit?.measure) ?? "$";
|
|
908
|
+
}
|
|
478
909
|
function StatementTable({
|
|
479
|
-
|
|
910
|
+
table,
|
|
911
|
+
units,
|
|
480
912
|
onCellClick,
|
|
481
|
-
|
|
482
|
-
|
|
913
|
+
selected = null,
|
|
914
|
+
dimensionPlacement,
|
|
915
|
+
onDimensionPlacementChange
|
|
483
916
|
}) {
|
|
484
|
-
const { columns, rows } =
|
|
485
|
-
const
|
|
917
|
+
const { columns, rows, columnHeaders, scale } = table;
|
|
918
|
+
const totalCols = columns.length;
|
|
919
|
+
const dimensional = table.config.rows.some((k) => k.startsWith("dim:")) || table.config.columns.some((k) => k.startsWith("dim:"));
|
|
920
|
+
const showToggle = onDimensionPlacementChange != null && dimensional;
|
|
486
921
|
return /* @__PURE__ */ jsxs("section", { style: styles3.wrap, children: [
|
|
487
922
|
/* @__PURE__ */ jsxs("header", { style: styles3.heading, children: [
|
|
488
|
-
/* @__PURE__ */ jsx("h3", { style: styles3.title, children:
|
|
489
|
-
|
|
490
|
-
|
|
923
|
+
/* @__PURE__ */ jsx("h3", { style: styles3.title, children: table.title }),
|
|
924
|
+
table.structureName ? /* @__PURE__ */ jsx("div", { style: styles3.subtitle, children: table.structureName }) : null,
|
|
925
|
+
scale.caption ? /* @__PURE__ */ jsx("div", { style: styles3.scaleCaption, children: scale.caption }) : null
|
|
491
926
|
] }),
|
|
492
|
-
/* @__PURE__ */
|
|
493
|
-
/* @__PURE__ */ jsx("
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
927
|
+
table.slicers.length ? /* @__PURE__ */ jsx("div", { style: styles3.slicers, children: table.slicers.map((s) => /* @__PURE__ */ jsxs("div", { style: styles3.slicer, children: [
|
|
928
|
+
/* @__PURE__ */ jsx("span", { style: styles3.slicerLabel, children: s.label }),
|
|
929
|
+
/* @__PURE__ */ jsx("span", { style: styles3.slicerValue, children: s.valueLabel })
|
|
930
|
+
] }, s.aspect)) }) : null,
|
|
931
|
+
showToggle ? /* @__PURE__ */ jsxs("div", { style: styles3.controls, children: [
|
|
932
|
+
/* @__PURE__ */ jsx("span", { style: styles3.controlLabel, children: "Dimensions" }),
|
|
933
|
+
/* @__PURE__ */ jsx("div", { style: styles3.segmented, role: "group", "aria-label": "Dimension placement", children: ["rows", "columns"].map((placement) => /* @__PURE__ */ jsx(
|
|
934
|
+
"button",
|
|
935
|
+
{
|
|
936
|
+
type: "button",
|
|
937
|
+
onClick: () => onDimensionPlacementChange?.(placement),
|
|
938
|
+
"aria-pressed": dimensionPlacement === placement,
|
|
939
|
+
style: {
|
|
940
|
+
...styles3.segment,
|
|
941
|
+
...dimensionPlacement === placement ? styles3.segmentActive : {}
|
|
942
|
+
},
|
|
943
|
+
children: placement === "rows" ? "As rows" : "As columns"
|
|
944
|
+
},
|
|
945
|
+
placement
|
|
946
|
+
)) })
|
|
947
|
+
] }) : null,
|
|
948
|
+
/* @__PURE__ */ jsx("div", { style: styles3.scroll, children: /* @__PURE__ */ jsxs("table", { style: styles3.table, children: [
|
|
949
|
+
/* @__PURE__ */ jsx("thead", { children: columnHeaders.map((level, levelIndex) => {
|
|
950
|
+
const isLast = levelIndex === columnHeaders.length - 1;
|
|
951
|
+
let leaf = 0;
|
|
952
|
+
return /* @__PURE__ */ jsxs("tr", { children: [
|
|
953
|
+
levelIndex === 0 ? /* @__PURE__ */ jsx(
|
|
954
|
+
"th",
|
|
955
|
+
{
|
|
956
|
+
rowSpan: columnHeaders.length,
|
|
957
|
+
style: { ...styles3.th, ...styles3.thConcept },
|
|
958
|
+
"aria-label": "Concept"
|
|
959
|
+
}
|
|
960
|
+
) : null,
|
|
961
|
+
level.map((h, i) => {
|
|
962
|
+
const key = `${levelIndex}-${i}-${leaf}`;
|
|
963
|
+
leaf += h.span;
|
|
964
|
+
return /* @__PURE__ */ jsx(
|
|
965
|
+
"th",
|
|
966
|
+
{
|
|
967
|
+
colSpan: h.span,
|
|
968
|
+
style: isLast ? { ...styles3.th, ...styles3.thNum } : styles3.thGroup,
|
|
969
|
+
children: h.label
|
|
970
|
+
},
|
|
971
|
+
key
|
|
972
|
+
);
|
|
973
|
+
})
|
|
974
|
+
] }, levelIndex);
|
|
975
|
+
}) }),
|
|
497
976
|
/* @__PURE__ */ jsx("tbody", { children: rows.map((row) => {
|
|
977
|
+
if (row.header) {
|
|
978
|
+
return /* @__PURE__ */ jsx("tr", { children: /* @__PURE__ */ jsx(
|
|
979
|
+
"td",
|
|
980
|
+
{
|
|
981
|
+
colSpan: totalCols + 1,
|
|
982
|
+
style: {
|
|
983
|
+
...styles3.headerRowLabel,
|
|
984
|
+
paddingLeft: `${row.depth * 20 + 12}px`
|
|
985
|
+
},
|
|
986
|
+
title: row.element.qname,
|
|
987
|
+
children: row.element.label
|
|
988
|
+
}
|
|
989
|
+
) }, row.key);
|
|
990
|
+
}
|
|
498
991
|
const textBlock = row.cells.find(
|
|
499
992
|
(c) => c.value === null && isExternalFactUrl(c.textValue)
|
|
500
993
|
);
|
|
501
994
|
if (textBlock?.textValue) {
|
|
502
|
-
return /* @__PURE__ */ jsx("tr", { children: /* @__PURE__ */ jsxs("td", { colSpan:
|
|
503
|
-
/* @__PURE__ */ jsx("div", { style: styles3.textBlockLabel, title: row.element.qname, children: row
|
|
995
|
+
return /* @__PURE__ */ jsx("tr", { children: /* @__PURE__ */ jsxs("td", { colSpan: totalCols + 1, style: styles3.textBlockCell, children: [
|
|
996
|
+
/* @__PURE__ */ jsx("div", { style: styles3.textBlockLabel, title: row.element.qname, children: rowLabel(row) }),
|
|
504
997
|
/* @__PURE__ */ jsx(ExternalTextBlock, { url: textBlock.textValue })
|
|
505
|
-
] }) }, row.
|
|
998
|
+
] }) }, row.key);
|
|
999
|
+
}
|
|
1000
|
+
if (row.element.itemType === "textBlock") {
|
|
1001
|
+
const inline = row.cells.find(
|
|
1002
|
+
(c) => c.value === null && c.textValue != null && c.textValue !== "" && !isExternalFactUrl(c.textValue)
|
|
1003
|
+
);
|
|
1004
|
+
if (inline?.textValue) {
|
|
1005
|
+
return /* @__PURE__ */ jsx("tr", { children: /* @__PURE__ */ jsxs("td", { colSpan: totalCols + 1, style: styles3.textBlockCell, children: [
|
|
1006
|
+
/* @__PURE__ */ jsx("div", { style: styles3.textBlockLabel, title: row.element.qname, children: rowLabel(row) }),
|
|
1007
|
+
/* @__PURE__ */ jsx(InlineTextBlock, { html: inline.textValue })
|
|
1008
|
+
] }) }, row.key);
|
|
1009
|
+
}
|
|
506
1010
|
}
|
|
1011
|
+
const kind = numericKindOf(row.element);
|
|
507
1012
|
const isGrandTotal = row.isSubtotal && row.depth === 0;
|
|
508
1013
|
const allZeroOrNull = row.cells.every((c) => c.value === null || c.value === 0);
|
|
509
1014
|
const rowStyle = {
|
|
@@ -517,11 +1022,14 @@ function StatementTable({
|
|
|
517
1022
|
borderBottom: isGrandTotal ? "3px double var(--rs-text, #111827)" : void 0
|
|
518
1023
|
};
|
|
519
1024
|
return /* @__PURE__ */ jsxs("tr", { style: rowStyle, children: [
|
|
520
|
-
/* @__PURE__ */ jsx("td", { style: labelStyle, title: row.element.qname, children: row
|
|
1025
|
+
/* @__PURE__ */ jsx("td", { style: labelStyle, title: row.element.qname, children: rowLabel(row) }),
|
|
521
1026
|
row.cells.map((cell, i) => {
|
|
522
|
-
const isSelected = selected !== null && selected.
|
|
1027
|
+
const isSelected = selected !== null && selected.rowKey === row.key && selected.columnIndex === i;
|
|
523
1028
|
const clickable = onCellClick && cell.fact !== null;
|
|
524
1029
|
const isText = cell.value === null && cell.textValue != null && cell.textValue !== "";
|
|
1030
|
+
const duration = isText ? humanizeDuration(cell.textValue) : null;
|
|
1031
|
+
const isProse = isText && !duration;
|
|
1032
|
+
const unit = cell.fact?.unit && units ? units[cell.fact.unit] : void 0;
|
|
525
1033
|
const numStyle = {
|
|
526
1034
|
...styles3.numCell,
|
|
527
1035
|
fontWeight: row.isSubtotal ? 600 : 400,
|
|
@@ -529,27 +1037,36 @@ function StatementTable({
|
|
|
529
1037
|
cursor: clickable ? "pointer" : "default",
|
|
530
1038
|
backgroundColor: isSelected ? "var(--rs-selected-bg, #dbeafe)" : void 0,
|
|
531
1039
|
color: !isText && !row.isSubtotal && (cell.value === null || cell.value === 0) ? "var(--rs-muted, #9ca3af)" : void 0,
|
|
532
|
-
...
|
|
1040
|
+
...isProse ? {
|
|
533
1041
|
textAlign: "left",
|
|
534
1042
|
whiteSpace: "normal",
|
|
535
1043
|
fontFamily: "var(--rs-font-sans, ui-sans-serif, system-ui, sans-serif)"
|
|
536
1044
|
} : {}
|
|
537
1045
|
};
|
|
1046
|
+
const display = isText ? duration ?? cell.textValue : cell.fact === null ? "" : cell.value === 0 ? "\u2014" : formatValue(cell.value, {
|
|
1047
|
+
numericKind: kind,
|
|
1048
|
+
symbol: cellSymbol(unit),
|
|
1049
|
+
scaleFactor: scale.factor
|
|
1050
|
+
});
|
|
538
1051
|
return /* @__PURE__ */ jsx(
|
|
539
1052
|
"td",
|
|
540
1053
|
{
|
|
541
1054
|
style: numStyle,
|
|
542
1055
|
onClick: clickable ? () => onCellClick?.(row, i) : void 0,
|
|
543
|
-
children:
|
|
1056
|
+
children: display
|
|
544
1057
|
},
|
|
545
1058
|
columns[i].key
|
|
546
1059
|
);
|
|
547
1060
|
})
|
|
548
|
-
] }, row.
|
|
1061
|
+
] }, row.key);
|
|
549
1062
|
}) })
|
|
550
|
-
] })
|
|
1063
|
+
] }) })
|
|
551
1064
|
] });
|
|
552
1065
|
}
|
|
1066
|
+
function rowLabel(row) {
|
|
1067
|
+
if (!row.members.length) return row.element.label;
|
|
1068
|
+
return row.members.map((m) => m.memberLabel).join(" \xB7 ");
|
|
1069
|
+
}
|
|
553
1070
|
var styles4 = {
|
|
554
1071
|
layout: {
|
|
555
1072
|
display: "grid",
|
|
@@ -573,11 +1090,19 @@ var styles4 = {
|
|
|
573
1090
|
},
|
|
574
1091
|
panel: { position: "sticky", top: "1rem" }
|
|
575
1092
|
};
|
|
576
|
-
function ReportView({ report,
|
|
577
|
-
const
|
|
1093
|
+
function ReportView({ report, inspect = true, dimensionAxis = "rows" }) {
|
|
1094
|
+
const [dimAxis, setDimAxis] = useState(dimensionAxis);
|
|
578
1095
|
const [selection, setSelection] = useState(null);
|
|
1096
|
+
const statements = useMemo(
|
|
1097
|
+
() => buildPivots(report, (_ib, cfg) => pivotDimensionsOn(cfg, dimAxis)),
|
|
1098
|
+
[report, dimAxis]
|
|
1099
|
+
);
|
|
579
1100
|
const selected = selection !== null ? statements[selection.statementIndex] : null;
|
|
580
|
-
const selectedRow = selected?.rows.find((r) => r.
|
|
1101
|
+
const selectedRow = selected?.rows.find((r) => r.key === selection?.rowKey) ?? null;
|
|
1102
|
+
const setPlacement = (placement) => {
|
|
1103
|
+
setSelection(null);
|
|
1104
|
+
setDimAxis(placement);
|
|
1105
|
+
};
|
|
581
1106
|
return /* @__PURE__ */ jsxs("div", { children: [
|
|
582
1107
|
report.entity ? /* @__PURE__ */ jsx("header", { style: styles4.entity, children: /* @__PURE__ */ jsx("h2", { style: styles4.entityName, children: report.entity.name }) }) : null,
|
|
583
1108
|
/* @__PURE__ */ jsxs(
|
|
@@ -591,17 +1116,12 @@ function ReportView({ report, currencySymbol = "$", inspect = true }) {
|
|
|
591
1116
|
/* @__PURE__ */ jsx("div", { children: statements.map((statement, statementIndex) => /* @__PURE__ */ jsx(
|
|
592
1117
|
StatementTable,
|
|
593
1118
|
{
|
|
594
|
-
statement,
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
} :
|
|
600
|
-
onCellClick: inspect ? (row, columnIndex) => setSelection({
|
|
601
|
-
statementIndex,
|
|
602
|
-
elementId: row.element.id,
|
|
603
|
-
columnIndex
|
|
604
|
-
}) : void 0
|
|
1119
|
+
table: statement,
|
|
1120
|
+
units: report.units,
|
|
1121
|
+
dimensionPlacement: dimAxis,
|
|
1122
|
+
onDimensionPlacementChange: setPlacement,
|
|
1123
|
+
selected: selection && selection.statementIndex === statementIndex ? { rowKey: selection.rowKey, columnIndex: selection.columnIndex } : null,
|
|
1124
|
+
onCellClick: inspect ? (row, columnIndex) => setSelection({ statementIndex, rowKey: row.key, columnIndex }) : void 0
|
|
605
1125
|
},
|
|
606
1126
|
statement.ib.id
|
|
607
1127
|
)) }),
|
|
@@ -609,10 +1129,9 @@ function ReportView({ report, currencySymbol = "$", inspect = true }) {
|
|
|
609
1129
|
FactInspector,
|
|
610
1130
|
{
|
|
611
1131
|
report,
|
|
612
|
-
|
|
1132
|
+
table: selected,
|
|
613
1133
|
row: selectedRow,
|
|
614
1134
|
columnIndex: selection.columnIndex,
|
|
615
|
-
currencySymbol,
|
|
616
1135
|
onClose: () => setSelection(null)
|
|
617
1136
|
}
|
|
618
1137
|
) }) : null
|
|
@@ -622,6 +1141,6 @@ function ReportView({ report, currencySymbol = "$", inspect = true }) {
|
|
|
622
1141
|
] });
|
|
623
1142
|
}
|
|
624
1143
|
|
|
625
|
-
export { ExternalTextBlock, FactInspector, ReportView, StatementTable,
|
|
1144
|
+
export { ExternalTextBlock, FactInspector, ReportView, StatementTable, buildPivot, buildPivots, calcSubtotals, defaultPivotConfig, footCheck, pivotDimensionsOn, presentationOrder, reportSections, sliceReportSection };
|
|
626
1145
|
//# sourceMappingURL=index.js.map
|
|
627
1146
|
//# sourceMappingURL=index.js.map
|