@cosmicdrift/kumiko-renderer 0.327.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 (257) 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 -44
  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 -38
  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/dist/inside-drawer.js +9 -0
  119. package/dist/page-header-slot.d.ts +2 -0
  120. package/dist/page-header-slot.js +9 -0
  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/changes.json +52 -0
  135. package/src/__tests__/error-i18n-defaults.test.ts +0 -82
  136. package/src/__tests__/format-when.test.ts +0 -12
  137. package/src/__tests__/i18n.test.tsx +0 -283
  138. package/src/__tests__/merge-search-params-into-initial.test.ts +0 -525
  139. package/src/__tests__/qn.test.ts +0 -83
  140. package/src/__tests__/share-links.test.ts +0 -26
  141. package/src/__tests__/sort-by-accessor.test.ts +0 -48
  142. package/src/__tests__/stringify-nav-params.test.ts +0 -33
  143. package/src/__tests__/use-list-url-state.test.tsx +0 -250
  144. package/src/app/__tests__/action-form-field-labels.test.tsx +0 -92
  145. package/src/app/__tests__/action-form-shim.test.ts +0 -137
  146. package/src/app/__tests__/build-list-query-payload.test.ts +0 -107
  147. package/src/app/__tests__/config-edit-shim.test.ts +0 -57
  148. package/src/app/__tests__/content-editors.test.tsx +0 -128
  149. package/src/app/__tests__/content-preview.test.tsx +0 -184
  150. package/src/app/__tests__/entity-edit-create-search-params.test.tsx +0 -236
  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 -111
  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 -3614
  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 -85
  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 -639
  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 -1669
  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 -60
  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 -467
  228. package/src/components/render-edit-action-button.tsx +0 -106
  229. package/src/components/render-edit-logic.ts +0 -85
  230. package/src/components/render-edit-types.ts +0 -216
  231. package/src/components/render-edit.tsx +0 -1700
  232. package/src/components/render-field.tsx +0 -942
  233. package/src/components/render-list.tsx +0 -561
  234. package/src/components/write-form-section.tsx +0 -199
  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-stream-handler.test.tsx +0 -107
  241. package/src/hooks/use-ai-text.ts +0 -172
  242. package/src/hooks/use-disclosure.ts +0 -20
  243. package/src/hooks/use-form.ts +0 -78
  244. package/src/hooks/use-list-url-state.ts +0 -171
  245. package/src/hooks/use-mutation.ts +0 -61
  246. package/src/hooks/use-query.ts +0 -132
  247. package/src/hooks/use-reference-lookup.ts +0 -76
  248. package/src/hooks/use-store.ts +0 -48
  249. package/src/hooks/use-stream-handler.ts +0 -134
  250. package/src/i18n-defaults.ts +0 -220
  251. package/src/i18n.tsx +0 -286
  252. package/src/index.ts +0 -272
  253. package/src/primitives.tsx +0 -1446
  254. package/src/share-links.ts +0 -12
  255. package/src/sort-by-accessor.ts +0 -20
  256. package/src/sse/live-events.tsx +0 -56
  257. package/src/tokens.tsx +0 -170
@@ -0,0 +1,14 @@
1
+ import type { ActionFormScreenDefinition, EntityDefinition, EntityEditScreenDefinition, FieldDefinition, SecretMintConfirmStep, SecretMintScreenDefinition } from "@cosmicdrift/kumiko-framework/ui-types";
2
+ /** Baut eine minimale EntityDefinition aus den Inline-Fields eines
3
+ * ActionForm- oder SecretMint-Screens. RenderEdit + computeEditViewModel
4
+ * iterieren über entity.fields zur Render-Zeit; alle weiteren
5
+ * EntityDefinition-Felder bleiben undefined. */
6
+ export declare function synthesizeActionFormEntity(fields: Readonly<Record<string, FieldDefinition>>): EntityDefinition;
7
+ /** Wandelt ein ActionFormScreenDefinition oder SecretMintScreenDefinition in
8
+ * die EntityEditScreen-Shape die RenderEdit erwartet. type wird auf
9
+ * "entityEdit" gesetzt damit der Type-Constraint hält; entity wird auf den
10
+ * Pseudo-Namen gepinnt — RenderEdit liest das Feld nicht. */
11
+ export declare function synthesizeActionFormScreen(screen: ActionFormScreenDefinition | SecretMintScreenDefinition): EntityEditScreenDefinition;
12
+ /** Separate id (`${screen.id}:confirm`) keeps this confirm-form screen from
13
+ * colliding with the mint-form screen's draft key. */
14
+ export declare function synthesizeSecretMintConfirmScreen(screen: SecretMintScreenDefinition, confirm: SecretMintConfirmStep): EntityEditScreenDefinition;
@@ -14,61 +14,43 @@
14
14
  // RenderActionForm-Komponente, die `fields` direkt als Input nimmt.
