@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.
- package/dist/app/action-form-body.d.ts +50 -0
- package/dist/app/action-form-body.js +275 -0
- package/dist/app/client-actions.js +2 -2
- package/dist/app/config-edit-body.d.ts +9 -0
- package/dist/app/config-edit-body.js +340 -0
- package/dist/app/entity-edit-prefill.d.ts +27 -0
- package/dist/app/entity-edit-prefill.js +377 -0
- package/dist/app/entity-edit-screen.d.ts +11 -0
- package/dist/app/entity-edit-screen.js +395 -0
- package/dist/app/entity-list-screen.d.ts +10 -0
- package/dist/app/entity-list-screen.js +547 -0
- package/dist/app/kumiko-screen.d.ts +1 -36
- package/dist/app/kumiko-screen.js +16 -2855
- package/dist/app/projection-detail-body.d.ts +12 -0
- package/dist/app/projection-detail-body.js +464 -0
- package/dist/app/projection-detail-shim.d.ts +1 -1
- package/dist/app/projection-detail-shim.js +5 -1
- package/dist/app/projection-list-body.d.ts +10 -0
- package/dist/app/projection-list-body.js +245 -0
- package/dist/app/projection-list-shim.d.ts +2 -1
- package/dist/app/projection-list-shim.js +4 -0
- package/dist/app/reference-facet-bridge.js +2 -2
- package/dist/app/row-actions.js +3 -4
- package/dist/app/screen-shared.d.ts +72 -0
- package/dist/app/screen-shared.js +325 -0
- package/dist/app/secret-mint-body.js +3 -3
- package/dist/components/edit-mounts.d.ts +33 -0
- package/dist/components/edit-mounts.js +53 -0
- package/dist/components/error-boundary.js +2 -2
- package/dist/components/reference-create-dialog.js +1 -1
- package/dist/components/related-list-section.js +29 -6
- package/dist/components/render-edit-helpers.d.ts +29 -0
- package/dist/components/render-edit-helpers.js +121 -0
- package/dist/components/render-edit.d.ts +1 -4
- package/dist/components/render-edit.js +41 -443
- package/dist/components/render-field.js +3 -4
- package/dist/components/render-list.d.ts +1 -1
- package/dist/components/render-list.js +2 -2
- package/dist/components/use-wizard-form-draft.d.ts +51 -0
- package/dist/components/use-wizard-form-draft.js +291 -0
- package/dist/dev-console.d.ts +3 -0
- package/dist/dev-console.js +15 -0
- package/dist/headless/contracts/primitives.js +14 -17
- package/dist/headless/format/index.js +3 -3
- package/dist/headless/view-model/edit.d.ts +1 -1
- package/dist/headless/view-model/edit.js +9 -16
- package/dist/headless/view-model/list.d.ts +1 -1
- package/dist/headless/view-model/list.js +3 -8
- package/dist/index.d.ts +2 -1
- package/dist/index.js +5 -5
- package/dist/live/error-mapping.js +3 -4
- package/dist/web/app/create-app.js +5 -8
- package/dist/web/app/dashboard-body.js +4 -599
- package/dist/web/app/dashboard-panels.d.ts +53 -0
- package/dist/web/app/dashboard-panels.js +373 -0
- package/dist/web/app/dashboard-shared.d.ts +90 -0
- package/dist/web/app/dashboard-shared.js +171 -0
- package/dist/web/app/dashboard-text.d.ts +6 -0
- package/dist/web/app/dashboard-text.js +65 -0
- package/dist/web/layout/nav-tree.js +3 -4
- package/dist/web/layout/target-resolver-stub.js +2 -2
- package/dist/web/primitives/banner.d.ts +4 -0
- package/dist/web/primitives/banner.js +28 -0
- package/dist/web/primitives/button.d.ts +7 -0
- package/dist/web/primitives/button.js +48 -0
- package/dist/web/primitives/card-styles.d.ts +8 -0
- package/dist/web/primitives/card-styles.js +18 -0
- package/dist/web/primitives/card.d.ts +4 -0
- package/dist/web/primitives/card.js +41 -0
- package/dist/web/primitives/contexts.d.ts +22 -0
- package/dist/web/primitives/contexts.js +50 -0
- package/dist/web/primitives/data-table-cell.d.ts +76 -0
- package/dist/web/primitives/data-table-cell.js +403 -0
- package/dist/web/primitives/data-table.d.ts +4 -0
- package/dist/web/primitives/data-table.js +279 -0
- package/dist/web/primitives/default-form.d.ts +4 -0
- package/dist/web/primitives/default-form.js +79 -0
- package/dist/web/primitives/facet-filter.d.ts +14 -0
- package/dist/web/primitives/facet-filter.js +39 -0
- package/dist/web/primitives/field.d.ts +63 -0
- package/dist/web/primitives/field.js +181 -0
- package/dist/web/primitives/form.d.ts +53 -0
- package/dist/web/primitives/form.js +252 -0
- package/dist/web/primitives/index.d.ts +7 -30
- package/dist/web/primitives/index.js +27 -2006
- package/dist/web/primitives/input.d.ts +4 -0
- package/dist/web/primitives/input.js +166 -0
- package/dist/web/primitives/layout-elements.d.ts +14 -0
- package/dist/web/primitives/layout-elements.js +194 -0
- package/dist/web/primitives/modal.js +1 -1
- package/dist/web/primitives/pager.d.ts +22 -0
- package/dist/web/primitives/pager.js +89 -0
- package/dist/web/primitives/row-actions.d.ts +13 -0
- package/dist/web/primitives/row-actions.js +178 -0
- package/dist/web/primitives/secret-reveal.d.ts +4 -0
- package/dist/web/primitives/secret-reveal.js +67 -0
- package/package.json +5 -5
- package/src/changes.json +6 -0
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
import { evalFieldCondition, isFieldsEditSection, normalizeEditField, sectionFieldSpecs, } from "@cosmicdrift/kumiko-framework/ui-types";
|
|
2
|
+
import { relevantFieldIssues, zodErrorToFieldIssues } from "../headless/index.js";
|
|
3
|
+
// End-to-end renderer for an entityEdit screen. Renders exclusively
|
|
4
|
+
// through primitives, no raw HTML. A native renderer that fills the same
|
|
5
|
+
// primitives registry gets the form without further changes.
|
|
6
|
+
function toConditionValue(cond) {
|
|
7
|
+
if (typeof cond === "boolean")
|
|
8
|
+
return cond;
|
|
9
|
+
// @cast-boundary form-values: TValues is structurally a record.
|
|
10
|
+
return (values) => evalFieldCondition(cond, values);
|
|
11
|
+
}
|
|
12
|
+
// Tab-strip key. The boot-validator makes `id` mandatory on a tabs layout and
|
|
13
|
+
// entityEdit only ever has "fields"/"extension" sections (relatedList and
|
|
14
|
+
// writeForm are rejected outright), so the positional fallback is unreachable
|
|
15
|
+
// for a tabs screen — it only keeps this total for other layouts.
|
|
16
|
+
export function tabIdAt(section, index) {
|
|
17
|
+
const declared = section?.kind === "fields" || section?.kind === "extension" ? section.id : undefined;
|
|
18
|
+
return declared ?? `section-${index}`;
|
|
19
|
+
}
|
|
20
|
+
export function deriveFormFields(screen) {
|
|
21
|
+
const out = {};
|
|
22
|
+
for (const section of screen.layout.sections) {
|
|
23
|
+
// relatedList carries no `fields` for the form-condition map either.
|
|
24
|
+
if (!isFieldsEditSection(section))
|
|
25
|
+
continue;
|
|
26
|
+
for (const spec of sectionFieldSpecs(section)) {
|
|
27
|
+
const normalized = normalizeEditField(spec);
|
|
28
|
+
out[normalized.field] = {
|
|
29
|
+
...(normalized.visible !== undefined && {
|
|
30
|
+
visible: toConditionValue(normalized.visible),
|
|
31
|
+
}),
|
|
32
|
+
...(normalized.readOnly !== undefined && {
|
|
33
|
+
readonly: toConditionValue(normalized.readOnly),
|
|
34
|
+
}),
|
|
35
|
+
...(normalized.required !== undefined && {
|
|
36
|
+
required: toConditionValue(normalized.required),
|
|
37
|
+
}),
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
return out;
|
|
42
|
+
}
|
|
43
|
+
// Dry-run parse against `schema` — NOT controller.validate(), which writes
|
|
44
|
+
// field errors into the snapshot. Undefined when the values parse cleanly.
|
|
45
|
+
// Parse once, then narrow per scope with scopedDryRunIssues: the wizard step
|
|
46
|
+
// check would otherwise re-parse the whole form per section on every keystroke.
|
|
47
|
+
export function dryRunParse(schema, snapshot) {
|
|
48
|
+
const parsed = schema.safeParse(snapshot.values);
|
|
49
|
+
if (parsed.success)
|
|
50
|
+
return undefined;
|
|
51
|
+
const hiddenFields = new Set(Object.entries(snapshot.fields)
|
|
52
|
+
.filter(([, state]) => !state.visible)
|
|
53
|
+
.map(([fieldKey]) => fieldKey));
|
|
54
|
+
return { issues: zodErrorToFieldIssues(parsed.error), hiddenFields };
|
|
55
|
+
}
|
|
56
|
+
// Issues are filtered exactly like the controller's validate(): hidden
|
|
57
|
+
// fields never count, `scope` narrows.
|
|
58
|
+
function scopedDryRunIssues(parse, scope, includeRoot) {
|
|
59
|
+
if (parse === undefined)
|
|
60
|
+
return [];
|
|
61
|
+
return relevantFieldIssues(parse.issues, {
|
|
62
|
+
hiddenFields: parse.hiddenFields,
|
|
63
|
+
...(scope !== undefined && { scope }),
|
|
64
|
+
includeRoot,
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
export function dryRunFieldIssues(schema, snapshot, scope, includeRoot) {
|
|
68
|
+
return scopedDryRunIssues(dryRunParse(schema, snapshot), scope, includeRoot);
|
|
69
|
+
}
|
|
70
|
+
// Index-independent: indices shift when a fields section hides.
|
|
71
|
+
export function wizardStepKey(section, index) {
|
|
72
|
+
const declaredId = section.kind === "fields" || section.kind === "extension" ? section.id : undefined;
|
|
73
|
+
return declaredId ?? section.title ?? `step-${index}`;
|
|
74
|
+
}
|
|
75
|
+
function isMoneyValue(value) {
|
|
76
|
+
return typeof value === "object" && value !== null && "amount" in value;
|
|
77
|
+
}
|
|
78
|
+
// The seeds buildInitialValues writes for NULL columns of an existing record.
|
|
79
|
+
function isEmptyFormValue(value) {
|
|
80
|
+
if (value === null || value === undefined || value === "" || value === 0 || value === false) {
|
|
81
|
+
return true;
|
|
82
|
+
}
|
|
83
|
+
if (Array.isArray(value))
|
|
84
|
+
return value.length === 0;
|
|
85
|
+
return isMoneyValue(value) && value.amount === 0;
|
|
86
|
+
}
|
|
87
|
+
// select/boolean are excluded from the "holds user data" check: they are
|
|
88
|
+
// often pre-filled (defaults, server-set values), so they say nothing about
|
|
89
|
+
// whether the step was filled in. They still count through the validation.
|
|
90
|
+
export function isFieldsStepFilled(section, parse) {
|
|
91
|
+
const fieldNames = section.fields.map((f) => f.field);
|
|
92
|
+
if (scopedDryRunIssues(parse, fieldNames, false).length > 0)
|
|
93
|
+
return false;
|
|
94
|
+
return section.fields.some((f) => f.visible &&
|
|
95
|
+
!f.readOnly &&
|
|
96
|
+
f.type !== "boolean" &&
|
|
97
|
+
f.type !== "select" &&
|
|
98
|
+
!isEmptyFormValue(f.value));
|
|
99
|
+
}
|
|
100
|
+
export function formSectionDomId(sectionIndex) {
|
|
101
|
+
return `form-section-${sectionIndex}`;
|
|
102
|
+
}
|
|
103
|
+
/** A record title is a non-blank string; anything else leaves the screen title alone. */
|
|
104
|
+
export function resolveRecordTitle(value) {
|
|
105
|
+
return typeof value === "string" && value.trim() !== "" ? value : undefined;
|
|
106
|
+
}
|
|
107
|
+
const TITLE_PLACEHOLDER_PATTERN = /\{(\w+)\}/g;
|
|
108
|
+
// Falls back to the plain title while any placeholder value is still empty,
|
|
109
|
+
// so the header never shows "Add " mid-typing.
|
|
110
|
+
export function resolveTitleTemplate(template, values, translate, fallback) {
|
|
111
|
+
if (template === undefined)
|
|
112
|
+
return fallback;
|
|
113
|
+
const placeholders = [...translate(template).matchAll(TITLE_PLACEHOLDER_PATTERN)].map((match) => match[1] ?? "");
|
|
114
|
+
const isFilled = (name) => {
|
|
115
|
+
const value = values[name];
|
|
116
|
+
return value !== undefined && value !== null && String(value).trim() !== "";
|
|
117
|
+
};
|
|
118
|
+
if (!placeholders.every(isFilled))
|
|
119
|
+
return fallback;
|
|
120
|
+
return translate(template, values);
|
|
121
|
+
}
|
|
@@ -1,8 +1,5 @@
|
|
|
1
|
+
import { type ReactNode } from "react";
|
|
1
2
|
import type { FormValues } from "../headless/index.ts";
|
|
2
3
|
import type { RenderEditProps } from "./render-edit-types.ts";
|
|
3
4
|
export type { RenderEditAction, RenderEditChangeState, RenderEditControls, RenderEditProps, } from "./render-edit-types.ts";
|
|
4
|
-
import { type ReactNode } from "react";
|
|
5
|
-
export declare const PATCH_DRAFT_SAVE_DEBOUNCE_MS = 500;
|
|
6
|
-
/** A record title is a non-blank string; anything else leaves the screen title alone. */
|
|
7
|
-
export declare function resolveRecordTitle(value: unknown): string | undefined;
|
|
8
5
|
export declare function RenderEdit<TValues extends FormValues, TCtx = unknown>(props: RenderEditProps<TValues, TCtx>): ReactNode;
|