@cosmicdrift/kumiko-renderer 0.389.0 → 0.390.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 (230) hide show
  1. package/dist/app/projection-detail-body.js +59 -394
  2. package/dist/app/projection-detail-header-model.d.ts +11 -0
  3. package/dist/app/projection-detail-header-model.js +33 -0
  4. package/dist/app/projection-detail-header-region.d.ts +28 -0
  5. package/dist/app/projection-detail-header-region.js +81 -0
  6. package/dist/app/projection-detail-header.d.ts +29 -0
  7. package/dist/app/projection-detail-header.js +84 -0
  8. package/dist/app/projection-detail-navigation.d.ts +13 -0
  9. package/dist/app/projection-detail-navigation.js +91 -0
  10. package/dist/app/projection-detail-states.d.ts +22 -0
  11. package/dist/app/projection-detail-states.js +26 -0
  12. package/dist/app/projection-drawer-host.d.ts +12 -0
  13. package/dist/app/projection-drawer-host.js +10 -0
  14. package/dist/app/projection-list-body.d.ts +1 -1
  15. package/dist/app/projection-list-body.js +69 -189
  16. package/dist/app/projection-list-render-props.d.ts +56 -0
  17. package/dist/app/projection-list-render-props.js +47 -0
  18. package/dist/app/projection-list-render.d.ts +26 -0
  19. package/dist/app/projection-list-render.js +20 -0
  20. package/dist/app/projection-list-row-click.d.ts +12 -0
  21. package/dist/app/projection-list-row-click.js +14 -0
  22. package/dist/app/use-projection-detail-actions.d.ts +35 -0
  23. package/dist/app/use-projection-detail-actions.js +156 -0
  24. package/dist/app/use-projection-detail-data.d.ts +19 -0
  25. package/dist/app/use-projection-detail-data.js +47 -0
  26. package/dist/app/use-projection-detail-layout.d.ts +17 -0
  27. package/dist/app/use-projection-detail-layout.js +23 -0
  28. package/dist/app/use-projection-list-actions.d.ts +31 -0
  29. package/dist/app/use-projection-list-actions.js +73 -0
  30. package/dist/app/use-projection-list-data.d.ts +20 -0
  31. package/dist/app/use-projection-list-data.js +26 -0
  32. package/dist/app/use-projection-list-definitions.d.ts +11 -0
  33. package/dist/app/use-projection-list-definitions.js +20 -0
  34. package/dist/app/use-projection-list-query.d.ts +28 -0
  35. package/dist/app/use-projection-list-query.js +83 -0
  36. package/dist/components/render-edit-banners.d.ts +12 -0
  37. package/dist/components/render-edit-banners.js +90 -0
  38. package/dist/components/render-edit-draft-save-helpers.d.ts +19 -0
  39. package/dist/components/render-edit-draft-save-helpers.js +42 -0
  40. package/dist/components/render-edit-field-grid.d.ts +4 -0
  41. package/dist/components/render-edit-field-grid.js +40 -0
  42. package/dist/components/render-edit-fields-section.d.ts +4 -0
  43. package/dist/components/render-edit-fields-section.js +76 -0
  44. package/dist/components/render-edit-form-actions.d.ts +4 -0
  45. package/dist/components/render-edit-form-actions.js +66 -0
  46. package/dist/components/render-edit-header-actions.d.ts +11 -0
  47. package/dist/components/render-edit-header-actions.js +120 -0
  48. package/dist/components/render-edit-layout-flags.d.ts +29 -0
  49. package/dist/components/render-edit-layout-flags.js +106 -0
  50. package/dist/components/render-edit-layout.d.ts +4 -0
  51. package/dist/components/render-edit-layout.js +79 -0
  52. package/dist/components/render-edit-render-model.d.ts +63 -0
  53. package/dist/components/render-edit-render-model.js +14 -0
  54. package/dist/components/render-edit-section-kinds.d.ts +4 -0
  55. package/dist/components/render-edit-section-kinds.js +115 -0
  56. package/dist/components/render-edit-submit-result.d.ts +8 -0
  57. package/dist/components/render-edit-submit-result.js +77 -0
  58. package/dist/components/render-edit-submit.d.ts +7 -0
  59. package/dist/components/render-edit-submit.js +113 -0
  60. package/dist/components/render-edit-titles.d.ts +17 -0
  61. package/dist/components/render-edit-titles.js +99 -0
  62. package/dist/components/render-edit-wizard-navigation.d.ts +11 -0
  63. package/dist/components/render-edit-wizard-navigation.js +115 -0
  64. package/dist/components/render-edit.d.ts +2 -2
  65. package/dist/components/render-edit.js +63 -1128
  66. package/dist/components/render-field-choice-inputs.d.ts +7 -0
  67. package/dist/components/render-field-choice-inputs.js +52 -0
  68. package/dist/components/render-field-control.d.ts +12 -0
  69. package/dist/components/render-field-control.js +93 -0
  70. package/dist/components/render-field-display-text.d.ts +4 -0
  71. package/dist/components/render-field-display-text.js +48 -0
  72. package/dist/components/render-field-fill-action.d.ts +13 -0
  73. package/dist/components/render-field-fill-action.js +63 -0
  74. package/dist/components/render-field-input-shared.d.ts +39 -0
  75. package/dist/components/render-field-input-shared.js +20 -0
  76. package/dist/components/render-field-input.d.ts +3 -0
  77. package/dist/components/render-field-input.js +34 -0
  78. package/dist/components/render-field-meta.d.ts +6 -0
  79. package/dist/components/render-field-meta.js +51 -0
  80. package/dist/components/render-field-read-only.d.ts +11 -0
  81. package/dist/components/render-field-read-only.js +75 -0
  82. package/dist/components/render-field-reference.d.ts +15 -0
  83. package/dist/components/render-field-reference.js +103 -0
  84. package/dist/components/render-field-scalar-inputs.d.ts +10 -0
  85. package/dist/components/render-field-scalar-inputs.js +35 -0
  86. package/dist/components/render-field-text-inputs.d.ts +3 -0
  87. package/dist/components/render-field-text-inputs.js +34 -0
  88. package/dist/components/render-field-values.d.ts +18 -0
  89. package/dist/components/render-field-values.js +111 -0
  90. package/dist/components/render-field-write-only.d.ts +9 -0
  91. package/dist/components/render-field-write-only.js +29 -0
  92. package/dist/components/render-field.d.ts +2 -2
  93. package/dist/components/render-field.js +39 -670
  94. package/dist/components/render-list-header-slot.d.ts +5 -0
  95. package/dist/components/render-list-header-slot.js +30 -0
  96. package/dist/components/render-list-reference-bridge.d.ts +3 -0
  97. package/dist/components/render-list-reference-bridge.js +25 -0
  98. package/dist/components/render-list-reference-columns.d.ts +25 -0
  99. package/dist/components/render-list-reference-columns.js +137 -0
  100. package/dist/components/render-list-table-props.d.ts +52 -0
  101. package/dist/components/render-list-table-props.js +53 -0
  102. package/dist/components/render-list-toolbar-model.d.ts +42 -0
  103. package/dist/components/render-list-toolbar-model.js +82 -0
  104. package/dist/components/render-list-toolbar.d.ts +38 -0
  105. package/dist/components/render-list-toolbar.js +40 -0
  106. package/dist/components/render-list-types.d.ts +113 -0
  107. package/dist/components/render-list-types.js +1 -0
  108. package/dist/components/render-list.d.ts +4 -113
  109. package/dist/components/render-list.js +91 -307
  110. package/dist/components/use-reference-input-state.d.ts +20 -0
  111. package/dist/components/use-reference-input-state.js +85 -0
  112. package/dist/components/use-render-edit-controlled-sync.d.ts +3 -0
  113. package/dist/components/use-render-edit-controlled-sync.js +26 -0
  114. package/dist/components/use-render-edit-draft-save.d.ts +29 -0
  115. package/dist/components/use-render-edit-draft-save.js +141 -0
  116. package/dist/components/use-render-edit-form.d.ts +10 -0
  117. package/dist/components/use-render-edit-form.js +101 -0
  118. package/dist/components/use-render-edit-sections.d.ts +15 -0
  119. package/dist/components/use-render-edit-sections.js +100 -0
  120. package/dist/components/use-render-edit-state.d.ts +65 -0
  121. package/dist/components/use-render-edit-state.js +158 -0
  122. package/dist/components/use-render-edit-steps.d.ts +13 -0
  123. package/dist/components/use-render-edit-steps.js +52 -0
  124. package/dist/components/use-render-list-columns.d.ts +18 -0
  125. package/dist/components/use-render-list-columns.js +41 -0
  126. package/dist/components/use-render-list-search.d.ts +4 -0
  127. package/dist/components/use-render-list-search.js +50 -0
  128. package/dist/primitives.d.ts +1 -1
  129. package/dist/web/app/dashboard-body.d.ts +1 -1
  130. package/dist/web/app/dashboard-body.js +42 -246
  131. package/dist/web/app/dashboard-header.d.ts +34 -0
  132. package/dist/web/app/dashboard-header.js +58 -0
  133. package/dist/web/app/dashboard-screen-controls.d.ts +11 -0
  134. package/dist/web/app/dashboard-screen-controls.js +42 -0
  135. package/dist/web/app/dashboard-screen-tiles.d.ts +8 -0
  136. package/dist/web/app/dashboard-screen-tiles.js +42 -0
  137. package/dist/web/app/dashboard-visibility.d.ts +42 -0
  138. package/dist/web/app/dashboard-visibility.js +102 -0
  139. package/dist/web/app/use-dashboard-screen-state.d.ts +35 -0
  140. package/dist/web/app/use-dashboard-screen-state.js +69 -0
  141. package/dist/web/primitives/data-table/actions-column.js +6 -5
  142. package/dist/web/primitives/data-table/card-body.d.ts +6 -0
  143. package/dist/web/primitives/data-table/card-body.js +32 -0
  144. package/dist/web/primitives/data-table/card-row.d.ts +5 -0
  145. package/dist/web/primitives/data-table/card-row.js +31 -0
  146. package/dist/web/primitives/data-table/card-view.d.ts +3 -0
  147. package/dist/web/primitives/data-table/card-view.js +13 -0
  148. package/dist/web/primitives/data-table/column-resize-handle.js +3 -1
  149. package/dist/web/primitives/data-table/data-cell-props.d.ts +7 -0
  150. package/dist/web/primitives/data-table/data-cell-props.js +8 -0
  151. package/dist/web/primitives/data-table/row-render-parts.d.ts +8 -0
  152. package/dist/web/primitives/data-table/row-render-parts.js +35 -0
  153. package/dist/web/primitives/data-table/table-body.d.ts +3 -0
  154. package/dist/web/primitives/data-table/table-body.js +32 -0
  155. package/dist/web/primitives/data-table/table-content.d.ts +3 -0
  156. package/dist/web/primitives/data-table/table-content.js +41 -0
  157. package/dist/web/primitives/data-table/table-data-cell.d.ts +4 -0
  158. package/dist/web/primitives/data-table/table-data-cell.js +25 -0
  159. package/dist/web/primitives/data-table/table-header-row.d.ts +3 -0
  160. package/dist/web/primitives/data-table/table-header-row.js +21 -0
  161. package/dist/web/primitives/data-table/table-view.d.ts +3 -0
  162. package/dist/web/primitives/data-table/table-view.js +25 -0
  163. package/dist/web/primitives/data-table/toolbar.d.ts +6 -0
  164. package/dist/web/primitives/data-table/toolbar.js +53 -0
  165. package/dist/web/primitives/data-table/use-data-table-state.d.ts +44 -0
  166. package/dist/web/primitives/data-table/use-data-table-state.js +123 -0
  167. package/dist/web/primitives/data-table.d.ts +3 -4
  168. package/dist/web/primitives/data-table.js +32 -252
  169. package/dist/web/primitives/file-value-list.js +1 -1
  170. package/dist/web/primitives/form-footer-parts.d.ts +25 -0
  171. package/dist/web/primitives/form-footer-parts.js +55 -0
  172. package/dist/web/primitives/form.js +33 -43
  173. package/dist/web/primitives/input-choice-kinds.d.ts +4 -0
  174. package/dist/web/primitives/input-choice-kinds.js +67 -0
  175. package/dist/web/primitives/input-file-kinds.d.ts +3 -0
  176. package/dist/web/primitives/input-file-kinds.js +6 -0
  177. package/dist/web/primitives/input-number-kinds.d.ts +4 -0
  178. package/dist/web/primitives/input-number-kinds.js +16 -0
  179. package/dist/web/primitives/input-optional-props.d.ts +20 -0
  180. package/dist/web/primitives/input-optional-props.js +24 -0
  181. package/dist/web/primitives/input-select-presentation.d.ts +13 -0
  182. package/dist/web/primitives/input-select-presentation.js +19 -0
  183. package/dist/web/primitives/input-shared.d.ts +22 -0
  184. package/dist/web/primitives/input-shared.js +10 -0
  185. package/dist/web/primitives/input-temporal-kinds.d.ts +5 -0
  186. package/dist/web/primitives/input-temporal-kinds.js +10 -0
  187. package/dist/web/primitives/input-text-kinds.d.ts +7 -0
  188. package/dist/web/primitives/input-text-kinds.js +33 -0
  189. package/dist/web/primitives/input.js +35 -161
  190. package/dist/web/widgets/chart-data.d.ts +35 -0
  191. package/dist/web/widgets/chart-data.js +37 -0
  192. package/dist/web/widgets/chart-markers.d.ts +26 -0
  193. package/dist/web/widgets/chart-markers.js +64 -0
  194. package/dist/web/widgets/chart-parts.d.ts +20 -0
  195. package/dist/web/widgets/chart-parts.js +15 -0
  196. package/dist/web/widgets/charts.d.ts +5 -78
  197. package/dist/web/widgets/charts.js +7 -485
  198. package/dist/web/widgets/drawer-panel-class.d.ts +3 -0
  199. package/dist/web/widgets/drawer-panel-class.js +40 -0
  200. package/dist/web/widgets/drawer-resize-controls.d.ts +11 -0
  201. package/dist/web/widgets/drawer-resize-controls.js +12 -0
  202. package/dist/web/widgets/drawer-sizing.d.ts +19 -0
  203. package/dist/web/widgets/drawer-sizing.js +60 -0
  204. package/dist/web/widgets/drawer.js +17 -116
  205. package/dist/web/widgets/stacked-area-brush.d.ts +13 -0
  206. package/dist/web/widgets/stacked-area-brush.js +91 -0
  207. package/dist/web/widgets/stacked-area-chart.d.ts +6 -0
  208. package/dist/web/widgets/stacked-area-chart.js +45 -0
  209. package/dist/web/widgets/stacked-area-chrome.d.ts +7 -0
  210. package/dist/web/widgets/stacked-area-chrome.js +77 -0
  211. package/dist/web/widgets/stacked-area-geometry.d.ts +54 -0
  212. package/dist/web/widgets/stacked-area-geometry.js +83 -0
  213. package/dist/web/widgets/stacked-area-model.d.ts +11 -0
  214. package/dist/web/widgets/stacked-area-model.js +1 -0
  215. package/dist/web/widgets/stacked-area-plot.d.ts +3 -0
  216. package/dist/web/widgets/stacked-area-plot.js +51 -0
  217. package/dist/web/widgets/stacked-area-props.d.ts +83 -0
  218. package/dist/web/widgets/stacked-area-props.js +16 -0
  219. package/dist/web/widgets/stacked-area-svg.d.ts +3 -0
  220. package/dist/web/widgets/stacked-area-svg.js +38 -0
  221. package/dist/web/widgets/stacked-area-tooltip.d.ts +3 -0
  222. package/dist/web/widgets/stacked-area-tooltip.js +86 -0
  223. package/dist/web/widgets/use-drawer-resize.d.ts +22 -0
  224. package/dist/web/widgets/use-drawer-resize.js +52 -0
  225. package/dist/web/widgets/use-stacked-area-tooltip.d.ts +9 -0
  226. package/dist/web/widgets/use-stacked-area-tooltip.js +34 -0
  227. package/dist/web/widgets/use-stacked-area-window.d.ts +20 -0
  228. package/dist/web/widgets/use-stacked-area-window.js +76 -0
  229. package/package.json +9 -9
  230. package/src/changes.json +54 -0
