@cosmicdrift/kumiko-renderer 0.386.0 → 0.388.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 (222) hide show
  1. package/LICENSE +21 -57
  2. package/dist/app/action-form-body.d.ts +2 -2
  3. package/dist/app/action-form-body.js +12 -4
  4. package/dist/app/action-form-shim.d.ts +8 -8
  5. package/dist/app/action-form-shim.js +20 -22
  6. package/dist/app/action-form-support.d.ts +1 -0
  7. package/dist/app/action-form-support.js +1 -1
  8. package/dist/app/app-features-context.js +4 -4
  9. package/dist/app/column-renderers.d.ts +7 -9
  10. package/dist/app/column-renderers.js +15 -18
  11. package/dist/app/config-edit-body.js +7 -3
  12. package/dist/app/config-edit-shim.d.ts +7 -8
  13. package/dist/app/config-edit-shim.js +18 -20
  14. package/dist/app/custom-screens.d.ts +3 -3
  15. package/dist/app/custom-screens.js +8 -8
  16. package/dist/app/dashboard-body.d.ts +2 -2
  17. package/dist/app/dashboard-body.js +2 -2
  18. package/dist/app/entity-edit-prefill.d.ts +11 -0
  19. package/dist/app/entity-edit-prefill.js +18 -13
  20. package/dist/app/entity-edit-screen.js +4 -4
  21. package/dist/app/entity-list-screen.js +3 -3
  22. package/dist/app/extension-form-submit.d.ts +1 -1
  23. package/dist/app/extension-form-submit.js +14 -15
  24. package/dist/app/extension-sections.d.ts +29 -28
  25. package/dist/app/extension-sections.js +10 -10
  26. package/dist/app/feature-schema.js +11 -11
  27. package/dist/app/form-schema.js +2 -2
  28. package/dist/app/header-actions-bar.js +2 -2
  29. package/dist/app/kumiko-screen.js +8 -10
  30. package/dist/app/layout-fields.js +1 -1
  31. package/dist/app/list-facets.js +3 -3
  32. package/dist/app/nav.d.ts +10 -10
  33. package/dist/app/nav.js +13 -13
  34. package/dist/app/projection-detail-body.js +4 -4
  35. package/dist/app/projection-detail-shim.d.ts +6 -5
  36. package/dist/app/projection-detail-shim.js +23 -22
  37. package/dist/app/projection-list-body.js +10 -10
  38. package/dist/app/projection-list-shim.d.ts +5 -5
  39. package/dist/app/projection-list-shim.js +17 -18
  40. package/dist/app/qn.js +10 -12
  41. package/dist/app/qualify-screen-id.js +1 -1
  42. package/dist/app/screen-access.js +2 -2
  43. package/dist/app/screen-shared.js +1 -1
  44. package/dist/app/secret-mint-body.js +4 -4
  45. package/dist/app/write-failed-error.js +8 -7
  46. package/dist/components/edit-mounts.d.ts +2 -2
  47. package/dist/components/embedded-list-field.js +5 -5
  48. package/dist/components/grid-cell-for-field.d.ts +1 -1
  49. package/dist/components/reference-create-dialog.js +3 -3
  50. package/dist/components/related-list-section.d.ts +1 -1
  51. package/dist/components/related-list-section.js +15 -2
  52. package/dist/components/render-edit-action-button.d.ts +1 -3
  53. package/dist/components/render-edit-action-button.js +2 -2
  54. package/dist/components/render-edit-logic.js +1 -1
  55. package/dist/components/render-edit-types.d.ts +6 -6
  56. package/dist/components/render-edit.js +74 -73
  57. package/dist/components/render-field.d.ts +7 -7
  58. package/dist/components/render-field.js +62 -61
  59. package/dist/components/render-list.d.ts +42 -43
  60. package/dist/components/render-list.js +93 -84
  61. package/dist/components/use-wizard-form-draft.js +10 -10
  62. package/dist/context/dispatcher-context.js +5 -5
  63. package/dist/context/user-roles-context.js +2 -2
  64. package/dist/flow-diagram/render.js +9 -1
  65. package/dist/headless/apex/index.d.ts +1 -2
  66. package/dist/headless/apex/index.js +5 -6
  67. package/dist/headless/form/form-controller.js +14 -6
  68. package/dist/headless/form/types.d.ts +1 -0
  69. package/dist/headless/form/zod-bridge.js +2 -2
  70. package/dist/headless/format/index.js +89 -64
  71. package/dist/headless/format/money.js +1 -1
  72. package/dist/headless/index.js +2 -2
  73. package/dist/headless/view-model/edit.js +4 -2
  74. package/dist/headless/view-model/list.js +184 -150
  75. package/dist/headless/view-model/types.d.ts +6 -3
  76. package/dist/hooks/live-refetch-scheduler.js +4 -0
  77. package/dist/hooks/reference-limits.js +11 -12
  78. package/dist/hooks/use-list-url-state.d.ts +13 -13
  79. package/dist/hooks/use-list-url-state.js +21 -22
  80. package/dist/hooks/use-query.js +3 -3
  81. package/dist/hooks/use-reference-lookup.d.ts +9 -1
  82. package/dist/hooks/use-reference-lookup.js +32 -19
  83. package/dist/hooks/use-store.js +18 -22
  84. package/dist/hooks/use-stream-handler.js +4 -2
  85. package/dist/i18n-defaults.js +6 -8
  86. package/dist/i18n.d.ts +10 -10
  87. package/dist/i18n.js +25 -25
  88. package/dist/index.d.ts +1 -0
  89. package/dist/index.js +6 -4
  90. package/dist/live/dispatcher-live.js +2 -2
  91. package/dist/primitives.d.ts +244 -221
  92. package/dist/primitives.js +1 -1
  93. package/dist/sse/live-events.d.ts +5 -5
  94. package/dist/sse/live-events.js +17 -17
  95. package/dist/tokens.d.ts +8 -8
  96. package/dist/tokens.js +16 -17
  97. package/dist/web/app/browser-locale.d.ts +9 -9
  98. package/dist/web/app/browser-locale.js +19 -19
  99. package/dist/web/app/client-plugin.d.ts +44 -52
  100. package/dist/web/app/client-plugin.js +4 -5
  101. package/dist/web/app/create-app.d.ts +28 -31
  102. package/dist/web/app/create-app.js +29 -25
  103. package/dist/web/app/dashboard-body.js +17 -1
  104. package/dist/web/app/dashboard-panels.js +12 -2
  105. package/dist/web/app/document-lang-sync.js +1 -1
  106. package/dist/web/app/draft-storage.js +1 -1
  107. package/dist/web/app/nav-providers-context.d.ts +3 -3
  108. package/dist/web/app/nav-providers-context.js +3 -3
  109. package/dist/web/app/nav.d.ts +18 -17
  110. package/dist/web/app/nav.js +66 -64
  111. package/dist/web/app/rich-content-editor.js +1 -1
  112. package/dist/web/components/config-cascade.js +17 -18
  113. package/dist/web/components/config-source-badge.js +4 -4
  114. package/dist/web/index.d.ts +1 -1
  115. package/dist/web/index.js +1 -1
  116. package/dist/web/layout/app-layout.d.ts +9 -9
  117. package/dist/web/layout/app-layout.js +2 -2
  118. package/dist/web/layout/avatar.d.ts +4 -3
  119. package/dist/web/layout/avatar.js +15 -17
  120. package/dist/web/layout/default-app-shell.d.ts +22 -23
  121. package/dist/web/layout/editor-panel.js +3 -3
  122. package/dist/web/layout/nav-tree.js +86 -84
  123. package/dist/web/layout/profile-menu.d.ts +1 -1
  124. package/dist/web/layout/shell-header.js +2 -1
  125. package/dist/web/layout/sidebar-brand.d.ts +7 -7
  126. package/dist/web/layout/sidebar-user.d.ts +1 -1
  127. package/dist/web/layout/sidebar-user.js +4 -4
  128. package/dist/web/layout/sidebar.d.ts +8 -8
  129. package/dist/web/layout/sidebar.js +7 -7
  130. package/dist/web/layout/target-resolver-stub.d.ts +5 -5
  131. package/dist/web/layout/target-resolver-stub.js +20 -20
  132. package/dist/web/layout/target-url.d.ts +7 -7
  133. package/dist/web/layout/target-url.js +22 -22
  134. package/dist/web/layout/theme-toggle.js +4 -5
  135. package/dist/web/layout/uniform-bar-controls.d.ts +1 -0
  136. package/dist/web/layout/uniform-bar-controls.js +4 -0
  137. package/dist/web/layout/workspace-shell.d.ts +21 -21
  138. package/dist/web/layout/workspace-shell.js +29 -30
  139. package/dist/web/lib/cn.d.ts +4 -4
  140. package/dist/web/lib/cn.js +4 -4
  141. package/dist/web/lib/file-ref-download.js +4 -1
  142. package/dist/web/primitives/action-menu.d.ts +8 -8
  143. package/dist/web/primitives/action-menu.js +14 -13
  144. package/dist/web/primitives/calendar-popover.d.ts +1 -1
  145. package/dist/web/primitives/calendar-popover.js +10 -10
  146. package/dist/web/primitives/card-styles.js +1 -1
  147. package/dist/web/primitives/card.js +2 -2
  148. package/dist/web/primitives/code-input.d.ts +6 -0
  149. package/dist/web/primitives/code-input.js +31 -0
  150. package/dist/web/primitives/combobox.d.ts +12 -12
  151. package/dist/web/primitives/combobox.js +34 -35
  152. package/dist/web/primitives/data-table-cell.js +2 -2
  153. package/dist/web/primitives/data-table.js +6 -6
  154. package/dist/web/primitives/date-field.js +2 -2
  155. package/dist/web/primitives/date-input.js +4 -4
  156. package/dist/web/primitives/default-form.js +2 -2
  157. package/dist/web/primitives/dropdown-menu.js +14 -15
  158. package/dist/web/primitives/embedded-list-input.js +3 -3
  159. package/dist/web/primitives/facet-filter.js +2 -2
  160. package/dist/web/primitives/field.js +9 -8
  161. package/dist/web/primitives/file-thumbnail.d.ts +3 -0
  162. package/dist/web/primitives/file-thumbnail.js +5 -0
  163. package/dist/web/primitives/form.d.ts +1 -1
  164. package/dist/web/primitives/form.js +6 -6
  165. package/dist/web/primitives/input.js +8 -3
  166. package/dist/web/primitives/layout-elements.js +7 -5
  167. package/dist/web/primitives/layout.js +2 -2
  168. package/dist/web/primitives/located-timestamp-input.js +4 -4
  169. package/dist/web/primitives/money-input.js +13 -17
  170. package/dist/web/primitives/page-header.js +3 -1
  171. package/dist/web/primitives/pager.js +1 -1
  172. package/dist/web/primitives/row-actions.js +6 -7
  173. package/dist/web/primitives/secret-reveal.js +1 -1
  174. package/dist/web/primitives/timestamp-input.d.ts +9 -9
  175. package/dist/web/primitives/timestamp-input.js +21 -21
  176. package/dist/web/primitives/toast.js +12 -13
  177. package/dist/web/primitives/use-focus-on-mount.d.ts +2 -0
  178. package/dist/web/primitives/use-focus-on-mount.js +9 -0
  179. package/dist/web/sse/live-events.d.ts +6 -6
  180. package/dist/web/sse/live-events.js +3 -3
  181. package/dist/web/tokens.d.ts +11 -12
  182. package/dist/web/tokens.js +35 -37
  183. package/dist/web/version/update-checker.js +14 -13
  184. package/dist/web/widgets/ai-text-field.js +1 -1
  185. package/dist/web/widgets/bounded-load-cache.d.ts +1 -1
  186. package/dist/web/widgets/bounded-load-cache.js +10 -4
  187. package/dist/web/widgets/charts.d.ts +10 -10
  188. package/dist/web/widgets/charts.js +8 -8
  189. package/dist/web/widgets/choice-cards.d.ts +17 -0
  190. package/dist/web/widgets/choice-cards.js +12 -0
  191. package/dist/web/widgets/collapsible-section.d.ts +3 -3
  192. package/dist/web/widgets/collapsible-section.js +7 -7
  193. package/dist/web/widgets/detail-list.d.ts +5 -3
  194. package/dist/web/widgets/detail-list.js +5 -3
  195. package/dist/web/widgets/feed-list.d.ts +2 -2
  196. package/dist/web/widgets/feed-list.js +2 -2
  197. package/dist/web/widgets/form-fields.d.ts +14 -14
  198. package/dist/web/widgets/form-fields.js +14 -13
  199. package/dist/web/widgets/index.d.ts +1 -0
  200. package/dist/web/widgets/index.js +5 -4
  201. package/dist/web/widgets/infinity-list.js +3 -3
  202. package/dist/web/widgets/mode-switch.d.ts +2 -2
  203. package/dist/web/widgets/mode-switch.js +2 -2
  204. package/dist/web/widgets/pdf-preview.js +1 -1
  205. package/dist/web/widgets/plan-card.d.ts +2 -0
  206. package/dist/web/widgets/plan-card.js +1 -1
  207. package/dist/web/widgets/progress-list.d.ts +1 -2
  208. package/dist/web/widgets/progress-list.js +1 -2
  209. package/dist/web/widgets/query-table.d.ts +6 -6
  210. package/dist/web/widgets/result-panel.d.ts +16 -16
  211. package/dist/web/widgets/result-panel.js +10 -10
  212. package/dist/web/widgets/section-card.d.ts +3 -3
  213. package/dist/web/widgets/section-card.js +3 -3
  214. package/dist/web/widgets/stat.d.ts +4 -4
  215. package/dist/web/widgets/stat.js +6 -6
  216. package/dist/web/widgets/states.d.ts +4 -4
  217. package/dist/web/widgets/states.js +4 -4
  218. package/dist/web/widgets/upload-zone.js +13 -5
  219. package/dist/web/widgets/use-draft.d.ts +7 -7
  220. package/dist/web/widgets/use-draft.js +7 -7
  221. package/package.json +6 -6
  222. package/src/changes.json +49 -0
