@cosmicdrift/kumiko-renderer 0.328.0 → 0.328.1

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 (259) hide show
  1. package/dist/app/action-form-shim.d.ts +14 -0
  2. package/{src/app/action-form-shim.ts → dist/app/action-form-shim.js} +26 -46
  3. package/dist/app/app-features-context.d.ts +8 -0
  4. package/dist/app/app-features-context.js +16 -0
  5. package/dist/app/column-renderers.d.ts +30 -0
  6. package/dist/app/column-renderers.js +34 -0
  7. package/dist/app/config-edit-shim.d.ts +11 -0
  8. package/{src/app/config-edit-shim.ts → dist/app/config-edit-shim.js} +12 -25
  9. package/dist/app/content-editors.d.ts +38 -0
  10. package/dist/app/content-editors.js +26 -0
  11. package/dist/app/content-preview.d.ts +11 -0
  12. package/dist/app/content-preview.js +30 -0
  13. package/dist/app/custom-screens.d.ts +11 -0
  14. package/dist/app/custom-screens.js +20 -0
  15. package/dist/app/dashboard-body.d.ts +16 -0
  16. package/dist/app/dashboard-body.js +11 -0
  17. package/dist/app/extension-form-submit.d.ts +32 -0
  18. package/dist/app/extension-form-submit.js +73 -0
  19. package/dist/app/extension-sections.d.ts +72 -0
  20. package/dist/app/extension-sections.js +34 -0
  21. package/dist/app/feature-schema.d.ts +4 -0
  22. package/{src/app/feature-schema.ts → dist/app/feature-schema.js} +12 -22
  23. package/dist/app/form-schema.d.ts +4 -0
  24. package/dist/app/form-schema.js +85 -0
  25. package/dist/app/kumiko-screen.d.ts +43 -0
  26. package/dist/app/kumiko-screen.js +2206 -0
  27. package/dist/app/layout-fields.d.ts +3 -0
  28. package/dist/app/layout-fields.js +20 -0
  29. package/dist/app/list-facets.d.ts +48 -0
  30. package/dist/app/list-facets.js +185 -0
  31. package/dist/app/nav.d.ts +61 -0
  32. package/dist/app/nav.js +139 -0
  33. package/dist/app/projection-detail-shim.d.ts +8 -0
  34. package/dist/app/projection-detail-shim.js +71 -0
  35. package/dist/app/projection-list-shim.d.ts +13 -0
  36. package/{src/app/projection-list-shim.ts → dist/app/projection-list-shim.js} +26 -41
  37. package/dist/app/qn.d.ts +7 -0
  38. package/{src/app/qn.ts → dist/app/qn.js} +9 -11
  39. package/dist/app/qualify-screen-id.d.ts +2 -0
  40. package/{src/app/qualify-screen-id.ts → dist/app/qualify-screen-id.js} +5 -6
  41. package/dist/app/reference-facet-bridge.d.ts +10 -0
  42. package/dist/app/reference-facet-bridge.js +22 -0
  43. package/dist/app/return-to.d.ts +31 -0
  44. package/dist/app/return-to.js +188 -0
  45. package/dist/app/row-actions.d.ts +77 -0
  46. package/dist/app/row-actions.js +416 -0
  47. package/dist/app/screen-access.d.ts +8 -0
  48. package/dist/app/screen-access.js +48 -0
  49. package/dist/app/secret-mint-body.d.ts +10 -0
  50. package/dist/app/secret-mint-body.js +140 -0
  51. package/dist/app/secrets-edit-body.d.ts +8 -0
  52. package/dist/app/secrets-edit-body.js +76 -0
  53. package/dist/app/use-embedded-screen.d.ts +6 -0
  54. package/dist/app/use-embedded-screen.js +19 -0
  55. package/dist/app/variable-chips.d.ts +7 -0
  56. package/dist/app/variable-chips.js +16 -0
  57. package/dist/app/write-failed-error.d.ts +6 -0
  58. package/dist/app/write-failed-error.js +21 -0
  59. package/dist/components/embedded-list-field.d.ts +10 -0
  60. package/dist/components/embedded-list-field.js +259 -0
  61. package/dist/components/grid-cell-for-field.d.ts +25 -0
  62. package/dist/components/grid-cell-for-field.js +31 -0
  63. package/dist/components/multi-select-checkboxes.d.ts +14 -0
  64. package/dist/components/multi-select-checkboxes.js +36 -0
  65. package/dist/components/reference-create-dialog.d.ts +13 -0
  66. package/dist/components/reference-create-dialog.js +46 -0
  67. package/dist/components/related-list-section.d.ts +25 -0
  68. package/dist/components/related-list-section.js +273 -0
  69. package/dist/components/render-edit-action-button.d.ts +22 -0
  70. package/dist/components/render-edit-action-button.js +43 -0
  71. package/dist/components/render-edit-logic.d.ts +6 -0
  72. package/dist/components/render-edit-logic.js +63 -0
  73. package/dist/components/render-edit-types.d.ts +209 -0
  74. package/dist/components/render-edit-types.js +1 -0
  75. package/dist/components/render-edit.d.ts +6 -0
  76. package/dist/components/render-edit.js +1169 -0
  77. package/dist/components/render-field.d.ts +38 -0
  78. package/dist/components/render-field.js +544 -0
  79. package/dist/components/render-list.d.ts +117 -0
  80. package/dist/components/render-list.js +232 -0
  81. package/dist/components/write-form-section.d.ts +17 -0
  82. package/dist/components/write-form-section.js +104 -0
  83. package/dist/context/dispatcher-context.d.ts +10 -0
  84. package/{src/context/dispatcher-context.tsx → dist/context/dispatcher-context.js} +16 -29
  85. package/dist/context/draft-storage-context.d.ts +12 -0
  86. package/dist/context/draft-storage-context.js +18 -0
  87. package/dist/context/user-roles-context.d.ts +7 -0
  88. package/{src/context/user-roles-context.tsx → dist/context/user-roles-context.js} +7 -15
  89. package/dist/format-when.d.ts +1 -0
  90. package/{src/format-when.ts → dist/format-when.js} +7 -7
  91. package/dist/hooks/reference-limits.d.ts +3 -0
  92. package/{src/hooks/reference-limits.ts → dist/hooks/reference-limits.js} +0 -1
  93. package/dist/hooks/use-ai-text.d.ts +52 -0
  94. package/dist/hooks/use-ai-text.js +90 -0
  95. package/dist/hooks/use-disclosure.d.ts +7 -0
  96. package/dist/hooks/use-disclosure.js +8 -0
  97. package/dist/hooks/use-form.d.ts +7 -0
  98. package/dist/hooks/use-form.js +36 -0
  99. package/dist/hooks/use-list-url-state.d.ts +43 -0
  100. package/dist/hooks/use-list-url-state.js +131 -0
  101. package/dist/hooks/use-mutation.d.ts +9 -0
  102. package/dist/hooks/use-mutation.js +37 -0
  103. package/dist/hooks/use-query.d.ts +14 -0
  104. package/dist/hooks/use-query.js +118 -0
  105. package/dist/hooks/use-reference-lookup.d.ts +14 -0
  106. package/dist/hooks/use-reference-lookup.js +63 -0
  107. package/dist/hooks/use-store.d.ts +3 -0
  108. package/dist/hooks/use-store.js +38 -0
  109. package/dist/hooks/use-stream-handler.d.ts +14 -0
  110. package/dist/hooks/use-stream-handler.js +93 -0
  111. package/dist/i18n-defaults.d.ts +2 -0
  112. package/dist/i18n-defaults.js +201 -0
  113. package/dist/i18n.d.ts +64 -0
  114. package/dist/i18n.js +166 -0
  115. package/dist/index.d.ts +77 -0
  116. package/dist/index.js +55 -0
  117. package/dist/inside-drawer.d.ts +2 -0
  118. package/{src/inside-drawer.ts → dist/inside-drawer.js} +2 -5
  119. package/dist/page-header-slot.d.ts +2 -0
  120. package/{src/page-header-slot.ts → dist/page-header-slot.js} +2 -5
  121. package/dist/primitives.d.ts +1351 -0
  122. package/dist/primitives.js +73 -0
  123. package/dist/screen-fills-height.d.ts +3 -0
  124. package/dist/screen-fills-height.js +3 -0
  125. package/dist/share-links.d.ts +4 -0
  126. package/dist/share-links.js +11 -0
  127. package/dist/sort-by-accessor.d.ts +5 -0
  128. package/dist/sort-by-accessor.js +16 -0
  129. package/dist/sse/live-events.d.ts +23 -0
  130. package/dist/sse/live-events.js +28 -0
  131. package/dist/tokens.d.ts +83 -0
  132. package/dist/tokens.js +80 -0
  133. package/package.json +16 -9
  134. package/src/__tests__/error-i18n-defaults.test.ts +0 -82
  135. package/src/__tests__/format-when.test.ts +0 -12
  136. package/src/__tests__/i18n.test.tsx +0 -283
  137. package/src/__tests__/merge-search-params-into-initial.test.ts +0 -525
  138. package/src/__tests__/qn.test.ts +0 -83
  139. package/src/__tests__/share-links.test.ts +0 -26
  140. package/src/__tests__/sort-by-accessor.test.ts +0 -48
  141. package/src/__tests__/stringify-nav-params.test.ts +0 -33
  142. package/src/__tests__/use-list-url-state.test.tsx +0 -250
  143. package/src/app/__tests__/action-form-field-labels.test.tsx +0 -92
  144. package/src/app/__tests__/action-form-shim.test.ts +0 -137
  145. package/src/app/__tests__/build-list-query-payload.test.ts +0 -107
  146. package/src/app/__tests__/config-edit-shim.test.ts +0 -57
  147. package/src/app/__tests__/content-editors.test.tsx +0 -128
  148. package/src/app/__tests__/content-preview.test.tsx +0 -184
  149. package/src/app/__tests__/entity-edit-create-search-params.test.tsx +0 -236
  150. package/src/app/__tests__/entity-edit-fill-height.test.tsx +0 -118
  151. package/src/app/__tests__/entity-edit-jsonb-embedded-submit.test.tsx +0 -239
  152. package/src/app/__tests__/entity-list-create-singleton.test.tsx +0 -128
  153. package/src/app/__tests__/entity-list-row-action-entity-target.test.tsx +0 -424
  154. package/src/app/__tests__/entity-list-row-action-icon.test.tsx +0 -248
  155. package/src/app/__tests__/entity-list-row-action-kumiko-actions-view.test.tsx +0 -162
  156. package/src/app/__tests__/entity-list-row-action-refetch.test.tsx +0 -401
  157. package/src/app/__tests__/entity-list-screen-padding.test.tsx +0 -128
  158. package/src/app/__tests__/feature-schema.test.ts +0 -40
  159. package/src/app/__tests__/form-schema.test.ts +0 -247
  160. package/src/app/__tests__/list-daterange-facet.test.ts +0 -165
  161. package/src/app/__tests__/list-filter-facets.test.tsx +0 -521
  162. package/src/app/__tests__/nav.test.ts +0 -198
  163. package/src/app/__tests__/projection-detail-actions.test.tsx +0 -719
  164. package/src/app/__tests__/projection-detail-reference-field.test.tsx +0 -165
  165. package/src/app/__tests__/projection-detail-shim.test.ts +0 -188
  166. package/src/app/__tests__/projection-detail-singleton.test.tsx +0 -191
  167. package/src/app/__tests__/projection-list-bad-shape.test.tsx +0 -152
  168. package/src/app/__tests__/projection-list-reference-column.test.tsx +0 -219
  169. package/src/app/__tests__/projection-list-search-sort.test.tsx +0 -212
  170. package/src/app/__tests__/qualified-names.test.ts +0 -37
  171. package/src/app/__tests__/return-to.test.ts +0 -396
  172. package/src/app/__tests__/row-actions-navigate-tab.test.ts +0 -223
  173. package/src/app/__tests__/row-default-edit-action.test.tsx +0 -324
  174. package/src/app/__tests__/screen-access-allows.test.ts +0 -34
  175. package/src/app/__tests__/secret-mint-body.test.tsx +0 -404
  176. package/src/app/__tests__/variable-chips.test.tsx +0 -70
  177. package/src/app/app-features-context.tsx +0 -25
  178. package/src/app/column-renderers.tsx +0 -68
  179. package/src/app/content-editors.tsx +0 -85
  180. package/src/app/content-preview.tsx +0 -67
  181. package/src/app/custom-screens.tsx +0 -29
  182. package/src/app/dashboard-body.tsx +0 -33
  183. package/src/app/extension-form-submit.tsx +0 -123
  184. package/src/app/extension-sections.tsx +0 -111
  185. package/src/app/form-schema.ts +0 -91
  186. package/src/app/kumiko-screen.tsx +0 -3801
  187. package/src/app/layout-fields.ts +0 -31
  188. package/src/app/list-facets.ts +0 -259
  189. package/src/app/nav.tsx +0 -258
  190. package/src/app/projection-detail-shim.ts +0 -86
  191. package/src/app/reference-facet-bridge.tsx +0 -58
  192. package/src/app/return-to.tsx +0 -234
  193. package/src/app/row-actions.ts +0 -640
  194. package/src/app/screen-access.ts +0 -63
  195. package/src/app/secret-mint-body.tsx +0 -259
  196. package/src/app/secrets-edit-body.tsx +0 -194
  197. package/src/app/use-embedded-screen.ts +0 -27
  198. package/src/app/variable-chips.tsx +0 -39
  199. package/src/app/write-failed-error.ts +0 -27
  200. package/src/components/__tests__/embedded-list-field.test.tsx +0 -531
  201. package/src/components/__tests__/multi-select-checkboxes.test.tsx +0 -162
  202. package/src/components/__tests__/related-list-section-empty-state.test.tsx +0 -143
  203. package/src/components/__tests__/related-list-section.test.tsx +0 -1733
  204. package/src/components/__tests__/render-edit-action-button.test.tsx +0 -205
  205. package/src/components/__tests__/render-edit-hidden-section.test.tsx +0 -128
  206. package/src/components/__tests__/render-edit-logic.test.ts +0 -314
  207. package/src/components/__tests__/render-edit-screen-description.test.tsx +0 -152
  208. package/src/components/__tests__/render-edit-submit-actions.test.tsx +0 -460
  209. package/src/components/__tests__/render-field-app-locale.test.tsx +0 -142
  210. package/src/components/__tests__/render-field-enum-option.test.tsx +0 -99
  211. package/src/components/__tests__/render-field-icon-derivation.test.tsx +0 -119
  212. package/src/components/__tests__/render-field-json-format.test.tsx +0 -164
  213. package/src/components/__tests__/render-field-money-embedded-list-consistency.test.tsx +0 -212
  214. package/src/components/__tests__/render-field-money-roundtrip.test.tsx +0 -217
  215. package/src/components/__tests__/render-field-number-grouping.test.tsx +0 -76
  216. package/src/components/__tests__/render-field-number-unit.test.tsx +0 -227
  217. package/src/components/__tests__/render-field-password-format.test.tsx +0 -101
  218. package/src/components/__tests__/render-field-select-display.test.tsx +0 -134
  219. package/src/components/__tests__/render-field-unit-format.test.tsx +0 -107
  220. package/src/components/__tests__/render-field-unsupported-types.test.tsx +0 -195
  221. package/src/components/__tests__/render-list-toolbar-icon-only.test.tsx +0 -146
  222. package/src/components/__tests__/write-form-section.test.tsx +0 -375
  223. package/src/components/embedded-list-field.tsx +0 -354
  224. package/src/components/grid-cell-for-field.tsx +0 -88
  225. package/src/components/multi-select-checkboxes.tsx +0 -93
  226. package/src/components/reference-create-dialog.tsx +0 -91
  227. package/src/components/related-list-section.tsx +0 -491
  228. package/src/components/render-edit-action-button.tsx +0 -109
  229. package/src/components/render-edit-logic.ts +0 -85
  230. package/src/components/render-edit-types.ts +0 -226
  231. package/src/components/render-edit.tsx +0 -1871
  232. package/src/components/render-field.tsx +0 -951
  233. package/src/components/render-list.tsx +0 -593
  234. package/src/components/write-form-section.tsx +0 -198
  235. package/src/context/draft-storage-context.tsx +0 -39
  236. package/src/hooks/__tests__/use-ai-text.test.tsx +0 -177
  237. package/src/hooks/__tests__/use-disclosure.test.tsx +0 -25
  238. package/src/hooks/__tests__/use-form.test.tsx +0 -65
  239. package/src/hooks/__tests__/use-mutation.test.tsx +0 -77
  240. package/src/hooks/__tests__/use-query.test.tsx +0 -149
  241. package/src/hooks/__tests__/use-stream-handler.test.tsx +0 -107
  242. package/src/hooks/use-ai-text.ts +0 -172
  243. package/src/hooks/use-disclosure.ts +0 -20
  244. package/src/hooks/use-form.ts +0 -78
  245. package/src/hooks/use-list-url-state.ts +0 -207
  246. package/src/hooks/use-mutation.ts +0 -61
  247. package/src/hooks/use-query.ts +0 -166
  248. package/src/hooks/use-reference-lookup.ts +0 -76
  249. package/src/hooks/use-store.ts +0 -48
  250. package/src/hooks/use-stream-handler.ts +0 -134
  251. package/src/i18n-defaults.ts +0 -240
  252. package/src/i18n.tsx +0 -286
  253. package/src/index.ts +0 -279
  254. package/src/primitives.tsx +0 -1567
  255. package/src/screen-fills-height.ts +0 -3
  256. package/src/share-links.ts +0 -12
  257. package/src/sort-by-accessor.ts +0 -20
  258. package/src/sse/live-events.tsx +0 -56
  259. package/src/tokens.tsx +0 -170
