@cosmicdrift/kumiko-renderer 0.315.0 → 0.316.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",
3
- "version": "0.315.0",
3
+ "version": "0.316.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.315.0",
19
- "@cosmicdrift/kumiko-headless": "0.315.0",
20
- "@cosmicdrift/kumiko-types": "0.315.0",
18
+ "@cosmicdrift/kumiko-framework": "0.316.0",
19
+ "@cosmicdrift/kumiko-headless": "0.316.0",
20
+ "@cosmicdrift/kumiko-types": "0.316.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.315.0"
31
+ "@cosmicdrift/kumiko-locale-de": "0.316.0"
32
32
  },
33
33
  "repository": {
34
34
  "type": "git",
package/src/changes.json CHANGED
@@ -1,4 +1,11 @@
1
1
  [
2
+ {
3
+ "version": "0.316.0",
4
+ "type": "fix",
5
+ "title": "An app footer-slot action can opt into the wizard's sticky primary group",
6
+ "detail": "fw#1918 pinned the primary action into a sticky footer on mobile by checking\neach form-action element's `type === \"submit\"` prop. An app's\n`screen.slots.footer` renders through EditSlotMount, which never carries\n`type=\"submit\"` (its button is opaque app code), so that slot always landed\nin the non-sticky secondary group even on a wizard's last step — regressing\napps like offlot-app whose wizard-final \"Publish\" action lives in the footer\nslot. `ScreenSlots.footerPrimary?: boolean` now marks that slot as the\nsticky-primary action; `FormFooter` in kumiko-renderer-web recognizes it via\nthe shared `STICKY_PRIMARY_ACTION_PROP` marker exported from kumiko-renderer.\nBuilt-in submit buttons are unaffected.",
7
+ "migration": "Additive — no action needed unless a footer-slot action must become the\nsticky primary action on mobile. Set `slots.footerPrimary: true` next to\nthat screen's `slots.footer` registration to opt in."
8
+ },
2
9
  {
3
10
  "version": "0.310.0",
4
11
  "type": "improvement",
@@ -37,7 +37,12 @@ import { useDraftStorage } from "../context/draft-storage-context";
37
37
  import { formatWhen } from "../format-when";
38
38
  import { useForm } from "../hooks/use-form";
39
39
  import { useTranslation } from "../i18n";
40
- import { shouldRenderActionsIconOnly, usePrimitives } from "../primitives";
40
+ import {
41
+ STICKY_PRIMARY_ACTION_PROP,
42
+ type StickyPrimaryActionMarker,
43
+ shouldRenderActionsIconOnly,
44
+ usePrimitives,
45
+ } from "../primitives";
41
46
  import { GridCellForField } from "./grid-cell-for-field";
42
47
  import { RelatedListSection } from "./related-list-section";
43
48
  import {
@@ -253,7 +258,7 @@ function EditSlotMount({
253
258
  readonly values: Readonly<Record<string, unknown>>;
254
259
  readonly hasUnsavedChanges?: boolean;
255
260
  readonly wizardStep?: { readonly index: number; readonly isLast: boolean };
256
- }): ReactNode {
261
+ } & StickyPrimaryActionMarker): ReactNode {
257
262
  const name = extensionSectionName(slot);
258
263
  const Component = useExtensionSectionComponent(name);
259
264
  useEffect(() => {
@@ -1199,6 +1204,7 @@ export function RenderEdit<TValues extends FormValues, TCtx = unknown>(
1199
1204
  values={snapshot.values}
1200
1205
  hasUnsavedChanges={snapshot.isDirty || extensionDirty}
1201
1206
  wizardStep={isWizard ? { index: currentStep, isLast: isLastWizardStep } : undefined}
1207
+ {...(screen.slots?.footerPrimary === true && { [STICKY_PRIMARY_ACTION_PROP]: true })}
1202
1208
  />
1203
1209
  )}
1204
1210
  {isWizard && !isLastWizardStep && (
package/src/index.ts CHANGED
@@ -231,12 +231,14 @@ export type {
231
231
  StatusBadgeProps,
232
232
  StatusTone,
233
233
  StepBarProps,
234
+ StickyPrimaryActionMarker,
234
235
  TabsProps,
235
236
  TextProps,
236
237
  WizardStepGroupProps,
237
238
  } from "./primitives";
238
239
  export {
239
240
  PrimitivesProvider,
241
+ STICKY_PRIMARY_ACTION_PROP,
240
242
  shouldRenderActionsIconOnly,
241
243
  statusToneForValue,
242
244
  usePrimitives,
@@ -66,6 +66,15 @@ export type { RuntimeRenderer };
66
66
  * element; native impls ignore it (precedent: `className`). */
67
67
  export type DataAttributes = Readonly<Record<`data-${string}`, string>>;
68
68
 
69
+ /** Structural marker a top-level `actions` node can carry so DefaultForm's
70
+ * sticky-footer split (fw#1918) treats it as the pinned primary action even
71
+ * though it isn't a `Button` with `type="submit"` — e.g. RenderEdit's
72
+ * footer-slot mount, whose actual rendered button is opaque app code the
73
+ * split can't inspect (see `ScreenSlots.footerPrimary`). */
74
+ export const STICKY_PRIMARY_ACTION_PROP = "kumikoStickyPrimaryAction" as const;
75
+
76
+ export type StickyPrimaryActionMarker = Partial<Record<typeof STICKY_PRIMARY_ACTION_PROP, boolean>>;
77
+
69
78
  /** Standard-Button. `loading` zeigt einen Spinner statt der Children
70
79
  * und sollte mit `disabled` kombiniert werden, wenn die Action wirklich
71
80
  * blockiert bis das Loading durch ist (z.B. async submit). Native-