@cosmicdrift/kumiko-renderer 0.384.0 → 0.386.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.
Files changed (98) hide show
  1. package/dist/app/action-form-body.d.ts +50 -0
  2. package/dist/app/action-form-body.js +275 -0
  3. package/dist/app/client-actions.js +2 -2
  4. package/dist/app/config-edit-body.d.ts +9 -0
  5. package/dist/app/config-edit-body.js +340 -0
  6. package/dist/app/entity-edit-prefill.d.ts +27 -0
  7. package/dist/app/entity-edit-prefill.js +377 -0
  8. package/dist/app/entity-edit-screen.d.ts +11 -0
  9. package/dist/app/entity-edit-screen.js +395 -0
  10. package/dist/app/entity-list-screen.d.ts +10 -0
  11. package/dist/app/entity-list-screen.js +547 -0
  12. package/dist/app/kumiko-screen.d.ts +1 -36
  13. package/dist/app/kumiko-screen.js +16 -2855
  14. package/dist/app/projection-detail-body.d.ts +12 -0
  15. package/dist/app/projection-detail-body.js +464 -0
  16. package/dist/app/projection-detail-shim.d.ts +1 -1
  17. package/dist/app/projection-detail-shim.js +5 -1
  18. package/dist/app/projection-list-body.d.ts +10 -0
  19. package/dist/app/projection-list-body.js +245 -0
  20. package/dist/app/projection-list-shim.d.ts +2 -1
  21. package/dist/app/projection-list-shim.js +4 -0
  22. package/dist/app/reference-facet-bridge.js +2 -2
  23. package/dist/app/row-actions.js +3 -4
  24. package/dist/app/screen-shared.d.ts +72 -0
  25. package/dist/app/screen-shared.js +325 -0
  26. package/dist/app/secret-mint-body.js +3 -3
  27. package/dist/components/edit-mounts.d.ts +33 -0
  28. package/dist/components/edit-mounts.js +53 -0
  29. package/dist/components/error-boundary.js +2 -2
  30. package/dist/components/reference-create-dialog.js +1 -1
  31. package/dist/components/related-list-section.js +29 -6
  32. package/dist/components/render-edit-helpers.d.ts +29 -0
  33. package/dist/components/render-edit-helpers.js +121 -0
  34. package/dist/components/render-edit.d.ts +1 -4
  35. package/dist/components/render-edit.js +41 -443
  36. package/dist/components/render-field.js +3 -4
  37. package/dist/components/render-list.d.ts +1 -1
  38. package/dist/components/render-list.js +2 -2
  39. package/dist/components/use-wizard-form-draft.d.ts +51 -0
  40. package/dist/components/use-wizard-form-draft.js +291 -0
  41. package/dist/dev-console.d.ts +3 -0
  42. package/dist/dev-console.js +15 -0
  43. package/dist/headless/contracts/primitives.js +14 -17
  44. package/dist/headless/format/index.js +3 -3
  45. package/dist/headless/view-model/edit.d.ts +1 -1
  46. package/dist/headless/view-model/edit.js +9 -16
  47. package/dist/headless/view-model/list.d.ts +1 -1
  48. package/dist/headless/view-model/list.js +3 -8
  49. package/dist/index.d.ts +2 -1
  50. package/dist/index.js +5 -5
  51. package/dist/live/error-mapping.js +3 -4
  52. package/dist/web/app/create-app.js +5 -8
  53. package/dist/web/app/dashboard-body.js +4 -599
  54. package/dist/web/app/dashboard-panels.d.ts +53 -0
  55. package/dist/web/app/dashboard-panels.js +373 -0
  56. package/dist/web/app/dashboard-shared.d.ts +90 -0
  57. package/dist/web/app/dashboard-shared.js +171 -0
  58. package/dist/web/app/dashboard-text.d.ts +6 -0
  59. package/dist/web/app/dashboard-text.js +65 -0
  60. package/dist/web/layout/nav-tree.js +3 -4
  61. package/dist/web/layout/target-resolver-stub.js +2 -2
  62. package/dist/web/primitives/banner.d.ts +4 -0
  63. package/dist/web/primitives/banner.js +28 -0
  64. package/dist/web/primitives/button.d.ts +7 -0
  65. package/dist/web/primitives/button.js +48 -0
  66. package/dist/web/primitives/card-styles.d.ts +8 -0
  67. package/dist/web/primitives/card-styles.js +18 -0
  68. package/dist/web/primitives/card.d.ts +4 -0
  69. package/dist/web/primitives/card.js +41 -0
  70. package/dist/web/primitives/contexts.d.ts +22 -0
  71. package/dist/web/primitives/contexts.js +50 -0
  72. package/dist/web/primitives/data-table-cell.d.ts +76 -0
  73. package/dist/web/primitives/data-table-cell.js +403 -0
  74. package/dist/web/primitives/data-table.d.ts +4 -0
  75. package/dist/web/primitives/data-table.js +279 -0
  76. package/dist/web/primitives/default-form.d.ts +4 -0
  77. package/dist/web/primitives/default-form.js +79 -0
  78. package/dist/web/primitives/facet-filter.d.ts +14 -0
  79. package/dist/web/primitives/facet-filter.js +39 -0
  80. package/dist/web/primitives/field.d.ts +63 -0
  81. package/dist/web/primitives/field.js +181 -0
  82. package/dist/web/primitives/form.d.ts +53 -0
  83. package/dist/web/primitives/form.js +252 -0
  84. package/dist/web/primitives/index.d.ts +7 -30
  85. package/dist/web/primitives/index.js +27 -2006
  86. package/dist/web/primitives/input.d.ts +4 -0
  87. package/dist/web/primitives/input.js +166 -0
  88. package/dist/web/primitives/layout-elements.d.ts +14 -0
  89. package/dist/web/primitives/layout-elements.js +194 -0
  90. package/dist/web/primitives/modal.js +1 -1
  91. package/dist/web/primitives/pager.d.ts +22 -0
  92. package/dist/web/primitives/pager.js +89 -0
  93. package/dist/web/primitives/row-actions.d.ts +13 -0
  94. package/dist/web/primitives/row-actions.js +178 -0
  95. package/dist/web/primitives/secret-reveal.d.ts +4 -0
  96. package/dist/web/primitives/secret-reveal.js +67 -0
  97. package/package.json +5 -5
  98. package/src/changes.json +6 -0
