@cosmicdrift/kumiko-renderer-web 0.163.2 → 0.164.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cosmicdrift/kumiko-renderer-web",
3
- "version": "0.163.2",
3
+ "version": "0.164.0",
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.163.2",
20
- "@cosmicdrift/kumiko-headless": "0.163.2",
21
- "@cosmicdrift/kumiko-renderer": "0.163.2",
19
+ "@cosmicdrift/kumiko-dispatcher-live": "0.164.0",
20
+ "@cosmicdrift/kumiko-headless": "0.164.0",
21
+ "@cosmicdrift/kumiko-renderer": "0.164.0",
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",
@@ -164,4 +164,19 @@ describe("defaultCellRender", () => {
164
164
  expect(defaultCellRender("hallo", "text")).toBe("hallo");
165
165
  expect(defaultCellRender(42, "number")).toBe("42");
166
166
  });
167
+
168
+ test("money → { amount, currency } formatiert, kein [object Object]", () => {
169
+ const result = defaultCellRender({ amount: 45000, currency: "EUR" }, "money");
170
+ expect(result).not.toBe("[object Object]");
171
+ expect(result.replace(/[^0-9]/g, "")).toBe("45000");
172
+ });
173
+
174
+ test("money → JPY ohne Nachkommastellen (currencyDecimals)", () => {
175
+ const result = defaultCellRender({ amount: 1000, currency: "JPY" }, "money");
176
+ expect(result.replace(/[^0-9]/g, "")).toBe("1000");
177
+ });
178
+
179
+ test("money → unerwarteter Value-Shape fällt auf String zurück", () => {
180
+ expect(defaultCellRender(45000, "money")).toBe("45000");
181
+ });
167
182
  });
@@ -79,7 +79,7 @@ import {
79
79
  import { FileUploadInput } from "./file-upload";
80
80
  import { DefaultLightbox } from "./lightbox";
81
81
  import { LocatedTimestampInput } from "./located-timestamp-input";
82
- import { MoneyInput } from "./money-input";
82
+ import { currencyDecimals, MoneyInput } from "./money-input";
83
83
  import { TimestampInput } from "./timestamp-input";
84
84
  import { useToast } from "./toast";
85
85
 
@@ -1256,6 +1256,15 @@ export function isComponentRendererRef(renderer: unknown): { readonly name: stri
1256
1256
  // applyFormatSpec re-exported from headless (platform-agnostic).
1257
1257
  export { applyFormatSpec };
1258
1258
 
1259
+ function isMoneyValue(value: unknown): value is { amount: number; currency: string } {
1260
+ return (
1261
+ typeof value === "object" &&
1262
+ value !== null &&
1263
+ typeof (value as Record<string, unknown>)["amount"] === "number" &&
1264
+ typeof (value as Record<string, unknown>)["currency"] === "string"
1265
+ );
1266
+ }
1267
+
1259
1268
  // Type-spezifische Default-Cell-Renderer. Author kann pro Spalte einen
1260
1269
  // expliziten renderer setzen (FormatSpec oder PlatformComponent); ohne
1261
1270
  // expliziten renderer fällt DataTableCell hier durch.
@@ -1263,6 +1272,7 @@ export { applyFormatSpec };
1263
1272
  // - boolean → ✓ / leer
1264
1273
  // - timestamp/date → locale-formatiert (kein roher ISO-String)
1265
1274
  // - select → human-lesbar (kebab-case → Title Case)
1275
+ // - money → { amount, currency } formatted via Intl (not "[object Object]")
1266
1276
  // - text/number/sonst → toString
1267
1277
  export function defaultCellRender(
1268
1278
  value: unknown,
@@ -1272,6 +1282,16 @@ export function defaultCellRender(
1272
1282
  if (value === null || value === undefined || value === "") return "";
1273
1283
  if (type === "boolean") return value === true ? "✓" : "";
1274
1284
  if (type === "timestamp" || type === "date") return applyFormatSpec({ format: type }, value);
1285
+ if (type === "money") {
1286
+ if (!isMoneyValue(value)) return String(value);
1287
+ const decimals = currencyDecimals(value.currency);
1288
+ return new Intl.NumberFormat(undefined, {
1289
+ style: "currency",
1290
+ currency: value.currency,
1291
+ minimumFractionDigits: decimals,
1292
+ maximumFractionDigits: decimals,
1293
+ }).format(value.amount / 10 ** decimals);
1294
+ }
1275
1295
  if (type === "select") {
1276
1296
  const raw = String(value);
1277
1297
  // Translated Label aus dem ViewModel-Builder (Convention-Key