@@ -0,0 +1,34 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { createContext, useContext } from "react";
3
+ /** Extrahiert den `__component`-Namen aus einer PlatformComponent. Liest
4
+ * react- und native-Branch (die App-Author registriert beide unter dem
5
+ * gleichen Namen); returnt den ersten gefundenen string. Pure narrowing
6
+ * via `in` — kein cast, kein assertion. */
7
+ export function extensionSectionName(component) {
8
+ for (const branch of [component.react, component.native]) {
9
+ if (branch !== null && typeof branch === "object" && "__component" in branch) {
10
+ const candidate = branch.__component;
11
+ if (typeof candidate === "string")
12
+ return candidate;
13
+ }
14
+ }
15
+ return undefined;
16
+ }
17
+ const ExtensionSectionsContext = createContext(undefined);
18
+ export function ExtensionSectionsProvider({ children, value, }) {
19
+ return (_jsx(ExtensionSectionsContext.Provider, { value: value, children: children }));
20
+ }
21
+ /** Schaut die Component für einen extension-section-Namen nach. Returnt
22
+ * undefined wenn weder Provider gemounted noch der Name in der Map
23
+ * registriert ist — der Caller (RenderEdit) zeigt dann seinen
24
+ * Placeholder-Banner. `name` ist optional damit Caller den Hook
25
+ * unkonditional aufrufen können (Rules-of-Hooks), ohne einen Stub-Key
26
+ * wie `""` reichen zu müssen — analog `useColumnRenderer`. */
27
+ export function useExtensionSectionComponent(name) {
28
+ const map = useContext(ExtensionSectionsContext);
29
+ if (name === undefined || name === "")
30
+ return undefined;
31
+ if (map === undefined)
32
+ return undefined;
33
+ return map[name];
34
+ }
@@ -0,0 +1,4 @@
1
+ import type { AppSchema, FeatureSchema, QualifiedContentCollection, WorkspaceSchema } from "@cosmicdrift/kumiko-framework/ui-types";
2
+ export type { AppSchema, FeatureSchema, QualifiedContentCollection, WorkspaceSchema };
3
+ export declare function toAppSchema(input: FeatureSchema | AppSchema): AppSchema;
4
+ export declare function isAppSchema(input: FeatureSchema | AppSchema): input is AppSchema;
@@ -21,40 +21,30 @@
21
21
  // };
