@cosmicdrift/kumiko-headless 0.225.0 → 0.226.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.
|
|
3
|
+
"version": "0.226.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.
|
|
39
|
+
"@cosmicdrift/kumiko-framework": "0.226.0",
|
|
40
40
|
"temporal-polyfill": "^0.3.2",
|
|
41
41
|
"zod": "^4.4.3"
|
|
42
42
|
},
|
|
@@ -14,6 +14,8 @@ const taskEntity = {
|
|
|
14
14
|
title: { type: "text", required: true, sortable: true },
|
|
15
15
|
done: { type: "boolean" },
|
|
16
16
|
priority: { type: "number", sortable: true },
|
|
17
|
+
role: { type: "select", options: ["admin", "member"] },
|
|
18
|
+
labels: { type: "multiSelect", options: ["urgent", "low-priority"] },
|
|
17
19
|
},
|
|
18
20
|
derivedFields: {
|
|
19
21
|
// Read-time computed (value appended by the list-query handler). The
|
|
@@ -232,6 +234,36 @@ describe("computeListViewModel", () => {
|
|
|
232
234
|
expect(vm.columns[0]?.renderer).toEqual(fmt);
|
|
233
235
|
});
|
|
234
236
|
|
|
237
|
+
test("select field column includes translated optionLabels", () => {
|
|
238
|
+
const vm = computeListViewModel({
|
|
239
|
+
screen: listScreen(["role"]),
|
|
240
|
+
entity: taskEntity,
|
|
241
|
+
rows: [],
|
|
242
|
+
translate: (key) => (key === "tasks:entity:task:field:role:option:admin" ? "Admin" : key),
|
|
243
|
+
featureName: "tasks",
|
|
244
|
+
});
|
|
245
|
+
|
|
246
|
+
expect(vm.columns[0]?.optionLabels).toEqual({
|
|
247
|
+
admin: "Admin",
|
|
248
|
+
member: "member",
|
|
249
|
+
});
|
|
250
|
+
});
|
|
251
|
+
|
|
252
|
+
test("multiSelect field column includes translated optionLabels (fw#2491)", () => {
|
|
253
|
+
const vm = computeListViewModel({
|
|
254
|
+
screen: listScreen(["labels"]),
|
|
255
|
+
entity: taskEntity,
|
|
256
|
+
rows: [],
|
|
257
|
+
translate: (key) => (key === "tasks:entity:task:field:labels:option:urgent" ? "Urgent" : key),
|
|
258
|
+
featureName: "tasks",
|
|
259
|
+
});
|
|
260
|
+
|
|
261
|
+
expect(vm.columns[0]?.optionLabels).toEqual({
|
|
262
|
+
urgent: "Urgent",
|
|
263
|
+
"low-priority": "low-priority",
|
|
264
|
+
});
|
|
265
|
+
});
|
|
266
|
+
|
|
235
267
|
test("slots pass through unchanged for the renderer to mount", () => {
|
|
236
268
|
const slots = { header: { react: { component: "HeaderRef" } } };
|
|
237
269
|
const vm = computeListViewModel({
|
package/src/view-model/list.ts
CHANGED
|
@@ -95,12 +95,12 @@ export function computeListViewModel(input: ComputeListViewModelInput): ListView
|
|
|
95
95
|
fieldDef.type === "reference"
|
|
96
96
|
? ((fieldDef as unknown as { labelField?: string }).labelField ?? "id")
|
|
97
97
|
: undefined;
|
|
98
|
-
//
|
|
99
|
-
//
|
|
100
|
-
//
|
|
101
|
-
//
|
|
98
|
+
// For select and multiSelect fields: bake in translated option labels.
|
|
99
|
+
// Convention matches the form path → one translation source for list +
|
|
100
|
+
// form. A missing key returns the key itself per convention; the
|
|
101
|
+
// renderer then falls back to humanizeSlug.
|
|
102
102
|
const optionLabels =
|
|
103
|
-
fieldDef.type === "select"
|
|
103
|
+
fieldDef.type === "select" || fieldDef.type === "multiSelect"
|
|
104
104
|
? buildOptionLabels(
|
|
105
105
|
translate,
|
|
106
106
|
(value) => fieldOptionLabelKey(featureName, screen.entity, normalized.field, value),
|
package/src/view-model/types.ts
CHANGED
|
@@ -43,9 +43,10 @@ export type ListColumnViewModel = {
|
|
|
43
43
|
readonly type: string; // field-type ("text", "number", "money", ...)
|
|
44
44
|
readonly renderer?: FieldRenderer | RuntimeRenderer;
|
|
45
45
|
readonly sortable: boolean;
|
|
46
|
-
/**
|
|
47
|
-
* value.
|
|
48
|
-
*
|
|
46
|
+
/** Only for `type: "select"` or `type: "multiSelect"` — translated option
|
|
47
|
+
* labels keyed by raw value. The renderer renders `optionLabels[value]`
|
|
48
|
+
* instead of humanizeSlug when present. Convention key:
|
|
49
|
+
* `<feature>:entity:<entity>:field:<field>:option:<value>`. */
|
|
49
50
|
readonly optionLabels?: Readonly<Record<string, string>>;
|
|
50
51
|
/** Nur bei `type: "reference"` — referenced Entity-Name für Bulk-
|
|
51
52
|
* Lookup im Renderer (`<refFeature>:query:<refEntity>:list`). */
|