@cosmicdrift/kumiko-renderer-web 0.156.1 → 0.156.3
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/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cosmicdrift/kumiko-renderer-web",
|
|
3
|
-
"version": "0.156.
|
|
3
|
+
"version": "0.156.3",
|
|
4
4
|
"description": "Web-platform bindings for @cosmicdrift/kumiko-renderer. HTML default-primitives, browser history-based navigation, EventSource-backed live events, and a one-call createKumikoApp that mounts the whole stack via react-dom.",
|
|
5
5
|
"license": "BUSL-1.1",
|
|
6
6
|
"author": "Marc Frost <marc@cosmicdriftgamestudio.com>",
|
|
@@ -16,9 +16,9 @@
|
|
|
16
16
|
"./styles.css": "./src/styles.css"
|
|
17
17
|
},
|
|
18
18
|
"dependencies": {
|
|
19
|
-
"@cosmicdrift/kumiko-dispatcher-live": "0.156.
|
|
20
|
-
"@cosmicdrift/kumiko-headless": "0.156.
|
|
21
|
-
"@cosmicdrift/kumiko-renderer": "0.156.
|
|
19
|
+
"@cosmicdrift/kumiko-dispatcher-live": "0.156.3",
|
|
20
|
+
"@cosmicdrift/kumiko-headless": "0.156.3",
|
|
21
|
+
"@cosmicdrift/kumiko-renderer": "0.156.3",
|
|
22
22
|
"@radix-ui/react-dialog": "^1.1.15",
|
|
23
23
|
"@radix-ui/react-dropdown-menu": "^2.1.16",
|
|
24
24
|
"@radix-ui/react-label": "^2.1.8",
|
|
@@ -32,6 +32,29 @@ describe("ResultTable", () => {
|
|
|
32
32
|
expect(container.querySelector(".rounded-lg.border.bg-card")).toBeNull();
|
|
33
33
|
expect(container.querySelector("thead.bg-muted")).toBeNull();
|
|
34
34
|
});
|
|
35
|
+
|
|
36
|
+
test("footer rows render as table rows spanning all-but-last column, value under the last column", () => {
|
|
37
|
+
const { container } = render(
|
|
38
|
+
<ResultTable
|
|
39
|
+
columns={COLUMNS}
|
|
40
|
+
rows={ROWS}
|
|
41
|
+
rowKey={(r) => String(r.year)}
|
|
42
|
+
testId="rt"
|
|
43
|
+
footer={[
|
|
44
|
+
{ label: "Subtotal", value: "300" },
|
|
45
|
+
{ label: "Total", value: "300", emphasize: true },
|
|
46
|
+
]}
|
|
47
|
+
/>,
|
|
48
|
+
);
|
|
49
|
+
const footerRows = container.querySelectorAll("tbody tr");
|
|
50
|
+
// 2 data rows + 2 footer rows.
|
|
51
|
+
expect(footerRows).toHaveLength(4);
|
|
52
|
+
const totalRow = footerRows[3];
|
|
53
|
+
expect(totalRow?.querySelector("td[colspan]")?.textContent).toBe("Total");
|
|
54
|
+
expect(totalRow?.querySelectorAll("td")[1]?.textContent).toBe("300");
|
|
55
|
+
expect(totalRow?.className).toContain("font-semibold");
|
|
56
|
+
expect(screen.getByText("Subtotal")).toBeTruthy();
|
|
57
|
+
});
|
|
35
58
|
});
|
|
36
59
|
|
|
37
60
|
describe("ComparisonTable", () => {
|
|
@@ -54,6 +54,12 @@ export interface ResultColumn<Row> {
|
|
|
54
54
|
readonly cell: (row: Row) => ReactNode;
|
|
55
55
|
}
|
|
56
56
|
|
|
57
|
+
export interface ResultTableFooterRow {
|
|
58
|
+
readonly label: string;
|
|
59
|
+
readonly value: ReactNode;
|
|
60
|
+
readonly emphasize?: boolean;
|
|
61
|
+
}
|
|
62
|
+
|
|
57
63
|
/** Statische, prop-getriebene Ergebnistabelle für berechnete Zeilen (Tranchen,
|
|
58
64
|
* Szenarien). Nimmt dem Screen die `<table>`+tabular-nums-Ketten ab.
|
|
59
65
|
* ponytail: bewusst die minimale Read-only-Tabelle — für Sort/Pager/Facets
|
|
@@ -65,6 +71,7 @@ export function ResultTable<Row>({
|
|
|
65
71
|
testId,
|
|
66
72
|
className,
|
|
67
73
|
card,
|
|
74
|
+
footer,
|
|
68
75
|
}: {
|
|
69
76
|
readonly columns: readonly ResultColumn<Row>[];
|
|
70
77
|
readonly rows: readonly Row[];
|
|
@@ -74,6 +81,11 @@ export function ResultTable<Row>({
|
|
|
74
81
|
/** Rahmen-Look wie die CRUD-Liste (DataTable): gerundeter Border-Container +
|
|
75
82
|
* bg-muted-Header-Band. Default = bare (nur die Tabelle, ohne Container). */
|
|
76
83
|
readonly card?: boolean;
|
|
84
|
+
/** Summary rows (Subtotal/Tax/Total) rendered as real `<tr>`s in the same
|
|
85
|
+
* `<table>` instead of a separate flex-div next to it — guarantees
|
|
86
|
+
* column-alignment to the last (typically "Amount") column instead of
|
|
87
|
+
* approximating it with an independent layout. */
|
|
88
|
+
readonly footer?: readonly ResultTableFooterRow[];
|
|
77
89
|
}): ReactNode {
|
|
78
90
|
const table = (
|
|
79
91
|
<div className="overflow-x-auto">
|
|
@@ -111,6 +123,28 @@ export function ResultTable<Row>({
|
|
|
111
123
|
))}
|
|
112
124
|
</tr>
|
|
113
125
|
))}
|
|
126
|
+
{footer?.map((row, i) => (
|
|
127
|
+
<tr
|
|
128
|
+
key={row.label}
|
|
129
|
+
className={cn(i === 0 && "border-t", row.emphasize === true && "font-semibold")}
|
|
130
|
+
>
|
|
131
|
+
<td
|
|
132
|
+
colSpan={Math.max(columns.length - 1, 1)}
|
|
133
|
+
className={cn(
|
|
134
|
+
"py-1.5 text-muted-foreground",
|
|
135
|
+
card === true && "px-3",
|
|
136
|
+
row.emphasize === true && "text-foreground",
|
|
137
|
+
)}
|
|
138
|
+
>
|
|
139
|
+
{row.label}
|
|
140
|
+
</td>
|
|
141
|
+
{columns.length > 1 && (
|
|
142
|
+
<td className={cn("py-1.5 text-right tabular-nums", card === true && "px-3")}>
|
|
143
|
+
{row.value}
|
|
144
|
+
</td>
|
|
145
|
+
)}
|
|
146
|
+
</tr>
|
|
147
|
+
))}
|
|
114
148
|
</tbody>
|
|
115
149
|
</table>
|
|
116
150
|
</div>
|