22
22
  //
23
23
  // // feature.ts (server-only — imports defineFeature)
24
- // import { taskEntity, editScreen, ... } from "./feature-schema";
24
+ // import { taskEntity, editScreen, ... } from "./feature-schema.js";
25
25
  // export const taskFeature = defineFeature("tasks", (r) => {
26
26
  // r.entity("task", taskEntity);
27
27
  // r.writeHandler(...);
28
28
  // r.screen(editScreen);
29
29
  // ...
30
30
  // });
31
-
32
- import type {
33
- AppSchema,
34
- FeatureSchema,
35
- QualifiedContentCollection,
36
- WorkspaceSchema,
37
- } from "@cosmicdrift/kumiko-framework/ui-types";
38
-
39
- export type { AppSchema, FeatureSchema, QualifiedContentCollection, WorkspaceSchema };
40
-
41
31
  // Normalisiert FeatureSchema → AppSchema. Idempotent für AppSchema.
42
32
  // Hebt eine Feature-lokal deklarierte `workspaces`-Liste (Legacy) auf
43
33
  // App-Ebene hoch, damit alle Layouts mit der neuen Form arbeiten können
44
34
  // ohne dass alte clientSchemas migriert werden müssen.
45
- export function toAppSchema(input: FeatureSchema | AppSchema): AppSchema {
46
- if ("features" in input) return input;
47
- // Old single-feature shape — wrap.
48
- const { workspaces, ...feature } = input;
49
- return {
50
- features: [feature],
51
- ...(workspaces !== undefined && { workspaces }),
52
- };
35
+ export function toAppSchema(input) {
36
+ if ("features" in input)
37
+ return input;
38
+ // Old single-feature shape — wrap.
39
+ const { workspaces, ...feature } = input;
40
+ return {
41
+ features: [feature],
42
+ ...(workspaces !== undefined && { workspaces }),
43
+ };
53
44
  }
54
-
55
45
  // TypeGuard — Caller die schon zur Laufzeit unterscheiden müssen
56
46
  // (selten; meist reicht toAppSchema). Nicht via `"features" in x` inline
57
47
  // machen — narrow'd TS dann auf den join-Typ statt die echte Differenz.
58
- export function isAppSchema(input: FeatureSchema | AppSchema): input is AppSchema {
59
- return "features" in input;
48
+ export function isAppSchema(input) {
49
+ return "features" in input;
60
50
  }
@@ -0,0 +1,4 @@
1
+ import type { EntityDefinition, EntityEditScreenDefinition } from "@cosmicdrift/kumiko-framework/ui-types";
2
+ import * as z from "zod";
3
+ export declare const REQUIRED_FIELD_I18N_KEY = "kumiko.validation.required";
4
+ export declare function buildFormSchema(entity: EntityDefinition, screen: EntityEditScreenDefinition): z.ZodType;
@@ -0,0 +1,85 @@
1
+ import { evalFieldCondition, NO_WIDGET_FIELD_TYPES } from "@cosmicdrift/kumiko-framework/ui-types";
2
+ import { I18N_KEY_PARAM } from "@cosmicdrift/kumiko-headless";
3
+ import * as z from "zod";
4
+ import { layoutEditFields } from "./layout-fields.js";
5
+ // `required` means "has a value", not "is truthy" — `false` and `0` count
6
+ // as present, only the actually-empty representations don't.
7
+ function isPresent(value) {
8
+ if (value === undefined || value === null || value === "")
9
+ return false;
10
+ if (Array.isArray(value) && value.length === 0)
11
+ return false;
12
+ return true;
13
+ }
14
+ function isEmbeddedListField(field) {
15
+ return field.type === "embedded" && field.multiple === true;
16
+ }
17
+ // Renders raw to the user without a de+en default in i18n-defaults.ts.
18
+ export const REQUIRED_FIELD_I18N_KEY = "kumiko.validation.required";
19
+ // Client-side presence validation for the auto-wired entityEdit path —
20
+ // checks that every rendered required field HAS a value, not that the
21
+ // value has the right shape. Format/range/type validation stays server-
22
+ // authoritative (buildInsertSchema/buildUpdateSchema): the form-state
23
+ // representation of a value can diverge from the server-payload shape (e.g.
24
+ // money is `{amount,currency}`, not a bare number), so a format check here
25
+ // would either reject valid values or need per-representation branches that
26
+ // rot the moment either side changes.
27
+ //
28
+ // One `superRefine` instead of a per-field shape: a field-level `.refine()`
29
+ // wouldn't run at all for a key that's simply absent from `values` —
30
+ // `superRefine` sees the whole object and catches that case too.
31
+ // `.passthrough()` is load-bearing: the default `z.object({})` STRIPS every
32
+ // key (there's no declared shape), so `superRefine` would see an empty
33
+ // object regardless of what was actually submitted — every required field
34
+ // would misreport as missing.
35
+ //
36
+ // Iterates the screen's layout field specs, not `entity.fields` — `required`
37
+ // and `readOnly` are per-spec, evaluated against the current values the
38
+ // same way `view-model/edit.ts` resolves them for the rendered form. Not
39
+ // checked here: `visible`. `runValidate` already filters issues on hidden
40
+ // fields via `computeFieldStates(options.fields, …)` (form-controller.ts:163,181),
41
+ // fed by `deriveFormFields(screen)` in render-edit.tsx.
42
+ export function buildFormSchema(entity, screen) {
43
+ const fields = layoutEditFields(screen);
44
+ return z
45
+ .object({})
46
+ .passthrough()
47
+ .superRefine((values, ctx) => {
48
+ // `.passthrough()` types `values` as a plain object but doesn't declare
49
+ // its keys — the runtime object always carries every form field.
50
+ // @cast-boundary form-values
51
+ const record = values;
52
+ for (const spec of fields) {
53
+ const field = entity.fields[spec.field];
54
+ if (!field)
55
+ continue;
56
+ // Not operable by the user — a presence error would be unresolvable,
57
+ // same reason as the NO_WIDGET_FIELD_TYPES check below.
58
+ if (spec.readOnly !== undefined && evalFieldCondition(spec.readOnly, record))
59
+ continue;
60
+ // Screen-spec `required` overrides the entity default, mirroring
61
+ // `view-model/edit.ts` — the rendered form is the reference, and a
62
+ // presence check stricter than the form blocks the user for nothing.
63
+ const entityRequired = "required" in field && field.required === true;
64
+ const isRequired = spec.required === undefined ? entityRequired : evalFieldCondition(spec.required, record);
65
+ if (!isRequired)
66
+ continue;
67
+ // Embedded LIST fields get their own EmbeddedListField grid widget
68
+ // (#1838) — they're fillable, so NO_WIDGET_FIELD_TYPES's "embedded"
69
+ // entry must not exempt them. A statically-`required: true` field
70
+ // with no bound widget is also caught at boot
71
+ // (validateNoWidgetRequiredField in boot-validator/screens.ts).
72
+ if (NO_WIDGET_FIELD_TYPES.includes(field.type) && !isEmbeddedListField(field))
73
+ continue;
74
+ if (isPresent(record[spec.field]))
75
+ continue;
76
+ ctx.addIssue({
77
+ code: "custom",
78
+ path: [spec.field],
79
+ message: `"${spec.field}" is required.`,
80
+ // I18N_KEY_PARAM override, see packages/headless/src/form/zod-bridge.ts.
81
+ params: { [I18N_KEY_PARAM]: REQUIRED_FIELD_I18N_KEY },
82
+ });
83
+ }
84
+ });
85
+ }
@@ -0,0 +1,43 @@
1
+ import type { ScreenDefinition } from "@cosmicdrift/kumiko-framework/ui-types";
2
+ import type { ListRowViewModel, Translate } from "@cosmicdrift/kumiko-headless";
3
+ import { type ReactNode } from "react";
4
+ import { type ListSort } from "../hooks/use-list-url-state.js";
5
+ import type { FeatureSchema } from "./feature-schema.js";
6
+ import { qualifyScreenId } from "./qualify-screen-id.js";
7
+ import { screenAccessAllows } from "./screen-access.js";
8
+ export type KumikoScreenProps = {
9
+ readonly schema: FeatureSchema;
10
+ readonly qn: string;
11
+ readonly translate?: Translate;
12
+ readonly entityId?: string;
13
+ readonly onRowClick?: (row: ListRowViewModel, entityName: string) => void;
14
+ readonly onCopyLink?: () => Promise<void> | void;
15
+ };
16
+ export { qualifyScreenId };
17
+ /** Mirrors qualifyScreenId for nav QNs (registry form `<feature>:nav:<short-id>`).
18
+ * Callers building QNs (e.g. the WorkspaceShell resolver) should use this instead of string-concat, so a QN-schema change only touches one place. */
19
+ export declare function qualifyNavId(featureName: string, navId: string): string;
20
+ export { screenAccessAllows };
21
+ export declare function KumikoScreen({ schema, qn, translate, entityId, onRowClick, onCopyLink, }: KumikoScreenProps): ReactNode;
22
+ export declare function buildInitialValues(fields: Readonly<Record<string, unknown>>, defaultCurrency?: string, moneyCurrencyOverrides?: Readonly<Record<string, string>>): Readonly<Record<string, unknown>>;
23
+ export declare function literalCurrencyOverrides(fields: Readonly<Record<string, unknown>>): Readonly<Record<string, string>>;
24
+ export type InitialValueSources = {
25
+ readonly searchParams: Readonly<Record<string, string>>;
26
+ readonly urlPrefillFields: readonly string[] | undefined;
27
+ readonly renderableFields?: ReadonlySet<string>;
28
+ readonly defaultCurrency?: string;
29
+ readonly moneyCurrencyOverrides?: Readonly<Record<string, string>>;
30
+ readonly drawerOverrides?: Readonly<Record<string, unknown>>;
31
+ readonly handoffValues?: Readonly<Record<string, unknown>>;
32
+ };
33
+ export declare function mergeSearchParamsIntoInitial(fields: Readonly<Record<string, unknown>>, sources: InitialValueSources): Record<string, unknown>;
34
+ export declare function buildListQueryPayload(state: {
35
+ readonly limit: number;
36
+ readonly search: string;
37
+ readonly sort: ListSort | null;
38
+ readonly usePager: boolean;
39
+ readonly page: number;
40
+ readonly useInfinite: boolean;
41
+ readonly cursor: string | undefined;
42
+ }): Record<string, unknown>;
43
+ export type { ScreenDefinition };