@@ -0,0 +1,178 @@
1
+ import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { Loader2, MoreHorizontal } from "lucide-react";
3
+ import { useState } from "react";
4
+ import { needsActionConfirm, shouldRenderActionsIconOnly, useTranslation, WriteFailedError, } from "../../index.js";
5
+ import { Icon } from "../icons.js";
6
+ import { cn } from "../lib/cn.js";
7
+ import { Button as UiButton } from "../ui/button.js";
8
+ import { DefaultDialog } from "./dialog.js";
9
+ import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger, } from "./dropdown-menu.js";
10
+ import { useToast } from "./toast.js";
11
+ import "../react-css-custom-properties.js";
12
+ import { actionIconFor, SECONDARY_BUTTON_EXTRA_CLASSES } from "./button.js";
13
+ // The primary row action is the one that always stays a visible text
14
+ // button — `edit` if declared, else the first visible action (fw
15
+ // bedienkonzept L3: "Bearbeiten steht in jeder Zeile, immer, als Text").
16
+ function primaryRowAction(actions) {
17
+ return actions.find((a) => a.id === "edit") ?? actions[0];
18
+ }
19
+ // RowActionsCell renders the row actions depending on `mode`:
20
+ // - "adaptive" (default): when the row itself is the link (`rowIsLink`)
21
+ // every action sits in the kebab; otherwise the primary action (see
22
+ // `primaryRowAction`) is a link-button and the rest goes into the kebab.
23
+ // A single action never gets a kebab.
24
+ // - "inline": ALWAYS inline buttons, left-aligned + full-width, even for
25
+ // >2 (no kebab). `w-full justify-start` pins the first button to the
26
+ // column's left edge so it sits at the same position across rows
27
+ // (otherwise it would drift with differently-sized labels).
28
+ // The isVisible filter runs here; an action hidden for a given row never
29
+ // reaches render. If every action is hidden, the cell stays empty (no
30
+ // phantom column).
31
+ export function RowActionsCell({ row, actions, mode = "adaptive", rowIsLink = false, compact = false, }) {
32
+ const visible = actions.filter((a) => a.isVisible === undefined || a.isVisible(row));
33
+ if (visible.length === 0)
34
+ return null;
35
+ const hasExplicitDisplay = visible.some((a) => a.display !== undefined);
36
+ if (mode === "inline") {
37
+ // Teil C: >2 actions all carrying an icon collapse to icon-only —
38
+ // otherwise "inline" is exactly the wall-to-wall text-button problem
39
+ // this feature exists to fix. An author-set `display` takes that choice over.
40
+ const iconOnly = !hasExplicitDisplay && shouldRenderActionsIconOnly(visible);
41
+ return (_jsx("div", { className: "flex w-full items-center gap-1 justify-start", children: visible.map((a) => (_jsx(RowActionButton, { row: row, action: a, iconOnly: iconOnly, compact: compact }, a.id))) }));
42
+ }
43
+ if (hasExplicitDisplay) {
44
+ const inline = visible.filter((a) => a.display !== undefined);
45
+ const rest = visible.filter((a) => a.display === undefined);
46
+ return (_jsxs("div", { className: "inline-flex flex-wrap items-center gap-1 justify-end", children: [inline.map((a) => (_jsx(RowActionButton, { row: row, action: a, compact: compact }, a.id))), rest.length > 0 && _jsx(RowActionsKebab, { row: row, actions: rest })] }));
47
+ }
48
+ if (rowIsLink) {
49
+ return (_jsx("div", { className: "inline-flex items-center justify-end", children: _jsx(RowActionsKebab, { row: row, actions: visible }) }));
50
+ }
51
+ const primary = primaryRowAction(visible);
52
+ const rest = visible.filter((a) => a.id !== primary?.id);
53
+ return (_jsxs("div", { className: "inline-flex flex-wrap items-center gap-1 justify-end", children: [primary !== undefined && _jsx(RowActionButton, { row: row, action: primary, asLink: true }), rest.length > 0 && _jsx(RowActionsKebab, { row: row, actions: rest })] }));
54
+ }
55
+ // Shared trigger state between inline button + kebab item: busy flag
56
+ // (while the async onTrigger runs) + confirm-pending action. Both
57
+ // sub-components had duplicated the same state block in parallel to the
58
+ // confirm dialog render logic; the hook consolidates that.
59
+ function useRowActionTrigger(row) {
60
+ const [busy, setBusy] = useState(false);
61
+ const { toast } = useToast();
62
+ const t = useTranslation();
63
+ const triggerNow = async (action) => {
64
+ setBusy(true);
65
+ try {
66
+ await action.onTrigger(row);
67
+ }
68
+ catch (e) {
69
+ // Surface instead of swallow: a swallowed write error looked like
70
+ // "nothing happened" to the user (prod bug 2026-06-07).
71
+ const dispatcherError = e instanceof WriteFailedError ? e.dispatcherError : undefined;
72
+ const docsUrl = dispatcherError?.docsUrl;
73
+ const requestId = dispatcherError?.requestId;
74
+ toast({
75
+ title: t("kumiko.rowAction.failed"),
76
+ description: e instanceof Error ? e.message : String(e),
77
+ variant: "bad",
78
+ ...(docsUrl !== undefined && { docsUrl }),
79
+ ...(requestId !== undefined && { requestId }),
80
+ });
81
+ }
82
+ finally {
83
+ setBusy(false);
84
+ }
85
+ };
86
+ return { busy, triggerNow };
87
+ }
88
+ // An icon-only form without a resolvable icon would render an empty button.
89
+ // `compact` is the narrow card layout, where "responsive" collapses to its icon.
90
+ function effectiveRowActionDisplay(display, hasIcon, compact) {
91
+ if (display === "responsive")
92
+ return hasIcon && compact ? "icon" : "button";
93
+ if (display === "icon" && !hasIcon)
94
+ return "link";
95
+ return display;
96
+ }
97
+ function RowActionButton({ row, action, iconOnly = false, asLink = false, compact = false, }) {
98
+ const { busy, triggerNow } = useRowActionTrigger(row);
99
+ const [confirmOpen, setConfirmOpen] = useState(false);
100
+ const resolvedIcon = actionIconFor(action.icon);
101
+ const display = effectiveRowActionDisplay(action.display, resolvedIcon !== undefined, compact);
102
+ const isBorderedButton = display === "button";
103
+ const showIconOnly = display === "icon" || (display === undefined && iconOnly && resolvedIcon !== undefined);
104
+ const linkLike = display === "link" || (display === undefined && asLink);
105
+ const variantClass = isBorderedButton
106
+ ? action.style === "primary"
107
+ ? "border border-transparent bg-primary text-primary-foreground hover:bg-primary/90"
108
+ : action.style === "danger"
109
+ ? "border border-destructive/40 bg-card text-destructive hover:bg-destructive/10"
110
+ : "border border-border-strong bg-card text-foreground hover:bg-accent"
111
+ : action.style === "danger"
112
+ ? "text-destructive hover:bg-destructive/10"
113
+ : linkLike
114
+ ? "font-medium text-primary hover:bg-muted"
115
+ : action.style === "primary"
116
+ ? "text-primary hover:bg-primary/10"
117
+ : "text-foreground hover:bg-accent";
118
+ return (_jsxs(_Fragment, { children: [_jsx("button", { type: "button", "data-testid": `row-${row.id}-action-${action.id}`, disabled: busy, ...(showIconOnly && { "aria-label": action.label, title: action.label }), onClick: (e) => {
119
+ e.stopPropagation();
120
+ if (needsActionConfirm(action)) {
121
+ setConfirmOpen(true);
122
+ }
123
+ else {
124
+ void triggerNow(action);
125
+ }
126
+ }, className: cn("inline-flex items-center justify-center gap-1.5 text-sm", isBorderedButton
127
+ ? "h-8 rounded-md px-3 font-medium max-md:h-11"
128
+ : linkLike
129
+ ? "h-7 rounded-md px-2.5 max-md:h-11"
130
+ : "h-8 rounded-sm max-md:h-11", showIconOnly ? "w-8 max-md:w-11" : !linkLike && !isBorderedButton && "px-2", "focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring", "disabled:opacity-50 disabled:pointer-events-none", variantClass), children: busy ? (_jsx(Loader2, { className: "size-3.5 animate-spin", "aria-hidden": "true" })) : resolvedIcon === undefined || (linkLike && !showIconOnly) ? (action.label) : showIconOnly ? (_jsx(Icon, { name: resolvedIcon, className: "size-4" })) : (_jsxs(_Fragment, { children: [_jsx(Icon, { name: resolvedIcon, className: "size-4" }), action.label] })) }), _jsx(DefaultDialog, { open: confirmOpen, onOpenChange: setConfirmOpen, title: action.label, ...(action.confirm !== undefined && { description: action.confirm }), confirmLabel: action.confirmLabel ?? action.label, ...(action.style === "danger" && { variant: "danger" }), onConfirm: () => triggerNow(action), testId: `row-${row.id}-action-${action.id}-dialog` })] }));
131
+ }
132
+ // Kebab dropdown for >2 actions, one inline confirm dialog per item like
133
+ // the inline-button path. Menu is controlled so it closes explicitly on
134
+ // select, instead of relying on Radix's auto-close, which preventDefault
135
+ // below blocks.
136
+ function RowActionsKebab({ row, actions, }) {
137
+ const { triggerNow } = useRowActionTrigger(row);
138
+ const t = useTranslation();
139
+ const [pendingConfirm, setPendingConfirm] = useState(null);
140
+ const [menuOpen, setMenuOpen] = useState(false);
141
+ return (_jsxs(_Fragment, { children: [_jsxs(DropdownMenu, { open: menuOpen, onOpenChange: setMenuOpen, children: [_jsx(DropdownMenuTrigger, { asChild: true, children: _jsx("button", { type: "button", "aria-label": t("kumiko.list.row-actions.more"), "data-testid": `row-${row.id}-actions-menu`, className: cn("inline-flex size-7 items-center justify-center rounded-md max-md:size-11", "hover:bg-accent text-muted-foreground hover:text-foreground", "focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring"), children: _jsx(MoreHorizontal, { className: "size-4", "aria-hidden": "true" }) }) }), _jsx(DropdownMenuContent, { align: "end",
142
+ // Radix refocuses the trigger after the exit animation, which by then sits behind the confirm dialog's aria-hidden.
143
+ onCloseAutoFocus: (e) => {
144
+ if (pendingConfirm !== null)
145
+ e.preventDefault();
146
+ }, children: actions.map((action) => (_jsx(DropdownMenuItem, { "data-testid": `row-${row.id}-action-${action.id}`, onSelect: (e) => {
147
+ e.preventDefault();
148
+ setMenuOpen(false);
149
+ if (needsActionConfirm(action)) {
150
+ setPendingConfirm(action);
151
+ }
152
+ else {
153
+ void triggerNow(action);
154
+ }
155
+ }, className: cn(action.style === "danger" && "text-destructive focus:text-destructive"), children: action.label }, action.id))) })] }), pendingConfirm !== null && (_jsx(DefaultDialog, { open: true, onOpenChange: (open) => {
156
+ if (!open)
157
+ setPendingConfirm(null);
158
+ }, title: pendingConfirm.label, ...(pendingConfirm.confirm !== undefined && { description: pendingConfirm.confirm }), confirmLabel: pendingConfirm.confirmLabel ?? pendingConfirm.label, ...(pendingConfirm.style === "danger" && { variant: "danger" }), onConfirm: async () => {
159
+ const action = pendingConfirm;
160
+ setPendingConfirm(null);
161
+ await triggerNow(action);
162
+ }, testId: `row-${row.id}-action-${pendingConfirm.id}-dialog` }))] }));
163
+ }
164
+ // Header/row-actions overflow menu (A7): the trigger carries the classes of a
165
+ // secondary icon Button so it matches neighbouring icon buttons, including
166
+ // the 44 px touch size on phones. Generic ActionMenuItemSpec items instead of
167
+ // the DataTableRowAction schema (callers own confirm/danger handling per item).
168
+ export function ActionOverflowMenu({ items, label, testId }) {
169
+ const [open, setOpen] = useState(false);
170
+ return (_jsxs(DropdownMenu, { open: open, onOpenChange: setOpen, children: [_jsx(DropdownMenuTrigger, { asChild: true, children: _jsx(UiButton, { type: "button", variant: "outline", size: "icon", className: SECONDARY_BUTTON_EXTRA_CLASSES, "aria-label": label, "data-testid": testId ?? "action-overflow-menu-trigger", children: _jsx(MoreHorizontal, { className: "size-4", "aria-hidden": "true" }) }) }), _jsx(DropdownMenuContent, { align: "end", children: items.map((item) => {
171
+ const resolvedIcon = actionIconFor(item.icon);
172
+ return (_jsxs(DropdownMenuItem, { "data-testid": item.testId ?? `${testId ?? "action-overflow-menu"}-item-${item.id}`, disabled: item.disabled === true, onSelect: (e) => {
173
+ e.preventDefault();
174
+ setOpen(false);
175
+ item.onSelect();
176
+ }, className: cn(item.variant === "danger" && "text-destructive focus:text-destructive"), children: [resolvedIcon !== undefined && _jsx(Icon, { name: resolvedIcon, className: "size-4" }), item.label] }, item.id));
177
+ }) })] }));
178
+ }
@@ -0,0 +1,4 @@
1
+ import { type ReactNode } from "react";
2
+ import type { SecretRevealProps } from "../../index.ts";
3
+ import "../react-css-custom-properties.ts";
4
+ export declare function DefaultSecretReveal({ values, copyLabel, copiedLabel, testId, }: SecretRevealProps): ReactNode;
@@ -0,0 +1,67 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ /// <reference path="../qrcode-browser.d.ts" />
3
+ import { useEffect, useState } from "react";
4
+ import { Button as UiButton } from "../ui/button.js";
5
+ import "../react-css-custom-properties.js";
6
+ // otpauth:// enrollment URI → scannable QR (errorCorrectionLevel "H", ~30%
7
+ // redundancy — more resilient to camera/lighting issues than the default, no
8
+ // downside for a code this short-lived). Own component (not inline in
9
+ // values.map) because QRCode.toString is async — a hook inside .map would
10
+ // violate the rules of hooks.
11
+ function QrSecretValue({ value }) {
12
+ const [svg, setSvg] = useState(null);
13
+ const [failed, setFailed] = useState(false);
14
+ useEffect(() => {
15
+ let cancelled = false;
16
+ setFailed(false);
17
+ // Loaded on first QR render, not with the primitives. The main entry pulls
18
+ // Node-only deps (yargs/pngjs) under bundlers that ignore package.json#browser
19
+ // (Metro), hence the explicit browser subpath.
20
+ import("qrcode/lib/browser.js")
21
+ .then(({ default: QRCode }) => QRCode.toString(value, { type: "svg", errorCorrectionLevel: "H" }))
22
+ .then((result) => {
23
+ if (!cancelled)
24
+ setSvg(result);
25
+ })
26
+ .catch(() => {
27
+ // A generic `qr` field may have no separate text display, so fall back to the plain value.
28
+ if (!cancelled)
29
+ setFailed(true);
30
+ });
31
+ return () => {
32
+ cancelled = true;
33
+ };
34
+ }, [value]);
35
+ if (failed) {
36
+ return (_jsx("code", { className: "flex-1 overflow-x-auto whitespace-pre-wrap break-all rounded bg-muted px-3 py-2 font-mono text-sm", children: value }));
37
+ }
38
+ if (svg === null)
39
+ return null;
40
+ return (_jsx("div", { className: "h-40 w-40",
41
+ // qrcode's own SVG string output, not user input — safe to inline
42
+ // biome-ignore lint/security/noDangerouslySetInnerHtml: qrcode-generated SVG, no user input
43
+ dangerouslySetInnerHTML: { __html: svg } }));
44
+ }
45
+ // One-time secret reveal (fw#2548, secretMint confirm phase) — monospaced
46
+ // per-value display with a copy button that flips to `copiedLabel` on
47
+ // success. Silent-catch on clipboard error mirrors the copy-link pattern in
48
+ // create-app.tsx.
49
+ export function DefaultSecretReveal({ values, copyLabel, copiedLabel, testId, }) {
50
+ const [copiedIndex, setCopiedIndex] = useState(null);
51
+ // Labels are not unique per reveal; suffix repeats so React keys stay distinct.
52
+ const seenLabels = new Map();
53
+ const rowKeys = values.map((v) => {
54
+ const occurrence = seenLabels.get(v.label) ?? 0;
55
+ seenLabels.set(v.label, occurrence + 1);
56
+ return `${v.label}#${occurrence}`;
57
+ });
58
+ return (_jsx("div", { "data-testid": testId, className: "flex flex-col gap-3", children: values.map((v, i) => (_jsxs("div", { className: "flex flex-col gap-1.5", children: [_jsx("span", { className: "text-sm font-medium text-muted-foreground", children: v.label }), _jsxs("div", { className: "flex items-start gap-2", children: [v.qr === true ? (_jsx(QrSecretValue, { value: v.value })) : v.multiline ? (_jsx("pre", { className: "flex-1 overflow-x-auto whitespace-pre-wrap break-all rounded bg-muted px-3 py-2 font-mono text-sm", children: v.value })) : (_jsx("code", { className: "flex-1 overflow-x-auto whitespace-pre-wrap break-all rounded bg-muted px-3 py-2 font-mono text-sm", children: v.value })), v.copyable && (_jsx(UiButton, { type: "button", variant: "outline", size: "sm", onClick: async () => {
59
+ try {
60
+ await navigator.clipboard.writeText(v.value);
61
+ setCopiedIndex(i);
62
+ }
63
+ catch {
64
+ // clipboard blocked (non-secure context) — no fallback UI needed here
65
+ }
66
+ }, children: copiedIndex === i ? copiedLabel : copyLabel }))] })] }, rowKeys[i]))) }));
67
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cosmicdrift/kumiko-renderer",
3
- "version": "0.384.0",
3
+ "version": "0.386.0",
4
4
  "description": "React renderer for Kumiko screens. The root export holds the platform-agnostic logic (primitives contract, hooks, KumikoScreen, navigation and SSE abstractions); ./headless the DOM-free UI logic, ./live the HTTP dispatcher, ./web the browser bindings (HTML primitives, history navigation, EventSource live events, createKumikoApp).",
5
5
  "license": "BUSL-1.1",
6
6
  "author": "Marc Frost <marc@cosmicdriftgamestudio.com>",
@@ -48,8 +48,8 @@
48
48
  }