package/LICENSE CHANGED
@@ -1,57 +1,21 @@
1
- Business Source License 1.1
2
-
3
- Parameters
4
-
5
- Licensor: Marc Frost
6
-
7
- Licensed Work: @cosmicdrift/kumiko-framework
8
- The Licensed Work is © 2026 Marc Frost.
9
-
10
- Additional Use Grant:
11
- You may use the Licensed Work in production for any purpose, including
12
- commercially, EXCEPT for the Restricted Use.
13
-
14
- "Restricted Use" is defined as using the Licensed Work to provide a platform
15
- or service to third parties that allows them to host, deploy, or run their
16
- own applications built with the Licensed Work. This includes, but is not
17
- limited to: managed hosting services, software-as-a-service (SaaS) platforms,
18
- platform-as-a-service (PaaS), developer platforms, or any multi-tenant
19
- managed offering of the Licensed Work.
20
-
21
- This restriction does not apply to the Licensor, any entity controlled by,
22
- controlling, or under common control with the Licensor ("Affiliates"), or
23
- contractors acting on their behalf. The Licensor remains free to use the
24
- Licensed Work for any purpose, including for the operation of kumiko.rocks.
25
-
26
- Change Date: 2030-05-05
27
- Change License: Apache License, Version 2.0
28
-
29
-
30
- Terms
31
-
32
- The Licensor hereby grants you the right to copy, modify, create derivative works,
33
- redistribute, and make non-production use of the Licensed Work. The Licensor may
34
- make an Additional Use Grant, above, permitting limited production use.
35
-
36
- Effective on the Change Date, or the fourth anniversary of the first publicly
37
- available distribution of the Licensed Work under this License, whichever comes
38
- first, this License will convert to the Change License.
39
-
40
- This Business Source License governs use of the Licensed Work in all cases, except
41
- as to any use that is explicitly granted in the Additional Use Grant above or
42
- under the Change License after the Change Date.
43
-
44
- If your use of the Licensed Work does not comply with the requirements of this
45
- License, you must cease use of the Licensed Work immediately.
46
-
47
- All copies of the Licensed Work, and all derivative works thereof, must include
48
- this License.
49
-
50
- This License does not grant you any right, title, or interest in any trademark,
51
- logo, or branding of the Licensor, except as required to comply with this License.
52
-
53
- TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON AN
54
- “AS IS” BASIS. LICENSOR DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING
55
- WITHOUT LIMITATION WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE,
56
- TITLE, AND NON-INFRINGEMENT. IN NO EVENT WILL LICENSOR BE LIABLE FOR ANY DAMAGES
57
- ARISING OUT OF OR RELATED TO THIS LICENSE OR THE USE OF THE LICENSED WORK.
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Marc Frost
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -28,11 +28,11 @@ export declare function ActionFormBody({ schema, screen, translate, entityId, in
28
28
  readonly translate?: Translate;
29
29
  /** Record id from the route path; the source of the `load` query's id. */
30
30
  readonly entityId?: string;
31
- /** Row-drawer usage (RowAction kind:"drawer", fw#2710): prefill extracted
31
+ /** Row-drawer usage (RowAction kind:"drawer"): prefill extracted
32
32
  * from the clicked row, applied on top of searchParams through the same
33
33
  * renderableFields/sensitive gates (see mergeSearchParamsIntoInitial). */
34
34
  readonly initialOverrides?: Readonly<Record<string, unknown>>;
35
- /** Drawer-hosted usage (toolbarAction kind:"drawer", fw#2225): called
35
+ /** Drawer-hosted usage (toolbarAction kind:"drawer"): called
36
36
  * instead of the redirect-based navigation on successful submit, so the
37
37
  * host closes the drawer + refetches its list regardless of whether
38
38
  * `screen.redirect` is set — a full-page redirect would navigate away
@@ -112,7 +112,7 @@ export function ActionFormBody({ schema, screen, translate, entityId, initialOve
112
112
  // A drawer-hosted form is not a navigation target, so it never takes a handoff.
113
113
  const handoffValues = onSuccess === undefined ? pendingHandoff : undefined;
114
114
  // This screen has no entity, so a money field here declares its own currency
115
- // source (fw#2839, boot-enforced) — without one the form would seed a bare
115
+ // source (boot-enforced) — without one the form would seed a bare
116
116
  // `0` the handler's schema rejects. When a tenant-declared field's config
117
117
  // query errors or holds no value there is no entity default to use, and
118
118
  // submitting a guessed currency would mis-book the amount — block instead.
@@ -129,6 +129,7 @@ export function ActionFormBody({ schema, screen, translate, entityId, initialOve
129
129
  })
130
130
  : undefined, loadableFieldNames);
131
131
  const loadedValues = loadState?.status === "ready" ? loadState.values : undefined;
132
+ const refetchLoadedValues = loadState?.status === "ready" ? loadState.refetch : undefined;
132
133
  const initial = useMemo(() => {
133
134
  // With `load` the loaded record is the only source of values: a crafted link
134
135
  // or a row's params must not seed fields the record would otherwise own.
@@ -204,8 +205,14 @@ export function ActionFormBody({ schema, screen, translate, entityId, initialOve
204
205
  else if (hasSuccessLinks || screen.resetOnSuccess === true) {
205
206
  publish(effectiveTranslate("kumiko.actionForm.success"));
206
207
  }
207
- if (screen.resetOnSuccess === true)
208
- setFormEpoch((epoch) => epoch + 1);
208
+ if (screen.resetOnSuccess === true) {
209
+ // A loaded record is stale after the write: reseed the form from the fresh one.
210
+ const remountForm = () => setFormEpoch((epoch) => epoch + 1);
211
+ if (refetchLoadedValues === undefined)
212
+ remountForm();
213
+ else
214
+ void refetchLoadedValues().finally(remountForm);
215
+ }
209
216
  }
210
217
  // Without a redirect the form stays put; returnTo only replaces an existing
211
218
  // navigation, and never one to a record screen (see redirectTargetsRecord).
@@ -227,6 +234,7 @@ export function ActionFormBody({ schema, screen, translate, entityId, initialOve
227
234
  dispatcher,
228
235
  locale,
229
236
  effectiveTranslate,
237
+ refetchLoadedValues,
230
238
  ]);
231
239
  // The success box disappears with the next edit; a submit clears it itself.
232
240
  const handleDirtyChange = useCallback((dirty) => {
@@ -251,7 +259,7 @@ export function ActionFormBody({ schema, screen, translate, entityId, initialOve
251
259
  return () => navigateToReturnOr(nav, returnTarget, () => nav.navigate({ screenId: lastSegment(target) }));
252
260
  }, [nav, screen.redirect, screen.cancelTarget, onCancelOverride, returnTarget]);
253
261
  // Rendering the form before a tenant-declared currency lands would show the
254
- // fallback and, on a fast click, submit it (fw#2933) — hold instead.
262
+ // fallback and, on a fast click, submit it — hold instead.
255
263
  if (currencyLoading) {
256
264
  return _jsx(QueryLoadingBanner, {});
257
265
  }
@@ -1,16 +1,16 @@
1
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. */
2
+ /** Builds a minimal EntityDefinition from the inline fields of an
3
+ * ActionForm or SecretMint screen. RenderEdit and computeEditViewModel
4
+ * iterate over entity.fields at render time; all other EntityDefinition
5
+ * fields remain undefined. */
6
6
  export declare function synthesizeActionFormEntity(fields: Readonly<Record<string, FieldDefinition>>): EntityDefinition;
7
7
  /** Fields the form may seed and submit. An excluded field the layout does not show
8
8
  * would otherwise reach the payload through its `default`, and the handler rejects it. */
9
9
  export declare function actionFormSubmittableFields(screen: ActionFormScreenDefinition): Readonly<Record<string, FieldDefinition>>;
10
- /** Wandelt ein ActionFormScreenDefinition oder SecretMintScreenDefinition in
11
- * die EntityEditScreen-Shape die RenderEdit erwartet. type wird auf
12
- * "entityEdit" gesetzt damit der Type-Constraint hält; entity wird auf den
13
- * Pseudo-Namen gepinnt — RenderEdit liest das Feld nicht. */
10
+ /** Converts an ActionFormScreenDefinition or SecretMintScreenDefinition to
11
+ * the EntityEditScreen shape expected by RenderEdit. `type` is set to
12
+ * "entityEdit" to satisfy the type constraint, and `entity` is pinned to
13
+ * the pseudo-name because RenderEdit does not read that field. */
14
14
  export declare function synthesizeActionFormScreen(screen: ActionFormScreenDefinition | SecretMintScreenDefinition): EntityEditScreenDefinition;
15
15
  /** Separate id (`${screen.id}:confirm`) keeps this confirm-form screen from
16
16
  * colliding with the mint-form screen's draft key. */
@@ -1,24 +1,22 @@
1
- // Shim für ActionForm-Renderer (Tier 2.7d).
1
+ // Shim for ActionForm rendering.
2
2
  //
3
- // RenderEdit verlangt heute eine `entity: EntityDefinition` + ein
4
- // `screen: EntityEditScreenDefinition` Pair, nutzt aber intern nur
5
- // `entity.fields` und `screen.layout`. ActionForm-Screens haben weder
6
- // eine Entity-Reference noch sind sie type: "entityEdit" — die zwei
7
- // Helper hier shapen den Daten-Input ad-hoc um, damit RenderEdit
8
- // reused werden kann ohne den Stack zu duplizieren.
3
+ // RenderEdit currently requires an `entity: EntityDefinition` and a
4
+ // `screen: EntityEditScreenDefinition` pair, but internally uses only
5
+ // `entity.fields` and `screen.layout`. ActionForm screens have neither an
6
+ // entity reference nor `type: "entityEdit"`; these helpers reshape the input
7
+ // so RenderEdit can be reused without duplicating the rendering stack.
9
8
  //
10
- // Schulden-Flag: Sobald RenderEdit auf entity.transitions / idType /
11
- // defaultCurrency / softDelete zugreift, oder ein zukünftiger Boot-
12
- // Validator die schema.entities-Map cross-referenziert, brechen die
13
- // Type-Lies hier silent. Dann ist es Zeit für eine echte
14
- // RenderActionForm-Komponente, die `fields` direkt als Input nimmt.
15
- // Der Boot-Validator kennt actionForm bereits eigenständig (kein
16
- // entity-Lookup), also ist der Server-Pfad davon nicht betroffen.
9
+ // This workaround becomes invalid if RenderEdit starts reading
10
+ // entity.transitions, idType, defaultCurrency, or softDelete, or if a future
11
+ // boot validator cross-references the schema.entities map. At that point,
12
+ // RenderActionForm should accept `fields` directly. The boot validator already
13
+ // handles actionForm independently without an entity lookup, so the server path
14
+ // is unaffected.
17
15
  import { ACTION_FORM_PSEUDO_ENTITY, isFieldsEditSection, normalizeEditField, sectionFieldSpecs, } from "@cosmicdrift/kumiko-framework/ui-types";
18
- /** Baut eine minimale EntityDefinition aus den Inline-Fields eines
19
- * ActionForm- oder SecretMint-Screens. RenderEdit + computeEditViewModel
20
- * iterieren über entity.fields zur Render-Zeit; alle weiteren
21
- * EntityDefinition-Felder bleiben undefined. */
16
+ /** Builds a minimal EntityDefinition from the inline fields of an
17
+ * ActionForm or SecretMint screen. RenderEdit and computeEditViewModel
18
+ * iterate over entity.fields at render time; all other EntityDefinition
19
+ * fields remain undefined. */
22
20
  export function synthesizeActionFormEntity(fields) {
23
21
  return { fields };
24
22
  }
@@ -68,10 +66,10 @@ export function actionFormSubmittableFields(screen) {
68
66
  : []));
69
67
  return Object.fromEntries(Object.entries(screen.fields).filter(([name]) => inLayout.has(name) || !excluded.includes(name)));
70
68
  }
