@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,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;