@cosmicdrift/kumiko-renderer 0.366.0 → 0.368.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/kumiko-screen.d.ts +7 -0
- package/dist/app/kumiko-screen.js +46 -13
- package/dist/app/projection-detail-shim.js +1 -0
- package/dist/components/render-edit.js +8 -1
- package/dist/i18n-defaults.js +4 -0
- package/dist/index.d.ts +2 -2
- package/dist/index.js +1 -1
- package/dist/primitives.d.ts +19 -0
- package/package.json +5 -5
- package/src/changes.json +25 -0
|
@@ -19,6 +19,13 @@ export { qualifyScreenId };
|
|
|
19
19
|
export declare function qualifyNavId(featureName: string, navId: string): string;
|
|
20
20
|
export { screenAccessAllows };
|
|
21
21
|
export declare function KumikoScreen({ schema, qn, translate, entityId, onRowClick, onCopyLink, }: KumikoScreenProps): ReactNode;
|
|
22
|
+
/** Empty state for a screen QN that is not in the schema (feature disabled for
|
|
23
|
+
* the tenant, stale link, miswired screen). The QN only goes to the console. */
|
|
24
|
+
export declare function ScreenMissingState({ screenQn, homeScreenId, testId, }: {
|
|
25
|
+
readonly screenQn: string;
|
|
26
|
+
readonly homeScreenId?: string;
|
|
27
|
+
readonly testId?: string;
|
|
28
|
+
}): ReactNode;
|
|
22
29
|
export declare function buildInitialValues(fields: Readonly<Record<string, unknown>>, defaultCurrency?: string, moneyCurrencyOverrides?: Readonly<Record<string, string>>): FormValues;
|
|
23
30
|
export declare function tenantCurrencyMoneyFieldNames(fields: Readonly<Record<string, unknown>>): readonly string[];
|
|
24
31
|
export declare function literalCurrencyOverrides(fields: Readonly<Record<string, unknown>>): Readonly<Record<string, string>>;
|
|
@@ -61,7 +61,6 @@ export function qualifyNavId(featureName, navId) {
|
|
|
61
61
|
}
|
|
62
62
|
export { screenAccessAllows };
|
|
63
63
|
export function KumikoScreen({ schema, qn, translate, entityId, onRowClick, onCopyLink, }) {
|
|
64
|
-
const { Banner, Text } = usePrimitives();
|
|
65
64
|
const userRoles = useUserRoles();
|
|
66
65
|
const outerHost = useReturnHost();
|
|
67
66
|
const screen = useMemo(() => schema.screens.find((s) => qualifyScreenId(schema.featureName, s.id) === qn), [schema.featureName, schema.screens, qn]);
|
|
@@ -71,10 +70,10 @@ export function KumikoScreen({ schema, qn, translate, entityId, onRowClick, onCo
|
|
|
71
70
|
...(entityId !== undefined && { entityId }),
|
|
72
71
|
}), [screen, entityId]);
|
|
73
72
|
if (!screen) {
|
|
74
|
-
return
|
|
73
|
+
return _jsx(ScreenMissingState, { screenQn: qn });
|
|
75
74
|
}
|
|
76
75
|
if (!screenAccessAllows(screen.access, userRoles)) {
|
|
77
|
-
return (
|
|
76
|
+
return _jsx(ScreenAccessDeniedBanner, { screenQn: qn, testId: "kumiko-screen-access-denied" });
|
|
78
77
|
}
|
|
79
78
|
const screenBody = renderScreenBody({
|
|
80
79
|
schema,
|
|
@@ -94,8 +93,7 @@ export function KumikoScreen({ schema, qn, translate, entityId, onRowClick, onCo
|
|
|
94
93
|
return _jsx(ReturnHostProvider, { value: ownHost, children: body });
|
|
95
94
|
}
|
|
96
95
|
function ScreenVisibilityGate({ featureName, visibleWhen, fallback, translate, children, }) {
|
|
97
|
-
const { Banner
|
|
98
|
-
const pageHeaderSlotAvailable = usePageHeaderSlotAvailable();
|
|
96
|
+
const { Banner } = usePrimitives();
|
|
99
97
|
const result = useQuery(visibleWhen.query, {}, { live: true });
|
|
100
98
|
const wasShown = useRef(false);
|
|
101
99
|
const verdict = evalVisibleWhenAfterShown(visibleWhen, result, wasShown.current);
|
|
@@ -108,9 +106,43 @@ function ScreenVisibilityGate({ featureName, visibleWhen, fallback, translate, c
|
|
|
108
106
|
if (verdict === "loading") {
|
|
109
107
|
return (_jsx(Banner, { padded: true, variant: "loading", testId: "kumiko-screen-loading", children: "Loading\u2026" }));
|
|
110
108
|
}
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
109
|
+
if (fallback !== undefined) {
|
|
110
|
+
return _jsx(FallbackScreen, { featureName: featureName, fallback: fallback, translate: translate });
|
|
111
|
+
}
|
|
112
|
+
return (_jsxs(_Fragment, { children: [_jsx(LockedScreenHeader, {}), _jsx(ScreenUnavailableBanner, {})] }));
|
|
113
|
+
}
|
|
114
|
+
// The route still names the locked screen; its breadcrumb must not label what stands in for it.
|
|
115
|
+
// With a stand-in the header is labelled with that screen instead, none if it has no title.
|
|
116
|
+
function LockedScreenHeader({ standInScreenId }) {
|
|
117
|
+
const { PageHeader } = usePrimitives();
|
|
118
|
+
const pageHeaderSlotAvailable = usePageHeaderSlotAvailable();
|
|
119
|
+
if (PageHeader === undefined || !pageHeaderSlotAvailable)
|
|
120
|
+
return null;
|
|
121
|
+
return standInScreenId !== undefined ? (_jsx(PageHeader, { hideBreadcrumb: true, breadcrumbScreenId: standInScreenId })) : (_jsx(PageHeader, { hideBreadcrumb: true }));
|
|
122
|
+
}
|
|
123
|
+
function ScreenMissingHomeButton({ homeScreenId, testId, }) {
|
|
124
|
+
const { Button } = usePrimitives();
|
|
125
|
+
const t = useTranslation();
|
|
126
|
+
const nav = useNav();
|
|
127
|
+
return (_jsx(Button, { variant: "secondary", onClick: () => nav.navigate({ screenId: homeScreenId }), testId: testId, children: t("kumiko.screen-missing.home") }));
|
|
128
|
+
}
|
|
129
|
+
/** Empty state for a screen QN that is not in the schema (feature disabled for
|
|
130
|
+
* the tenant, stale link, miswired screen). The QN only goes to the console. */
|
|
131
|
+
export function ScreenMissingState({ screenQn, homeScreenId, testId = "kumiko-screen-not-found", }) {
|
|
132
|
+
const { Card, Text } = usePrimitives();
|
|
133
|
+
const t = useTranslation();
|
|
134
|
+
useEffect(() => {
|
|
135
|
+
console.warn(`[kumiko] screen "${screenQn}" is not in the schema (feature disabled, stale link or miswired screen).`);
|
|
136
|
+
}, [screenQn]);
|
|
137
|
+
return (_jsxs(Card, { options: { padded: true }, testId: testId, children: [_jsx(Text, { testId: `${testId}-title`, children: t("kumiko.screen-missing.title") }), _jsx(Text, { variant: "muted", children: t("kumiko.screen-missing.hint") }), homeScreenId !== undefined && (_jsx(ScreenMissingHomeButton, { homeScreenId: homeScreenId, testId: `${testId}-home` }))] }));
|
|
138
|
+
}
|
|
139
|
+
function ScreenAccessDeniedBanner({ screenQn, testId, }) {
|
|
140
|
+
const { Banner } = usePrimitives();
|
|
141
|
+
const t = useTranslation();
|
|
142
|
+
useEffect(() => {
|
|
143
|
+
console.warn(`[kumiko] access to screen "${screenQn}" denied for the current roles.`);
|
|
144
|
+
}, [screenQn]);
|
|
145
|
+
return (_jsx(Banner, { padded: true, variant: "error", testId: testId, children: t("kumiko.screen-access-denied.title") }));
|
|
114
146
|
}
|
|
115
147
|
function ScreenUnavailableBanner() {
|
|
116
148
|
const { Banner } = usePrimitives();
|
|
@@ -121,9 +153,10 @@ function FallbackScreen({ featureName, fallback, translate, }) {
|
|
|
121
153
|
const target = useEmbeddedScreen(featureName, fallback);
|
|
122
154
|
// Also undefined when the user lacks access to the fallback screen, which is
|
|
123
155
|
// not a framework error.
|
|
124
|
-
if (target === undefined)
|
|
125
|
-
return _jsx(ScreenUnavailableBanner, {});
|
|
126
|
-
|
|
156
|
+
if (target === undefined) {
|
|
157
|
+
return (_jsxs(_Fragment, { children: [_jsx(LockedScreenHeader, {}), _jsx(ScreenUnavailableBanner, {})] }));
|
|
158
|
+
}
|
|
159
|
+
return (_jsxs(_Fragment, { children: [_jsx(LockedScreenHeader, { standInScreenId: lastSegment(target.qn) }), _jsx(KumikoScreen, { schema: target.schema, qn: target.qn, translate: translate })] }));
|
|
127
160
|
}
|
|
128
161
|
function renderScreenBody({ schema, screen, translate, entityId, onRowClick, onCopyLink, }) {
|
|
129
162
|
switch (screen.type) {
|
|
@@ -1143,7 +1176,7 @@ function useDrawerAction(schema) {
|
|
|
1143
1176
|
};
|
|
1144
1177
|
}
|
|
1145
1178
|
function DrawerHost({ schema, drawerAction, drawerScreen, drawerInitialValues, userRoles, translate, onClose, onSuccess, }) {
|
|
1146
|
-
const { Drawer,
|
|
1179
|
+
const { Drawer, Dialog } = usePrimitives();
|
|
1147
1180
|
const t = useTranslation();
|
|
1148
1181
|
const effectiveTranslate = translate ?? t;
|
|
1149
1182
|
const locale = useLocale().locale();
|
|
@@ -1185,7 +1218,7 @@ function DrawerHost({ schema, drawerAction, drawerScreen, drawerInitialValues, u
|
|
|
1185
1218
|
requestClose();
|
|
1186
1219
|
}, title: effectiveTranslate(drawerAction.title ?? drawerAction.label, titleParams), ...(drawerAction.subtitle !== undefined && {
|
|
1187
1220
|
subtitle: effectiveTranslate(drawerAction.subtitle, titleParams),
|
|
1188
|
-
}), testId: `toolbar-drawer-${drawerAction.id}`, children: _jsx(PageHeaderSlotAvailableProvider, { value: false, children: _jsx(InsideDrawerProvider, { value: true, children: drawerScreen === undefined ? (
|
|
1221
|
+
}), testId: `toolbar-drawer-${drawerAction.id}`, children: _jsx(PageHeaderSlotAvailableProvider, { value: false, children: _jsx(InsideDrawerProvider, { value: true, children: drawerScreen === undefined ? (_jsx(ScreenMissingState, { screenQn: drawerAction.screen, testId: "kumiko-toolbar-drawer-not-found" })) : !allowed ? (_jsx(ScreenAccessDeniedBanner, { screenQn: drawerAction.screen, testId: "kumiko-toolbar-drawer-access-denied" })) : (_jsx(ActionFormBody, { schema: schema, screen: drawerScreen, ...(translate !== undefined && { translate }), ...(drawerInitialValues !== undefined && {
|
|
1189
1222
|
initialOverrides: drawerInitialValues,
|
|
1190
1223
|
}), onSuccess: () => {
|
|
1191
1224
|
setHasUnsavedInput(false);
|
|
@@ -63,6 +63,7 @@ export function synthesizeProjectionDetailScreen(screen) {
|
|
|
63
63
|
allowCreate: false,
|
|
64
64
|
allowDelete: false,
|
|
65
65
|
...(screen.description !== undefined && { description: screen.description }),
|
|
66
|
+
...(screen.recordTitleField !== undefined && { recordTitleField: screen.recordTitleField }),
|
|
66
67
|
...(screen.fieldLabels !== undefined && { fieldLabels: screen.fieldLabels }),
|
|
67
68
|
...(screen.slots !== undefined && { slots: screen.slots }),
|
|
68
69
|
...(screen.access !== undefined && { access: screen.access }),
|
|
@@ -1240,6 +1240,12 @@ export function RenderEdit(props) {
|
|
|
1240
1240
|
// floating as a heading above the band.
|
|
1241
1241
|
const titleInSettingsHeader = isSettingsList && !titleInShell;
|
|
1242
1242
|
const usesFieldFlow = isScreenForm || insideDrawer;
|
|
1243
|
+
// The caller's headerRegion already shows the record title in the shell page
|
|
1244
|
+
// header, so the type title ("Release") above the form would repeat it.
|
|
1245
|
+
const recordTitleInHeaderRegion = headerRegion !== undefined &&
|
|
1246
|
+
recordTitle !== undefined &&
|
|
1247
|
+
PageHeader !== undefined &&
|
|
1248
|
+
pageHeaderSlotAvailable;
|
|
1243
1249
|
const allRequiredHint = (_jsx(Text, { variant: "muted", testId: "render-edit-all-required-hint", children: translate("kumiko.form.all-required") }));
|
|
1244
1250
|
const stepRail = isWizard && isScreenForm && StepBar !== undefined;
|
|
1245
1251
|
const upNextSection = screen.layout.wizard?.aside?.upNext === true ? filteredSections[currentStep + 1] : undefined;
|
|
@@ -1270,7 +1276,8 @@ export function RenderEdit(props) {
|
|
|
1270
1276
|
actions: (_jsx(ActionOverflowMenu, { label: translate("kumiko.list.row-actions.more"), items: headerMenuItems, testId: "render-edit-header-menu" })),
|
|
1271
1277
|
}) })), _jsx(Form, { onSubmit: () => void handleSubmit(), ...(hideSectionTitles !== true &&
|
|
1272
1278
|
!titleInShell &&
|
|
1273
|
-
!titleInSettingsHeader &&
|
|
1279
|
+
!titleInSettingsHeader &&
|
|
1280
|
+
!recordTitleInHeaderRegion && { title: formTitle }), ...(formSubtitle !== undefined &&
|
|
1274
1281
|
!stepRail &&
|
|
1275
1282
|
!titleInSettingsHeader && { subtitle: formSubtitle }), ...(isScreenForm && { screenForm: true }), ...(unsavedCount !== undefined &&
|
|
1276
1283
|
(unsavedCount > 0 || hasDirtyFooter) && { unsavedCount }), ...(sectionNavItems.length > 0 && { sectionNav: sectionNavItems }), ...(stepRail && {
|
package/dist/i18n-defaults.js
CHANGED
|
@@ -135,6 +135,10 @@ export const kumikoDefaultTranslations = {
|
|
|
135
135
|
"kumiko.app-boot.no-open-screen": "This app has no screen that's accessible without a role restriction.",
|
|
136
136
|
"kumiko.widget.loading": "Loading…",
|
|
137
137
|
"kumiko.widget.error.title": "Couldn't load.",
|
|
138
|
+
"kumiko.screen-missing.title": "This page is not available",
|
|
139
|
+
"kumiko.screen-missing.hint": "It is not enabled for your account or no longer exists.",
|
|
140
|
+
"kumiko.screen-access-denied.title": "You do not have access to this page.",
|
|
141
|
+
"kumiko.screen-missing.home": "Go to start page",
|
|
138
142
|
"kumiko.screen-error.title": "This screen failed to render.",
|
|
139
143
|
"kumiko.screen-error.detail": "Screen: {screen}. {message}",
|
|
140
144
|
"kumiko.screen-error.screen": "Screen: {screen}",
|
package/dist/index.d.ts
CHANGED
|
@@ -19,7 +19,7 @@ export { ExtensionSectionsProvider, extensionSectionName, useExtensionSectionCom
|
|
|
19
19
|
export type { AppSchema, FeatureSchema, QualifiedContentCollection, WorkspaceSchema, } from "./app/feature-schema.js";
|
|
20
20
|
export { isAppSchema, toAppSchema } from "./app/feature-schema.js";
|
|
21
21
|
export type { KumikoScreenProps } from "./app/kumiko-screen.js";
|
|
22
|
-
export { KumikoScreen, qualifyNavId, qualifyScreenId } from "./app/kumiko-screen.js";
|
|
22
|
+
export { KumikoScreen, qualifyNavId, qualifyScreenId, ScreenMissingState, } from "./app/kumiko-screen.js";
|
|
23
23
|
export type { DateRangeBound, DateRangeValue, ResolvedDateRangeFacet } from "./app/list-facets.js";
|
|
24
24
|
export { buildDateRangePayload, clampDateRange, readDateRange, resolveDateRangeFacets, } from "./app/list-facets.js";
|
|
25
25
|
export type { NavApi, NavigateOptions, NavProviderProps, NavRoute, NavTarget, ObjectTarget, ScreenTarget, } from "./app/nav.js";
|
|
@@ -75,7 +75,7 @@ export { createStaticLocaleResolver, FormalityProvider, LocaleProvider, mergeTra
|
|
|
75
75
|
export { kumikoDefaultTranslations } from "./i18n-defaults.js";
|
|
76
76
|
export { InsideDrawerProvider, useInsideDrawer } from "./inside-drawer.js";
|
|
77
77
|
export { PageHeaderCompactProvider, PageHeaderSlotAvailableProvider, usePageHeaderCompact, usePageHeaderSlotAvailable, } from "./page-header-slot.js";
|
|
78
|
-
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, LightboxImage, 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";
|
|
78
|
+
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, LightboxImage, LightboxProps, LinkProps, MetricBandProps, MetricProps, ModalProps, PageHeaderProps, PickedFile, PrimitivesProviderProps, PrimitivesRegistry, ProgressProps, ProgressTone, PromoPanelAction, PromoPanelProps, RuntimeRenderer, SecretRevealProps, SecretRevealValue, SectionProps, ShareButtonProps, StatusBadgeProps, StatusTone, StepBarProps, StickyActionBarProps, StickyPrimaryActionMarker, TabsProps, TextProps, TrailingInputAction, WizardStepGroupProps, } from "./primitives.js";
|
|
79
79
|
export { FOOTER_ACTION_ROLE_PROP, NARROW_LABEL_PROP, PrimitivesProvider, STICKY_PRIMARY_ACTION_PROP, shouldRenderActionsIconOnly, statusToneForOptionTone, statusToneForValue, useOptionalPrimitives, usePrimitives, } from "./primitives.js";
|
|
80
80
|
export type { SessionEndedSignal, SessionEndedSignalProviderProps, } from "./session/session-ended.js";
|
|
81
81
|
export { createSessionEndedSignal, isSessionEndedError, SESSION_ENDED_ERROR_CODES, SessionEndedSignalProvider, useSessionEndedSignal, withSessionEndedDetection, } from "./session/session-ended.js";
|
package/dist/index.js
CHANGED
|
@@ -19,7 +19,7 @@ export { DashboardBodyProvider, useDashboardBody } from "./app/dashboard-body.js
|
|
|
19
19
|
export { ExtensionFormRegistryProvider, useExtensionFormSubmit, } from "./app/extension-form-submit.js";
|
|
20
20
|
export { ExtensionSectionsProvider, extensionSectionName, useExtensionSectionComponent, } from "./app/extension-sections.js";
|
|
21
21
|
export { isAppSchema, toAppSchema } from "./app/feature-schema.js";
|
|
22
|
-
export { KumikoScreen, qualifyNavId, qualifyScreenId } from "./app/kumiko-screen.js";
|
|
22
|
+
export { KumikoScreen, qualifyNavId, qualifyScreenId, ScreenMissingState, } from "./app/kumiko-screen.js";
|
|
23
23
|
export { buildDateRangePayload, clampDateRange, readDateRange, resolveDateRangeFacets, } from "./app/list-facets.js";
|
|
24
24
|
export { formatPath, hasDetailScreen, NavProvider, parsePath, resolveTarget, useNav, useNavigateWithInitialValues, } from "./app/nav.js";
|
|
25
25
|
export { lastSegment } from "./app/qn.js";
|
package/dist/primitives.d.ts
CHANGED
|
@@ -180,6 +180,14 @@ export type TrailingInputAction = {
|
|
|
180
180
|
readonly onPress: () => void;
|
|
181
181
|
readonly testId?: string;
|
|
182
182
|
};
|
|
183
|
+
/** Platform-neutral view of a picked file; the DOM `File` satisfies it. */
|
|
184
|
+
export type PickedFile = {
|
|
185
|
+
readonly name: string;
|
|
186
|
+
readonly size: number;
|
|
187
|
+
readonly type: string;
|
|
188
|
+
readonly webkitRelativePath: string;
|
|
189
|
+
readonly arrayBuffer: () => Promise<ArrayBuffer>;
|
|
190
|
+
};
|
|
183
191
|
export type InputProps = {
|
|
184
192
|
readonly kind: "text";
|
|
185
193
|
readonly id: string;
|
|
@@ -318,6 +326,14 @@ export type InputProps = {
|
|
|
318
326
|
/** Only for kind:"image" — forwarded to the file input's `capture`
|
|
319
327
|
* attribute so a phone opens the camera instead of the file picker. */
|
|
320
328
|
readonly capture?: "environment" | "user";
|
|
329
|
+
/** Web-only folder picker: the picked files (with `webkitRelativePath`)
|
|
330
|
+
* go to `onFilesPicked` and nothing is uploaded. Native impls ignore it. */
|
|
331
|
+
readonly directory?: boolean;
|
|
332
|
+
readonly onFilesPicked?: (files: readonly PickedFile[]) => void;
|
|
333
|
+
/** Translated label of the pick button; absent → the upload/change default. */
|
|
334
|
+
readonly pickLabel?: string;
|
|
335
|
+
/** Hidden file input gets `${testId}-input`, the pick button `${testId}-pick`. */
|
|
336
|
+
readonly testId?: string;
|
|
321
337
|
} | {
|
|
322
338
|
readonly kind: "date";
|
|
323
339
|
readonly id: string;
|
|
@@ -1337,6 +1353,9 @@ export type PageHeaderProps = {
|
|
|
1337
1353
|
/** Hide the shell header's breadcrumb while mounted, for a screen that stands in
|
|
1338
1354
|
* for the one the route names (a locked screen's fallback). */
|
|
1339
1355
|
readonly hideBreadcrumb?: boolean;
|
|
1356
|
+
/** Label the breadcrumb with this screen (id as in the route) instead of the one
|
|
1357
|
+
* the route names, for a locked screen's fallback. Wins over `hideBreadcrumb`. */
|
|
1358
|
+
readonly breadcrumbScreenId?: string;
|
|
1340
1359
|
};
|
|
1341
1360
|
/** One item in an `ActionOverflowMenu` (A7: header/row actions beyond the
|
|
1342
1361
|
* primary one collapse into this menu instead of a wall of buttons). */
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cosmicdrift/kumiko-renderer",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.368.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.368.0",
|
|
19
|
+
"@cosmicdrift/kumiko-headless": "0.368.0",
|
|
20
|
+
"@cosmicdrift/kumiko-types": "0.368.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.368.0"
|
|
32
32
|
},
|
|
33
33
|
"repository": {
|
|
34
34
|
"type": "git",
|
package/src/changes.json
CHANGED
|
@@ -1,4 +1,29 @@
|
|
|
1
1
|
[
|
|
2
|
+
{
|
|
3
|
+
"version": "0.368.0",
|
|
4
|
+
"type": "fix",
|
|
5
|
+
"title": "A screen that falls back via visibleWhen shows the fallback's title",
|
|
6
|
+
"detail": "When visibleWhen locks a screen and its fallback renders instead, the header no longer stays empty. It shows the title of the fallback screen (resolved like any other screen title, from its nav label), never the locked screen's. A fallback without a title still leaves the header empty. PageHeader takes a new breadcrumbScreenId prop for this."
|
|
7
|
+
},
|
|
8
|
+
{
|
|
9
|
+
"version": "0.367.0",
|
|
10
|
+
"type": "fix",
|
|
11
|
+
"title": "projectionDetail no longer shows an empty type-title block above the record",
|
|
12
|
+
"detail": "The projectionDetail shim dropped recordTitleField, so the duplicate-title fix never applied to real projectionDetail screens. The synthesized edit screen now carries it, and the page header shows the record title once."
|
|
13
|
+
},
|
|
14
|
+
{
|
|
15
|
+
"version": "0.367.0",
|
|
16
|
+
"type": "fix",
|
|
17
|
+
"title": "A route to a screen missing from the schema shows an empty state",
|
|
18
|
+
"detail": "A tenant-disabled feature, stale link or typo no longer falls back to the first feature or shows \"Screen not found: <qn>\". The app renders \"This page is not available\" with a button to the landing screen; the qualified name only goes to the console. New i18n keys kumiko.screen-missing.title, .hint and .home (en, de, es). The access-denied banner of KumikoScreen and the toolbar drawer is now translated too (kumiko.screen-access-denied.title) and no longer prints the qualified name.",
|
|
19
|
+
"migration": "e2e checks on the text \"Screen not found\" should use the testId kumiko-screen-not-found; the testIds are unchanged."
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
"version": "0.367.0",
|
|
23
|
+
"type": "fix",
|
|
24
|
+
"title": "projectionDetail drops the duplicate title block",
|
|
25
|
+
"detail": "A screen with recordTitleField no longer repeats the screen title above the form when the page header already shows the record title."
|
|
26
|
+
},
|
|
2
27
|
{
|
|
3
28
|
"version": "0.365.0",
|
|
4
29
|
"type": "fix",
|