@cosmicdrift/kumiko-headless 0.295.0 → 0.297.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.297.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.297.0",
|
|
40
40
|
"temporal-polyfill": "^0.3.2",
|
|
41
41
|
"zod": "^4.4.3"
|
|
42
42
|
},
|
|
@@ -119,6 +119,47 @@ describe("computeEditViewModel", () => {
|
|
|
119
119
|
expect(asFields(vm.sections[1]).columns).toBe(1);
|
|
120
120
|
});
|
|
121
121
|
|
|
122
|
+
// The two-column default came in with projectionDetail tabs and now also
|
|
123
|
+
// covers entityEdit tabs (fw#3134) — a tab is its own panel, where a stacked
|
|
124
|
+
// form's single column wastes the width.
|
|
125
|
+
test("a tabs layout defaults sections to 2 columns, not 1", () => {
|
|
126
|
+
const vm = computeEditViewModel({
|
|
127
|
+
screen: editScreen({
|
|
128
|
+
mode: "tabs",
|
|
129
|
+
sections: [
|
|
130
|
+
{ id: "main", title: "Main", fields: ["customerName"] },
|
|
131
|
+
{ id: "notes", title: "Notes", columns: 1, fields: ["notes"] },
|
|
132
|
+
],
|
|
133
|
+
}),
|
|
134
|
+
entity: orderEntity,
|
|
135
|
+
values: {},
|
|
136
|
+
translate,
|
|
137
|
+
featureName: "orders",
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
expect(asFields(vm.sections[0]).columns).toBe(2);
|
|
141
|
+
expect(asFields(vm.sections[1]).columns).toBe(1);
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
test("tabs sections carry their declared id into the view model", () => {
|
|
145
|
+
const vm = computeEditViewModel({
|
|
146
|
+
screen: editScreen({
|
|
147
|
+
mode: "tabs",
|
|
148
|
+
sections: [
|
|
149
|
+
{ id: "main", title: "Main", fields: ["customerName"] },
|
|
150
|
+
{ id: "notes", title: "Notes", fields: ["notes"] },
|
|
151
|
+
],
|
|
152
|
+
}),
|
|
153
|
+
entity: orderEntity,
|
|
154
|
+
values: {},
|
|
155
|
+
translate,
|
|
156
|
+
featureName: "orders",
|
|
157
|
+
});
|
|
158
|
+
|
|
159
|
+
expect(asFields(vm.sections[0]).id).toBe("main");
|
|
160
|
+
expect(asFields(vm.sections[1]).id).toBe("notes");
|
|
161
|
+
});
|
|
162
|
+
|
|
122
163
|
test("visible predicate evaluated against current values (live-reactive)", () => {
|
|
123
164
|
const screen = editScreen({
|
|
124
165
|
sections: [
|
package/src/view-model/edit.ts
CHANGED
|
@@ -149,6 +149,7 @@ export function computeEditViewModel<
|
|
|
149
149
|
if (isExtensionEditSection(sectionSpec)) {
|
|
150
150
|
return {
|
|
151
151
|
kind: "extension" as const,
|
|
152
|
+
...(sectionSpec.id !== undefined && { id: sectionSpec.id }),
|
|
152
153
|
title: translate(sectionSpec.title),
|
|
153
154
|
component: sectionSpec.component,
|
|
154
155
|
contributesToFormSubmit: sectionSpec.contributesToFormSubmit === true,
|
|
@@ -441,8 +442,9 @@ export function computeEditViewModel<
|
|
|
441
442
|
// Boot-validator rejects fields.length === 0 with no groups (screens.ts),
|
|
442
443
|
// so an empty section never reaches this code.
|
|
443
444
|
const visible = fields.some((field) => field.visible);
|
|
444
|
-
// Tabs mode renders this section as its own
|
|
445
|
-
// better than the single-column default a stacked form keeps.
|
|
445
|
+
// Tabs mode renders this section as its own panel, where two columns reads
|
|
446
|
+
// better than the single-column default a stacked form keeps. Applies to
|
|
447
|
+
// entityEdit tabs as well since fw#3134, not just projectionDetail.
|
|
446
448
|
const defaultColumns = screen.layout.mode === "tabs" ? 2 : 1;
|
|
447
449
|
const groups = sectionSpec.groups?.map((group) => ({
|
|
448
450
|
title: translate(group.title),
|
|
@@ -461,6 +463,7 @@ export function computeEditViewModel<
|
|
|
461
463
|
}));
|
|
462
464
|
return {
|
|
463
465
|
kind: "fields" as const,
|
|
466
|
+
...(sectionSpec.id !== undefined && { id: sectionSpec.id }),
|
|
464
467
|
visible,
|
|
465
468
|
// Titellose Section (flache Form) → kein h3; nur übersetzen wenn gesetzt.
|
|
466
469
|
...(sectionSpec.title !== undefined && { title: translate(sectionSpec.title) }),
|
package/src/view-model/types.ts
CHANGED
|
@@ -266,6 +266,10 @@ export type EditSectionViewModel =
|
|
|
266
266
|
|
|
267
267
|
export type EditFieldsSectionViewModel = {
|
|
268
268
|
readonly kind: "fields";
|
|
269
|
+
/** From `EditFieldsSection.id`. The boot-validator makes it mandatory under
|
|
270
|
+
* `layout.mode: "tabs"` so the tab strip has a stable key per tab; other
|
|
271
|
+
* layouts leave it unset. */
|
|
272
|
+
readonly id?: string;
|
|
269
273
|
/** False when the section has fields but none of them is visible.
|
|
270
274
|
* The renderer then draws nothing, but the section stays in the array
|
|
271
275
|
* (key stability). */
|
|
@@ -291,6 +295,9 @@ export type EditFieldsSectionViewModel = {
|
|
|
291
295
|
|
|
292
296
|
export type EditExtensionSectionViewModel = {
|
|
293
297
|
readonly kind: "extension";
|
|
298
|
+
/** From `EditExtensionSection.id` — same tab-strip role as on a "fields"
|
|
299
|
+
* section, see EditFieldsSectionViewModel.id. */
|
|
300
|
+
readonly id?: string;
|
|
294
301
|
readonly title: string;
|
|
295
302
|
readonly component: PlatformComponent;
|
|
296
303
|
readonly contributesToFormSubmit: boolean;
|