@cosmicdrift/kumiko-renderer 0.361.0 → 0.362.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/dist/app/header-actions.js +7 -7
- package/dist/app/kumiko-screen.js +10 -3
- package/package.json +5 -5
- package/src/changes.json +12 -0
|
@@ -9,19 +9,19 @@ export function primaryHeaderAction(actions, preferredId) {
|
|
|
9
9
|
actions.find((a) => a.style === "primary") ??
|
|
10
10
|
actions[0]);
|
|
11
11
|
}
|
|
12
|
-
//
|
|
13
|
-
//
|
|
12
|
+
// The undeclared fallback picks an action nobody chose for the header, so a
|
|
13
|
+
// destructive or confirm-gated one (a bare "x" reads as "close") may not stand alone.
|
|
14
14
|
function canStandAsIconButton(action) {
|
|
15
15
|
return action?.icon !== undefined && action.style !== "danger" && !needsActionConfirm(action);
|
|
16
16
|
}
|
|
17
|
-
// A declared, visible `primaryAction` is always the phone header's button
|
|
18
|
-
//
|
|
19
|
-
// and `edit` moves into the menu. Without one the
|
|
20
|
-
// stays visible, falling back to the precedence-only primary.
|
|
17
|
+
// A declared, visible `primaryAction` is always the phone header's button, icon
|
|
18
|
+
// only when it has an icon (the author chose the icon, the label is its aria-label),
|
|
19
|
+
// so it matches the desktop header and `edit` moves into the menu. Without one the
|
|
20
|
+
// pencil-style icon action stays visible, falling back to the precedence-only primary.
|
|
21
21
|
export function compactHeaderPrimary(actions, preferredId) {
|
|
22
22
|
const declared = preferredId !== undefined ? actions.find((a) => a.id === preferredId) : undefined;
|
|
23
23
|
if (declared !== undefined)
|
|
24
|
-
return { action: declared, iconOnly:
|
|
24
|
+
return { action: declared, iconOnly: declared.icon !== undefined };
|
|
25
25
|
const iconAction = primaryHeaderAction(actions);
|
|
26
26
|
return canStandAsIconButton(iconAction) ? { action: iconAction, iconOnly: true } : undefined;
|
|
27
27
|
}
|
|
@@ -254,6 +254,11 @@ export function buildInitialValues(fields, defaultCurrency, moneyCurrencyOverrid
|
|
|
254
254
|
out[name] = shape.default;
|
|
255
255
|
continue;
|
|
256
256
|
}
|
|
257
|
+
// An untouched optional number must not persist as a deliberate 0.
|
|
258
|
+
if (shape.type === "number" && shape.required !== true) {
|
|
259
|
+
out[name] = undefined;
|
|
260
|
+
continue;
|
|
261
|
+
}
|
|
257
262
|
if (shape.type === "embedded" && shape.multiple === true) {
|
|
258
263
|
out[name] = [];
|
|
259
264
|
continue;
|
|
@@ -1161,7 +1166,8 @@ function EntityListScreen({ schema, screen, translate, onRowClick, }) {
|
|
|
1161
1166
|
function EntityListBody({ schema, screen, entity, translate, onRowClick, }) {
|
|
1162
1167
|
const isEmbeddedScreen = useIsEmbeddedScreen();
|
|
1163
1168
|
const featureName = schema.featureName;
|
|
1164
|
-
const
|
|
1169
|
+
const resolvedCreate = useNavigateToCreateFor(schema, screen.entity, screen.createScreen, screen.createUnavailable);
|
|
1170
|
+
const onCreate = screen.allowCreate === false ? undefined : resolvedCreate;
|
|
1165
1171
|
const { Banner } = usePrimitives();
|
|
1166
1172
|
const queryType = entityQueryCommand(featureName, screen.entity, "list");
|
|
1167
1173
|
const nav = useNav();
|
|
@@ -2559,8 +2565,9 @@ function mapFailedConfigCommandIssuesToField(error, failedIndex, commandFieldNam
|
|
|
2559
2565
|
},
|
|
2560
2566
|
};
|
|
2561
2567
|
}
|
|
2562
|
-
// A
|
|
2563
|
-
// maps it to 0, which a save would persist as a deliberate "0" override
|
|
2568
|
+
// A money field without a declared default starts empty too (buildInitialValues
|
|
2569
|
+
// maps it to 0, which a save would persist as a deliberate "0" override); numbers
|
|
2570
|
+
// are handled there, except a required one, which config fields never are.
|
|
2564
2571
|
function buildConfigEditDefaults(fields) {
|
|
2565
2572
|
const defaults = buildInitialValues(fields); // @cast-boundary render-helper
|
|
2566
2573
|
for (const [shortName, fieldDef] of Object.entries(fields)) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cosmicdrift/kumiko-renderer",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.362.0",
|
|
4
4
|
"description": "Platform-agnostic React renderer for Kumiko screens. Contains the shared logic — primitives-contract, hooks, KumikoScreen, navigation & SSE abstractions — that any platform-specific renderer (web, native) composes. No DOM, no EventSource, no react-dom.",
|
|
5
5
|
"license": "BUSL-1.1",
|
|
6
6
|
"author": "Marc Frost <marc@cosmicdriftgamestudio.com>",
|
|
@@ -15,9 +15,9 @@
|
|
|
15
15
|
}
|
|
16
16
|
},
|
|
17
17
|
"dependencies": {
|
|
18
|
-
"@cosmicdrift/kumiko-framework": "0.
|
|
19
|
-
"@cosmicdrift/kumiko-headless": "0.
|
|
20
|
-
"@cosmicdrift/kumiko-types": "0.
|
|
18
|
+
"@cosmicdrift/kumiko-framework": "0.362.0",
|
|
19
|
+
"@cosmicdrift/kumiko-headless": "0.362.0",
|
|
20
|
+
"@cosmicdrift/kumiko-types": "0.362.0",
|
|
21
21
|
"react": "^19.2.6",
|
|
22
22
|
"temporal-polyfill": "^0.3.2",
|
|
23
23
|
"zod": "^4.4.3"
|
|
@@ -28,7 +28,7 @@
|
|
|
28
28
|
"@types/react-dom": "^19.2.3",
|
|
29
29
|
"jsdom": "^29.1.1",
|
|
30
30
|
"react-dom": "^19.2.6",
|
|
31
|
-
"@cosmicdrift/kumiko-locale-de": "0.
|
|
31
|
+
"@cosmicdrift/kumiko-locale-de": "0.362.0"
|
|
32
32
|
},
|
|
33
33
|
"repository": {
|
|
34
34
|
"type": "git",
|
package/src/changes.json
CHANGED
|
@@ -1,4 +1,16 @@
|
|
|
1
1
|
[
|
|
2
|
+
{
|
|
3
|
+
"version": "0.362.0",
|
|
4
|
+
"type": "improvement",
|
|
5
|
+
"title": "entityList honours allowCreate false",
|
|
6
|
+
"detail": "EntityListBody passes no onCreate when the list sets allowCreate false."
|
|
7
|
+
},
|
|
8
|
+
{
|
|
9
|
+
"version": "0.362.0",
|
|
10
|
+
"type": "fix",
|
|
11
|
+
"title": "A declared primaryAction with an icon is icon-only in the phone header",
|
|
12
|
+
"detail": "Regardless of confirm or style; the label is the button's aria-label and title. Without an icon it stays a text button. The ui-walkthrough terminate sample uses the circle-stop icon, since a bare x reads as close."
|
|
13
|
+
},
|
|
2
14
|
{
|
|
3
15
|
"version": "0.361.0",
|
|
4
16
|
"type": "improvement",
|