49
49
  },
50
50
  "dependencies": {
51
- "@cosmicdrift/kumiko-framework": "0.384.0",
52
- "@cosmicdrift/kumiko-types": "0.384.0",
51
+ "@cosmicdrift/kumiko-framework": "0.386.0",
52
+ "@cosmicdrift/kumiko-types": "0.386.0",
53
53
  "@radix-ui/react-dialog": "^1.1.15",
54
54
  "@radix-ui/react-dropdown-menu": "^2.1.16",
55
55
  "@radix-ui/react-label": "^2.1.8",
@@ -92,8 +92,8 @@
92
92
  }
93
93
  },
94
94
  "devDependencies": {
95
- "@cosmicdrift/kumiko-locale-de": "0.384.0",
96
- "@cosmicdrift/kumiko-testing": "0.384.0",
95
+ "@cosmicdrift/kumiko-locale-de": "0.386.0",
96
+ "@cosmicdrift/kumiko-testing": "0.386.0",
97
97
  "@tailwindcss/cli": "^4.3.0",
98
98
  "@testing-library/react": "^16.3.2",
99
99
  "@testing-library/user-event": "^14.6.1",
package/src/changes.json CHANGED
@@ -1,4 +1,10 @@
1
1
  [
2
+ {
3
+ "version": "0.385.0",
4
+ "type": "improvement",
5
+ "title": "View-model inputs take only the entity parts they read",
6
+ "detail": "ComputeEditViewModelInput.entity and ComputeListViewModelInput.entity are typed as the Pick of EntityDefinition they actually read, so synthesized entities need no cast. Passing a full EntityDefinition keeps working. Renderer console output goes through one dev-console module."
7
+ },
2
8
  {
3
9
  "version": "0.384.0",
4
10
  "type": "fix",