15
15
  // Der Boot-Validator kennt actionForm bereits eigenständig (kein
16
16
  // entity-Lookup), also ist der Server-Pfad davon nicht betroffen.
17
-
18
- import type {
19
- ActionFormScreenDefinition,
20
- EntityDefinition,
21
- EntityEditScreenDefinition,
22
- FieldDefinition,
23
- SecretMintConfirmStep,
24
- SecretMintScreenDefinition,
25
- } from "@cosmicdrift/kumiko-framework/ui-types";
26
-
27
17
  const ACTION_FORM_PSEUDO_ENTITY = "__action-form__";
28
-
29
18
  /** Baut eine minimale EntityDefinition aus den Inline-Fields eines
30
19
  * ActionForm- oder SecretMint-Screens. RenderEdit + computeEditViewModel
31
20
  * iterieren über entity.fields zur Render-Zeit; alle weiteren
32
21
  * EntityDefinition-Felder bleiben undefined. */
33
- export function synthesizeActionFormEntity(
34
- fields: Readonly<Record<string, FieldDefinition>>,
35
- ): EntityDefinition {
36
- return { fields } as EntityDefinition;
22
+ export function synthesizeActionFormEntity(fields) {
23
+ return { fields };
37
24
  }
38
-
39
25
  /** Wandelt ein ActionFormScreenDefinition oder SecretMintScreenDefinition in
40
26
  * die EntityEditScreen-Shape die RenderEdit erwartet. type wird auf
41
27
  * "entityEdit" gesetzt damit der Type-Constraint hält; entity wird auf den
42
28
  * Pseudo-Namen gepinnt — RenderEdit liest das Feld nicht. */
43
- export function synthesizeActionFormScreen(
44
- screen: ActionFormScreenDefinition | SecretMintScreenDefinition,
45
- ): EntityEditScreenDefinition {
46
- return {
47
- id: screen.id,
48
- type: "entityEdit",
49
- entity: ACTION_FORM_PSEUDO_ENTITY,
50
- layout: screen.layout,
51
- ...(screen.description !== undefined && { description: screen.description }),
52
- ...(screen.access !== undefined && { access: screen.access }),
53
- // Only ActionFormScreenDefinition carries slots/fieldLabels; `in` narrows
54
- // without a cast since SecretMintScreenDefinition has neither.
55
- ...("slots" in screen && screen.slots !== undefined && { slots: screen.slots }),
56
- ...("fieldLabels" in screen &&
57
- screen.fieldLabels !== undefined && { fieldLabels: screen.fieldLabels }),
58
- };
29
+ export function synthesizeActionFormScreen(screen) {
30
+ return {
31
+ id: screen.id,
32
+ type: "entityEdit",
33
+ entity: ACTION_FORM_PSEUDO_ENTITY,
34
+ layout: screen.layout,
35
+ ...(screen.description !== undefined && { description: screen.description }),
36
+ ...(screen.access !== undefined && { access: screen.access }),
37
+ // Only ActionFormScreenDefinition carries slots/fieldLabels; `in` narrows
38
+ // without a cast since SecretMintScreenDefinition has neither.
39
+ ...("slots" in screen && screen.slots !== undefined && { slots: screen.slots }),
40
+ ...("fillHeight" in screen &&
41
+ screen.fillHeight !== undefined && { fillHeight: screen.fillHeight }),
42
+ ...("fieldLabels" in screen &&
43
+ screen.fieldLabels !== undefined && { fieldLabels: screen.fieldLabels }),
44
+ };
59
45
  }
60
-
61
46
  /** Separate id (`${screen.id}:confirm`) keeps this confirm-form screen from
62
47
  * colliding with the mint-form screen's draft key. */
63
- export function synthesizeSecretMintConfirmScreen(
64
- screen: SecretMintScreenDefinition,
65
- confirm: SecretMintConfirmStep,
66
- ): EntityEditScreenDefinition {
67
- return {
68
- id: `${screen.id}:confirm`,
69
- type: "entityEdit",
70
- entity: ACTION_FORM_PSEUDO_ENTITY,
71
- layout: confirm.layout,
72
- ...(screen.access !== undefined && { access: screen.access }),
73
- };
48
+ export function synthesizeSecretMintConfirmScreen(screen, confirm) {
49
+ return {
50
+ id: `${screen.id}:confirm`,
51
+ type: "entityEdit",
52
+ entity: ACTION_FORM_PSEUDO_ENTITY,
53
+ layout: confirm.layout,
54
+ ...(screen.access !== undefined && { access: screen.access }),
55
+ };
74
56
  }
@@ -0,0 +1,8 @@
1
+ import { type ReactNode } from "react";
2
+ import type { FeatureSchema } from "./feature-schema.js";
3
+ export type AppFeaturesProviderProps = {
4
+ readonly features: readonly FeatureSchema[];
5
+ readonly children: ReactNode;
6
+ };
7
+ export declare function AppFeaturesProvider({ features, children }: AppFeaturesProviderProps): ReactNode;
8
+ export declare function useAppFeatures(): readonly FeatureSchema[];
@@ -0,0 +1,16 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ // Cross-feature schema access for components that need to resolve a
3
+ // screen owned by a DIFFERENT feature than the one they're rendering
4
+ // under — e.g. a reference field opening the target entity's create
5
+ // screen (kumiko-framework#1681). `createKumikoApp` provides the full
6
+ // `app.features` list; components elsewhere in the render tree default
7
+ // to an empty list (no cross-feature schema known, e.g. outside
8
+ // createKumikoApp or in isolated tests).
9
+ import { createContext, useContext } from "react";
10
+ const AppFeaturesContext = createContext([]);
11
+ export function AppFeaturesProvider({ features, children }) {
12
+ return _jsx(AppFeaturesContext.Provider, { value: features, children: children });
13
+ }
14
+ export function useAppFeatures() {
15
+ return useContext(AppFeaturesContext);
16
+ }
@@ -0,0 +1,30 @@
1
+ import { type ComponentType, type ReactNode } from "react";
2
+ export type ColumnRendererProps = {
3
+ readonly value: unknown;
4
+ readonly row: Readonly<Record<string, unknown>>;
5
+ readonly column: {
6
+ readonly field: string;
7
+ };
8
+ /** Set only when the caller (DataTable's `onCellChange`) wired an
9
+ * editable path for this cell — undefined means read-only. A renderer
10
+ * can branch its own markup (input vs. plain text) on presence alone. */
11
+ readonly onChange?: (value: unknown) => void;
12
+ };
13
+ export type ColumnRendererComponent = ComponentType<ColumnRendererProps>;
14
+ export type ColumnRenderersMap = Readonly<Record<string, ColumnRendererComponent>>;
15
+ export type ColumnRenderersProviderProps = {
16
+ readonly children: ReactNode;
17
+ readonly value: ColumnRenderersMap;
18
+ };
19
+ export declare function ColumnRenderersProvider({ children, value, }: ColumnRenderersProviderProps): ReactNode;
20
+ /** Schaut die Component für einen Renderer-Key nach. Returnt undefined
21
+ * wenn `name` leer/undefined ist (Caller hat keinen __component-Renderer)
22
+ * oder weder Provider gemounted noch der Key in der Map ist. Der Caller
23
+ * (DataTable.renderCell) loggt dann eine Warnung und fällt auf den
24
+ * Default-Type-Renderer zurück.
25
+ *
26
+ * `name` ist optional damit Caller den Hook unkonditional aufrufen
27
+ * können — Rules-of-Hooks verbieten einen Function-Branch der den Hook
28
+ * überspringt. So bleibt der Aufruf eine einzige Zeile, ohne dass der
29
+ * Caller einen Stub-Key wie `""` reichen muss. */
30
+ export declare function useColumnRenderer(name?: string): ColumnRendererComponent | undefined;
@@ -0,0 +1,34 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ // Column-Renderer-Map: client-side Lookup für ListColumn-Spalten die im
3
+ // Schema einen PlatformComponent-Renderer (`{ react: { __component: "Name" } }`)
4
+ // statt einer String-Funktion angeben. createKumikoApp im renderer-web sammelt
5
+ // alle clientFeatures.columnRenderers und mountet den Provider; der DataTable-
6
+ // Cell-Renderer schlägt den Component über `useColumnRenderer(name)` nach.
7
+ //
8
+ // Analog zu CustomScreensProvider — der Renderer-Web-Bootstrap mounted beide
9
+ // Provider an derselben Stelle. Schemas selbst bleiben serializable: der
10
+ // Component wird nur per String-Key referenziert, die Map liegt allein
11
+ // client-seitig.
12
+ import { createContext, useContext } from "react";
13
+ const ColumnRenderersContext = createContext(undefined);
14
+ export function ColumnRenderersProvider({ children, value, }) {
15
+ return (_jsx(ColumnRenderersContext.Provider, { value: value, children: children }));
16
+ }
17
+ /** Schaut die Component für einen Renderer-Key nach. Returnt undefined
18
+ * wenn `name` leer/undefined ist (Caller hat keinen __component-Renderer)
19
+ * oder weder Provider gemounted noch der Key in der Map ist. Der Caller
20
+ * (DataTable.renderCell) loggt dann eine Warnung und fällt auf den
21
+ * Default-Type-Renderer zurück.
22
+ *
23
+ * `name` ist optional damit Caller den Hook unkonditional aufrufen
24
+ * können — Rules-of-Hooks verbieten einen Function-Branch der den Hook
25
+ * überspringt. So bleibt der Aufruf eine einzige Zeile, ohne dass der
26
+ * Caller einen Stub-Key wie `""` reichen muss. */
27
+ export function useColumnRenderer(name) {
28
+ const map = useContext(ColumnRenderersContext);
29
+ if (name === undefined || name === "")
30
+ return undefined;
31
+ if (map === undefined)
32
+ return undefined;
33
+ return map[name];
34
+ }
@@ -0,0 +1,11 @@
1
+ import type { ConfigEditScreenDefinition, EntityDefinition, EntityEditScreenDefinition } from "@cosmicdrift/kumiko-framework/ui-types";
2
+ /** Baut eine minimale EntityDefinition aus den Inline-Fields des
3
+ * ConfigEdit-Screens. RenderEdit + computeEditViewModel iterieren
4
+ * über entity.fields zur Render-Zeit; alle weiteren EntityDefinition-
5
+ * Felder bleiben undefined. */
6
+ export declare function synthesizeConfigEditEntity(fields: ConfigEditScreenDefinition["fields"]): EntityDefinition;
7
+ /** Wandelt ein ConfigEditScreenDefinition in die EntityEditScreen-
8
+ * Shape die RenderEdit erwartet. type wird auf "entityEdit" gesetzt
9
+ * damit der Type-Constraint hält; entity wird auf den Pseudo-Namen
10
+ * gepinnt — RenderEdit liest das Feld nicht. */
11
+ export declare function synthesizeConfigEditScreen(screen: ConfigEditScreenDefinition): EntityEditScreenDefinition;
@@ -12,39 +12,26 @@
12
12
  // zukünftiger Boot-Validator die schema.entities-Map cross-referenziert,
13
13
  // brechen die Type-Lies hier silent. Dann ist Zeit für eine echte
14
14
  // RenderConfigEdit-Komponente die direkt fields nimmt.
15
-
16
- import type {
17
- ConfigEditScreenDefinition,
18
- EntityDefinition,
19
- EntityEditScreenDefinition,
20
- } from "@cosmicdrift/kumiko-framework/ui-types";
21
-
22
15
  const CONFIG_EDIT_PSEUDO_ENTITY = "__config-edit__";
23
-
24
16
  /** Baut eine minimale EntityDefinition aus den Inline-Fields des
25
17
  * ConfigEdit-Screens. RenderEdit + computeEditViewModel iterieren
26
18
  * über entity.fields zur Render-Zeit; alle weiteren EntityDefinition-
27
19
  * Felder bleiben undefined. */
28
- export function synthesizeConfigEditEntity(
29
- fields: ConfigEditScreenDefinition["fields"],
30
- ): EntityDefinition {
31
- return { fields } as EntityDefinition;
20
+ export function synthesizeConfigEditEntity(fields) {
21
+ return { fields };
32
22
  }
33
-
34
23
  /** Wandelt ein ConfigEditScreenDefinition in die EntityEditScreen-
35
24
  * Shape die RenderEdit erwartet. type wird auf "entityEdit" gesetzt
36
25
  * damit der Type-Constraint hält; entity wird auf den Pseudo-Namen
37
26
  * gepinnt — RenderEdit liest das Feld nicht. */
38
- export function synthesizeConfigEditScreen(
39
- screen: ConfigEditScreenDefinition,
40
- ): EntityEditScreenDefinition {
41
- return {
42
- id: screen.id,
43
- type: "entityEdit",
44
- entity: CONFIG_EDIT_PSEUDO_ENTITY,
45
- layout: screen.layout,
46
- ...(screen.description !== undefined && { description: screen.description }),
47
- ...(screen.fieldLabels !== undefined && { fieldLabels: screen.fieldLabels }),
48
- ...(screen.access !== undefined && { access: screen.access }),
49
- };
27
+ export function synthesizeConfigEditScreen(screen) {
28
+ return {
29
+ id: screen.id,
30
+ type: "entityEdit",
31
+ entity: CONFIG_EDIT_PSEUDO_ENTITY,
32
+ layout: screen.layout,
33
+ ...(screen.description !== undefined && { description: screen.description }),
34
+ ...(screen.fieldLabels !== undefined && { fieldLabels: screen.fieldLabels }),
35
+ ...(screen.access !== undefined && { access: screen.access }),
36
+ };
50
37
  }
@@ -0,0 +1,38 @@
1
+ import type { ContentEditorFormat } from "@cosmicdrift/kumiko-types/nav";
2
+ import { type ComponentType, type ReactNode } from "react";
3
+ export type ContentEditorProps = {
4
+ /** DOM id every registered editor must render onto its own focusable
5
+ * root element. Callers that wrap an editor in a `Field` (label +
6
+ * htmlFor) pass a stable id here so the label stays associated with
7
+ * whatever element actually renders — a fixed constant would break as
8
+ * soon as a registered editor swaps in for the textarea fallback. */
9
+ readonly id: string;
10
+ readonly value: string;
11
+ readonly onChange: (value: string) => void;
12
+ /** Variable names insertable as chips (from the collection's
13
+ * variableSchema). Empty until the variable-chip step wires it up —
14
+ * editors must accept it now, that's the point of fixing the signature
15
+ * here. */
16
+ readonly variables: readonly string[];
17
+ readonly readOnly: boolean;
18
+ };
19
+ export type ContentEditorComponent = ComponentType<ContentEditorProps>;
20
+ /** Default id value for callers that don't generate their own (e.g. a
21
+ * standalone TextareaContentEditor render outside a multi-editor page).
22
+ * Registered editors don't apply this automatically — every caller passes
23
+ * its own id via ContentEditorProps.id. */
24
+ export declare const CONTENT_EDITOR_ELEMENT_ID = "content-editor-textarea";
25
+ export type ContentEditorsMap = Partial<Record<ContentEditorFormat, ContentEditorComponent>>;
26
+ export type ContentEditorsProviderProps = {
27
+ readonly children: ReactNode;
28
+ readonly value: ContentEditorsMap;
29
+ };
30
+ export declare function ContentEditorsProvider({ children, value, }: ContentEditorsProviderProps): ReactNode;
31
+ /** Plain-textarea fallback for a contentFormat with no registered editor.
32
+ * Uses the primitives Input like every other form field, so it renders on
33
+ * every platform without requiring the platform's DOM/native equivalent. */
34
+ export declare function TextareaContentEditor({ id, value, onChange, readOnly, }: ContentEditorProps): ReactNode;
35
+ /** Resolves the editor for a contentFormat, falling back to the plain
36
+ * textarea when no clientFeature registered one. `contentFormat`
37
+ * undefined (collection didn't declare one) behaves like "plain". */
38
+ export declare function useContentEditor(contentFormat?: ContentEditorFormat): ContentEditorComponent;
@@ -0,0 +1,26 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { createContext, useContext } from "react";
3
+ import { usePrimitives } from "../primitives.js";
4
+ /** Default id value for callers that don't generate their own (e.g. a
5
+ * standalone TextareaContentEditor render outside a multi-editor page).
6
+ * Registered editors don't apply this automatically — every caller passes
7
+ * its own id via ContentEditorProps.id. */
8
+ export const CONTENT_EDITOR_ELEMENT_ID = "content-editor-textarea";
9
+ const ContentEditorsContext = createContext({});
10
+ export function ContentEditorsProvider({ children, value, }) {
11
+ return _jsx(ContentEditorsContext.Provider, { value: value, children: children });
12
+ }
13
+ /** Plain-textarea fallback for a contentFormat with no registered editor.
14
+ * Uses the primitives Input like every other form field, so it renders on
15
+ * every platform without requiring the platform's DOM/native equivalent. */
16
+ export function TextareaContentEditor({ id, value, onChange, readOnly, }) {
17
+ const { Input } = usePrimitives();
18
+ return (_jsx(Input, { kind: "textarea", id: id, name: CONTENT_EDITOR_ELEMENT_ID, value: value, onChange: onChange, readOnly: readOnly, rows: 14 }));
19
+ }
20
+ /** Resolves the editor for a contentFormat, falling back to the plain
21
+ * textarea when no clientFeature registered one. `contentFormat`
22
+ * undefined (collection didn't declare one) behaves like "plain". */
23
+ export function useContentEditor(contentFormat) {
24
+ const map = useContext(ContentEditorsContext);
25
+ return map[contentFormat ?? "plain"] ?? TextareaContentEditor;
26
+ }
@@ -0,0 +1,11 @@
1
+ import type { ContentEditorFormat } from "@cosmicdrift/kumiko-types/nav";
2
+ import { type ReactNode } from "react";
3
+ /** A name with no example value (or not in the schema at all) stays as the
4
+ * literal `{{name}}` placeholder — there is nothing else to show for it. */
5
+ export declare function substituteVariables(content: string, variables: Readonly<Record<string, string>>): string;
6
+ export type ContentPreviewProps = {
7
+ readonly content: string;
8
+ readonly variables: Readonly<Record<string, string>>;
9
+ readonly contentFormat?: ContentEditorFormat;
10
+ };
11
+ export declare function ContentPreview({ content, variables, contentFormat, }: ContentPreviewProps): ReactNode;
@@ -0,0 +1,30 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { useId } from "react";
3
+ import { useContentEditor } from "./content-editors.js";
4
+ const VARIABLE_PATTERN = /\{\{\s*(\w+)\s*\}\}/g;
5
+ const noop = () => { };
6
+ /** A name with no example value (or not in the schema at all) stays as the
7
+ * literal `{{name}}` placeholder — there is nothing else to show for it. */
8
+ export function substituteVariables(content, variables) {
9
+ return content.replace(VARIABLE_PATTERN, (match, name) => Object.hasOwn(variables, name) ? (variables[name] ?? match) : match);
10
+ }
11
+ function escapeHtml(value) {
12
+ return value
13
+ .replace(/&/g, "&amp;")
14
+ .replace(/</g, "&lt;")
15
+ .replace(/>/g, "&gt;")
16
+ .replace(/"/g, "&quot;")
17
+ .replace(/'/g, "&#39;");
18
+ }
19
+ export function ContentPreview({ content, variables, contentFormat, }) {
20
+ const Editor = useContentEditor(contentFormat);
21
+ const id = useId();
22
+ // "rich" content is HTML (see ContentCollectionDefinition.contentFormat) —
23
+ // an example value substituted in raw could break the markup (`<`) or
24
+ // render as an unescaped entity (`&`). "plain"/"markdown" content is text,
25
+ // no escaping wanted there.
26
+ const safeVariables = contentFormat === "rich"
27
+ ? Object.fromEntries(Object.entries(variables).map(([name, value]) => [name, escapeHtml(value)]))
28
+ : variables;
29
+ return (_jsx(Editor, { id: id, value: substituteVariables(content, safeVariables), onChange: noop, variables: [], readOnly: true }));
30
+ }
@@ -0,0 +1,11 @@
1
+ import { type ComponentType, type ReactNode } from "react";
2
+ export type CustomScreensMap = Readonly<Record<string, ComponentType>>;
3
+ export type CustomScreensProviderProps = {
4
+ readonly children: ReactNode;
5
+ readonly value: CustomScreensMap;
6
+ };
7
+ export declare function CustomScreensProvider({ children, value }: CustomScreensProviderProps): ReactNode;
8
+ /** Schaut die Component für ein Custom-Screen nach. Returnt undefined
9
+ * wenn weder Provider gemounted noch screenId in der Map ist — der
10
+ * Caller (KumikoScreen) zeigt dann seinen Placeholder-Banner. */
11
+ export declare function useCustomScreenComponent(screenId: string): ComponentType | undefined;
@@ -0,0 +1,20 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ // Custom-Screen-Components-Map: client-side Lookup für Screens vom Typ
3
+ // `custom`. KumikoScreen schaut hier nach `screen.id` (oder qn) und
4
+ // rendert die passende Component. createKumikoApp im renderer-web sammelt
5
+ // alle clientFeatures.components und mountet den Provider; Tests die
6
+ // einzelne Custom-Screens prüfen wollen, mounten den Provider direkt.
7
+ import { createContext, useContext } from "react";
8
+ const CustomScreensContext = createContext(undefined);
9
+ export function CustomScreensProvider({ children, value }) {
10
+ return _jsx(CustomScreensContext.Provider, { value: value, children: children });
11
+ }
12
+ /** Schaut die Component für ein Custom-Screen nach. Returnt undefined
13
+ * wenn weder Provider gemounted noch screenId in der Map ist — der
14
+ * Caller (KumikoScreen) zeigt dann seinen Placeholder-Banner. */
15
+ export function useCustomScreenComponent(screenId) {
16
+ const map = useContext(CustomScreensContext);
17
+ if (map === undefined)
18
+ return undefined;
19
+ return map[screenId];
20
+ }
@@ -0,0 +1,16 @@
1
+ import type { DashboardScreenDefinition } from "@cosmicdrift/kumiko-framework/ui-types";
2
+ import type { Translate } from "@cosmicdrift/kumiko-headless";
3
+ import { type ComponentType, type ReactNode } from "react";
4
+ export type DashboardBodyProps = {
5
+ readonly featureName: string;
6
+ readonly screen: DashboardScreenDefinition;
7
+ readonly translate?: Translate;
8
+ };
9
+ export type DashboardBodyProviderProps = {
10
+ readonly children: ReactNode;
11
+ readonly value: ComponentType<DashboardBodyProps>;
12
+ };
13
+ export declare function DashboardBodyProvider({ children, value }: DashboardBodyProviderProps): ReactNode;
14
+ /** Undefined wenn kein Platform-Package einen Dashboard-Body registriert
15
+ * hat — KumikoScreen zeigt dann seinen Placeholder-Banner. */
16
+ export declare function useDashboardBody(): ComponentType<DashboardBodyProps> | undefined;
@@ -0,0 +1,11 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { createContext, useContext } from "react";
3
+ const DashboardBodyContext = createContext(undefined);
4
+ export function DashboardBodyProvider({ children, value }) {
5
+ return _jsx(DashboardBodyContext.Provider, { value: value, children: children });
6
+ }
7
+ /** Undefined wenn kein Platform-Package einen Dashboard-Body registriert
8
+ * hat — KumikoScreen zeigt dann seinen Placeholder-Banner. */
9
+ export function useDashboardBody() {
10
+ return useContext(DashboardBodyContext);
11
+ }
@@ -0,0 +1,32 @@
1
+ export type ExtensionSubmitContext = {
2
+ readonly entityId: string;
3
+ };
4
+ export type ExtensionSubmitResult = {
5
+ readonly isSuccess: boolean;
6
+ /** i18n-Key für die Fehlermeldung, die die Form als Banner zeigt. */
7
+ readonly errorKey?: string;
8
+ };
9
+ export type ExtensionFormSubmitHandler = (ctx: ExtensionSubmitContext) => Promise<ExtensionSubmitResult>;
10
+ type Registration = {
11
+ readonly key: string;
12
+ readonly dirty: boolean;
13
+ readonly handler: ExtensionFormSubmitHandler;
14
+ };
15
+ export type ExtensionFormRegistry = {
16
+ readonly upsert: (reg: Registration) => void;
17
+ readonly remove: (key: string) => void;
18
+ };
19
+ export declare const ExtensionFormRegistryProvider: import("react").Provider<ExtensionFormRegistry | null>;
20
+ export type ExtensionFormHostStatus = {
21
+ readonly anyDirty: boolean;
22
+ readonly hasRegistrations: boolean;
23
+ };
24
+ export declare function useExtensionFormHost(onStatusChange: (status: ExtensionFormHostStatus) => void): {
25
+ readonly registry: ExtensionFormRegistry;
26
+ readonly runAll: (ctx: ExtensionSubmitContext) => Promise<readonly ExtensionSubmitResult[]>;
27
+ };
28
+ export declare function useExtensionFormSubmit(opts: {
29
+ readonly dirty: boolean;
30
+ readonly onSubmit: ExtensionFormSubmitHandler;
31
+ }): boolean;
32
+ export {};
@@ -0,0 +1,73 @@
1
+ // @runtime client
2
+ // Extension-Form-Submit-Registry — erlaubt einer Extension-Section (z.B.
3
+ // Custom-Fields), beim Submit des umgebenden entityEdit-Forms mitzuschreiben,
4
+ // statt einen eigenen Save-Button zu führen ("composed form, ein Save",
5
+ // Bug-Bash 3 #1). Die Section meldet (a) einen Submit-Handler und (b) ihren
6
+ // dirty-State an die Form; die Form aktiviert ihren Save-Button auch wenn nur
7
+ // eine Section dirty ist und ruft nach dem Entity-Write alle Section-Handler
8
+ // mit der entityId.
9
+ //
10
+ // Ohne umgebende Form (Context === null) fällt die Section auf ihren eigenen
11
+ // Save-Button zurück (Standalone-Backward-Compat).
12
+ import { createContext, useContext, useEffect, useId, useMemo, useRef } from "react";
13
+ const ExtensionFormRegistryContext = createContext(null);
14
+ export const ExtensionFormRegistryProvider = ExtensionFormRegistryContext.Provider;
15
+ export function useExtensionFormHost(onStatusChange) {
16
+ const regsRef = useRef(new Map());
17
+ const onStatusRef = useRef(onStatusChange);
18
+ onStatusRef.current = onStatusChange;
19
+ const registry = useMemo(() => {
20
+ const emitDirty = () => {
21
+ let any = false;
22
+ for (const r of regsRef.current.values()) {
23
+ if (r.dirty) {
24
+ any = true;
25
+ break;
26
+ }
27
+ }
28
+ onStatusRef.current({ anyDirty: any, hasRegistrations: regsRef.current.size > 0 });
29
+ };
30
+ return {
31
+ upsert: (reg) => {
32
+ regsRef.current.set(reg.key, reg);
33
+ emitDirty();
34
+ },
35
+ remove: (key) => {
36
+ regsRef.current.delete(key);
37
+ emitDirty();
38
+ },
39
+ };
40
+ }, []);
41
+ const runAll = useMemo(() => async (ctx) => {
42
+ const results = [];
43
+ // Insertion-Order (Map) = Section-Reihenfolge im Form.
44
+ for (const reg of regsRef.current.values()) {
45
+ results.push(await reg.handler(ctx));
46
+ }
47
+ return results;
48
+ }, []);
49
+ return { registry, runAll };
50
+ }
51
+ // Section-Seite: meldet Handler + dirty an die umgebende Form. Returnt true
52
+ // wenn eine composed-Form vorhanden ist (Section blendet dann ihren eigenen
53
+ // Save-Button aus); false = standalone (eigener Save-Button bleibt).
54
+ export function useExtensionFormSubmit(opts) {
55
+ const registry = useContext(ExtensionFormRegistryContext);
56
+ const key = useId();
57
+ // Handler über ref, damit das Re-Registrieren NICHT an jeder Handler-
58
+ // Identity hängt (nur an dirty); der Handler liest immer den frischen
59
+ // Closure-State (pending) zur Aufruf-Zeit.
60
+ const handlerRef = useRef(opts.onSubmit);
61
+ handlerRef.current = opts.onSubmit;
62
+ useEffect(() => {
63
+ if (registry === null)
64
+ return;
65
+ registry.upsert({
66
+ key,
67
+ dirty: opts.dirty,
68
+ handler: (ctx) => handlerRef.current(ctx),
69
+ });
70
+ return () => registry.remove(key);
71
+ }, [registry, key, opts.dirty]);
72
+ return registry !== null;
73
+ }
@@ -0,0 +1,72 @@
1
+ import type { PlatformComponent } from "@cosmicdrift/kumiko-framework/ui-types";
2
+ import { type ComponentType, type ReactNode } 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 declare function extensionSectionName(component: PlatformComponent): string | undefined;
8
+ export type ExtensionSectionProps = {
9
+ readonly entityName: string;
10
+ readonly entityId: string | null;
11
+ /** Bereits gespeicherte Extension-Werte der Entity (aus der geladenen
12
+ * detail-row durchgereicht). `undefined` im Create-Mode oder wenn der
13
+ * Host-Screen keine Werte liefert. Erlaubt der Section, den Bestand
14
+ * beim Edit anzuzeigen statt write-only zu sein. */
15
+ readonly initialValues?: Readonly<Record<string, unknown>>;
16
+ /** Nur im List-Header-Slot gesetzt (entityId ist dort null): die screen.id
17
+ * der Liste, damit ein Header-Control den per-Screen URL-Filter-State
18
+ * (useListUrlState) ansprechen kann — z.B. ein Tag-Filter der die Liste auf
19
+ * eine id-Menge narrowed. In entityEdit-Sections undefined. */
20
+ readonly screenId?: string;
21
+ /** Nur im Dashboard-`custom`-Panel gesetzt: der aktuell gewählte Wert des
22
+ * Screen-Filters (siehe DashboardFilterDefinition), gemerged wie bei jeder
23
+ * anderen Panel-Query. In allen anderen Mount-Orten undefined. Dashboard-
24
+ * Panels haben keine Entity — entityName/entityId tragen dort die
25
+ * screen.id bzw. null, siehe CustomPanelBody in dashboard-body.tsx. */
26
+ readonly filterParams?: Readonly<Record<string, unknown>>;
27
+ /** Current form values of the host RenderEdit (controlled mode,
28
+ * issue #1887/#1888) — same snapshot reference as
29
+ * `RenderEditChangeState.values`. Lets the section read the host
30
+ * form's live state (e.g. for a review step). Only set in
31
+ * entityEdit sections; undefined in list-header and dashboard
32
+ * mounts, where no host form exists. */
33
+ readonly values?: Readonly<Record<string, unknown>>;
34
+ /** Sets host RenderEdit form values from outside (e.g. a VIN-decode
35
+ * roundtrip that fills other fields) — same function as
36
+ * `RenderEditControls.patch`, merges only the given keys. `patch` must
37
+ * converge: `setValues` is a no-op only when the merged result is
38
+ * reference-equal to the current values, so an unconditional
39
+ * `patch(...)` from a `values`-dependent effect loops. Undefined outside
40
+ * entityEdit sections. */
41
+ readonly patch?: (partial: Readonly<Record<string, unknown>>) => void;
42
+ /** Validates the host form without writing — same function as
43
+ * `RenderEditControls.validate`; field errors land in
44
+ * `snapshot.errors` on the field instead of a collective message.
45
+ * Undefined outside entityEdit sections. */
46
+ readonly validate?: () => boolean;
47
+ /** Whether the host form has unsaved changes. Only set in the entityEdit
48
+ * footer slot (`screen.slots.footer`); undefined in all other mounts. */
49
+ readonly hasUnsavedChanges?: boolean;
50
+ /** Current wizard step, only set for `layout.mode === "wizard"` forms.
51
+ * Only set in the entityEdit footer slot (`screen.slots.footer`);
52
+ * undefined in all other mounts, and undefined there too for a
53
+ * non-wizard form. */
54
+ readonly wizardStep?: {
55
+ readonly index: number;
56
+ readonly isLast: boolean;
57
+ };
58
+ };
59
+ export type ExtensionSectionComponent = ComponentType<ExtensionSectionProps>;
60
+ export type ExtensionSectionsMap = Readonly<Record<string, ExtensionSectionComponent>>;
61
+ export type ExtensionSectionsProviderProps = {
62
+ readonly children: ReactNode;
63
+ readonly value: ExtensionSectionsMap;
64
+ };
65
+ export declare function ExtensionSectionsProvider({ children, value, }: ExtensionSectionsProviderProps): ReactNode;
66
+ /** Schaut die Component für einen extension-section-Namen nach. Returnt
67
+ * undefined wenn weder Provider gemounted noch der Name in der Map
68
+ * registriert ist — der Caller (RenderEdit) zeigt dann seinen
69
+ * Placeholder-Banner. `name` ist optional damit Caller den Hook
70
+ * unkonditional aufrufen können (Rules-of-Hooks), ohne einen Stub-Key
71
+ * wie `""` reichen zu müssen — analog `useColumnRenderer`. */
72
+ export declare function useExtensionSectionComponent(name?: string): ExtensionSectionComponent | undefined;