@cosmicdrift/kumiko-headless 0.231.0 → 0.233.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-headless",
3
- "version": "0.231.0",
3
+ "version": "0.233.0",
4
4
  "description": "Headless UI logic for Kumiko — Dispatcher contract, Form-Controller, View-Model, Nav-Resolver. Plattform- und React-frei; jeder Renderer (renderer, renderer-web, renderer-native, …) komponiert darauf.",
5
5
  "license": "BUSL-1.1",
6
6
  "author": "Marc Frost <marc@cosmicdriftgamestudio.com>",
@@ -36,7 +36,7 @@
36
36
  }
37
37
  },
38
38
  "dependencies": {
39
- "@cosmicdrift/kumiko-framework": "0.231.0",
39
+ "@cosmicdrift/kumiko-framework": "0.233.0",
40
40
  "temporal-polyfill": "^0.3.2",
41
41
  "zod": "^4.4.3"
42
42
  },
@@ -121,6 +121,17 @@ describe("applyFormatSpec — unit (fw#2187)", () => {
121
121
  );
122
122
  });
123
123
 
124
+ test("mi (Meilen) geht über Intl.NumberFormat(style:'unit') genau wie km", () => {
125
+ expect(applyFormatSpec({ format: "unit", unit: "mi" }, 58)).toBe(
126
+ new Intl.NumberFormat(undefined, {
127
+ style: "unit",
128
+ unit: "mile",
129
+ unitDisplay: "short",
130
+ }).format(58),
131
+ );
132
+ expect(applyFormatSpec({ format: "unit", unit: "mi", locale: "en-US" }, 12)).toBe("12 mi");
133
+ });
134
+
124
135
  test("m2 hat kein ECMA-402-sanktioniertes Intl-Unit (RangeError für 'square-meter') — Zahl + literales Suffix", () => {
125
136
  expect(applyFormatSpec({ format: "unit", unit: "m2", locale: "de-DE" }, 58)).toBe("58 m²");
126
137
  expect(applyFormatSpec({ format: "unit", unit: "m2", locale: "de-DE" }, 1234.5)).toBe(
@@ -201,7 +212,7 @@ describe("applyFormatSpec — enumOption (fw#2315)", () => {
201
212
  describe("unit format keys stay in lockstep with UnitKey", () => {
202
213
  // Mirror of packages/types/src/screen.ts UnitKey — keep lists equal without
203
214
  // adding a kumiko-types dependency to headless.
204
- const TYPE_UNIT_KEYS = ["m2", "km", "m", "kg", "percent"] as const;
215
+ const TYPE_UNIT_KEYS = ["m2", "km", "m", "kg", "percent", "mi"] as const;
205
216
  test("every UnitKey formats with a non-bare number", () => {
206
217
  for (const k of TYPE_UNIT_KEYS) {
207
218
  expect(UNIT_FORMAT_KEYS.includes(k)).toBe(true);
@@ -90,6 +90,7 @@ const UNIT_INTL_IDS = {
90
90
  m: "meter",
91
91
  kg: "kilogram",
92
92
  percent: "percent",
93
+ mi: "mile",
93
94
  } as const;
94
95
 
95
96
  // "m2" (square meter) has no ECMA-402 sanctioned unit — Intl.NumberFormat
@@ -316,6 +316,7 @@ export function computeEditViewModel<
316
316
  // per row — one value for the whole embedded list.
317
317
  ...(embeddedListDef !== undefined && { embeddedListCurrency: resolvedCurrency }),
318
318
  ...(fieldDef.type === "money" && { currency: resolvedCurrency }),
319
+ ...(fieldDef.type === "number" && fieldDef.unit !== undefined && { unit: fieldDef.unit }),
319
320
  };
320
321
  return view;
321
322
  });
@@ -234,6 +234,10 @@ export type EditFieldViewModel = {
234
234
  * falls back to "EUR"). The renderer needs this to build the payload's
235
235
  * `{amount, currency}` shape (kumiko-framework#1923). */
236
236
  readonly currency?: string;
237
+ /** Only set for `type: "number"` when NumberFieldDef.unit is set — a static
238
+ * suffix string, or a sibling-field reference the renderer resolves against
239
+ * the live row values. Display-only, never converts the stored number. */
240
+ readonly unit?: string | { readonly field: string };
237
241
  };
238
242
 
239
243
  // Discriminated by `kind` — mirrors EditSectionSpec on the engine side.