@cosmicdrift/kumiko-renderer 0.335.0 → 0.336.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.
@@ -57,9 +57,9 @@ export type ExtensionSectionProps = {
57
57
  };
58
58
  /** Only set for extension steps of a `layout.mode: "wizard"` entityEdit
59
59
  * editing an existing record (update mode); undefined everywhere else.
60
- * Call it (typically from an effect) with whether the step already holds
61
- * its data, so the step bar shows the step as done. Repeated calls with
62
- * the same value are cheap. */
60
+ * Report through `useReportStepComplete(reportStepComplete, complete)`
61
+ * (`null` while the step's data loads) with whether the step already holds
62
+ * its data, so the step bar shows the step as done. */
63
63
  readonly reportStepComplete?: (complete: boolean) => void;
64
64
  };
65
65
  export type ExtensionSectionComponent = ComponentType<ExtensionSectionProps>;
@@ -14,7 +14,7 @@ import { useForm } from "../hooks/use-form.js";
14
14
  import { useTranslation } from "../i18n.js";
15
15
  import { useInsideDrawer } from "../inside-drawer.js";
16
16
  import { usePageHeaderCompact, usePageHeaderSlotAvailable } from "../page-header-slot.js";
17
- import { STICKY_PRIMARY_ACTION_PROP, shouldRenderActionsIconOnly, usePrimitives, } from "../primitives.js";
17
+ import { FOOTER_ACTION_ROLE_PROP, NARROW_LABEL_PROP, STICKY_PRIMARY_ACTION_PROP, shouldRenderActionsIconOnly, usePrimitives, } from "../primitives.js";
18
18
  import { GridCellForField } from "./grid-cell-for-field.js";
19
19
  import { RelatedListSection } from "./related-list-section.js";
20
20
  import { filterEditSections, hasEditableSection, hasIssueWithoutRenderedField, resolveExtensionEntityId, shouldNotifyCaller, } from "./render-edit-logic.js";
