@robosystems/report-components 0.1.0 → 0.1.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/README.md +7 -7
- package/dist/adapters/index.d.ts +2 -5
- package/dist/adapters/index.js +2 -2
- package/dist/adapters/index.js.map +1 -1
- package/dist/chunk-FNRQJVAH.js +284 -0
- package/dist/chunk-FNRQJVAH.js.map +1 -0
- package/dist/{model.d.ts → index-DlTmV_mJ.d.ts} +87 -17
- package/dist/index.d.ts +119 -23
- package/dist/index.js +491 -23
- package/dist/index.js.map +1 -1
- package/package.json +5 -2
- package/dist/adapters/cypher.d.ts +0 -21
- package/dist/adapters/cypher.d.ts.map +0 -1
- package/dist/adapters/cypher.js +0 -9
- package/dist/adapters/cypher.js.map +0 -1
- package/dist/adapters/index.d.ts.map +0 -1
- package/dist/adapters/trig.d.ts +0 -7
- package/dist/adapters/trig.d.ts.map +0 -1
- package/dist/adapters/trig.js +0 -183
- package/dist/adapters/trig.js.map +0 -1
- package/dist/adapters/types.d.ts +0 -16
- package/dist/adapters/types.d.ts.map +0 -1
- package/dist/adapters/types.js +0 -2
- package/dist/adapters/types.js.map +0 -1
- package/dist/components/FactInspector.d.ts +0 -11
- package/dist/components/FactInspector.d.ts.map +0 -1
- package/dist/components/FactInspector.js +0 -79
- package/dist/components/FactInspector.js.map +0 -1
- package/dist/components/ReportView.d.ts +0 -9
- package/dist/components/ReportView.d.ts.map +0 -1
- package/dist/components/ReportView.js +0 -51
- package/dist/components/ReportView.js.map +0 -1
- package/dist/components/StatementTable.d.ts +0 -15
- package/dist/components/StatementTable.d.ts.map +0 -1
- package/dist/components/StatementTable.js +0 -86
- package/dist/components/StatementTable.js.map +0 -1
- package/dist/constants.d.ts +0 -71
- package/dist/constants.d.ts.map +0 -1
- package/dist/constants.js +0 -115
- package/dist/constants.js.map +0 -1
- package/dist/format.d.ts +0 -17
- package/dist/format.d.ts.map +0 -1
- package/dist/format.js +0 -34
- package/dist/format.js.map +0 -1
- package/dist/index.d.ts.map +0 -1
- package/dist/model.d.ts.map +0 -1
- package/dist/model.js +0 -15
- package/dist/model.js.map +0 -1
- package/dist/project.d.ts +0 -39
- package/dist/project.d.ts.map +0 -1
- package/dist/project.js +0 -201
- package/dist/project.js.map +0 -1
package/dist/index.d.ts
CHANGED
|
@@ -1,26 +1,122 @@
|
|
|
1
|
+
import { P as PeriodInfo, E as ElementInfo, N as NormalizedReport, S as Statement, a as StatementRow } from './index-DlTmV_mJ.js';
|
|
2
|
+
export { B as BalanceType, C as CalcAssociation, b as CypherAdapterConfig, c as EntityInfo, F as Fact, I as InformationBlock, d as PeriodType, e as PresAssociation, R as ReportAdapter, f as RowCell, g as StatementColumn, h as StructureInfo, U as UnitInfo, i as cypherAdapter, j as jsonldFileAdapter, p as parseJsonld, k as parseStore, l as parseTrig, t as trigFileAdapter } from './index-DlTmV_mJ.js';
|
|
3
|
+
import * as react from 'react';
|
|
4
|
+
import 'n3';
|
|
5
|
+
|
|
1
6
|
/**
|
|
2
|
-
*
|
|
7
|
+
* RDF vocabulary and display helpers shared across adapters and projection.
|
|
3
8
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
9
|
+
* A `holon.trig` mixes several vocabularies: `rs:` for structure, `skos:` for
|
|
10
|
+
* human labels, and the XBRL family (`xlink:` / `xbrli:` / `link:`) for the
|
|
11
|
+
* networks. These constants are the single source of truth for the full IRIs.
|
|
12
|
+
*/
|
|
13
|
+
declare const NS: {
|
|
14
|
+
readonly rdf: "http://www.w3.org/1999/02/22-rdf-syntax-ns#";
|
|
15
|
+
readonly rs: "https://robosystems.ai/vocab/";
|
|
16
|
+
readonly rsgaap: "https://robosystems.ai/taxonomy/rs-gaap/v1/";
|
|
17
|
+
readonly skos: "http://www.w3.org/2004/02/skos/core#";
|
|
18
|
+
readonly xlink: "http://www.w3.org/1999/xlink#";
|
|
19
|
+
readonly xbrli: "http://www.xbrl.org/2003/instance#";
|
|
20
|
+
readonly link: "http://www.xbrl.org/2003/linkbase#";
|
|
21
|
+
readonly iso4217: "http://www.xbrl.org/2003/iso4217#";
|
|
22
|
+
};
|
|
23
|
+
/** Compact a concept IRI to `prefix:Local` (e.g. `rs-gaap:Assets`). */
|
|
24
|
+
declare function qname(iri: string): string;
|
|
25
|
+
/**
|
|
26
|
+
* Readable concept name from a local name when no `skos:prefLabel` is present —
|
|
27
|
+
* splits CamelCase into words (`AssetsCurrent` → `Assets Current`). A graceful
|
|
28
|
+
* fallback for bundles that predate label emit.
|
|
29
|
+
*/
|
|
30
|
+
declare function humanize(iri: string): string;
|
|
31
|
+
/** Stable display order for the canonical statement blocks; others fall after. */
|
|
32
|
+
declare const BLOCK_ORDER: Record<string, number>;
|
|
33
|
+
/** Friendly section headings keyed by block type. */
|
|
34
|
+
declare const BLOCK_TITLES: Record<string, string>;
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Pure formatting helpers shared by the projection and the components. No React
|
|
38
|
+
* here, so the projection can depend on it without pulling in a renderer.
|
|
39
|
+
*/
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Accounting-style money: negatives in parentheses, no sign, an em-dash for
|
|
43
|
+
* absent values. Matches the RoboLedger statement renderer.
|
|
44
|
+
*/
|
|
45
|
+
declare function formatMoney(value: number | null | undefined, opts?: {
|
|
46
|
+
currencySymbol?: string;
|
|
47
|
+
}): string;
|
|
48
|
+
/** `2024-03-31` → `Mar 31, 2024`. Falls back to the raw string if unparseable. */
|
|
49
|
+
declare function formatDate(iso: string | null | undefined): string;
|
|
50
|
+
/** A human description of a period — "As of …" for instants, a span for durations. */
|
|
51
|
+
declare function formatPeriod(period: PeriodInfo): string;
|
|
52
|
+
|
|
53
|
+
interface OrderEntry {
|
|
54
|
+
order: number;
|
|
55
|
+
depth: number;
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Post-order the presentation arcs of one structure → `{element: {order, depth}}`.
|
|
59
|
+
* Roots (a `from` that is never a `to`) are visited by their subtree's leading
|
|
60
|
+
* arc order, so a balance sheet's roots (Assets, then Liabilities and Equity)
|
|
61
|
+
* come out in the right sequence.
|
|
62
|
+
*/
|
|
63
|
+
declare function presentationOrder(model: NormalizedReport, structureId: string): Map<string, OrderEntry>;
|
|
64
|
+
/** Concepts that are calculation parents — the authoritative subtotal set. */
|
|
65
|
+
declare function calcSubtotals(model: NormalizedReport): Set<string>;
|
|
66
|
+
/** Reconstruct every statement in the report, in canonical block order. */
|
|
67
|
+
declare function buildStatements(model: NormalizedReport): Statement[];
|
|
68
|
+
interface FootTerm {
|
|
69
|
+
element: ElementInfo;
|
|
70
|
+
weight: number;
|
|
71
|
+
value: number | null;
|
|
72
|
+
}
|
|
73
|
+
interface FootCheck {
|
|
74
|
+
element: ElementInfo;
|
|
75
|
+
columnIndex: number;
|
|
76
|
+
terms: FootTerm[];
|
|
77
|
+
/** Σ child·weight over the present terms, or null if none are present. */
|
|
78
|
+
expected: number | null;
|
|
79
|
+
/** The subtotal's own reported value in this column. */
|
|
80
|
+
actual: number | null;
|
|
81
|
+
ok: boolean;
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Foot a subtotal live: sum its calculation children (× weight) and compare to
|
|
85
|
+
* its reported value, e.g. `13,550 + 900 = 14,450 ✓`. Returns `null` when the
|
|
86
|
+
* element is not a calculation parent (nothing to foot).
|
|
11
87
|
*/
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
88
|
+
declare function footCheck(model: NormalizedReport, statement: Statement, elementId: string, columnIndex: number): FootCheck | null;
|
|
89
|
+
|
|
90
|
+
interface FactInspectorProps {
|
|
91
|
+
report: NormalizedReport;
|
|
92
|
+
statement: Statement;
|
|
93
|
+
row: StatementRow;
|
|
94
|
+
columnIndex: number;
|
|
95
|
+
onClose?: () => void;
|
|
96
|
+
currencySymbol?: string;
|
|
97
|
+
}
|
|
98
|
+
declare function FactInspector({ report, statement, row, columnIndex, onClose, currencySymbol, }: FactInspectorProps): react.JSX.Element;
|
|
99
|
+
|
|
100
|
+
interface ReportViewProps {
|
|
101
|
+
report: NormalizedReport;
|
|
102
|
+
currencySymbol?: string;
|
|
103
|
+
/** Disable the click-to-inspect fact panel (render-only). */
|
|
104
|
+
inspect?: boolean;
|
|
105
|
+
}
|
|
106
|
+
declare function ReportView({ report, currencySymbol, inspect }: ReportViewProps): react.JSX.Element;
|
|
107
|
+
|
|
108
|
+
interface StatementTableProps {
|
|
109
|
+
statement: Statement;
|
|
110
|
+
/** Called when a value cell is clicked — drives fact inspection. */
|
|
111
|
+
onCellClick?: (row: StatementRow, columnIndex: number) => void;
|
|
112
|
+
/** Currency symbol for values (default `$`). */
|
|
113
|
+
currencySymbol?: string;
|
|
114
|
+
/** The currently-selected cell, highlighted. */
|
|
115
|
+
selected?: {
|
|
116
|
+
elementId: string;
|
|
117
|
+
columnIndex: number;
|
|
118
|
+
} | null;
|
|
119
|
+
}
|
|
120
|
+
declare function StatementTable({ statement, onCellClick, currencySymbol, selected, }: StatementTableProps): react.JSX.Element;
|
|
121
|
+
|
|
122
|
+
export { BLOCK_ORDER, BLOCK_TITLES, ElementInfo, FactInspector, type FactInspectorProps, type FootCheck, type FootTerm, NS, NormalizedReport, PeriodInfo, ReportView, type ReportViewProps, Statement, StatementRow, StatementTable, type StatementTableProps, buildStatements, calcSubtotals, footCheck, formatDate, formatMoney, formatPeriod, humanize, presentationOrder, qname };
|
package/dist/index.js
CHANGED
|
@@ -1,24 +1,492 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
1
|
+
import { BLOCK_ORDER, BLOCK_TITLES, humanize, qname } from './chunk-FNRQJVAH.js';
|
|
2
|
+
export { BLOCK_ORDER, BLOCK_TITLES, NS, cypherAdapter, humanize, jsonldFileAdapter, parseJsonld, parseStore, parseTrig, qname, trigFileAdapter } from './chunk-FNRQJVAH.js';
|
|
3
|
+
import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
|
|
4
|
+
import { useMemo, useState } from 'react';
|
|
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
|
+
// src/project.ts
|
|
33
|
+
function fallbackElement(id) {
|
|
34
|
+
return {
|
|
35
|
+
id,
|
|
36
|
+
qname: qname(id),
|
|
37
|
+
label: humanize(id),
|
|
38
|
+
balance: null,
|
|
39
|
+
periodType: null,
|
|
40
|
+
abstract: false,
|
|
41
|
+
monetary: false
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
function presentationOrder(model, structureId) {
|
|
45
|
+
const children = /* @__PURE__ */ new Map();
|
|
46
|
+
const froms = /* @__PURE__ */ new Set();
|
|
47
|
+
const tos = /* @__PURE__ */ new Set();
|
|
48
|
+
for (const assoc of model.presAssociations) {
|
|
49
|
+
if (assoc.structure !== structureId) continue;
|
|
50
|
+
const kids = children.get(assoc.parent) ?? [];
|
|
51
|
+
kids.push([assoc.order, assoc.child]);
|
|
52
|
+
children.set(assoc.parent, kids);
|
|
53
|
+
froms.add(assoc.parent);
|
|
54
|
+
tos.add(assoc.child);
|
|
55
|
+
}
|
|
56
|
+
for (const kids of children.values()) {
|
|
57
|
+
kids.sort((a, b) => a[0] - b[0]);
|
|
58
|
+
}
|
|
59
|
+
const out = /* @__PURE__ */ new Map();
|
|
60
|
+
const seen = /* @__PURE__ */ new Set();
|
|
61
|
+
let counter = 0;
|
|
62
|
+
const walk = (node, depth) => {
|
|
63
|
+
if (seen.has(node)) return;
|
|
64
|
+
seen.add(node);
|
|
65
|
+
for (const [, child] of children.get(node) ?? []) {
|
|
66
|
+
walk(child, depth + 1);
|
|
67
|
+
}
|
|
68
|
+
out.set(node, { order: counter, depth });
|
|
69
|
+
counter += 1;
|
|
70
|
+
};
|
|
71
|
+
const rootKey = (root) => {
|
|
72
|
+
const kids = children.get(root);
|
|
73
|
+
return kids && kids.length ? kids[0][0] : 0;
|
|
74
|
+
};
|
|
75
|
+
const roots = [...froms].filter((f) => !tos.has(f)).sort((a, b) => rootKey(a) - rootKey(b));
|
|
76
|
+
for (const root of roots) walk(root, 0);
|
|
77
|
+
return out;
|
|
78
|
+
}
|
|
79
|
+
function calcSubtotals(model) {
|
|
80
|
+
const out = /* @__PURE__ */ new Set();
|
|
81
|
+
for (const assoc of model.calcAssociations) out.add(assoc.parent);
|
|
82
|
+
return out;
|
|
83
|
+
}
|
|
84
|
+
function structureForBlock(model, blockType) {
|
|
85
|
+
return model.structures.find((s) => s.blockType === blockType) ?? null;
|
|
86
|
+
}
|
|
87
|
+
function columnLabel(period) {
|
|
88
|
+
return formatDate(period.end);
|
|
89
|
+
}
|
|
90
|
+
function deriveColumns(model, facts) {
|
|
91
|
+
const byEnd = /* @__PURE__ */ new Map();
|
|
92
|
+
for (const fact of facts) {
|
|
93
|
+
const period = model.periods[fact.period];
|
|
94
|
+
if (!period || !period.end) continue;
|
|
95
|
+
const existing = byEnd.get(period.end);
|
|
96
|
+
if (!existing || existing.type === "instant" && period.type === "duration") {
|
|
97
|
+
byEnd.set(period.end, period);
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
return [...byEnd.values()].sort((a, b) => {
|
|
101
|
+
const aStart = a.startDate ?? a.end;
|
|
102
|
+
const bStart = b.startDate ?? b.end;
|
|
103
|
+
return aStart.localeCompare(bStart) || a.end.localeCompare(b.end);
|
|
104
|
+
}).map((period) => ({ key: period.end, label: columnLabel(period), period }));
|
|
105
|
+
}
|
|
106
|
+
function buildStatement(model, ib, subtotals) {
|
|
107
|
+
const structure = structureForBlock(model, ib.blockType);
|
|
108
|
+
const order = structure ? presentationOrder(model, structure.id) : /* @__PURE__ */ new Map();
|
|
109
|
+
const facts = model.facts.filter((f) => f.factSet !== null && f.factSet === ib.factSet);
|
|
110
|
+
const columns = deriveColumns(model, facts);
|
|
111
|
+
const colIndex = new Map(columns.map((c, i) => [c.key, i]));
|
|
112
|
+
const cellsByElement = /* @__PURE__ */ new Map();
|
|
113
|
+
for (const fact of facts) {
|
|
114
|
+
const period = model.periods[fact.period];
|
|
115
|
+
if (!period) continue;
|
|
116
|
+
const idx = colIndex.get(period.end);
|
|
117
|
+
if (idx === void 0) continue;
|
|
118
|
+
let cells = cellsByElement.get(fact.element);
|
|
119
|
+
if (!cells) {
|
|
120
|
+
cells = columns.map(() => ({ value: null, fact: null }));
|
|
121
|
+
cellsByElement.set(fact.element, cells);
|
|
122
|
+
}
|
|
123
|
+
cells[idx] = { value: fact.value, fact };
|
|
124
|
+
}
|
|
125
|
+
const rows = [...cellsByElement.keys()].map((id) => {
|
|
126
|
+
const entry = order.get(id);
|
|
127
|
+
return {
|
|
128
|
+
id,
|
|
129
|
+
order: entry ? entry.order : Number.MAX_SAFE_INTEGER,
|
|
130
|
+
depth: entry ? entry.depth : 0
|
|
131
|
+
};
|
|
132
|
+
}).sort((a, b) => a.order - b.order || a.id.localeCompare(b.id)).map(({ id, depth }) => ({
|
|
133
|
+
element: model.elements[id] ?? fallbackElement(id),
|
|
134
|
+
depth,
|
|
135
|
+
isSubtotal: subtotals.has(id),
|
|
136
|
+
cells: cellsByElement.get(id)
|
|
137
|
+
}));
|
|
138
|
+
return {
|
|
139
|
+
ib,
|
|
140
|
+
blockType: ib.blockType,
|
|
141
|
+
title: BLOCK_TITLES[ib.blockType] ?? ib.label ?? ib.blockType,
|
|
142
|
+
structureName: structure?.structureName ?? ib.label ?? null,
|
|
143
|
+
columns,
|
|
144
|
+
rows
|
|
145
|
+
};
|
|
146
|
+
}
|
|
147
|
+
function buildStatements(model) {
|
|
148
|
+
const subtotals = calcSubtotals(model);
|
|
149
|
+
return [...model.informationBlocks].sort(
|
|
150
|
+
(a, b) => (BLOCK_ORDER[a.blockType] ?? 99) - (BLOCK_ORDER[b.blockType] ?? 99) || a.blockType.localeCompare(b.blockType)
|
|
151
|
+
).map((ib) => buildStatement(model, ib, subtotals));
|
|
152
|
+
}
|
|
153
|
+
function footCheck(model, statement, elementId, columnIndex) {
|
|
154
|
+
const kids = model.calcAssociations.filter((a) => a.parent === elementId);
|
|
155
|
+
if (!kids.length) return null;
|
|
156
|
+
const valueOf = (id) => {
|
|
157
|
+
const row = statement.rows.find((r) => r.element.id === id);
|
|
158
|
+
return row ? row.cells[columnIndex]?.value ?? null : null;
|
|
159
|
+
};
|
|
160
|
+
const terms = kids.slice().sort((a, b) => a.order - b.order).map((a) => ({
|
|
161
|
+
element: model.elements[a.child] ?? fallbackElement(a.child),
|
|
162
|
+
weight: a.weight,
|
|
163
|
+
value: valueOf(a.child)
|
|
164
|
+
}));
|
|
165
|
+
const present = terms.filter((t) => t.value !== null);
|
|
166
|
+
const expected = present.length ? present.reduce((sum, t) => sum + t.value * t.weight, 0) : null;
|
|
167
|
+
const actual = valueOf(elementId);
|
|
168
|
+
const ok = expected !== null && actual !== null && Math.abs(expected - actual) < 5e-3;
|
|
169
|
+
return {
|
|
170
|
+
element: model.elements[elementId] ?? fallbackElement(elementId),
|
|
171
|
+
columnIndex,
|
|
172
|
+
terms,
|
|
173
|
+
expected,
|
|
174
|
+
actual,
|
|
175
|
+
ok
|
|
176
|
+
};
|
|
177
|
+
}
|
|
178
|
+
var styles = {
|
|
179
|
+
panel: {
|
|
180
|
+
fontFamily: "var(--rs-font-sans, ui-sans-serif, system-ui, sans-serif)",
|
|
181
|
+
color: "var(--rs-text, #111827)",
|
|
182
|
+
border: "1px solid var(--rs-border, #e5e7eb)",
|
|
183
|
+
borderRadius: "12px",
|
|
184
|
+
padding: "1rem 1.25rem",
|
|
185
|
+
background: "var(--rs-panel-bg, #ffffff)",
|
|
186
|
+
boxShadow: "0 1px 3px rgba(0,0,0,0.08)"
|
|
187
|
+
},
|
|
188
|
+
header: {
|
|
189
|
+
display: "flex",
|
|
190
|
+
justifyContent: "space-between",
|
|
191
|
+
alignItems: "flex-start",
|
|
192
|
+
gap: "1rem",
|
|
193
|
+
marginBottom: "0.75rem"
|
|
194
|
+
},
|
|
195
|
+
label: { fontSize: "1rem", fontWeight: 700, margin: 0 },
|
|
196
|
+
qname: {
|
|
197
|
+
fontFamily: "var(--rs-font-mono, ui-monospace, monospace)",
|
|
198
|
+
fontSize: "0.8rem",
|
|
199
|
+
color: "var(--rs-primary-700, #1d4ed8)"
|
|
200
|
+
},
|
|
201
|
+
close: {
|
|
202
|
+
border: "none",
|
|
203
|
+
background: "transparent",
|
|
204
|
+
fontSize: "1.25rem",
|
|
205
|
+
lineHeight: 1,
|
|
206
|
+
cursor: "pointer",
|
|
207
|
+
color: "var(--rs-muted, #6b7280)"
|
|
208
|
+
},
|
|
209
|
+
grid: {
|
|
210
|
+
display: "grid",
|
|
211
|
+
gridTemplateColumns: "auto 1fr",
|
|
212
|
+
gap: "0.35rem 1rem",
|
|
213
|
+
fontSize: "0.85rem",
|
|
214
|
+
margin: "0.5rem 0"
|
|
215
|
+
},
|
|
216
|
+
key: { color: "var(--rs-muted, #6b7280)" },
|
|
217
|
+
mono: { fontFamily: "var(--rs-font-mono, ui-monospace, monospace)" },
|
|
218
|
+
footing: {
|
|
219
|
+
marginTop: "0.85rem",
|
|
220
|
+
paddingTop: "0.75rem",
|
|
221
|
+
borderTop: "1px solid var(--rs-border, #e5e7eb)"
|
|
222
|
+
},
|
|
223
|
+
footTitle: {
|
|
224
|
+
fontSize: "0.75rem",
|
|
225
|
+
textTransform: "uppercase",
|
|
226
|
+
letterSpacing: "0.05em",
|
|
227
|
+
color: "var(--rs-muted, #6b7280)",
|
|
228
|
+
marginBottom: "0.4rem"
|
|
229
|
+
},
|
|
230
|
+
equation: {
|
|
231
|
+
fontFamily: "var(--rs-font-mono, ui-monospace, monospace)",
|
|
232
|
+
fontSize: "0.85rem",
|
|
233
|
+
lineHeight: 1.6
|
|
234
|
+
}
|
|
235
|
+
};
|
|
236
|
+
function Field({ k, children }) {
|
|
237
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
238
|
+
/* @__PURE__ */ jsx("span", { style: styles.key, children: k }),
|
|
239
|
+
/* @__PURE__ */ jsx("span", { children })
|
|
240
|
+
] });
|
|
241
|
+
}
|
|
242
|
+
function FactInspector({
|
|
243
|
+
report,
|
|
244
|
+
statement,
|
|
245
|
+
row,
|
|
246
|
+
columnIndex,
|
|
247
|
+
onClose,
|
|
248
|
+
currencySymbol = "$"
|
|
249
|
+
}) {
|
|
250
|
+
const { element } = row;
|
|
251
|
+
const cell = row.cells[columnIndex];
|
|
252
|
+
const column = statement.columns[columnIndex];
|
|
253
|
+
const unit = cell.fact?.unit ? report.units[cell.fact.unit] : null;
|
|
254
|
+
const foot = footCheck(report, statement, element.id, columnIndex);
|
|
255
|
+
const sym = currencySymbol;
|
|
256
|
+
return /* @__PURE__ */ jsxs("div", { style: styles.panel, children: [
|
|
257
|
+
/* @__PURE__ */ jsxs("div", { style: styles.header, children: [
|
|
258
|
+
/* @__PURE__ */ jsxs("div", { children: [
|
|
259
|
+
/* @__PURE__ */ jsx("p", { style: styles.label, children: element.label }),
|
|
260
|
+
/* @__PURE__ */ jsx("span", { style: styles.qname, children: element.qname })
|
|
261
|
+
] }),
|
|
262
|
+
onClose ? /* @__PURE__ */ jsx("button", { style: styles.close, onClick: onClose, "aria-label": "Close", children: "\xD7" }) : null
|
|
263
|
+
] }),
|
|
264
|
+
/* @__PURE__ */ jsxs("div", { style: styles.grid, children: [
|
|
265
|
+
/* @__PURE__ */ jsx(Field, { k: "Value", children: /* @__PURE__ */ jsx("span", { style: styles.mono, children: formatMoney(cell.value, { currencySymbol: sym }) }) }),
|
|
266
|
+
/* @__PURE__ */ jsxs(Field, { k: "Period", children: [
|
|
267
|
+
formatPeriod(column.period),
|
|
268
|
+
" ",
|
|
269
|
+
/* @__PURE__ */ jsxs("span", { style: styles.key, children: [
|
|
270
|
+
"(",
|
|
271
|
+
column.period.type,
|
|
272
|
+
")"
|
|
273
|
+
] })
|
|
274
|
+
] }),
|
|
275
|
+
/* @__PURE__ */ jsx(Field, { k: "Unit", children: unit ? unit.label : "\u2014" }),
|
|
276
|
+
element.balance ? /* @__PURE__ */ jsx(Field, { k: "Balance", children: element.balance }) : null,
|
|
277
|
+
cell.fact?.decimals ? /* @__PURE__ */ jsx(Field, { k: "Decimals", children: cell.fact.decimals }) : null
|
|
278
|
+
] }),
|
|
279
|
+
foot ? /* @__PURE__ */ jsxs("div", { style: styles.footing, children: [
|
|
280
|
+
/* @__PURE__ */ jsxs("div", { style: styles.footTitle, children: [
|
|
281
|
+
"Calculation ",
|
|
282
|
+
foot.ok ? "\u2713 foots" : "\u26A0 does not foot"
|
|
283
|
+
] }),
|
|
284
|
+
/* @__PURE__ */ jsxs("div", { style: styles.equation, children: [
|
|
285
|
+
foot.terms.map((term, i) => {
|
|
286
|
+
const op = i === 0 ? term.weight < 0 ? "\u2212" : "" : term.weight < 0 ? " \u2212 " : " + ";
|
|
287
|
+
return /* @__PURE__ */ jsxs("span", { title: term.element.qname, children: [
|
|
288
|
+
op,
|
|
289
|
+
formatMoney(term.value === null ? 0 : Math.abs(term.value), {
|
|
290
|
+
currencySymbol: sym
|
|
291
|
+
})
|
|
292
|
+
] }, term.element.id);
|
|
293
|
+
}),
|
|
294
|
+
" = ",
|
|
295
|
+
/* @__PURE__ */ jsx("strong", { children: formatMoney(foot.expected, { currencySymbol: sym }) }),
|
|
296
|
+
" ",
|
|
297
|
+
foot.ok ? /* @__PURE__ */ jsx("span", { style: { color: "var(--rs-success, #00875a)" }, children: "\u2713" }) : /* @__PURE__ */ jsxs("span", { style: { color: "var(--rs-error, #dc2626)" }, children: [
|
|
298
|
+
"\u2717 (reported ",
|
|
299
|
+
formatMoney(foot.actual, { currencySymbol: sym }),
|
|
300
|
+
")"
|
|
301
|
+
] })
|
|
302
|
+
] })
|
|
303
|
+
] }) : null
|
|
304
|
+
] });
|
|
305
|
+
}
|
|
306
|
+
var styles2 = {
|
|
307
|
+
wrap: {
|
|
308
|
+
fontFamily: "var(--rs-font-sans, ui-sans-serif, system-ui, sans-serif)",
|
|
309
|
+
color: "var(--rs-text, #111827)",
|
|
310
|
+
marginBottom: "2.5rem"
|
|
311
|
+
},
|
|
312
|
+
heading: {
|
|
313
|
+
textAlign: "center",
|
|
314
|
+
marginBottom: "1rem"
|
|
315
|
+
},
|
|
316
|
+
title: {
|
|
317
|
+
fontFamily: "var(--rs-font-heading, var(--rs-font-sans, sans-serif))",
|
|
318
|
+
fontSize: "1.15rem",
|
|
319
|
+
fontWeight: 700,
|
|
320
|
+
letterSpacing: "0.02em",
|
|
321
|
+
margin: 0
|
|
322
|
+
},
|
|
323
|
+
subtitle: {
|
|
324
|
+
fontSize: "0.85rem",
|
|
325
|
+
color: "var(--rs-muted, #6b7280)",
|
|
326
|
+
marginTop: "0.25rem"
|
|
327
|
+
},
|
|
328
|
+
table: {
|
|
329
|
+
width: "100%",
|
|
330
|
+
borderCollapse: "collapse",
|
|
331
|
+
fontSize: "0.875rem"
|
|
332
|
+
},
|
|
333
|
+
th: {
|
|
334
|
+
borderBottom: "2px solid var(--rs-border-strong, #9ca3af)",
|
|
335
|
+
padding: "0.5rem 0.75rem",
|
|
336
|
+
fontWeight: 600,
|
|
337
|
+
color: "var(--rs-muted, #6b7280)",
|
|
338
|
+
fontSize: "0.8rem"
|
|
339
|
+
},
|
|
340
|
+
thConcept: { textAlign: "left" },
|
|
341
|
+
thNum: { textAlign: "right", whiteSpace: "nowrap" },
|
|
342
|
+
labelCell: {
|
|
343
|
+
padding: "0.3rem 0.75rem",
|
|
344
|
+
whiteSpace: "normal"
|
|
345
|
+
},
|
|
346
|
+
numCell: {
|
|
347
|
+
padding: "0.3rem 0.75rem",
|
|
348
|
+
textAlign: "right",
|
|
349
|
+
whiteSpace: "nowrap",
|
|
350
|
+
fontFamily: "var(--rs-font-mono, ui-monospace, SFMono-Regular, monospace)",
|
|
351
|
+
fontVariantNumeric: "tabular-nums"
|
|
352
|
+
}
|
|
353
|
+
};
|
|
354
|
+
function StatementTable({
|
|
355
|
+
statement,
|
|
356
|
+
onCellClick,
|
|
357
|
+
currencySymbol = "$",
|
|
358
|
+
selected = null
|
|
359
|
+
}) {
|
|
360
|
+
const { columns, rows } = statement;
|
|
361
|
+
const periodCaption = columns.length === 1 ? formatPeriod(columns[0].period) : null;
|
|
362
|
+
return /* @__PURE__ */ jsxs("section", { style: styles2.wrap, children: [
|
|
363
|
+
/* @__PURE__ */ jsxs("header", { style: styles2.heading, children: [
|
|
364
|
+
/* @__PURE__ */ jsx("h3", { style: styles2.title, children: statement.title }),
|
|
365
|
+
statement.structureName ? /* @__PURE__ */ jsx("div", { style: styles2.subtitle, children: statement.structureName }) : null,
|
|
366
|
+
periodCaption ? /* @__PURE__ */ jsx("div", { style: styles2.subtitle, children: periodCaption }) : null
|
|
367
|
+
] }),
|
|
368
|
+
/* @__PURE__ */ jsxs("table", { style: styles2.table, children: [
|
|
369
|
+
/* @__PURE__ */ jsx("thead", { children: /* @__PURE__ */ jsxs("tr", { children: [
|
|
370
|
+
/* @__PURE__ */ jsx("th", { style: { ...styles2.th, ...styles2.thConcept }, children: "Concept" }),
|
|
371
|
+
columns.map((col) => /* @__PURE__ */ jsx("th", { style: { ...styles2.th, ...styles2.thNum }, children: col.label }, col.key))
|
|
372
|
+
] }) }),
|
|
373
|
+
/* @__PURE__ */ jsx("tbody", { children: rows.map((row) => {
|
|
374
|
+
const isGrandTotal = row.isSubtotal && row.depth === 0;
|
|
375
|
+
const allZeroOrNull = row.cells.every((c) => c.value === null || c.value === 0);
|
|
376
|
+
const rowStyle = {
|
|
377
|
+
backgroundColor: row.isSubtotal ? "var(--rs-subtotal-bg, #f9fafb)" : void 0
|
|
378
|
+
};
|
|
379
|
+
const labelStyle = {
|
|
380
|
+
...styles2.labelCell,
|
|
381
|
+
paddingLeft: `${row.depth * 20 + 12}px`,
|
|
382
|
+
fontWeight: row.isSubtotal ? 600 : 400,
|
|
383
|
+
color: !row.isSubtotal && allZeroOrNull ? "var(--rs-muted, #9ca3af)" : void 0,
|
|
384
|
+
borderBottom: isGrandTotal ? "3px double var(--rs-text, #111827)" : void 0
|
|
385
|
+
};
|
|
386
|
+
return /* @__PURE__ */ jsxs("tr", { style: rowStyle, children: [
|
|
387
|
+
/* @__PURE__ */ jsx("td", { style: labelStyle, title: row.element.qname, children: row.element.label }),
|
|
388
|
+
row.cells.map((cell, i) => {
|
|
389
|
+
const isSelected = selected !== null && selected.elementId === row.element.id && selected.columnIndex === i;
|
|
390
|
+
const clickable = onCellClick && cell.fact !== null;
|
|
391
|
+
const numStyle = {
|
|
392
|
+
...styles2.numCell,
|
|
393
|
+
fontWeight: row.isSubtotal ? 600 : 400,
|
|
394
|
+
borderBottom: isGrandTotal ? "3px double var(--rs-text, #111827)" : void 0,
|
|
395
|
+
cursor: clickable ? "pointer" : "default",
|
|
396
|
+
backgroundColor: isSelected ? "var(--rs-selected-bg, #dbeafe)" : void 0,
|
|
397
|
+
color: !row.isSubtotal && (cell.value === null || cell.value === 0) ? "var(--rs-muted, #9ca3af)" : void 0
|
|
398
|
+
};
|
|
399
|
+
return /* @__PURE__ */ jsx(
|
|
400
|
+
"td",
|
|
401
|
+
{
|
|
402
|
+
style: numStyle,
|
|
403
|
+
onClick: clickable ? () => onCellClick?.(row, i) : void 0,
|
|
404
|
+
children: formatMoney(cell.value, { currencySymbol })
|
|
405
|
+
},
|
|
406
|
+
columns[i].key
|
|
407
|
+
);
|
|
408
|
+
})
|
|
409
|
+
] }, row.element.id);
|
|
410
|
+
}) })
|
|
411
|
+
] })
|
|
412
|
+
] });
|
|
413
|
+
}
|
|
414
|
+
var styles3 = {
|
|
415
|
+
layout: {
|
|
416
|
+
display: "grid",
|
|
417
|
+
gridTemplateColumns: "minmax(0, 1fr)",
|
|
418
|
+
gap: "1.5rem",
|
|
419
|
+
alignItems: "start"
|
|
420
|
+
},
|
|
421
|
+
layoutWithPanel: {
|
|
422
|
+
gridTemplateColumns: "minmax(0, 1fr) 340px"
|
|
423
|
+
},
|
|
424
|
+
entity: {
|
|
425
|
+
fontFamily: "var(--rs-font-heading, var(--rs-font-sans, sans-serif))",
|
|
426
|
+
textAlign: "center",
|
|
427
|
+
marginBottom: "1.5rem"
|
|
428
|
+
},
|
|
429
|
+
entityName: {
|
|
430
|
+
fontSize: "1.5rem",
|
|
431
|
+
fontWeight: 700,
|
|
432
|
+
margin: 0,
|
|
433
|
+
color: "var(--rs-text, #111827)"
|
|
434
|
+
},
|
|
435
|
+
entitySub: { fontSize: "0.85rem", color: "var(--rs-muted, #6b7280)" },
|
|
436
|
+
panel: { position: "sticky", top: "1rem" }
|
|
437
|
+
};
|
|
438
|
+
function ReportView({ report, currencySymbol = "$", inspect = true }) {
|
|
439
|
+
const statements = useMemo(() => buildStatements(report), [report]);
|
|
440
|
+
const [selection, setSelection] = useState(null);
|
|
441
|
+
const selected = selection !== null ? statements[selection.statementIndex] : null;
|
|
442
|
+
const selectedRow = selected?.rows.find((r) => r.element.id === selection?.elementId) ?? null;
|
|
443
|
+
return /* @__PURE__ */ jsxs("div", { children: [
|
|
444
|
+
report.entity ? /* @__PURE__ */ jsxs("header", { style: styles3.entity, children: [
|
|
445
|
+
/* @__PURE__ */ jsx("h2", { style: styles3.entityName, children: report.entity.name }),
|
|
446
|
+
report.entity.country ? /* @__PURE__ */ jsx("div", { style: styles3.entitySub, children: report.entity.country }) : null
|
|
447
|
+
] }) : null,
|
|
448
|
+
/* @__PURE__ */ jsxs(
|
|
449
|
+
"div",
|
|
450
|
+
{
|
|
451
|
+
style: {
|
|
452
|
+
...styles3.layout,
|
|
453
|
+
...inspect && selectedRow ? styles3.layoutWithPanel : {}
|
|
454
|
+
},
|
|
455
|
+
children: [
|
|
456
|
+
/* @__PURE__ */ jsx("div", { children: statements.map((statement, statementIndex) => /* @__PURE__ */ jsx(
|
|
457
|
+
StatementTable,
|
|
458
|
+
{
|
|
459
|
+
statement,
|
|
460
|
+
currencySymbol,
|
|
461
|
+
selected: selection && selection.statementIndex === statementIndex ? {
|
|
462
|
+
elementId: selection.elementId,
|
|
463
|
+
columnIndex: selection.columnIndex
|
|
464
|
+
} : null,
|
|
465
|
+
onCellClick: inspect ? (row, columnIndex) => setSelection({
|
|
466
|
+
statementIndex,
|
|
467
|
+
elementId: row.element.id,
|
|
468
|
+
columnIndex
|
|
469
|
+
}) : void 0
|
|
470
|
+
},
|
|
471
|
+
statement.ib.id
|
|
472
|
+
)) }),
|
|
473
|
+
inspect && selected && selectedRow && selection ? /* @__PURE__ */ jsx("div", { style: styles3.panel, children: /* @__PURE__ */ jsx(
|
|
474
|
+
FactInspector,
|
|
475
|
+
{
|
|
476
|
+
report,
|
|
477
|
+
statement: selected,
|
|
478
|
+
row: selectedRow,
|
|
479
|
+
columnIndex: selection.columnIndex,
|
|
480
|
+
currencySymbol,
|
|
481
|
+
onClose: () => setSelection(null)
|
|
482
|
+
}
|
|
483
|
+
) }) : null
|
|
484
|
+
]
|
|
485
|
+
}
|
|
486
|
+
)
|
|
487
|
+
] });
|
|
488
|
+
}
|
|
489
|
+
|
|
490
|
+
export { FactInspector, ReportView, StatementTable, buildStatements, calcSubtotals, footCheck, formatDate, formatMoney, formatPeriod, presentationOrder };
|
|
491
|
+
//# sourceMappingURL=index.js.map
|
|
24
492
|
//# sourceMappingURL=index.js.map
|