@@ -0,0 +1,5 @@
1
+ import type { EntityListScreenDefinition } from "@cosmicdrift/kumiko-framework/ui-types";
2
+ import { type ReactNode } from "react";
3
+ export declare function ListHeaderSlotMount({ screen, }: {
4
+ readonly screen: EntityListScreenDefinition;
5
+ }): ReactNode;
@@ -0,0 +1,30 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { useEffect } from "react";
3
+ import { extensionSectionName, useExtensionSectionComponent } from "../app/extension-sections.js";
4
+ import { rendererWarn } from "../dev-console.js";
5
+ // Header slot in the list toolbar (toolbarEnd): `screen.slots.header` is
6
+ // a PlatformComponent (`{ react: { __component: "X" } }`) resolved through
7
+ // the same ExtensionSectionsProvider registry as entityEdit sections.
8
+ // entityId is null in the list context because there is no row; the component
9
+ // loads its own data (for example, a cap counter from a usage query). A
10
+ // separate component is required by the Rules of Hooks because
11
+ // useExtensionSectionComponent must not run conditionally in RenderList.
12
+ export function ListHeaderSlotMount({ screen, }) {
13
+ const header = screen.slots?.header;
14
+ const name = header !== undefined ? extensionSectionName(header) : undefined;
15
+ const Component = useExtensionSectionComponent(name);
16
+ // A declared-but-unregistered header slot renders nothing; warn so the author
17
+ // finds the typo / missing clientFeatures.extensionSectionComponents entry,
18
+ // mirroring the diagnostic banner in render-edit's ExtensionSectionMount
19
+ // (the toolbar has no room for a banner, so a dev-warn it is).
20
+ useEffect(() => {
21
+ if (name !== undefined && Component === undefined) {
22
+ rendererWarn(`[kumiko] List header slot component "${name}" on screen "${screen.id}" is not registered in clientFeatures.extensionSectionComponents — the header slot renders nothing.`);
23
+ }
24
+ }, [name, Component, screen.id]);
25
+ if (Component === undefined)
26
+ return null;
27
+ // screenId lets a header control drive this list's URL-filter state
28
+ // (useListUrlState) — e.g. a tag filter narrowing the list to an id-set.
29
+ return _jsx(Component, { entityName: screen.entity, entityId: null, screenId: screen.id });
30
+ }
@@ -0,0 +1,3 @@
1
+ import type { ReactNode } from "react";
2
+ import type { PublishedReferenceLookup, ReferenceColumnSpec } from "./render-list-reference-columns.ts";
3
+ export declare function renderReferenceLookupBridges(referenceColumns: readonly ReferenceColumnSpec[], onMap: (field: string, lookup: PublishedReferenceLookup) => void): ReactNode;
@@ -0,0 +1,25 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { useEffect } from "react";
3
+ import { useReferenceLookup } from "../hooks/use-reference-lookup.js";
4
+ // Bridge component for each reference column. It is mounted once per
5
+ // column, calls useReferenceLookup unconditionally, and publishes the map
6
+ // to the parent through onMap. React manages mounting and unmounting when
7
+ // the schema changes through the key prop in the parent's map loop.
8
+ function ReferenceLookupBridge({ field, refEntity, labelField, featureName, onMap, }) {
9
+ const lookup = useReferenceLookup(featureName, refEntity, labelField);
10
+ // Use an effect rather than calling directly so setState runs outside the
11
+ // render path; otherwise React warns about updating one component while
12
+ // rendering another.
13
+ // Do not publish while loading or after a failed lookup: a missing map means
14
+ // "not resolved", whereas an empty published map means "nothing found".
15
+ // Only the latter may display "Unknown".
16
+ const resolved = !lookup.loading && !lookup.failed;
17
+ useEffect(() => {
18
+ if (resolved)
19
+ onMap(field, { map: lookup.map, complete: lookup.complete });
20
+ }, [field, lookup.map, lookup.complete, resolved, onMap]);
21
+ return null;
22
+ }
23
+ export function renderReferenceLookupBridges(referenceColumns, onMap) {
24
+ return referenceColumns.map((rc) => (_jsx(ReferenceLookupBridge, { field: rc.field, refEntity: rc.refEntity, labelField: rc.labelField, featureName: rc.refFeature, onMap: onMap }, rc.field)));
25
+ }
@@ -0,0 +1,25 @@
1
+ import type { useReferenceLinkResolver } from "../app/reference-link.ts";
2
+ import type { ListColumnViewModel, Translate } from "../headless/index.ts";
3
+ import type { ReferenceLookupMap } from "../hooks/use-reference-lookup.ts";
4
+ export type PublishedReferenceLookup = {
5
+ readonly map: ReferenceLookupMap;
6
+ readonly complete: boolean;
7
+ };
8
+ export type ReferenceColumnSpec = {
9
+ readonly field: string;
10
+ readonly refEntity: string;
11
+ readonly refFeature: string;
12
+ readonly labelField: string;
13
+ };
14
+ type ResolveReferenceLink = ReturnType<typeof useReferenceLinkResolver>;
15
+ export declare function selectReferenceColumns(columns: readonly ListColumnViewModel[], featureName: string): ReferenceColumnSpec[];
16
+ export type EnrichReferenceColumnsInput = {
17
+ readonly columns: readonly ListColumnViewModel[];
18
+ readonly referenceColumns: readonly ReferenceColumnSpec[];
19
+ readonly referenceLookups: Readonly<Record<string, PublishedReferenceLookup>>;
20
+ readonly resolveReferenceLink: ResolveReferenceLink;
21
+ readonly featureName: string;
22
+ readonly translate: Translate;
23
+ };
24
+ export declare function enrichReferenceColumns(input: EnrichReferenceColumnsInput): readonly ListColumnViewModel[];
25
+ export {};
@@ -0,0 +1,137 @@
1
+ import { UNRESOLVED_REFERENCE_LABEL_KEYS } from "@cosmicdrift/kumiko-framework/ui-types";
2
+ import { EMPTY_VALUE_PLACEHOLDER } from "../headless/index.js";
3
+ function isPlainRecord(value) {
4
+ return typeof value === "object" && value !== null && !Array.isArray(value);
5
+ }
6
+ // The server leaves a missing or unreadable target out of `_refs`, and a null
7
+ // entry means the same: both read as unresolved.
8
+ function eagerloadedRef(row, field) {
9
+ // skip: row carries no eager-loaded refs, so the lookup map decides
10
+ if (!isPlainRecord(row) || !isPlainRecord(row["_refs"]))
11
+ return undefined;
12
+ const ref = row["_refs"][field];
13
+ if (Array.isArray(ref))
14
+ return ref.filter(isPlainRecord);
15
+ return isPlainRecord(ref) ? ref : undefined;
16
+ }
17
+ export function selectReferenceColumns(columns, featureName) {
18
+ return columns
19
+ .filter((c) => c.type === "reference" && c.refEntity !== undefined)
20
+ .map((c) => ({
21
+ field: c.field,
22
+ refEntity: c.refEntity ?? "",
23
+ // refFeature comes from parseRefTarget in the ViewModel
24
+ // (default = the current featureName).
25
+ refFeature: c.refFeature ?? featureName,
26
+ labelField: c.refLabelField ?? "id",
27
+ }));
28
+ }
29
+ // No raw id for entities that opt in: a placeholder while the lookup
30
+ // loads, the "unknown" label once the complete lookup found nothing. A
31
+ // capped lookup page cannot prove absence, so it keeps the raw id.
32
+ function unresolvedLabelFor(unknownKey, published, translate) {
33
+ return (id) => unknownKey === undefined
34
+ ? id
35
+ : published === undefined
36
+ ? EMPTY_VALUE_PLACEHOLDER
37
+ : published.complete
38
+ ? translate(unknownKey)
39
+ : id;
40
+ }
41
+ // Only a row the user can see is linkable: resolved by the server
42
+ // eagerload or by the lookup query. A multi-reference links per entry via linkItemsFor.
43
+ function buildLinkFor(lookup) {
44
+ const { col, map, refEntity, resolveReferenceLink } = lookup;
45
+ return (value, row) => {
46
+ // skip: empty and multi-valued cells have no single target to link
47
+ if (value === null || value === undefined || value === "" || Array.isArray(value)) {
48
+ return undefined;
49
+ }
50
+ const id = String(value);
51
+ const eagerloaded = eagerloadedRef(row, col.field);
52
+ // The server leaves a missing or unreadable target out; null is treated the same.
53
+ const resolved = (typeof eagerloaded === "object" && eagerloaded !== null && !Array.isArray(eagerloaded)) ||
54
+ map?.has(id);
55
+ return resolved === true ? resolveReferenceLink(refEntity, id) : undefined;
56
+ };
57
+ }
58
+ function buildLinkItemsFor(lookup) {
59
+ const { col, map, refEntity, labelField, resolveReferenceLink, unresolvedLabel } = lookup;
60
+ return (value, row) => {
61
+ // skip: only a non-empty array is a multi-reference value
62
+ if (!Array.isArray(value) || value.length === 0)
63
+ return undefined;
64
+ const eagerloaded = eagerloadedRef(row, col.field);
65
+ const eagerById = new Map(Array.isArray(eagerloaded) ? eagerloaded.map((r) => [String(r["id"]), r]) : []);
66
+ return value.map((v) => {
67
+ const id = String(v);
68
+ const target = eagerById.get(id);
69
+ const label = String(target?.[labelField] ?? map?.get(id) ?? unresolvedLabel(id));
70
+ // Only a row the user can see is linkable: server eagerload or lookup query.
71
+ const link = target !== undefined || map?.has(id) === true
72
+ ? resolveReferenceLink(refEntity, id)
73
+ : undefined;
74
+ return { id, label, ...(link !== undefined && { link }) };
75
+ });
76
+ };
77
+ }
78
+ function buildReferenceRenderer(lookup) {
79
+ const { col, map, labelField, unresolvedLabel } = lookup;
80
+ return (value, row) => {
81
+ // Server eager loading: when the server includes _refs, read the display
82
+ // value directly from the resolved row. This avoids a round trip
83
+ // through the bridge map and the limit:200 constraint. The
84
+ // EagerloadedRow type from @cosmicdrift/kumiko-framework/db defines
85
+ // the shape of _refs.
86
+ const resolved = eagerloadedRef(row, col.field);
87
+ if (Array.isArray(resolved) && resolved.length > 0) {
88
+ return resolved.map((r) => String(r[labelField] ?? r["id"] ?? "")).join(", ");
89
+ }
90
+ if (isPlainRecord(resolved)) {
91
+ return String(resolved[labelField] ?? resolved["id"] ?? "");
92
+ }
93
+ // Renderer-side fallback when server eager loading is not active.
94
+ if (Array.isArray(value)) {
95
+ if (value.length === 0)
96
+ return EMPTY_VALUE_PLACEHOLDER;
97
+ return value.map((v) => map?.get(String(v)) ?? unresolvedLabel(String(v))).join(", ");
98
+ }
99
+ if (value === null || value === undefined || value === "")
100
+ return EMPTY_VALUE_PLACEHOLDER;
101
+ const idStr = String(value);
102
+ return map?.get(idStr) ?? unresolvedLabel(idStr);
103
+ };
104
+ }
105
+ function enrichReferenceColumn(col, input) {
106
+ const { referenceLookups, resolveReferenceLink, featureName, translate } = input;
107
+ // skip: only reference columns are enriched
108
+ if (col.type !== "reference")
109
+ return col;
110
+ // skip: an author-declared renderer always takes precedence; the default
111
+ // is used only when none is set.
112
+ if (col.renderer !== undefined)
113
+ return col;
114
+ const published = referenceLookups[col.field];
115
+ const unknownKey = UNRESOLVED_REFERENCE_LABEL_KEYS[`${col.refFeature ?? featureName}:${col.refEntity ?? ""}`];
116
+ const lookup = {
117
+ col,
118
+ map: published?.map,
119
+ refEntity: col.refEntity ?? "",
120
+ labelField: col.refLabelField ?? "id",
121
+ resolveReferenceLink,
122
+ unresolvedLabel: unresolvedLabelFor(unknownKey, published, translate),
123
+ };
124
+ return {
125
+ ...col,
126
+ renderer: buildReferenceRenderer(lookup),
127
+ linkFor: buildLinkFor(lookup),
128
+ linkItemsFor: buildLinkItemsFor(lookup),
129
+ };
130
+ }
131
+ export function enrichReferenceColumns(input) {
132
+ const { columns, referenceColumns } = input;
133
+ // skip: without reference columns the view-model columns pass through untouched
134
+ if (referenceColumns.length === 0)
135
+ return columns;
136
+ return columns.map((col) => enrichReferenceColumn(col, input));
137
+ }
@@ -0,0 +1,52 @@
1
+ import type { ReactNode } from "react";
2
+ import type { RenderListProps } from "./render-list-types.ts";
3
+ type Pick2<K extends keyof RenderListProps> = Pick<RenderListProps, K>;
4
+ export declare function tableChromeProps(p: Pick2<"onRowClick" | "description"> & {
5
+ readonly composedEmptyState: ReactNode;
6
+ readonly toolbarStart: ReactNode;
7
+ readonly toolbarEnd: ReactNode;
8
+ readonly itemNoun: ((count: number) => string) | undefined;
9
+ }): {
10
+ onRowClick?: ((row: import("../headless/index.ts").ListRowViewModel) => void) | undefined;
11
+ emptyState?: string | number | bigint | boolean | Iterable<ReactNode> | Promise<string | number | bigint | boolean | Iterable<ReactNode> | import("react").ReactElement<unknown, string | import("react").JSXElementConstructor<any>> | import("react").ReactPortal | null | undefined> | import("react").ReactElement<unknown, string | import("react").JSXElementConstructor<any>> | import("react").ReactPortal | null | undefined;
12
+ toolbarStart?: string | number | bigint | boolean | Iterable<ReactNode> | Promise<string | number | bigint | boolean | Iterable<ReactNode> | import("react").ReactElement<unknown, string | import("react").JSXElementConstructor<any>> | import("react").ReactPortal | null | undefined> | import("react").ReactElement<unknown, string | import("react").JSXElementConstructor<any>> | import("react").ReactPortal | null | undefined;
13
+ toolbarDescription?: string | undefined;
14
+ toolbarEnd?: string | number | bigint | boolean | Iterable<ReactNode> | Promise<string | number | bigint | boolean | Iterable<ReactNode> | import("react").ReactElement<unknown, string | import("react").JSXElementConstructor<any>> | import("react").ReactPortal | null | undefined> | import("react").ReactElement<unknown, string | import("react").JSXElementConstructor<any>> | import("react").ReactPortal | null | undefined;
15
+ itemNoun?: ((count: number) => string) | undefined;
16
+ };
17
+ export declare function tableSortPagingProps(p: Pick2<"sort" | "onSortChange" | "pager" | "onReachEnd" | "loadingMore" | "hasMore">): {
18
+ sort?: import("../primitives.tsx").DataTableSort | null | undefined;
19
+ onSortChange?: ((next: import("../index.ts").ListSort | null) => void) | undefined;
20
+ pager?: {
21
+ readonly page: number;
22
+ readonly limit: number;
23
+ readonly total: number;
24
+ readonly onPageChange: (next: number) => void;
25
+ } | undefined;
26
+ onReachEnd?: (() => void) | undefined;
27
+ loadingMore?: boolean | undefined;
28
+ hasMore?: boolean | undefined;
29
+ };
30
+ export declare function tableRowProps(p: Pick2<"rowActions" | "rowActionMode" | "bulk" | "rowTone">): {
31
+ rowActions?: readonly import("../primitives.tsx").DataTableRowAction[] | undefined;
32
+ rowActionMode?: import("../primitives.tsx").DataTableRowActionMode | undefined;
33
+ bulk?: import("../data-table-bulk-types.ts").DataTableBulk | undefined;
34
+ rowTone?: ((row: import("../headless/index.ts").ListRowViewModel) => import("@cosmicdrift/kumiko-types/fields").SelectOptionTone | undefined) | undefined;
35
+ };
36
+ export declare function tableFilterProps(p: Pick2<"filterFacets" | "filterValues" | "onFilterChange" | "onFilterReset" | "dateRangeFacets" | "onDateRangeChange">): {
37
+ filterFacets?: readonly import("../data-table-facet-types.ts").DataTableFacet[] | undefined;
38
+ filterValues?: Readonly<Record<string, readonly string[]>> | undefined;
39
+ onFilterChange?: ((field: string, values: readonly string[]) => void) | undefined;
40
+ onFilterReset?: (() => void) | undefined;
41
+ dateRangeFacets?: readonly import("../data-table-facet-types.ts").DataTableDateRangeFacet[] | undefined;
42
+ onDateRangeChange?: ((field: string, bound: "from" | "to", value: string) => void) | undefined;
43
+ };
44
+ export declare function tableLayoutProps(p: Pick2<"chromeless" | "scrollBody" | "screenPadding" | "expandedRowIds" | "onToggleRowExpanded" | "renderExpandedRow">): {
45
+ chromeless?: boolean | undefined;
46
+ scrollBody?: boolean | undefined;
47
+ screenPadding?: boolean | undefined;
48
+ expandedRowIds?: ReadonlySet<string> | undefined;
49
+ onToggleRowExpanded?: ((rowId: string) => void) | undefined;
50
+ renderExpandedRow?: ((row: import("../headless/index.ts").ListRowViewModel) => ReactNode) | undefined;
51
+ };
52
+ export {};
@@ -0,0 +1,53 @@
1
+ export function tableChromeProps(p) {
2
+ const { onRowClick, composedEmptyState, toolbarStart, description, toolbarEnd, itemNoun } = p;
3
+ return {
4
+ ...(onRowClick !== undefined && { onRowClick }),
5
+ ...(composedEmptyState !== undefined && { emptyState: composedEmptyState }),
6
+ ...(toolbarStart !== undefined && { toolbarStart }),
7
+ ...(description !== undefined && { toolbarDescription: description }),
8
+ ...(toolbarEnd !== undefined && { toolbarEnd }),
9
+ ...(itemNoun !== undefined && { itemNoun }),
10
+ };
11
+ }
12
+ export function tableSortPagingProps(p) {
13
+ const { sort, onSortChange, pager, onReachEnd, loadingMore, hasMore } = p;
14
+ return {
15
+ ...(sort !== undefined && { sort }),
16
+ ...(onSortChange !== undefined && { onSortChange }),
17
+ ...(pager !== undefined && { pager }),
18
+ ...(onReachEnd !== undefined && { onReachEnd }),
19
+ ...(loadingMore !== undefined && { loadingMore }),
20
+ ...(hasMore !== undefined && { hasMore }),
21
+ };
22
+ }
23
+ export function tableRowProps(p) {
24
+ const { rowActions, rowActionMode, bulk, rowTone } = p;
25
+ return {
26
+ ...(rowActions !== undefined && { rowActions }),
27
+ ...(rowActionMode !== undefined && { rowActionMode }),
28
+ ...(bulk !== undefined && { bulk }),
29
+ ...(rowTone !== undefined && { rowTone }),
30
+ };
31
+ }
32
+ export function tableFilterProps(p) {
33
+ const { filterFacets, filterValues, onFilterChange, onFilterReset, dateRangeFacets, onDateRangeChange, } = p;
34
+ return {
35
+ ...(filterFacets !== undefined && { filterFacets }),
36
+ ...(filterValues !== undefined && { filterValues }),
37
+ ...(onFilterChange !== undefined && { onFilterChange }),
38
+ ...(onFilterReset !== undefined && { onFilterReset }),
39
+ ...(dateRangeFacets !== undefined && { dateRangeFacets }),
40
+ ...(onDateRangeChange !== undefined && { onDateRangeChange }),
41
+ };
42
+ }
43
+ export function tableLayoutProps(p) {
44
+ const { chromeless, scrollBody, screenPadding, expandedRowIds, onToggleRowExpanded, renderExpandedRow, } = p;
45
+ return {
46
+ ...(chromeless !== undefined && { chromeless }),
47
+ ...(scrollBody !== undefined && { scrollBody }),
48
+ ...(screenPadding !== undefined && { screenPadding }),
49
+ ...(expandedRowIds !== undefined && { expandedRowIds }),
50
+ ...(onToggleRowExpanded !== undefined && { onToggleRowExpanded }),
51
+ ...(renderExpandedRow !== undefined && { renderExpandedRow }),
52
+ };
53
+ }
@@ -0,0 +1,42 @@
1
+ import type { EntityListScreenDefinition } from "@cosmicdrift/kumiko-framework/ui-types";
2
+ import type { Translate } from "../headless/index.ts";
3
+ import { type ActionMenuItemSpec } from "../primitives.tsx";
4
+ import type { ToolbarActionButton } from "./render-list-toolbar-action.tsx";
5
+ type ToolbarModelInput = {
6
+ readonly toolbarActions: readonly ToolbarActionButton[] | undefined;
7
+ readonly pageHeaderAvailable: boolean;
8
+ readonly pageHeaderSlotAvailable: boolean;
9
+ readonly pageHeaderCompact: boolean;
10
+ readonly createInPageHeader: boolean;
11
+ };
12
+ export type ToolbarActionSplit = {
13
+ readonly toolbarIconOnly: boolean;
14
+ readonly promotedToolbarActions: readonly ToolbarActionButton[];
15
+ readonly promotedInOverflowMenu: boolean;
16
+ readonly toolbarActionsInToolbar: readonly ToolbarActionButton[];
17
+ readonly hasToolbarActionsInToolbar: boolean;
18
+ };
19
+ export declare function splitToolbarActions(input: ToolbarModelInput): ToolbarActionSplit;
20
+ type MenuItemInput = {
21
+ readonly promotedToolbarActions: readonly ToolbarActionButton[];
22
+ readonly promotedInOverflowMenu: boolean;
23
+ readonly menuActionBusyId: string | null;
24
+ readonly setMenuActionBusyId: (id: string | null) => void;
25
+ readonly setMenuActionError: (message: string | null) => void;
26
+ };
27
+ export declare function buildPromotedMenuItems(input: MenuItemInput): readonly ActionMenuItemSpec[];
28
+ type ListLabelInput = {
29
+ readonly screen: EntityListScreenDefinition;
30
+ readonly translate: Translate;
31
+ readonly createLabel: string | undefined;
32
+ readonly searchPlaceholder: string | undefined;
33
+ readonly itemNounKey: string | undefined;
34
+ readonly featureName: string;
35
+ };
36
+ export declare function resolveToolbarLabels(input: ListLabelInput): {
37
+ effectiveCreateLabel: string;
38
+ effectiveSearchPlaceholder: string;
39
+ };
40
+ export declare function resolveItemNoun(input: ListLabelInput): ((count: number) => string) | undefined;
41
+ export declare function resolveToolbarTitle(screen: EntityListScreenDefinition, translate: Translate): string;
42
+ export {};
@@ -0,0 +1,82 @@
1
+ import { shouldRenderActionsIconOnly } from "../primitives.js";
2
+ import { needsActionConfirm } from "./render-edit-action-button.js";
3
+ // Icon-less actions are promoted too; on phones the call site falls back to a
4
+ // "plus" icon, on desktop the label carries the action.
5
+ function isHeaderPromotableToolbarAction(action) {
6
+ return action.style === "primary" && !needsActionConfirm(action);
7
+ }
8
+ export function splitToolbarActions(input) {
9
+ const { toolbarActions, pageHeaderAvailable, pageHeaderSlotAvailable, pageHeaderCompact, createInPageHeader, } = input;
10
+ const hasToolbarActions = toolbarActions !== undefined && toolbarActions.length > 0;
11
+ const toolbarIconOnly = hasToolbarActions && shouldRenderActionsIconOnly(toolbarActions);
12
+ // Every primary toolbar action takes the page-header slot, left of the create
13
+ // button (which stays the rightmost primary action): labelled on desktop, so
14
+ // projection lists look like entity lists. On phones an icon button, or, next to
15
+ // the create button, an entry in the header's overflow menu: the header has no
16
+ // room for a labelled action beside it.
17
+ const promotedToolbarActions = pageHeaderAvailable && pageHeaderSlotAvailable
18
+ ? (toolbarActions?.filter(isHeaderPromotableToolbarAction) ?? [])
19
+ : [];
20
+ const promotedInOverflowMenu = pageHeaderCompact && createInPageHeader && promotedToolbarActions.length > 0;
21
+ const toolbarActionsInToolbar = toolbarActions?.filter((a) => !promotedToolbarActions.includes(a)) ?? [];
22
+ const hasToolbarActionsInToolbar = toolbarActionsInToolbar.length > 0;
23
+ return {
24
+ toolbarIconOnly,
25
+ promotedToolbarActions,
26
+ promotedInOverflowMenu,
27
+ toolbarActionsInToolbar,
28
+ hasToolbarActionsInToolbar,
29
+ };
30
+ }
31
+ export function buildPromotedMenuItems(input) {
32
+ const { promotedToolbarActions, promotedInOverflowMenu, menuActionBusyId, setMenuActionBusyId, setMenuActionError, } = input;
33
+ return promotedInOverflowMenu
34
+ ? promotedToolbarActions.map((a) => ({
35
+ id: a.id,
36
+ label: a.label,
37
+ ...(a.icon !== undefined && { icon: a.icon }),
38
+ ...(menuActionBusyId !== null && { disabled: true }),
39
+ testId: `render-list-toolbar-action-${a.id}`,
40
+ onSelect: () => {
41
+ setMenuActionBusyId(a.id);
42
+ setMenuActionError(null);
43
+ void (async () => {
44
+ try {
45
+ await a.onTrigger();
46
+ }
47
+ catch (e) {
48
+ setMenuActionError(e instanceof Error ? e.message : String(e));
49
+ }
50
+ finally {
51
+ setMenuActionBusyId(null);
52
+ }
53
+ })();
54
+ },
55
+ }))
56
+ : [];
57
+ }
58
+ export function resolveToolbarLabels(input) {
59
+ const { screen, translate, createLabel, searchPlaceholder } = input;
60
+ // i18n defaults for toolbar and empty-state strings. The caller can
61
+ // override each one through a prop; otherwise the framework bundles provide
62
+ // them (kumiko.actions.create, kumiko.list.search-placeholder, …).
63
+ const effectiveCreateLabel = translate(createLabel ?? screen.createLabel ?? "kumiko.actions.create");
64
+ const effectiveSearchPlaceholder = translate(searchPlaceholder ?? screen.searchPlaceholder ?? "kumiko.list.search-placeholder");
65
+ return { effectiveCreateLabel, effectiveSearchPlaceholder };
66
+ }
67
+ export function resolveItemNoun(input) {
68
+ const { screen, translate, itemNounKey, featureName } = input;
69
+ const nounKey = itemNounKey ?? `${featureName}:entity:${screen.entity}:noun`;
70
+ return (itemNounKey !== undefined || !screen.entity.startsWith("__")) &&
71
+ translate(nounKey, { count: 2 }) !== nounKey
72
+ ? (count) => translate(nounKey, { count })
73
+ : undefined;
74
+ }
75
+ // Title resolution uses the conventional i18n key `screen:<id>.title`.
76
+ // If the bundle knows the key, use its translated title; otherwise use
77
+ // screenId so the app developer can see that the translation is missing.
78
+ export function resolveToolbarTitle(screen, translate) {
79
+ const titleKey = `screen:${screen.id}.title`;
80
+ const resolvedTitle = translate(titleKey);
81
+ return resolvedTitle === titleKey ? screen.id : resolvedTitle;
82
+ }
@@ -0,0 +1,38 @@
1
+ import type { EntityListScreenDefinition } from "@cosmicdrift/kumiko-framework/ui-types";
2
+ import type { ReactNode } from "react";
3
+ import type { Translate } from "../headless/index.ts";
4
+ import type { ActionMenuItemSpec, usePrimitives } from "../primitives.tsx";
5
+ import { type ListEmptyStateContent } from "./list-empty-state.tsx";
6
+ import type { ToolbarActionSplit } from "./render-list-toolbar-model.ts";
7
+ type Primitives = ReturnType<typeof usePrimitives>;
8
+ export type ListToolbarModel = {
9
+ readonly screen: EntityListScreenDefinition;
10
+ readonly Button: Primitives["Button"];
11
+ readonly Dialog: Primitives["Dialog"];
12
+ readonly Banner: Primitives["Banner"];
13
+ readonly onCreate: (() => void) | undefined;
14
+ readonly createInPageHeader: boolean;
15
+ readonly pageHeaderCompact: boolean;
16
+ readonly effectiveCreateLabel: string;
17
+ readonly split: ToolbarActionSplit;
18
+ };
19
+ export declare function renderCreateButton(model: ListToolbarModel): ReactNode;
20
+ export declare function renderHeaderActions(model: ListToolbarModel, createButton: ReactNode): ReactNode;
21
+ export declare function renderToolbarEnd(model: ListToolbarModel, createButton: ReactNode): ReactNode;
22
+ export declare function renderSearchInput(Input: Primitives["Input"], localQ: string, setLocalQ: (next: string) => void, placeholder: string): ReactNode;
23
+ type EmptyStateModel = {
24
+ readonly Button: Primitives["Button"];
25
+ readonly emptyState: ReactNode;
26
+ readonly onCreate: (() => void) | undefined;
27
+ readonly emptyContent: ListEmptyStateContent | undefined;
28
+ readonly narrowed: boolean;
29
+ readonly defaultFilterActive: boolean;
30
+ readonly onFilterReset: (() => void) | undefined;
31
+ readonly translate: Translate;
32
+ readonly createInPageHeader: boolean;
33
+ readonly effectiveCreateLabel: string;
34
+ };
35
+ export declare function composeEmptyState(model: EmptyStateModel): ReactNode;
36
+ export declare function renderPageHeader(PageHeader: NonNullable<Primitives["PageHeader"]>, headerActions: ReactNode, promotedInOverflowMenu: boolean, promotedMenuItems: readonly ActionMenuItemSpec[]): ReactNode;
37
+ export declare function renderMenuActionError(Banner: Primitives["Banner"], menuActionError: string): ReactNode;
38
+ export {};
@@ -0,0 +1,40 @@
1
+ import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { ListEmptyStateBody } from "./list-empty-state.js";
3
+ import { ListHeaderSlotMount } from "./render-list-header-slot.js";
4
+ import { ToolbarActionView } from "./render-list-toolbar-action.js";
5
+ export function renderCreateButton(model) {
6
+ const { Button, onCreate, createInPageHeader, pageHeaderCompact, effectiveCreateLabel } = model;
7
+ return onCreate !== undefined && createInPageHeader && pageHeaderCompact ? (_jsx(Button, { variant: "primary", icon: "plus", size: "icon", ariaLabel: effectiveCreateLabel, title: effectiveCreateLabel, onClick: onCreate, testId: "render-list-create" })) : onCreate !== undefined ? (_jsx(Button, { variant: "primary", icon: "plus", onClick: onCreate, testId: "render-list-create", className: "px-3.5", children: effectiveCreateLabel })) : undefined;
8
+ }
9
+ export function renderHeaderActions(model, createButton) {
10
+ const { Button, Dialog, Banner, createInPageHeader, pageHeaderCompact, split } = model;
11
+ const { promotedToolbarActions, promotedInOverflowMenu } = split;
12
+ return promotedToolbarActions.length > 0 && !promotedInOverflowMenu ? (_jsxs(_Fragment, { children: [promotedToolbarActions.map((a) => (_jsx(ToolbarActionView, { action: pageHeaderCompact ? { ...a, icon: a.icon ?? "plus" } : a, iconOnly: pageHeaderCompact, Button: Button, Dialog: Dialog, Banner: Banner }, a.id))), createInPageHeader && createButton] })) : createInPageHeader ? (createButton) : undefined;
13
+ }
14
+ export function renderToolbarEnd(model, createButton) {
15
+ const { screen, Button, Dialog, Banner, onCreate, createInPageHeader, split } = model;
16
+ const { toolbarActionsInToolbar, hasToolbarActionsInToolbar, toolbarIconOnly } = split;
17
+ const hasHeaderSlot = screen.slots?.header !== undefined;
18
+ return hasHeaderSlot ||
19
+ hasToolbarActionsInToolbar ||
20
+ (onCreate !== undefined && !createInPageHeader) ? (_jsxs(_Fragment, { children: [hasHeaderSlot && _jsx(ListHeaderSlotMount, { screen: screen }), hasToolbarActionsInToolbar &&
21
+ toolbarActionsInToolbar.map((a) => (_jsx(ToolbarActionView, { action: a, iconOnly: toolbarIconOnly, Button: Button, Dialog: Dialog, Banner: Banner }, a.id))), !createInPageHeader && createButton] })) : undefined;
22
+ }
23
+ export function renderSearchInput(Input, localQ, setLocalQ, placeholder) {
24
+ return (_jsx(Input, { kind: "text", id: "render-list-search", name: "search", value: localQ, onChange: setLocalQ, placeholder: placeholder }));
25
+ }
26
+ // Empty state: by default, show a heading, description, and optional CTA
27
+ // button. The caller can replace it completely through emptyState.
28
+ // Without onCreate or an override, DataTable uses its default
29
+ // (`kumiko.list.no-entries`).
30
+ export function composeEmptyState(model) {
31
+ const { Button, emptyState, onCreate, emptyContent, narrowed, defaultFilterActive, onFilterReset, translate, createInPageHeader, effectiveCreateLabel, } = model;
32
+ return (emptyState ??
33
+ (onCreate !== undefined || emptyContent !== undefined || narrowed || defaultFilterActive ? (_jsx(ListEmptyStateBody, { content: emptyContent, narrowed: narrowed, defaultFilterActive: defaultFilterActive, ...(onFilterReset !== undefined && { onShowAll: onFilterReset }), translate: translate, createButton: onCreate !== undefined && !narrowed && !defaultFilterActive && !createInPageHeader ? (_jsx(Button, { variant: "primary", icon: "plus", onClick: onCreate, testId: "render-list-empty-create", children: effectiveCreateLabel })) : undefined })) : undefined));
34
+ }
35
+ export function renderPageHeader(PageHeader, headerActions, promotedInOverflowMenu, promotedMenuItems) {
36
+ return (_jsx(PageHeader, { actions: headerActions, ...(promotedInOverflowMenu && { overflowItems: promotedMenuItems }) }));
37
+ }
38
+ export function renderMenuActionError(Banner, menuActionError) {
39
+ return (_jsx(Banner, { variant: "error", testId: "render-list-toolbar-action-error", children: menuActionError }));
40
+ }