@@ -1107,7 +1107,8 @@ export function RenderEdit(props) {
1107
1107
  ? 1
1108
1108
  : 0;
1109
1109
  const isSettingsList = screen.layout.variant === "settings-list" && hideSectionTitles !== true;
1110
- const formActions = (_jsxs(_Fragment, { children: [showWizardBack && (_jsx(Button, { type: "button", variant: "secondary", icon: "chevron-left", onClick: handleWizardBack, testId: "render-edit-wizard-back", children: translate("kumiko.actions.back") })), footerSlot !== undefined && (_jsx(EditSlotMount, { slot: footerSlot, slotName: "footer", screenId: screen.id, entityName: vm.entityName, entityId: resolveExtensionEntityId(entityIdProp, vm.id), values: snapshot.values, hasUnsavedChanges: hasUnsavedInput, wizardStep: isWizard ? { index: currentStep, isLast: isLastWizardStep } : undefined, ...(screen.slots?.footerPrimary === true && { [STICKY_PRIMARY_ACTION_PROP]: true }) })), isWizard && !isLastWizardStep && showsSubmit && !isCreateMode && (_jsx(Button, { type: "button", variant: "ghost", disabled: isSubmitting || disabled, onClick: () => void handleSubmit({ saveNow: true }), testId: "render-edit-wizard-save-close", [STICKY_PRIMARY_ACTION_PROP]: true, children: translate("kumiko.wizard.save-and-close") })), showWizardNext && (_jsx(Button, { type: "submit", variant: "primary", iconEnd: "chevron-right", testId: "render-edit-wizard-next", children: nextStepTitle !== undefined
1110
+ const formActions = (_jsxs(_Fragment, { children: [showWizardBack && (_jsx(Button, { type: "button", variant: "secondary", icon: "chevron-left", onClick: handleWizardBack, testId: "render-edit-wizard-back", [FOOTER_ACTION_ROLE_PROP]: "back", children: translate("kumiko.actions.back") })), footerSlot !== undefined && (_jsx(EditSlotMount, { slot: footerSlot, slotName: "footer", screenId: screen.id, entityName: vm.entityName, entityId: resolveExtensionEntityId(entityIdProp, vm.id), values: snapshot.values, hasUnsavedChanges: hasUnsavedInput, wizardStep: isWizard ? { index: currentStep, isLast: isLastWizardStep } : undefined, ...(screen.slots?.footerPrimary === true && { [STICKY_PRIMARY_ACTION_PROP]: true }) })), isWizard && !isLastWizardStep && showsSubmit && !isCreateMode && (_jsx(Button, { type: "button", variant: "ghost", disabled: isSubmitting || disabled, onClick: () => void handleSubmit({ saveNow: true }), testId: "render-edit-wizard-save-close", [STICKY_PRIMARY_ACTION_PROP]: true, children: translate("kumiko.wizard.save-and-close") })), showWizardNext && (_jsx(Button, { type: "submit", variant: "primary", iconEnd: "chevron-right", testId: "render-edit-wizard-next", [FOOTER_ACTION_ROLE_PROP]: "primary",
1111
+ [NARROW_LABEL_PROP]: translate("kumiko.actions.next"), children: nextStepTitle !== undefined
1111
1112
  ? translate("kumiko.wizard.next-with-title", { title: nextStepTitle })
1112
1113
  : translate("kumiko.actions.next") })), showSubmit &&
1113
1114
  footerActions?.map((action) => (_jsx(Button, { type: "button", variant: action.variant ?? "secondary", ...(action.icon !== undefined && { icon: action.icon }), disabled: isSubmitting || disabled, onClick: () => {
@@ -0,0 +1,2 @@
1
+ import type { ExtensionSectionProps } from "../app/extension-sections.js";
2
+ export declare function useReportStepComplete(reportStepComplete: ExtensionSectionProps["reportStepComplete"], complete: boolean | null): void;
@@ -0,0 +1,13 @@
1
+ import { useEffect } from "react";
2
+ // Lets an extension wizard step report whether it already holds its data
3
+ // without a raw useEffect in app code (the no-raw-hooks guard forbids those).
4
+ // `complete === null` means the step's data is still loading: nothing is
5
+ // reported, so a loading step never flashes "not done" over a passed-via-Next
6
+ // state. Outside update-mode wizards `reportStepComplete` is undefined and the
7
+ // hook does nothing.
8
+ export function useReportStepComplete(reportStepComplete, complete) {
9
+ useEffect(() => {
10
+ if (reportStepComplete !== undefined && complete !== null)
11
+ reportStepComplete(complete);
12
+ }, [reportStepComplete, complete]);
13
+ }
package/dist/index.d.ts CHANGED
@@ -61,6 +61,7 @@ export type { UseMutationResult } from "./hooks/use-mutation.js";
61
61
  export { useMutation } from "./hooks/use-mutation.js";
62
62
  export type { UseQueryOptions, UseQueryResult } from "./hooks/use-query.js";
63
63
  export { entityFromQueryType, useQuery } from "./hooks/use-query.js";
64
+ export { useReportStepComplete } from "./hooks/use-report-step-complete.js";
64
65
  export { useStore, useStoreSelector } from "./hooks/use-store.js";
65
66
  export type { StreamStatus, UseStreamHandlerOptions, UseStreamHandlerResult, } from "./hooks/use-stream-handler.js";
66
67
  export { useStreamHandler } from "./hooks/use-stream-handler.js";
@@ -69,8 +70,8 @@ export { createStaticLocaleResolver, FormalityProvider, LocaleProvider, mergeTra
69
70
  export { kumikoDefaultTranslations } from "./i18n-defaults.js";
70
71
  export { InsideDrawerProvider, useInsideDrawer } from "./inside-drawer.js";
71
72
  export { PageHeaderCompactProvider, PageHeaderSlotAvailableProvider, usePageHeaderCompact, usePageHeaderSlotAvailable, } from "./page-header-slot.js";
72
- export type { ActionMenuItemSpec, ActionOverflowMenuProps, AppPrimitives, BannerProps, ButtonProps, CardOptions, CardProps, CardSlots, CopyButtonProps, CorePrimitives, DataTableDateRangeFacet, DataTableFacet, DataTableFacetChip, DataTableProps, DataTableRowAction, DataTableRowActionMode, DataTableRowGrouping, DataTableSort, DataTableSortDir, DialogProps, DrawerProps, EmbeddedListCellType, EmbeddedListColumn, EmbeddedListInputProps, EmbeddedListTotal, FieldCellWidth, FieldProps, FillContainerProps, FormProps, FormSectionNavItem, FormWidth, GridCellProps, GridProps, HeadingProps, InputProps, JsonViewProps, LightboxProps, LinkProps, MetricBandProps, MetricProps, ModalProps, PageHeaderProps, PrimitivesProviderProps, PrimitivesRegistry, ProgressProps, ProgressTone, PromoPanelAction, PromoPanelProps, RuntimeRenderer, SecretRevealProps, SecretRevealValue, SectionProps, ShareButtonProps, StatusBadgeProps, StatusTone, StepBarProps, StickyActionBarProps, StickyPrimaryActionMarker, TabsProps, TextProps, TrailingInputAction, WizardStepGroupProps, } from "./primitives.js";
73
- export { PrimitivesProvider, STICKY_PRIMARY_ACTION_PROP, shouldRenderActionsIconOnly, statusToneForOptionTone, statusToneForValue, usePrimitives, } from "./primitives.js";
73
+ export type { ActionMenuItemSpec, ActionOverflowMenuProps, AppPrimitives, BannerProps, ButtonProps, CardOptions, CardProps, CardSlots, CopyButtonProps, CorePrimitives, DataTableDateRangeFacet, DataTableFacet, DataTableFacetChip, DataTableProps, DataTableRowAction, DataTableRowActionMode, DataTableRowGrouping, DataTableSort, DataTableSortDir, DialogProps, DrawerProps, EmbeddedListCellType, EmbeddedListColumn, EmbeddedListInputProps, EmbeddedListTotal, FieldCellWidth, FieldProps, FillContainerProps, FooterActionMarker, FooterActionRole, FormProps, FormSectionNavItem, FormWidth, GridCellProps, GridProps, HeadingProps, InputProps, JsonViewProps, LightboxProps, LinkProps, MetricBandProps, MetricProps, ModalProps, PageHeaderProps, PrimitivesProviderProps, PrimitivesRegistry, ProgressProps, ProgressTone, PromoPanelAction, PromoPanelProps, RuntimeRenderer, SecretRevealProps, SecretRevealValue, SectionProps, ShareButtonProps, StatusBadgeProps, StatusTone, StepBarProps, StickyActionBarProps, StickyPrimaryActionMarker, TabsProps, TextProps, TrailingInputAction, WizardStepGroupProps, } from "./primitives.js";
74
+ export { FOOTER_ACTION_ROLE_PROP, NARROW_LABEL_PROP, PrimitivesProvider, STICKY_PRIMARY_ACTION_PROP, shouldRenderActionsIconOnly, statusToneForOptionTone, statusToneForValue, usePrimitives, } from "./primitives.js";
74
75
  export type { SessionEndedSignal, SessionEndedSignalProviderProps, } from "./session/session-ended.js";
75
76
  export { createSessionEndedSignal, isSessionEndedError, SESSION_ENDED_ERROR_CODES, SessionEndedSignalProvider, useSessionEndedSignal, withSessionEndedDetection, } from "./session/session-ended.js";
76
77
  export { buildWhatsAppShareUrl } from "./share-links.js";
package/dist/index.js CHANGED
@@ -44,13 +44,14 @@ export { useForm } from "./hooks/use-form.js";
44
44
  export { useListUrlState } from "./hooks/use-list-url-state.js";
45
45
  export { useMutation } from "./hooks/use-mutation.js";
46
46
  export { entityFromQueryType, useQuery } from "./hooks/use-query.js";
47
+ export { useReportStepComplete } from "./hooks/use-report-step-complete.js";
47
48
  export { useStore, useStoreSelector } from "./hooks/use-store.js";
48
49
  export { useStreamHandler } from "./hooks/use-stream-handler.js";
49
50
  export { createStaticLocaleResolver, FormalityProvider, LocaleProvider, mergeTranslations, translationsByLocaleFromKeys, useFormality, useLocale, useOptionalLocale, useOptionalTranslation, useTranslation, } from "./i18n.js";
50
51
  export { kumikoDefaultTranslations } from "./i18n-defaults.js";
51
52
  export { InsideDrawerProvider, useInsideDrawer } from "./inside-drawer.js";
52
53
  export { PageHeaderCompactProvider, PageHeaderSlotAvailableProvider, usePageHeaderCompact, usePageHeaderSlotAvailable, } from "./page-header-slot.js";
53
- export { PrimitivesProvider, STICKY_PRIMARY_ACTION_PROP, shouldRenderActionsIconOnly, statusToneForOptionTone, statusToneForValue, usePrimitives, } from "./primitives.js";
54
+ export { FOOTER_ACTION_ROLE_PROP, NARROW_LABEL_PROP, PrimitivesProvider, STICKY_PRIMARY_ACTION_PROP, shouldRenderActionsIconOnly, statusToneForOptionTone, statusToneForValue, usePrimitives, } from "./primitives.js";
54
55
  export { createSessionEndedSignal, isSessionEndedError, SESSION_ENDED_ERROR_CODES, SessionEndedSignalProvider, useSessionEndedSignal, withSessionEndedDetection, } from "./session/session-ended.js";
55
56
  export { buildWhatsAppShareUrl } from "./share-links.js";
56
57
  export { sortByAccessor } from "./sort-by-accessor.js";
@@ -14,6 +14,16 @@ export type DataAttributes = Readonly<Record<`data-${string}`, string>>;
14
14
  * split can't inspect (see `ScreenSlots.footerPrimary`). */
15
15
  export declare const STICKY_PRIMARY_ACTION_PROP: "kumikoStickyPrimaryAction";
16
16
  export type StickyPrimaryActionMarker = Partial<Record<typeof STICKY_PRIMARY_ACTION_PROP, boolean>>;
17
+ export type FooterActionRole = "back" | "primary";
18
+ /** Tells the pinned phone footer which node is Back and which is the primary
19
+ * action, for buttons that are not `type="submit"` (e.g. the wizard Back). */
20
+ export declare const FOOTER_ACTION_ROLE_PROP: "kumikoFooterActionRole";
21
+ /** Short label a footer action uses instead of its children below `sm`. */
22
+ export declare const NARROW_LABEL_PROP: "kumikoNarrowLabel";
23
+ export type FooterActionMarker = {
24
+ readonly [FOOTER_ACTION_ROLE_PROP]?: FooterActionRole;
25
+ readonly [NARROW_LABEL_PROP]?: string;
26
+ };
17
27
  /** Standard-Button. `loading` zeigt einen Spinner statt der Children
18
28
  * und sollte mit `disabled` kombiniert werden, wenn die Action wirklich
19
29
  * blockiert bis das Loading durch ist (z.B. async submit). Native-
@@ -1157,7 +1167,9 @@ export type ProgressProps = {
1157
1167
  * buttons (every non-current step with `selectableSteps: "all"`); the caller
1158
1168
  * owns the validation gate for forward jumps. Implementations render a
1159
1169
  * narrow-viewport fallback showing `compactLabel` instead (caller
1160
- * supplies it pre-translated, e.g. "Step 2 of 5 · Industry") — which of
1170
+ * supplies it pre-translated, e.g. "Step 2 of 5 · Industry"). With
1171
+ * `onStepSelect` and `selectableSteps: "all"` that fallback is a dropdown
1172
+ * listing all steps so narrow viewports can jump too — which of
1161
1173
  * the two is visible is a responsive layout choice owned by the
1162
1174
  * implementation, not this contract. */
1163
1175
  export type StepBarProps = {
@@ -1169,7 +1181,8 @@ export type StepBarProps = {
1169
1181
  * index is below `currentIndex`. The current step is never done. */
1170
1182
  readonly doneSteps?: readonly boolean[];
1171
1183
  /** "done" (default): only done steps are jump targets. "all": every
1172
- * non-current step is, when `onStepSelect` is set. */
1184
+ * non-current step is, when `onStepSelect` is set; the compact label then
1185
+ * becomes a step picker. */
1173
1186
  readonly selectableSteps?: "done" | "all";
1174
1187
  /** "label" (default) swaps the step row for `compactLabel` on narrow
1175
1188
  * viewports; "steps" keeps the row there too — for short wizards whose
@@ -6,6 +6,11 @@ import { createContext, useContext, } from "react";
6
6
  * footer-slot mount, whose actual rendered button is opaque app code the
7
7
  * split can't inspect (see `ScreenSlots.footerPrimary`). */
8
8
  export const STICKY_PRIMARY_ACTION_PROP = "kumikoStickyPrimaryAction";
9
+ /** Tells the pinned phone footer which node is Back and which is the primary
10
+ * action, for buttons that are not `type="submit"` (e.g. the wizard Back). */
11
+ export const FOOTER_ACTION_ROLE_PROP = "kumikoFooterActionRole";
12
+ /** Short label a footer action uses instead of its children below `sm`. */
13
+ export const NARROW_LABEL_PROP = "kumikoNarrowLabel";
9
14
  /** Teil-C action-icon collapse rule: a group of more than two actions where
10
15
  * every member carries an icon renders icon-only instead of wall-to-wall
11
16
  * text buttons; any icon-less member keeps the whole group on text so it
@@ -4,8 +4,8 @@ export type LiveEvent = {
4
4
  readonly data: {
5
5
  readonly id: string;
6
6
  readonly aggregateType: string;
7
+ readonly eventType: string;
7
8
  readonly version: number;
8
- readonly payload: unknown;
9
9
  readonly createdAt: string;
10
10
  };
11
11
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cosmicdrift/kumiko-renderer",
3
- "version": "0.335.0",
3
+ "version": "0.336.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.335.0",
19
- "@cosmicdrift/kumiko-headless": "0.335.0",
20
- "@cosmicdrift/kumiko-types": "0.335.0",
18
+ "@cosmicdrift/kumiko-framework": "0.336.0",
19
+ "@cosmicdrift/kumiko-headless": "0.336.0",
20
+ "@cosmicdrift/kumiko-types": "0.336.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.335.0"
31
+ "@cosmicdrift/kumiko-locale-de": "0.336.0"
32
32
  },
33
33
  "repository": {
34
34
  "type": "git",
package/src/changes.json CHANGED
@@ -1,4 +1,18 @@
1
1
  [
2
+ {
3
+ "version": "0.336.0",
4
+ "type": "breaking",
5
+ "title": "LiveEvent data has no payload, it carries eventType",
6
+ "detail": "`LiveEvent.data` is now `{ id, aggregateType, eventType, version, createdAt }`. The server sends signals only, so consumers refetch through a query.",
7
+ "migration": "Replace reads of `event.data.payload` with a query refetch. `useQuery({ live: true })` already does this and needs no change."
8
+ },
9
+ {
10
+ "version": "0.336.0",
11
+ "type": "improvement",
12
+ "title": "useReportStepComplete reports an extension wizard step's completeness without a raw useEffect",
13
+ "detail": "`useReportStepComplete(props.reportStepComplete, complete)` with `complete: boolean | null`. `null` reports nothing (data loading), a boolean is reported whenever it changes. Outside update-mode wizards `reportStepComplete` is undefined and the hook does nothing.",
14
+ "migration": "Extension steps that call `reportStepComplete` from a `useEffect` should switch to `useReportStepComplete(reportStepComplete, complete)`; app repos need this to pass the no-raw-hooks guard."
15
+ },
2
16
  {
3
17
  "version": "0.335.0",
4
18
  "type": "fix",