71
- /** Wandelt ein ActionFormScreenDefinition oder SecretMintScreenDefinition in
72
- * die EntityEditScreen-Shape die RenderEdit erwartet. type wird auf
73
- * "entityEdit" gesetzt damit der Type-Constraint hält; entity wird auf den
74
- * Pseudo-Namen gepinnt — RenderEdit liest das Feld nicht. */
69
+ /** Converts an ActionFormScreenDefinition or SecretMintScreenDefinition to
70
+ * the EntityEditScreen shape expected by RenderEdit. `type` is set to
71
+ * "entityEdit" to satisfy the type constraint, and `entity` is pinned to
72
+ * the pseudo-name because RenderEdit does not read that field. */
75
73
  export function synthesizeActionFormScreen(screen) {
76
74
  return {
77
75
  id: screen.id,
@@ -21,6 +21,7 @@ export type ActionFormLoadState = {
21
21
  } | {
22
22
  readonly status: "ready";
23
23
  readonly values: Readonly<Record<string, unknown>>;
24
+ readonly refetch: () => Promise<void>;
24
25
  };
25
26
  /** A sensitive, writeOnly or password field never takes a value from a loaded
26
27
  * record: the form must not echo a secret back into an input. */
@@ -53,7 +53,7 @@ export function useActionFormLoad(load, recordId, fieldNames) {
53
53
  return { status: "loading" };
54
54
  if (query.data === null)
55
55
  return { status: "missing-record" };
56
- return { status: "ready", values };
56
+ return { status: "ready", values, refetch: query.refetch };
57
57
  }
58
58
  /** Banner for every `load` state that is not "ready". */
59
59
  export function ActionFormLoadStatus({ state, screenId, translate, }) {
@@ -2,10 +2,10 @@ import { jsx as _jsx } from "react/jsx-runtime";
2
2
  // Cross-feature schema access for components that need to resolve a
3
3
  // screen owned by a DIFFERENT feature than the one they're rendering
4
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).
5
+ // screen. `createKumikoApp` provides the full `app.features` list;
6
+ // components elsewhere in the render tree default to an empty list (no
7
+ // cross-feature schema known, e.g. outside `createKumikoApp` or in
8
+ // isolated tests).
9
9
  import { createContext, useContext } from "react";
10
10
  const AppFeaturesContext = createContext([]);
11
11
  export function AppFeaturesProvider({ features, children }) {
@@ -17,14 +17,12 @@ export type ColumnRenderersProviderProps = {
17
17
  readonly value: ColumnRenderersMap;
18
18
  };
19
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.
20
+ /** Looks up the component for a renderer key. Returns undefined when `name` is
21
+ * empty/undefined (the caller has no __component renderer), or when no provider
22
+ * is mounted or the key is absent from the map. The caller (DataTable.renderCell)
23
+ * then logs a warning and falls back to the default type renderer.
25
24
  *
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. */
25
+ * `name` is optional so callers can invoke the hook unconditionally—Rules of
26
+ * Hooks prohibit a function branch that skips the hook. This keeps the call to
27
+ * a single line without requiring the caller to provide a stub key such as `""`. */
30
28
  export declare function useColumnRenderer(name?: string): ColumnRendererComponent | undefined;
@@ -1,29 +1,26 @@
1
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.
2
+ // Column-Renderer-Map: client-side lookup for ListColumn columns that specify a
3
+ // PlatformComponent renderer (`{ react: { __component: "Name" } }`) in the schema
4
+ // instead of a string function. createKumikoApp in renderer/web collects all
5
+ // clientFeatures.columnRenderers and mounts the provider; the DataTable cell
6
+ // renderer looks up the component through `useColumnRenderer(name)`.
7
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.
8
+ // Like CustomScreensProvider, the renderer web bootstrap mounts both providers
9
+ // at the same location. Schemas remain serializable: the component is referenced
10
+ // only by string key, while the map exists solely on the client.
12
11
  import { createContext, useContext } from "react";
13
12
  const ColumnRenderersContext = createContext(undefined);
14
13
  export function ColumnRenderersProvider({ children, value, }) {
15
14
  return (_jsx(ColumnRenderersContext.Provider, { value: value, children: children }));
16
15
  }
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.
16
+ /** Looks up the component for a renderer key. Returns undefined when `name` is
17
+ * empty/undefined (the caller has no __component renderer), or when no provider
18
+ * is mounted or the key is absent from the map. The caller (DataTable.renderCell)
19
+ * then logs a warning and falls back to the default type renderer.
22
20
  *
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. */
21
+ * `name` is optional so callers can invoke the hook unconditionally—Rules of
22
+ * Hooks prohibit a function branch that skips the hook. This keeps the call to
23
+ * a single line without requiring the caller to provide a stub key such as `""`. */
27
24
  export function useColumnRenderer(name) {
28
25
  const map = useContext(ColumnRenderersContext);
29
26
  if (name === undefined || name === "")
@@ -15,7 +15,7 @@ import { buildInitialValues } from "./entity-edit-prefill.js";
15
15
  import { layoutEditFields } from "./layout-fields.js";
16
16
  import { QueryErrorBanner, QueryLoadingBanner } from "./query-state-banners.js";
17
17
  // A money-typed config-edit field renders through RenderField's entityEdit
18
- // `{amount, currency}` payload shape (render-field.tsx, #1923), but
18
+ // `{amount, currency}` payload shape (render-field.tsx), but
19
19
  // `ConfigKeyType` (write-helpers.ts validateType) only ever knows
20
20
  // number/boolean/text/select — a config value is always a bare scalar.
21
21
  // Unwrap back to the amount before it hits config:write:set.
@@ -97,8 +97,12 @@ export function ConfigEditBody({ schema, screen, translate, }) {
97
97
  // Detail load: config:query:values returns ALL keys of the tenant.
98
98
  // We map them via screen.configKeys from short to qualified name onto our
99
99
  // form field values.
100
- const valuesQuery = useQuery("config:query:values", {});
101
- const cascadeQuery = useQuery("config:query:cascade", {});
100
+ const valuesQuery = useQuery("config:query:values", {
101
+ scope: screen.scope,
102
+ });
103
+ const cascadeQuery = useQuery("config:query:cascade", {
104
+ scope: screen.scope,
105
+ });
102
106
  const secretKeys = screen.secretKeys;
103
107
  const secretsQuery = useQuery("secrets:query:list", {}, { enabled: secretKeys !== undefined });
104
108
  const synthEntity = useMemo(() => synthesizeConfigEditEntity(screen.fields), [screen.fields]);
@@ -1,14 +1,13 @@
1
1
  import type { ConfigEditScreenDefinition, EntityDefinition, EntityEditScreenDefinition } from "@cosmicdrift/kumiko-framework/ui-types";
2
2
  import * as z from "zod";
3
- /** Baut eine minimale EntityDefinition aus den Inline-Fields des
4
- * ConfigEdit-Screens. RenderEdit + computeEditViewModel iterieren
5
- * über entity.fields zur Render-Zeit; alle weiteren EntityDefinition-
6
- * Felder bleiben undefined. */
3
+ /** Builds a minimal EntityDefinition from the ConfigEdit screen's inline
4
+ * fields. RenderEdit + computeEditViewModel iterate over entity.fields
5
+ * at render time; all other EntityDefinition fields remain undefined. */
7
6
  export declare function synthesizeConfigEditEntity(fields: ConfigEditScreenDefinition["fields"]): EntityDefinition;
8
- /** Wandelt ein ConfigEditScreenDefinition in die EntityEditScreen-
9
- * Shape die RenderEdit erwartet. type wird auf "entityEdit" gesetzt
10
- * damit der Type-Constraint hält; entity wird auf den Pseudo-Namen
11
- * gepinnt — RenderEdit liest das Feld nicht. */
7
+ /** Converts a ConfigEditScreenDefinition to the EntityEditScreen shape
8
+ * expected by RenderEdit. `type` is set to "entityEdit" to satisfy the
9
+ * type constraint; `entity` is pinned to the pseudo-name — RenderEdit
10
+ * does not read this field. */
12
11
  export declare function synthesizeConfigEditScreen(screen: ConfigEditScreenDefinition): EntityEditScreenDefinition;
13
12
  /** Client-side range check for number keys with declared bounds, so an
14
13
  * out-of-range value surfaces on its field instead of as the server's
@@ -1,31 +1,29 @@
1
- // Shim für ConfigEdit-Renderer (analog zu action-form-shim.ts).
1
+ // Shim for the ConfigEdit renderer (analogous to action-form-shim.ts).
2
2
  //
3
- // RenderEdit verlangt eine `entity: EntityDefinition` + ein
4
- // `screen: EntityEditScreenDefinition` Pair, nutzt aber intern nur
5
- // `entity.fields` und `screen.layout` für das Rendern. ConfigEdit-
6
- // Screens haben weder eine Entity-Reference noch sind sie
7
- // type: "entityEdit" — die zwei Helper hier shapen den Daten-Input
8
- // ad-hoc um, damit RenderEdit reused werden kann.
3
+ // RenderEdit requires an `entity: EntityDefinition` +
4
+ // `screen: EntityEditScreenDefinition` pair, but internally uses only
5
+ // `entity.fields` and `screen.layout` for rendering. ConfigEdit screens
6
+ // have neither an entity reference nor `type: "entityEdit"` — these two
7
+ // helpers reshape the data input ad hoc so RenderEdit can be reused.
9
8
  //
10
- // Selbe Schulden-Reservation wie bei action-form-shim: sobald RenderEdit
11
- // auf entity.transitions / idType / softDelete zugreift, oder ein
12
- // zukünftiger Boot-Validator die schema.entities-Map cross-referenziert,
13
- // brechen die Type-Lies hier silent. Dann ist Zeit für eine echte
14
- // RenderConfigEdit-Komponente die direkt fields nimmt.
9
+ // The same debt reservation as in action-form-shim applies: if RenderEdit
10
+ // starts accessing entity.transitions / idType / softDelete, or a future
11
+ // boot validator cross-references the schema.entities map, these type lies
12
+ // will fail silently. At that point, a real RenderConfigEdit component
13
+ // that takes fields directly is needed.
15
14
  import * as z from "zod";
16
15
  import { I18N_KEY_PARAM } from "../headless/index.js";
17
16
  const CONFIG_EDIT_PSEUDO_ENTITY = "__config-edit__";
18
- /** Baut eine minimale EntityDefinition aus den Inline-Fields des
19
- * ConfigEdit-Screens. RenderEdit + computeEditViewModel iterieren
20
- * über entity.fields zur Render-Zeit; alle weiteren EntityDefinition-
21
- * Felder bleiben undefined. */
17
+ /** Builds a minimal EntityDefinition from the ConfigEdit screen's inline
18
+ * fields. RenderEdit + computeEditViewModel iterate over entity.fields
19
+ * at render time; all other EntityDefinition fields remain undefined. */
22
20
  export function synthesizeConfigEditEntity(fields) {
23
21
  return { fields };
24
22
  }
25
- /** Wandelt ein ConfigEditScreenDefinition in die EntityEditScreen-
26
- * Shape die RenderEdit erwartet. type wird auf "entityEdit" gesetzt
27
- * damit der Type-Constraint hält; entity wird auf den Pseudo-Namen
28
- * gepinnt — RenderEdit liest das Feld nicht. */
23
+ /** Converts a ConfigEditScreenDefinition to the EntityEditScreen shape
24
+ * expected by RenderEdit. `type` is set to "entityEdit" to satisfy the
25
+ * type constraint; `entity` is pinned to the pseudo-name — RenderEdit
26
+ * does not read this field. */
29
27
  export function synthesizeConfigEditScreen(screen) {
30
28
  return {
31
29
  id: screen.id,
@@ -5,7 +5,7 @@ export type CustomScreensProviderProps = {
5
5
  readonly value: CustomScreensMap;
6
6
  };
7
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. */
8
+ /** Looks up the component for a custom screen. Returns undefined
9
+ * when neither a provider is mounted nor screenId is in the map—the
10
+ * caller (KumikoScreen) then displays its placeholder banner. */
11
11
  export declare function useCustomScreenComponent(screenId: string): ComponentType | undefined;
@@ -1,17 +1,17 @@
1
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.
2
+ // Custom-screen component map: client-side lookup for screens of type
3
+ // `custom`. KumikoScreen looks up `screen.id` (or qn) here and renders
4
+ // the matching component. createKumikoApp in renderer/web collects all
5
+ // clientFeatures.components and mounts the provider; tests that check
6
+ // individual custom screens mount the provider directly.
7
7
  import { createContext, useContext } from "react";
8
8
  const CustomScreensContext = createContext(undefined);
9
9
  export function CustomScreensProvider({ children, value }) {
10
10
  return _jsx(CustomScreensContext.Provider, { value: value, children: children });
11
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. */
12
+ /** Looks up the component for a custom screen. Returns undefined
13
+ * when neither a provider is mounted nor screenId is in the map—the
14
+ * caller (KumikoScreen) then displays its placeholder banner. */
15
15
  export function useCustomScreenComponent(screenId) {
16
16
  const map = useContext(CustomScreensContext);
17
17
  if (map === undefined)
@@ -11,6 +11,6 @@ export type DashboardBodyProviderProps = {
11
11
  readonly value: ComponentType<DashboardBodyProps>;
12
12
  };
13
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. */
14
+ /** Undefined when no platform package has registered a dashboard body;
15
+ * KumikoScreen then displays its placeholder banner. */
16
16
  export declare function useDashboardBody(): ComponentType<DashboardBodyProps> | undefined;
@@ -4,8 +4,8 @@ const DashboardBodyContext = createContext(undefined);
4
4
  export function DashboardBodyProvider({ children, value }) {
5
5
  return _jsx(DashboardBodyContext.Provider, { value: value, children: children });
6
6
  }
7
- /** Undefined wenn kein Platform-Package einen Dashboard-Body registriert
8
- * hat — KumikoScreen zeigt dann seinen Placeholder-Banner. */
7
+ /** Undefined when no platform package has registered a dashboard body;
8
+ * KumikoScreen then displays its placeholder banner. */
9
9
  export function useDashboardBody() {
10
10
  return useContext(DashboardBodyContext);
11
11
  }
@@ -2,6 +2,17 @@ import type { FormValues } from "../headless/index.ts";
2
2
  export declare function versionOf(record: Readonly<Record<string, unknown>>): number;
3
3
  export declare function buildInitialValues(fields: Readonly<Record<string, unknown>>, defaultCurrency?: string, moneyCurrencyOverrides?: Readonly<Record<string, string>>): FormValues;
4
4
  export declare function tenantCurrencyMoneyFieldNames(fields: Readonly<Record<string, unknown>>): readonly string[];
5
+ export type TenantCurrencyResolution = {
6
+ readonly status: "not-needed";
7
+ } | {
8
+ readonly status: "loading";
9
+ } | {
10
+ readonly status: "unresolved";
11
+ } | {
12
+ readonly status: "ready";
13
+ readonly currency: string;
14
+ };
15
+ export declare function useTenantCurrency(needed: boolean, fallback: string | undefined): TenantCurrencyResolution;
5
16
  export declare function literalCurrencyOverrides(fields: Readonly<Record<string, unknown>>): Readonly<Record<string, string>>;
6
17
  export declare function useMoneyCurrencyOverrides(fields: Readonly<Record<string, unknown>>, tenantFieldNames: readonly string[], fallback: string | undefined): {
7
18
  readonly overrides: Readonly<Record<string, string>> | undefined;