@cohesivesystems/presentation-react-shadcn 0.1.0-alpha.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.
- package/LICENSE +55 -0
- package/dist/document-workspace-surface-slot-renderers.d.ts +58 -0
- package/dist/document-workspace-surface-slot-renderers.d.ts.map +1 -0
- package/dist/document-workspace-surface-slot-renderers.js +206 -0
- package/dist/document-workspace-surface-slot-renderers.js.map +1 -0
- package/dist/index.d.ts +53 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +53 -0
- package/dist/index.js.map +1 -0
- package/dist/navigation-shell-frame-renderer-registry.d.ts +8 -0
- package/dist/navigation-shell-frame-renderer-registry.d.ts.map +1 -0
- package/dist/navigation-shell-frame-renderer-registry.js +2 -0
- package/dist/navigation-shell-frame-renderer-registry.js.map +1 -0
- package/dist/navigation-shell-slot-renderer-registry.d.ts +9 -0
- package/dist/navigation-shell-slot-renderer-registry.d.ts.map +1 -0
- package/dist/navigation-shell-slot-renderer-registry.js +2 -0
- package/dist/navigation-shell-slot-renderer-registry.js.map +1 -0
- package/dist/page-host-unavailable-renderer.d.ts +10 -0
- package/dist/page-host-unavailable-renderer.d.ts.map +1 -0
- package/dist/page-host-unavailable-renderer.js +27 -0
- package/dist/page-host-unavailable-renderer.js.map +1 -0
- package/dist/presentation-action-group.d.ts +99 -0
- package/dist/presentation-action-group.d.ts.map +1 -0
- package/dist/presentation-action-group.js +214 -0
- package/dist/presentation-action-group.js.map +1 -0
- package/dist/presentation-badge-target-interpreter.d.ts +26 -0
- package/dist/presentation-badge-target-interpreter.d.ts.map +1 -0
- package/dist/presentation-badge-target-interpreter.js +17 -0
- package/dist/presentation-badge-target-interpreter.js.map +1 -0
- package/dist/presentation-component-groups.d.ts +968 -0
- package/dist/presentation-component-groups.d.ts.map +1 -0
- package/dist/presentation-component-groups.js +505 -0
- package/dist/presentation-component-groups.js.map +1 -0
- package/dist/presentation-component-system-diagnostics.d.ts +27 -0
- package/dist/presentation-component-system-diagnostics.d.ts.map +1 -0
- package/dist/presentation-component-system-diagnostics.js +399 -0
- package/dist/presentation-component-system-diagnostics.js.map +1 -0
- package/dist/presentation-component-system.d.ts +31 -0
- package/dist/presentation-component-system.d.ts.map +1 -0
- package/dist/presentation-component-system.js +61 -0
- package/dist/presentation-component-system.js.map +1 -0
- package/dist/presentation-icon-diagnostics.d.ts +12 -0
- package/dist/presentation-icon-diagnostics.d.ts.map +1 -0
- package/dist/presentation-icon-diagnostics.js +17 -0
- package/dist/presentation-icon-diagnostics.js.map +1 -0
- package/dist/presentation-icon-registry.d.ts +28 -0
- package/dist/presentation-icon-registry.d.ts.map +1 -0
- package/dist/presentation-icon-registry.js +80 -0
- package/dist/presentation-icon-registry.js.map +1 -0
- package/dist/presentation-projection-trace-panel.d.ts +10 -0
- package/dist/presentation-projection-trace-panel.d.ts.map +1 -0
- package/dist/presentation-projection-trace-panel.js +48 -0
- package/dist/presentation-projection-trace-panel.js.map +1 -0
- package/dist/presentation-routed-surface-host.d.ts +19 -0
- package/dist/presentation-routed-surface-host.d.ts.map +1 -0
- package/dist/presentation-routed-surface-host.js +12 -0
- package/dist/presentation-routed-surface-host.js.map +1 -0
- package/dist/presentation-shadcn-component-system.d.ts +22 -0
- package/dist/presentation-shadcn-component-system.d.ts.map +1 -0
- package/dist/presentation-shadcn-component-system.js +2 -0
- package/dist/presentation-shadcn-component-system.js.map +1 -0
- package/dist/presentation-standard-renderers.d.ts +168 -0
- package/dist/presentation-standard-renderers.d.ts.map +1 -0
- package/dist/presentation-standard-renderers.js +440 -0
- package/dist/presentation-standard-renderers.js.map +1 -0
- package/dist/presentation-surface-renderer.d.ts +23 -0
- package/dist/presentation-surface-renderer.d.ts.map +1 -0
- package/dist/presentation-surface-renderer.js +119 -0
- package/dist/presentation-surface-renderer.js.map +1 -0
- package/dist/presentation-value-renderers.d.ts +10 -0
- package/dist/presentation-value-renderers.d.ts.map +1 -0
- package/dist/presentation-value-renderers.js +14 -0
- package/dist/presentation-value-renderers.js.map +1 -0
- package/dist/process-task-icons.d.ts +49 -0
- package/dist/process-task-icons.d.ts.map +1 -0
- package/dist/process-task-icons.js +154 -0
- package/dist/process-task-icons.js.map +1 -0
- package/dist/projected-activity-state.d.ts +17 -0
- package/dist/projected-activity-state.d.ts.map +1 -0
- package/dist/projected-activity-state.js +22 -0
- package/dist/projected-activity-state.js.map +1 -0
- package/dist/projected-collection-action-runtime-diagnostics.d.ts +4 -0
- package/dist/projected-collection-action-runtime-diagnostics.d.ts.map +1 -0
- package/dist/projected-collection-action-runtime-diagnostics.js +9 -0
- package/dist/projected-collection-action-runtime-diagnostics.js.map +1 -0
- package/dist/projected-collection-view.d.ts +90 -0
- package/dist/projected-collection-view.d.ts.map +1 -0
- package/dist/projected-collection-view.js +532 -0
- package/dist/projected-collection-view.js.map +1 -0
- package/dist/projected-document-action-status-notices.d.ts +15 -0
- package/dist/projected-document-action-status-notices.d.ts.map +1 -0
- package/dist/projected-document-action-status-notices.js +33 -0
- package/dist/projected-document-action-status-notices.js.map +1 -0
- package/dist/projected-document-badges.d.ts +24 -0
- package/dist/projected-document-badges.d.ts.map +1 -0
- package/dist/projected-document-badges.js +53 -0
- package/dist/projected-document-badges.js.map +1 -0
- package/dist/projected-document-editor-surface.d.ts +46 -0
- package/dist/projected-document-editor-surface.d.ts.map +1 -0
- package/dist/projected-document-editor-surface.js +399 -0
- package/dist/projected-document-editor-surface.js.map +1 -0
- package/dist/projected-document-workspace-notices.d.ts +24 -0
- package/dist/projected-document-workspace-notices.d.ts.map +1 -0
- package/dist/projected-document-workspace-notices.js +14 -0
- package/dist/projected-document-workspace-notices.js.map +1 -0
- package/dist/projected-document-workspace-prompt-child-view-registry.d.ts +25 -0
- package/dist/projected-document-workspace-prompt-child-view-registry.d.ts.map +1 -0
- package/dist/projected-document-workspace-prompt-child-view-registry.js +41 -0
- package/dist/projected-document-workspace-prompt-child-view-registry.js.map +1 -0
- package/dist/projected-document-workspace-prompt-child-view-renderers.d.ts +32 -0
- package/dist/projected-document-workspace-prompt-child-view-renderers.d.ts.map +1 -0
- package/dist/projected-document-workspace-prompt-child-view-renderers.js +77 -0
- package/dist/projected-document-workspace-prompt-child-view-renderers.js.map +1 -0
- package/dist/projected-document-workspace-shell.d.ts +100 -0
- package/dist/projected-document-workspace-shell.d.ts.map +1 -0
- package/dist/projected-document-workspace-shell.js +153 -0
- package/dist/projected-document-workspace-shell.js.map +1 -0
- package/dist/projected-document-workspace.d.ts +39 -0
- package/dist/projected-document-workspace.d.ts.map +1 -0
- package/dist/projected-document-workspace.js +63 -0
- package/dist/projected-document-workspace.js.map +1 -0
- package/dist/projected-field-value-rendering.d.ts +94 -0
- package/dist/projected-field-value-rendering.d.ts.map +1 -0
- package/dist/projected-field-value-rendering.js +377 -0
- package/dist/projected-field-value-rendering.js.map +1 -0
- package/dist/projected-inline-list.d.ts +20 -0
- package/dist/projected-inline-list.d.ts.map +1 -0
- package/dist/projected-inline-list.js +149 -0
- package/dist/projected-inline-list.js.map +1 -0
- package/dist/projected-input-form.d.ts +143 -0
- package/dist/projected-input-form.d.ts.map +1 -0
- package/dist/projected-input-form.js +612 -0
- package/dist/projected-input-form.js.map +1 -0
- package/dist/projected-metric-dashboard.d.ts +26 -0
- package/dist/projected-metric-dashboard.d.ts.map +1 -0
- package/dist/projected-metric-dashboard.js +20 -0
- package/dist/projected-metric-dashboard.js.map +1 -0
- package/dist/projected-metric-strip.d.ts +20 -0
- package/dist/projected-metric-strip.d.ts.map +1 -0
- package/dist/projected-metric-strip.js +131 -0
- package/dist/projected-metric-strip.js.map +1 -0
- package/dist/projected-navigation-shell-view-host.d.ts +34 -0
- package/dist/projected-navigation-shell-view-host.d.ts.map +1 -0
- package/dist/projected-navigation-shell-view-host.js +75 -0
- package/dist/projected-navigation-shell-view-host.js.map +1 -0
- package/dist/projected-navigation-shell.d.ts +33 -0
- package/dist/projected-navigation-shell.d.ts.map +1 -0
- package/dist/projected-navigation-shell.js +112 -0
- package/dist/projected-navigation-shell.js.map +1 -0
- package/dist/projected-presentation-badges.d.ts +34 -0
- package/dist/projected-presentation-badges.d.ts.map +1 -0
- package/dist/projected-presentation-badges.js +22 -0
- package/dist/projected-presentation-badges.js.map +1 -0
- package/dist/projected-presentation-diagnostics.d.ts +10 -0
- package/dist/projected-presentation-diagnostics.d.ts.map +1 -0
- package/dist/projected-presentation-diagnostics.js +40 -0
- package/dist/projected-presentation-diagnostics.js.map +1 -0
- package/dist/projected-presentation-flow-layer.d.ts +33 -0
- package/dist/projected-presentation-flow-layer.d.ts.map +1 -0
- package/dist/projected-presentation-flow-layer.js +71 -0
- package/dist/projected-presentation-flow-layer.js.map +1 -0
- package/dist/projected-process-task-notices.d.ts +37 -0
- package/dist/projected-process-task-notices.d.ts.map +1 -0
- package/dist/projected-process-task-notices.js +225 -0
- package/dist/projected-process-task-notices.js.map +1 -0
- package/dist/projected-prompt-child-view-renderer.d.ts +101 -0
- package/dist/projected-prompt-child-view-renderer.d.ts.map +1 -0
- package/dist/projected-prompt-child-view-renderer.js +442 -0
- package/dist/projected-prompt-child-view-renderer.js.map +1 -0
- package/dist/projected-prompt-document-preview.d.ts +39 -0
- package/dist/projected-prompt-document-preview.d.ts.map +1 -0
- package/dist/projected-prompt-document-preview.js +50 -0
- package/dist/projected-prompt-document-preview.js.map +1 -0
- package/dist/projected-prompt-view.d.ts +35 -0
- package/dist/projected-prompt-view.d.ts.map +1 -0
- package/dist/projected-prompt-view.js +292 -0
- package/dist/projected-prompt-view.js.map +1 -0
- package/dist/projected-query-form.d.ts +56 -0
- package/dist/projected-query-form.d.ts.map +1 -0
- package/dist/projected-query-form.js +100 -0
- package/dist/projected-query-form.js.map +1 -0
- package/dist/projected-record-details.d.ts +20 -0
- package/dist/projected-record-details.d.ts.map +1 -0
- package/dist/projected-record-details.js +60 -0
- package/dist/projected-record-details.js.map +1 -0
- package/dist/projected-routed-surface-runtime.d.ts +86 -0
- package/dist/projected-routed-surface-runtime.d.ts.map +1 -0
- package/dist/projected-routed-surface-runtime.js +332 -0
- package/dist/projected-routed-surface-runtime.js.map +1 -0
- package/dist/projected-tabs-view.d.ts +21 -0
- package/dist/projected-tabs-view.d.ts.map +1 -0
- package/dist/projected-tabs-view.js +140 -0
- package/dist/projected-tabs-view.js.map +1 -0
- package/dist/projected-view-chrome.d.ts +15 -0
- package/dist/projected-view-chrome.d.ts.map +1 -0
- package/dist/projected-view-chrome.js +67 -0
- package/dist/projected-view-chrome.js.map +1 -0
- package/dist/projected-view-surface.d.ts +34 -0
- package/dist/projected-view-surface.d.ts.map +1 -0
- package/dist/projected-view-surface.js +40 -0
- package/dist/projected-view-surface.js.map +1 -0
- package/dist/standard-collection-chrome-slot-renderers.d.ts +26 -0
- package/dist/standard-collection-chrome-slot-renderers.d.ts.map +1 -0
- package/dist/standard-collection-chrome-slot-renderers.js +250 -0
- package/dist/standard-collection-chrome-slot-renderers.js.map +1 -0
- package/dist/standard-view-chrome-slot-renderers.d.ts +57 -0
- package/dist/standard-view-chrome-slot-renderers.d.ts.map +1 -0
- package/dist/standard-view-chrome-slot-renderers.js +614 -0
- package/dist/standard-view-chrome-slot-renderers.js.map +1 -0
- package/package.json +68 -0
- package/src/document-workspace-surface-slot-renderers.tsx +395 -0
- package/src/index.ts +53 -0
- package/src/navigation-shell-frame-renderer-registry.ts +29 -0
- package/src/navigation-shell-slot-renderer-registry.ts +46 -0
- package/src/page-host-unavailable-renderer.tsx +79 -0
- package/src/presentation-action-group.tsx +475 -0
- package/src/presentation-badge-target-interpreter.ts +54 -0
- package/src/presentation-component-groups.ts +2505 -0
- package/src/presentation-component-system-diagnostics.ts +848 -0
- package/src/presentation-component-system.ts +365 -0
- package/src/presentation-icon-diagnostics.ts +53 -0
- package/src/presentation-icon-registry.tsx +181 -0
- package/src/presentation-projection-trace-panel.tsx +140 -0
- package/src/presentation-routed-surface-host.tsx +48 -0
- package/src/presentation-shadcn-component-system.ts +102 -0
- package/src/presentation-standard-renderers.tsx +1290 -0
- package/src/presentation-surface-renderer.tsx +263 -0
- package/src/presentation-value-renderers.tsx +40 -0
- package/src/process-task-icons.tsx +258 -0
- package/src/projected-activity-state.tsx +63 -0
- package/src/projected-collection-action-runtime-diagnostics.ts +22 -0
- package/src/projected-collection-view.tsx +1273 -0
- package/src/projected-document-action-status-notices.tsx +66 -0
- package/src/projected-document-badges.tsx +134 -0
- package/src/projected-document-editor-surface.tsx +808 -0
- package/src/projected-document-workspace-notices.tsx +77 -0
- package/src/projected-document-workspace-prompt-child-view-registry.ts +99 -0
- package/src/projected-document-workspace-prompt-child-view-renderers.tsx +205 -0
- package/src/projected-document-workspace-shell.tsx +427 -0
- package/src/projected-document-workspace.tsx +216 -0
- package/src/projected-field-value-rendering.tsx +704 -0
- package/src/projected-inline-list.tsx +434 -0
- package/src/projected-input-form.tsx +1218 -0
- package/src/projected-metric-dashboard.tsx +106 -0
- package/src/projected-metric-strip.tsx +244 -0
- package/src/projected-navigation-shell-view-host.tsx +177 -0
- package/src/projected-navigation-shell.tsx +219 -0
- package/src/projected-presentation-badges.tsx +95 -0
- package/src/projected-presentation-diagnostics.tsx +120 -0
- package/src/projected-presentation-flow-layer.tsx +186 -0
- package/src/projected-process-task-notices.tsx +501 -0
- package/src/projected-prompt-child-view-renderer.tsx +698 -0
- package/src/projected-prompt-document-preview.tsx +197 -0
- package/src/projected-prompt-view.tsx +592 -0
- package/src/projected-query-form.tsx +286 -0
- package/src/projected-record-details.tsx +133 -0
- package/src/projected-routed-surface-runtime.tsx +713 -0
- package/src/projected-tabs-view.tsx +308 -0
- package/src/projected-view-chrome.tsx +148 -0
- package/src/projected-view-surface.tsx +131 -0
- package/src/standard-collection-chrome-slot-renderers.tsx +391 -0
- package/src/standard-view-chrome-slot-renderers.tsx +1064 -0
|
@@ -0,0 +1,1290 @@
|
|
|
1
|
+
import type { ReactNode } from 'react'
|
|
2
|
+
|
|
3
|
+
import {
|
|
4
|
+
createPresentationViewActivityState,
|
|
5
|
+
createPresentationTestAttributes,
|
|
6
|
+
createRelationQueryInputFormTarget,
|
|
7
|
+
defaultPresentationComponentSet,
|
|
8
|
+
findPresentationQueryForm,
|
|
9
|
+
findPresentationInputForm,
|
|
10
|
+
findPresentationInputFormForView,
|
|
11
|
+
findPresentationQueryFormForView,
|
|
12
|
+
getRegionViewIds,
|
|
13
|
+
isViewChromeSlotKind,
|
|
14
|
+
readPresentationDataSourceItems,
|
|
15
|
+
resolveCollectionChromeSlotRenderer,
|
|
16
|
+
type CollectionChromeSlotRendererRegistry,
|
|
17
|
+
type CollectionChromeSlotDefinition,
|
|
18
|
+
type PresentationActionRuntimeBinding,
|
|
19
|
+
type PresentationDataSourceState,
|
|
20
|
+
type ProjectedCollectionActionExecutionContext,
|
|
21
|
+
type ProjectedCollectionPaginationInput,
|
|
22
|
+
type ProjectedCollectionRuntime,
|
|
23
|
+
type ViewChromeSlotDefinition,
|
|
24
|
+
type ViewDefinition,
|
|
25
|
+
type ViewRegionDefinition,
|
|
26
|
+
} from '@cohesivesystems/presentation-core'
|
|
27
|
+
import {
|
|
28
|
+
renderStandardCollectionChromeSlot,
|
|
29
|
+
} from './standard-collection-chrome-slot-renderers'
|
|
30
|
+
import type {
|
|
31
|
+
PresentationShadcnComponentSystem as PresentationComponentSystem,
|
|
32
|
+
} from './presentation-shadcn-component-system'
|
|
33
|
+
import {
|
|
34
|
+
renderStandardViewChromeSlot,
|
|
35
|
+
} from './standard-view-chrome-slot-renderers'
|
|
36
|
+
import type {
|
|
37
|
+
PresentationDesignSystem,
|
|
38
|
+
} from '@cohesivesystems/presentation-tailwind'
|
|
39
|
+
import type {
|
|
40
|
+
ProjectedCollectionChromeSlotRenderContext,
|
|
41
|
+
ProjectedCollectionDetailFieldRenderContext,
|
|
42
|
+
ProjectedFieldRenderContext,
|
|
43
|
+
} from './projected-collection-view'
|
|
44
|
+
import {
|
|
45
|
+
mergePresentationRendererRegistries,
|
|
46
|
+
type PresentationRendererRegistry,
|
|
47
|
+
type PresentationViewRenderContext,
|
|
48
|
+
type PresentationViewRenderer,
|
|
49
|
+
} from '@cohesivesystems/presentation-react'
|
|
50
|
+
import {
|
|
51
|
+
ProjectedActivityStateBoundary,
|
|
52
|
+
ProjectedStatusBlock,
|
|
53
|
+
} from './projected-activity-state'
|
|
54
|
+
import { ProjectedCollectionView } from './projected-collection-view'
|
|
55
|
+
import { ProjectedMetricDashboard } from './projected-metric-dashboard'
|
|
56
|
+
import { ProjectedMetricStrip } from './projected-metric-strip'
|
|
57
|
+
import {
|
|
58
|
+
ProjectedRecordDetails,
|
|
59
|
+
type ProjectedRecordFieldRenderContext,
|
|
60
|
+
} from './projected-record-details'
|
|
61
|
+
import {
|
|
62
|
+
ProjectedInputForm,
|
|
63
|
+
type ProjectedInputFormChoiceClassNameResolver,
|
|
64
|
+
type ProjectedInputFormChoiceToneResolver,
|
|
65
|
+
type ProjectedInputFormFieldRenderer,
|
|
66
|
+
type ProjectedInputFormRuntime,
|
|
67
|
+
} from './projected-input-form'
|
|
68
|
+
import { ProjectedInlineList } from './projected-inline-list'
|
|
69
|
+
import {
|
|
70
|
+
ProjectedQueryForm,
|
|
71
|
+
type ProjectedQueryFormChoiceClassNameResolver,
|
|
72
|
+
type ProjectedQueryFormChoiceToneResolver,
|
|
73
|
+
type ProjectedQueryFormFieldRenderer,
|
|
74
|
+
type ProjectedQueryFormRuntime,
|
|
75
|
+
} from './projected-query-form'
|
|
76
|
+
import { ProjectedTabsView } from './projected-tabs-view'
|
|
77
|
+
import {
|
|
78
|
+
ProjectedViewSurface,
|
|
79
|
+
type ProjectedViewSurfaceContentTopInset,
|
|
80
|
+
type ProjectedViewSurfaceVerticalResizeOptions,
|
|
81
|
+
} from './projected-view-surface'
|
|
82
|
+
import {
|
|
83
|
+
PresentationActionGroup,
|
|
84
|
+
type PresentationActionGroupOptions,
|
|
85
|
+
} from './presentation-action-group'
|
|
86
|
+
import {
|
|
87
|
+
type ViewKind,
|
|
88
|
+
fieldDisplayKinds,
|
|
89
|
+
viewChromeSlotKinds,
|
|
90
|
+
viewKindLabels,
|
|
91
|
+
viewKinds,
|
|
92
|
+
viewRegionKindLabels,
|
|
93
|
+
viewRegionKinds,
|
|
94
|
+
} from '@cohesivesystems/presentation-contracts'
|
|
95
|
+
import {
|
|
96
|
+
presentationViewComponentRoles,
|
|
97
|
+
} from '@cohesivesystems/presentation-contracts'
|
|
98
|
+
|
|
99
|
+
export type PresentationFieldRenderer<TData extends object = object> = (
|
|
100
|
+
context: ProjectedFieldRenderContext<TData>,
|
|
101
|
+
) => ReactNode
|
|
102
|
+
|
|
103
|
+
export type PresentationRecordFieldRenderer<TData extends object = object> = (
|
|
104
|
+
context: ProjectedRecordFieldRenderContext<TData>,
|
|
105
|
+
) => ReactNode
|
|
106
|
+
|
|
107
|
+
export type PresentationCollectionDetailFieldRenderer<TData extends object = object> = (
|
|
108
|
+
context: ProjectedCollectionDetailFieldRenderContext<TData>,
|
|
109
|
+
) => ReactNode
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* App-level customization for the standard presentation renderer set. The
|
|
113
|
+
* options style is intentionally declarative: callers provide styling hooks,
|
|
114
|
+
* icon maps, field renderers, and escape hatches while traversal and data-source
|
|
115
|
+
* resolution stay owned by the projection runtime.
|
|
116
|
+
*/
|
|
117
|
+
export interface PresentationStandardRendererOptions<TContext> {
|
|
118
|
+
/** Component implementation set used by standard projected renderers. */
|
|
119
|
+
readonly componentSystem: PresentationRequiredValueOption<TContext, PresentationComponentSystem>
|
|
120
|
+
|
|
121
|
+
/** Component binding set used to resolve target-specific component keys. */
|
|
122
|
+
readonly componentSet?: PresentationStringOption<TContext>
|
|
123
|
+
|
|
124
|
+
/** Design-system interpretation used by standard projected renderers. */
|
|
125
|
+
readonly designSystem: PresentationRequiredValueOption<TContext, PresentationDesignSystem>
|
|
126
|
+
|
|
127
|
+
/** Configures rendering and execution behavior for view action placements. */
|
|
128
|
+
readonly actionGroup?: PresentationActionGroupOptions<TContext>
|
|
129
|
+
|
|
130
|
+
/** Customizes table-like collection views rendered from primary data sources. */
|
|
131
|
+
readonly collection?: {
|
|
132
|
+
/** Frontend-local interpretations for projected collection row/selection actions. */
|
|
133
|
+
readonly actionRuntimeBindings?: PresentationValueOption<
|
|
134
|
+
TContext,
|
|
135
|
+
readonly PresentationActionRuntimeBinding<
|
|
136
|
+
ProjectedCollectionActionExecutionContext<object>,
|
|
137
|
+
ReactNode
|
|
138
|
+
>[]
|
|
139
|
+
>
|
|
140
|
+
|
|
141
|
+
/** Message shown when the resolved collection has no visible records. */
|
|
142
|
+
readonly emptyMessage?: PresentationStringOption<TContext>
|
|
143
|
+
|
|
144
|
+
/** Field-specific cell renderers keyed by presentation field id or field path. */
|
|
145
|
+
readonly fieldRenderers?: PresentationValueOption<
|
|
146
|
+
TContext,
|
|
147
|
+
Readonly<Record<string, PresentationFieldRenderer>>
|
|
148
|
+
>
|
|
149
|
+
|
|
150
|
+
/** Field-specific renderers for inline detail views projected from selected rows. */
|
|
151
|
+
readonly detailFieldRenderers?: PresentationValueOption<
|
|
152
|
+
TContext,
|
|
153
|
+
Readonly<Record<string, PresentationCollectionDetailFieldRenderer>>
|
|
154
|
+
>
|
|
155
|
+
|
|
156
|
+
/** Resolves pagination/windowing runtime state for the collection projection. */
|
|
157
|
+
readonly pagination?: (
|
|
158
|
+
context: PresentationCollectionRenderContext<TContext>,
|
|
159
|
+
) => ProjectedCollectionPaginationInput | null | undefined
|
|
160
|
+
|
|
161
|
+
/** Additional class name applied to metric summary slots. */
|
|
162
|
+
readonly summaryClassName?: PresentationStringOption<TContext>
|
|
163
|
+
|
|
164
|
+
/** Renders supplemental collection chrome such as pagination controls. */
|
|
165
|
+
readonly renderFooter?: (
|
|
166
|
+
context: PresentationCollectionRenderContext<TContext>,
|
|
167
|
+
) => ReactNode
|
|
168
|
+
|
|
169
|
+
/** Slot renderer registry keyed by Collection.Chrome slot kind and placement. */
|
|
170
|
+
readonly chromeSlotRenderers?: PresentationValueOption<
|
|
171
|
+
TContext,
|
|
172
|
+
CollectionChromeSlotRendererRegistry<
|
|
173
|
+
PresentationCollectionChromeSlotRenderContext<TContext>,
|
|
174
|
+
ReactNode
|
|
175
|
+
>
|
|
176
|
+
>
|
|
177
|
+
|
|
178
|
+
/** Interprets collection chrome slots declared by Collection.Chrome. */
|
|
179
|
+
readonly renderChromeSlot?: (
|
|
180
|
+
context: PresentationCollectionChromeSlotRenderContext<TContext>,
|
|
181
|
+
) => ReactNode
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
/** Customizes compact list views rendered from projected collection fields. */
|
|
185
|
+
readonly inlineList?: {
|
|
186
|
+
/** Message or node-compatible text shown when the inline list has no items. */
|
|
187
|
+
readonly emptyMessage?: PresentationStringOption<TContext>
|
|
188
|
+
|
|
189
|
+
/** Optional escape hatch for app-specific inline-list item rendering. */
|
|
190
|
+
readonly renderItems?: (
|
|
191
|
+
context: PresentationInlineListRenderContext<TContext>,
|
|
192
|
+
) => ReactNode
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
/** Customizes dashboard and metric-summary views. */
|
|
196
|
+
readonly metricDashboard?: {
|
|
197
|
+
/** Additional class name applied to the dashboard container. */
|
|
198
|
+
readonly className?: PresentationStringOption<TContext>
|
|
199
|
+
|
|
200
|
+
/** Optional dashboard description shown alongside the projected metrics. */
|
|
201
|
+
readonly description?: PresentationStringOption<TContext>
|
|
202
|
+
|
|
203
|
+
/** Icons keyed by metric field id for projected metric cards. */
|
|
204
|
+
readonly iconByFieldId?: PresentationValueOption<
|
|
205
|
+
TContext,
|
|
206
|
+
Readonly<Record<string, ReactNode>>
|
|
207
|
+
>
|
|
208
|
+
|
|
209
|
+
/** Loading label used while dashboard data sources are pending. */
|
|
210
|
+
readonly pendingLabel?: PresentationStringOption<TContext>
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
/** Customizes generic input-form views rendered from InputFormDefinition. */
|
|
214
|
+
readonly inputForm?: {
|
|
215
|
+
/** Maps projected choices to target toggle classes, usually through an app design-system binding. */
|
|
216
|
+
readonly choiceToggleClassName?: PresentationValueOption<
|
|
217
|
+
TContext,
|
|
218
|
+
ProjectedInputFormChoiceClassNameResolver
|
|
219
|
+
>
|
|
220
|
+
|
|
221
|
+
/** Resolves semantic tone for projected choices before design-system class binding. */
|
|
222
|
+
readonly choiceTone?: PresentationValueOption<
|
|
223
|
+
TContext,
|
|
224
|
+
ProjectedInputFormChoiceToneResolver
|
|
225
|
+
>
|
|
226
|
+
|
|
227
|
+
/** Additional class name applied to the input form surface. */
|
|
228
|
+
readonly className?: PresentationStringOption<TContext>
|
|
229
|
+
|
|
230
|
+
/** Additional class name applied to the input form content area. */
|
|
231
|
+
readonly contentClassName?: PresentationStringOption<TContext>
|
|
232
|
+
|
|
233
|
+
/** Field-specific input controls keyed by input-form field id or presentation field id. */
|
|
234
|
+
readonly fieldRenderers?: PresentationValueOption<
|
|
235
|
+
TContext,
|
|
236
|
+
Readonly<Record<string, ProjectedInputFormFieldRenderer>>
|
|
237
|
+
>
|
|
238
|
+
|
|
239
|
+
/** Resolves the mutable form runtime for the current route context. */
|
|
240
|
+
readonly runtime: (
|
|
241
|
+
context: PresentationViewRenderContext<TContext>,
|
|
242
|
+
) => ProjectedInputFormRuntime | null
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
/** Customizes query-form views rendered from InputFormDefinition plus a relation-query target. */
|
|
246
|
+
readonly queryForm?: {
|
|
247
|
+
/** Maps projected choices to target toggle classes, usually through an app design-system binding. */
|
|
248
|
+
readonly choiceToggleClassName?: PresentationValueOption<
|
|
249
|
+
TContext,
|
|
250
|
+
ProjectedQueryFormChoiceClassNameResolver
|
|
251
|
+
>
|
|
252
|
+
|
|
253
|
+
/** Resolves semantic tone for projected choices before design-system class binding. */
|
|
254
|
+
readonly choiceTone?: PresentationValueOption<
|
|
255
|
+
TContext,
|
|
256
|
+
ProjectedQueryFormChoiceToneResolver
|
|
257
|
+
>
|
|
258
|
+
|
|
259
|
+
/** Additional class name applied to the query form surface. */
|
|
260
|
+
readonly className?: PresentationStringOption<TContext>
|
|
261
|
+
|
|
262
|
+
/** Additional class name applied to the query form content area. */
|
|
263
|
+
readonly contentClassName?: PresentationStringOption<TContext>
|
|
264
|
+
|
|
265
|
+
/** Field-specific query controls keyed by query-form field id or presentation field id. */
|
|
266
|
+
readonly fieldRenderers?: PresentationValueOption<
|
|
267
|
+
TContext,
|
|
268
|
+
Readonly<Record<string, ProjectedQueryFormFieldRenderer>>
|
|
269
|
+
>
|
|
270
|
+
|
|
271
|
+
/** Resolves the mutable form runtime for the current route context. */
|
|
272
|
+
readonly runtime: (
|
|
273
|
+
context: PresentationViewRenderContext<TContext>,
|
|
274
|
+
) => ProjectedQueryFormRuntime | null
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
/** Final registry layer that can replace or extend standard renderer choices. */
|
|
278
|
+
readonly overrides?: PresentationRendererRegistry<TContext>
|
|
279
|
+
|
|
280
|
+
/** Customizes record-detail views rendered from a primary record data source. */
|
|
281
|
+
readonly recordDetail?: {
|
|
282
|
+
/** Additional class name applied to the detail surface container. */
|
|
283
|
+
readonly className?: PresentationStringOption<TContext>
|
|
284
|
+
|
|
285
|
+
/** Additional class name applied to the detail surface content area. */
|
|
286
|
+
readonly contentClassName?: PresentationStringOption<TContext>
|
|
287
|
+
|
|
288
|
+
/** Message shown when no record detail data is available. */
|
|
289
|
+
readonly emptyMessage?: PresentationStringOption<TContext>
|
|
290
|
+
|
|
291
|
+
/** Field-specific detail renderers keyed by presentation field id or field path. */
|
|
292
|
+
readonly fieldRenderers?: PresentationValueOption<
|
|
293
|
+
TContext,
|
|
294
|
+
Readonly<Record<string, PresentationRecordFieldRenderer>>
|
|
295
|
+
>
|
|
296
|
+
|
|
297
|
+
/** Detail field ids or field paths whose label cell should not be rendered. */
|
|
298
|
+
readonly hiddenFieldLabels?: PresentationValueOption<TContext, readonly string[]>
|
|
299
|
+
|
|
300
|
+
/** Title override for the detail surface; defaults to the view name. */
|
|
301
|
+
readonly title?: PresentationStringOption<TContext>
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
/** Customizes general nested surface views. */
|
|
305
|
+
readonly surface?: {
|
|
306
|
+
/** Additional class name applied to the surface container. */
|
|
307
|
+
readonly className?: PresentationStringOption<TContext>
|
|
308
|
+
|
|
309
|
+
/** Additional class name applied to the surface content area. */
|
|
310
|
+
readonly contentClassName?: PresentationStringOption<TContext>
|
|
311
|
+
|
|
312
|
+
/** Controls the semantic top inset between surface chrome and content. */
|
|
313
|
+
readonly contentTopInset?: PresentationValueOption<
|
|
314
|
+
TContext,
|
|
315
|
+
ProjectedViewSurfaceContentTopInset | null
|
|
316
|
+
>
|
|
317
|
+
|
|
318
|
+
/** Small label rendered above the surface title. */
|
|
319
|
+
readonly eyebrow?: PresentationStringOption<TContext>
|
|
320
|
+
|
|
321
|
+
/** Title override for the surface; defaults to the projected view chrome. */
|
|
322
|
+
readonly title?: PresentationStringOption<TContext>
|
|
323
|
+
|
|
324
|
+
/** Enables vertical resize affordances for the surface. */
|
|
325
|
+
readonly verticalResize?: PresentationValueOption<
|
|
326
|
+
TContext,
|
|
327
|
+
boolean | ProjectedViewSurfaceVerticalResizeOptions | null
|
|
328
|
+
>
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
/** Customizes tabbed-surface views. */
|
|
332
|
+
readonly tabs?: {
|
|
333
|
+
/** Icons keyed by tab region id. */
|
|
334
|
+
readonly iconByRegionId?: PresentationValueOption<
|
|
335
|
+
TContext,
|
|
336
|
+
Readonly<Record<string, ReactNode>>
|
|
337
|
+
>
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
/**
|
|
342
|
+
* Specialized list renderers receive already resolved items so app code does
|
|
343
|
+
* not need to know how a semantic view binds to its primary data source.
|
|
344
|
+
*/
|
|
345
|
+
export interface PresentationInlineListRenderContext<TContext>
|
|
346
|
+
extends PresentationViewRenderContext<TContext> {
|
|
347
|
+
readonly dataSource: PresentationDataSourceState | undefined
|
|
348
|
+
readonly items: readonly object[]
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
/**
|
|
352
|
+
* Collection escape-hatch renderers receive the same resolved data source and
|
|
353
|
+
* item projection as the standard table renderer.
|
|
354
|
+
*/
|
|
355
|
+
export interface PresentationCollectionRenderContext<TContext>
|
|
356
|
+
extends PresentationViewRenderContext<TContext> {
|
|
357
|
+
readonly collectionRuntime?: ProjectedCollectionRuntime<object>
|
|
358
|
+
readonly dataSource: PresentationDataSourceState | undefined
|
|
359
|
+
readonly items: readonly object[]
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
export type PresentationCollectionChromeSlotRenderContext<TContext> =
|
|
363
|
+
PresentationCollectionRenderContext<TContext> &
|
|
364
|
+
ProjectedCollectionChromeSlotRenderContext<object> & {
|
|
365
|
+
readonly collectionRuntime: ProjectedCollectionRuntime<object>
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
type PresentationStringOption<TContext> =
|
|
369
|
+
| ((context: PresentationViewRenderContext<TContext>) => string | undefined)
|
|
370
|
+
| string
|
|
371
|
+
|
|
372
|
+
type PresentationValueOption<TContext, TValue> =
|
|
373
|
+
| ((context: PresentationViewRenderContext<TContext>) => TValue | undefined)
|
|
374
|
+
| TValue
|
|
375
|
+
|
|
376
|
+
type PresentationRequiredValueOption<TContext, TValue> =
|
|
377
|
+
| ((context: PresentationViewRenderContext<TContext>) => TValue)
|
|
378
|
+
| TValue
|
|
379
|
+
|
|
380
|
+
/**
|
|
381
|
+
* Creates the app-wide default renderer registry for common semantic view
|
|
382
|
+
* constructs: surface roots, dashboards, surfaces, tabbed surfaces, collections,
|
|
383
|
+
* and simple inline lists. Specific apps can layer overrides on top without
|
|
384
|
+
* reimplementing recursive rendering or activity/data-source handling.
|
|
385
|
+
*/
|
|
386
|
+
export function createStandardPresentationRendererRegistry<TContext>(
|
|
387
|
+
options: PresentationStandardRendererOptions<TContext>,
|
|
388
|
+
): PresentationRendererRegistry<TContext> {
|
|
389
|
+
const collectionRenderer = createCollectionRenderer(options)
|
|
390
|
+
const inputFormRenderer = createInputFormRenderer(options)
|
|
391
|
+
const drawerRenderer = createDrawerRenderer()
|
|
392
|
+
const metricDashboardRenderer = createMetricDashboardRenderer(options)
|
|
393
|
+
const queryFormRenderer = createQueryFormRenderer(options)
|
|
394
|
+
const recordDetailRenderer = createRecordDetailRenderer(options)
|
|
395
|
+
const surfaceRenderer = createSurfaceRenderer(options)
|
|
396
|
+
const tabsRenderer = createTabsRenderer(options)
|
|
397
|
+
|
|
398
|
+
const registry = {
|
|
399
|
+
composites: {
|
|
400
|
+
byComponentRole: {
|
|
401
|
+
[presentationViewComponentRoles.collectionView]: collectionRenderer,
|
|
402
|
+
[presentationViewComponentRoles.inputForm]: inputFormRenderer,
|
|
403
|
+
[presentationViewComponentRoles.metricDashboard]: metricDashboardRenderer,
|
|
404
|
+
[presentationViewComponentRoles.queryForm]: queryFormRenderer,
|
|
405
|
+
[presentationViewComponentRoles.tabsView]: tabsRenderer,
|
|
406
|
+
[presentationViewComponentRoles.viewSurface]: surfaceRenderer,
|
|
407
|
+
},
|
|
408
|
+
bySemanticRole: {
|
|
409
|
+
collection: collectionRenderer,
|
|
410
|
+
dashboard: metricDashboardRenderer,
|
|
411
|
+
detail: recordDetailRenderer,
|
|
412
|
+
drawer: drawerRenderer,
|
|
413
|
+
form: surfaceRenderer,
|
|
414
|
+
'inline-list': createInlineListRenderer(options),
|
|
415
|
+
'input-form': inputFormRenderer,
|
|
416
|
+
prompt: surfaceRenderer,
|
|
417
|
+
query: queryFormRenderer,
|
|
418
|
+
recordDetail: recordDetailRenderer,
|
|
419
|
+
search: queryFormRenderer,
|
|
420
|
+
summary: metricDashboardRenderer,
|
|
421
|
+
surface: surfaceRenderer,
|
|
422
|
+
'surface-root': renderSurfaceRoot,
|
|
423
|
+
tabs: tabsRenderer,
|
|
424
|
+
'record-detail': recordDetailRenderer,
|
|
425
|
+
},
|
|
426
|
+
byViewKind: createStandardViewKindRenderers({
|
|
427
|
+
collectionRenderer,
|
|
428
|
+
drawerRenderer,
|
|
429
|
+
metricDashboardRenderer,
|
|
430
|
+
queryFormRenderer,
|
|
431
|
+
recordDetailRenderer,
|
|
432
|
+
surfaceRenderer,
|
|
433
|
+
tabsRenderer,
|
|
434
|
+
}),
|
|
435
|
+
},
|
|
436
|
+
} satisfies PresentationRendererRegistry<TContext>
|
|
437
|
+
|
|
438
|
+
return options.overrides
|
|
439
|
+
? mergePresentationRendererRegistries(registry, options.overrides)
|
|
440
|
+
: registry
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
function createStandardViewKindRenderers<TContext>({
|
|
444
|
+
collectionRenderer,
|
|
445
|
+
drawerRenderer,
|
|
446
|
+
metricDashboardRenderer,
|
|
447
|
+
queryFormRenderer,
|
|
448
|
+
recordDetailRenderer,
|
|
449
|
+
surfaceRenderer,
|
|
450
|
+
tabsRenderer,
|
|
451
|
+
}: {
|
|
452
|
+
readonly collectionRenderer: PresentationViewRenderer<TContext>
|
|
453
|
+
readonly drawerRenderer: PresentationViewRenderer<TContext>
|
|
454
|
+
readonly metricDashboardRenderer: PresentationViewRenderer<TContext>
|
|
455
|
+
readonly queryFormRenderer: PresentationViewRenderer<TContext>
|
|
456
|
+
readonly recordDetailRenderer: PresentationViewRenderer<TContext>
|
|
457
|
+
readonly surfaceRenderer: PresentationViewRenderer<TContext>
|
|
458
|
+
readonly tabsRenderer: PresentationViewRenderer<TContext>
|
|
459
|
+
}) {
|
|
460
|
+
const renderers: Record<string, PresentationViewRenderer<TContext>> = {}
|
|
461
|
+
|
|
462
|
+
addViewKindRenderer(renderers, viewKinds.collection, collectionRenderer)
|
|
463
|
+
addViewKindRenderer(renderers, viewKinds.dashboard, metricDashboardRenderer)
|
|
464
|
+
addViewKindRenderer(renderers, viewKinds.drawer, drawerRenderer)
|
|
465
|
+
addViewKindRenderer(renderers, viewKinds.form, surfaceRenderer)
|
|
466
|
+
addViewKindRenderer(renderers, viewKinds.graph, surfaceRenderer)
|
|
467
|
+
addViewKindRenderer(renderers, viewKinds.page, renderSurfaceRoot)
|
|
468
|
+
addViewKindRenderer(renderers, viewKinds.prompt, surfaceRenderer)
|
|
469
|
+
addViewKindRenderer(renderers, viewKinds.recordDetail, recordDetailRenderer)
|
|
470
|
+
addViewKindRenderer(renderers, viewKinds.search, queryFormRenderer)
|
|
471
|
+
addViewKindRenderer(renderers, viewKinds.surface, surfaceRenderer)
|
|
472
|
+
addViewKindRenderer(renderers, viewKinds.tabbedSurface, tabsRenderer)
|
|
473
|
+
addViewKindRenderer(renderers, viewKinds.timeline, surfaceRenderer)
|
|
474
|
+
|
|
475
|
+
return renderers
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
function createDrawerRenderer<TContext>() {
|
|
479
|
+
return function renderDrawer(context: PresentationViewRenderContext<TContext>) {
|
|
480
|
+
return <div className="grid gap-2">{context.renderRegions(context.view)}</div>
|
|
481
|
+
}
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
function addViewKindRenderer<TContext>(
|
|
485
|
+
renderers: Record<string, PresentationViewRenderer<TContext>>,
|
|
486
|
+
kind: ViewKind,
|
|
487
|
+
renderer: PresentationViewRenderer<TContext>,
|
|
488
|
+
) {
|
|
489
|
+
const label = viewKindLabels[kind]
|
|
490
|
+
|
|
491
|
+
renderers[String(kind)] = renderer
|
|
492
|
+
renderers[label] = renderer
|
|
493
|
+
renderers[label.charAt(0).toLowerCase() + label.slice(1)] = renderer
|
|
494
|
+
}
|
|
495
|
+
|
|
496
|
+
/**
|
|
497
|
+
* Root surfaces are structural containers. Their renderer should project child
|
|
498
|
+
* regions and avoid adding visual chrome of its own.
|
|
499
|
+
*/
|
|
500
|
+
function renderSurfaceRoot<TContext>({
|
|
501
|
+
renderView,
|
|
502
|
+
view,
|
|
503
|
+
}: PresentationViewRenderContext<TContext>) {
|
|
504
|
+
return (
|
|
505
|
+
<div
|
|
506
|
+
className="flex min-h-0 flex-1 flex-col gap-5"
|
|
507
|
+
{...createPresentationTestAttributes({ viewId: view.Id })}
|
|
508
|
+
>
|
|
509
|
+
{renderSurfaceRegionViews({
|
|
510
|
+
regions: orderSurfaceRegions(view.Regions),
|
|
511
|
+
renderView,
|
|
512
|
+
stretchPrimaryRegions: true,
|
|
513
|
+
})}
|
|
514
|
+
</div>
|
|
515
|
+
)
|
|
516
|
+
}
|
|
517
|
+
|
|
518
|
+
function createMetricDashboardRenderer<TContext>(
|
|
519
|
+
options: PresentationStandardRendererOptions<TContext>,
|
|
520
|
+
) {
|
|
521
|
+
return function renderMetricDashboard(
|
|
522
|
+
context: PresentationViewRenderContext<TContext>,
|
|
523
|
+
) {
|
|
524
|
+
const { dataSourceResolver, view } = context
|
|
525
|
+
const dataSource = dataSourceResolver.resolveViewPrimary(view)
|
|
526
|
+
|
|
527
|
+
return (
|
|
528
|
+
<ProjectedActivityStateBoundary
|
|
529
|
+
state={createPresentationViewActivityState({
|
|
530
|
+
dataSourceResolver,
|
|
531
|
+
pendingLabel:
|
|
532
|
+
resolveStringOption(options.metricDashboard?.pendingLabel, context) ??
|
|
533
|
+
'Loading view data...',
|
|
534
|
+
view,
|
|
535
|
+
})}
|
|
536
|
+
>
|
|
537
|
+
<ProjectedMetricDashboard
|
|
538
|
+
action={renderPresentationViewActionFallback({ context, options, view })}
|
|
539
|
+
className={resolveStringOption(options.metricDashboard?.className, context)}
|
|
540
|
+
componentSystem={resolveRequiredValueOption(options.componentSystem, context)}
|
|
541
|
+
dataSourceResolver={dataSourceResolver}
|
|
542
|
+
description={resolveStringOption(options.metricDashboard?.description, context)}
|
|
543
|
+
iconByFieldId={resolveValueOption(
|
|
544
|
+
options.metricDashboard?.iconByFieldId,
|
|
545
|
+
context,
|
|
546
|
+
)}
|
|
547
|
+
renderChromeSlot={createPresentationViewChromeSlotRenderer({
|
|
548
|
+
context,
|
|
549
|
+
options,
|
|
550
|
+
resource: dataSource?.data,
|
|
551
|
+
})}
|
|
552
|
+
view={view}
|
|
553
|
+
viewId={view.Id}
|
|
554
|
+
/>
|
|
555
|
+
</ProjectedActivityStateBoundary>
|
|
556
|
+
)
|
|
557
|
+
}
|
|
558
|
+
}
|
|
559
|
+
|
|
560
|
+
function createInputFormRenderer<TContext>(
|
|
561
|
+
options: PresentationStandardRendererOptions<TContext>,
|
|
562
|
+
) {
|
|
563
|
+
return function renderInputForm(context: PresentationViewRenderContext<TContext>) {
|
|
564
|
+
const { dataSourceResolver, module, view } = context
|
|
565
|
+
const inputForm = findPresentationInputFormForView(module, view)
|
|
566
|
+
const dataSource = dataSourceResolver.resolveViewPrimary(view)
|
|
567
|
+
|
|
568
|
+
return (
|
|
569
|
+
<ProjectedInputForm
|
|
570
|
+
choiceToggleClassName={resolveValueOption(
|
|
571
|
+
options.inputForm?.choiceToggleClassName,
|
|
572
|
+
context,
|
|
573
|
+
)}
|
|
574
|
+
choiceTone={resolveValueOption(options.inputForm?.choiceTone, context)}
|
|
575
|
+
className={resolveStringOption(options.inputForm?.className, context)}
|
|
576
|
+
componentSet={resolveStandardPresentationComponentSet(options, context)}
|
|
577
|
+
componentSystem={resolveRequiredValueOption(options.componentSystem, context)}
|
|
578
|
+
contentClassName={resolveStringOption(options.inputForm?.contentClassName, context)}
|
|
579
|
+
dataSourceResolver={dataSourceResolver}
|
|
580
|
+
designSystem={resolveRequiredValueOption(options.designSystem, context)}
|
|
581
|
+
fieldRenderers={resolveValueOption(options.inputForm?.fieldRenderers, context)}
|
|
582
|
+
inputForm={inputForm}
|
|
583
|
+
module={module}
|
|
584
|
+
renderChromeSlot={createPresentationViewChromeSlotRenderer({
|
|
585
|
+
context,
|
|
586
|
+
options,
|
|
587
|
+
resource: dataSource?.data,
|
|
588
|
+
})}
|
|
589
|
+
runtime={options.inputForm?.runtime(context) ?? null}
|
|
590
|
+
view={view}
|
|
591
|
+
/>
|
|
592
|
+
)
|
|
593
|
+
}
|
|
594
|
+
}
|
|
595
|
+
|
|
596
|
+
function createQueryFormRenderer<TContext>(
|
|
597
|
+
options: PresentationStandardRendererOptions<TContext>,
|
|
598
|
+
) {
|
|
599
|
+
return function renderQueryForm(context: PresentationViewRenderContext<TContext>) {
|
|
600
|
+
const { dataSourceResolver, module, view } = context
|
|
601
|
+
const queryForm = findPresentationQueryFormForView(module, view)
|
|
602
|
+
const dataSource = dataSourceResolver.resolveViewPrimary(view)
|
|
603
|
+
|
|
604
|
+
if (queryForm && options.queryForm) {
|
|
605
|
+
return (
|
|
606
|
+
<ProjectedQueryForm
|
|
607
|
+
choiceToggleClassName={resolveValueOption(
|
|
608
|
+
options.queryForm.choiceToggleClassName,
|
|
609
|
+
context,
|
|
610
|
+
)}
|
|
611
|
+
choiceTone={resolveValueOption(options.queryForm.choiceTone, context)}
|
|
612
|
+
className={resolveStringOption(options.queryForm.className, context)}
|
|
613
|
+
componentSet={resolveStandardPresentationComponentSet(options, context)}
|
|
614
|
+
componentSystem={resolveRequiredValueOption(options.componentSystem, context)}
|
|
615
|
+
contentClassName={resolveStringOption(options.queryForm.contentClassName, context)}
|
|
616
|
+
dataSourceResolver={dataSourceResolver}
|
|
617
|
+
designSystem={resolveRequiredValueOption(options.designSystem, context)}
|
|
618
|
+
fieldRenderers={resolveValueOption(options.queryForm.fieldRenderers, context)}
|
|
619
|
+
module={module}
|
|
620
|
+
queryForm={queryForm}
|
|
621
|
+
renderChromeSlot={createPresentationViewChromeSlotRenderer({
|
|
622
|
+
context,
|
|
623
|
+
options,
|
|
624
|
+
resource: dataSource?.data,
|
|
625
|
+
})}
|
|
626
|
+
runtime={options.queryForm.runtime(context)}
|
|
627
|
+
view={view}
|
|
628
|
+
/>
|
|
629
|
+
)
|
|
630
|
+
}
|
|
631
|
+
|
|
632
|
+
if (options.inputForm) {
|
|
633
|
+
const inputForm = queryForm
|
|
634
|
+
? findPresentationInputForm(module, queryForm.FormId)
|
|
635
|
+
: findPresentationInputFormForView(module, view)
|
|
636
|
+
const target = queryForm && inputForm
|
|
637
|
+
? createRelationQueryInputFormTarget({
|
|
638
|
+
dataSourceResolver,
|
|
639
|
+
inputForm,
|
|
640
|
+
queryForm,
|
|
641
|
+
view,
|
|
642
|
+
})
|
|
643
|
+
: null
|
|
644
|
+
|
|
645
|
+
return (
|
|
646
|
+
<ProjectedInputForm
|
|
647
|
+
choiceToggleClassName={resolveValueOption(
|
|
648
|
+
options.inputForm.choiceToggleClassName,
|
|
649
|
+
context,
|
|
650
|
+
)}
|
|
651
|
+
choiceTone={resolveValueOption(options.inputForm.choiceTone, context)}
|
|
652
|
+
className={resolveStringOption(options.inputForm.className, context)}
|
|
653
|
+
componentSet={resolveStandardPresentationComponentSet(options, context)}
|
|
654
|
+
componentSystem={resolveRequiredValueOption(options.componentSystem, context)}
|
|
655
|
+
contentClassName={resolveStringOption(options.inputForm.contentClassName, context)}
|
|
656
|
+
dataSourceResolver={dataSourceResolver}
|
|
657
|
+
designSystem={resolveRequiredValueOption(options.designSystem, context)}
|
|
658
|
+
fieldRenderers={resolveValueOption(options.inputForm.fieldRenderers, context)}
|
|
659
|
+
inputForm={inputForm}
|
|
660
|
+
module={module}
|
|
661
|
+
renderChromeSlot={createPresentationViewChromeSlotRenderer({
|
|
662
|
+
context,
|
|
663
|
+
options,
|
|
664
|
+
resource: dataSource?.data,
|
|
665
|
+
})}
|
|
666
|
+
runtime={options.inputForm.runtime(context)}
|
|
667
|
+
target={target}
|
|
668
|
+
view={view}
|
|
669
|
+
/>
|
|
670
|
+
)
|
|
671
|
+
}
|
|
672
|
+
|
|
673
|
+
return (
|
|
674
|
+
<ProjectedQueryForm
|
|
675
|
+
choiceToggleClassName={resolveValueOption(
|
|
676
|
+
options.queryForm?.choiceToggleClassName,
|
|
677
|
+
context,
|
|
678
|
+
)}
|
|
679
|
+
choiceTone={resolveValueOption(options.queryForm?.choiceTone, context)}
|
|
680
|
+
className={resolveStringOption(options.queryForm?.className, context)}
|
|
681
|
+
componentSet={resolveStandardPresentationComponentSet(options, context)}
|
|
682
|
+
componentSystem={resolveRequiredValueOption(options.componentSystem, context)}
|
|
683
|
+
contentClassName={resolveStringOption(options.queryForm?.contentClassName, context)}
|
|
684
|
+
dataSourceResolver={dataSourceResolver}
|
|
685
|
+
designSystem={resolveRequiredValueOption(options.designSystem, context)}
|
|
686
|
+
fieldRenderers={resolveValueOption(options.queryForm?.fieldRenderers, context)}
|
|
687
|
+
module={module}
|
|
688
|
+
queryForm={queryForm}
|
|
689
|
+
renderChromeSlot={createPresentationViewChromeSlotRenderer({
|
|
690
|
+
context,
|
|
691
|
+
options,
|
|
692
|
+
resource: dataSource?.data,
|
|
693
|
+
})}
|
|
694
|
+
runtime={options.queryForm?.runtime(context) ?? null}
|
|
695
|
+
view={view}
|
|
696
|
+
/>
|
|
697
|
+
)
|
|
698
|
+
}
|
|
699
|
+
}
|
|
700
|
+
|
|
701
|
+
function createSurfaceRenderer<TContext>(
|
|
702
|
+
options: PresentationStandardRendererOptions<TContext>,
|
|
703
|
+
) {
|
|
704
|
+
return function renderSurface(context: PresentationViewRenderContext<TContext>) {
|
|
705
|
+
const { dataSourceResolver, renderView, view } = context
|
|
706
|
+
const dataSource = dataSourceResolver.resolveViewPrimary(view)
|
|
707
|
+
const verticalResize = resolveValueOption(options.surface?.verticalResize, context)
|
|
708
|
+
const isVerticallyResizable = isSurfaceVerticalResizeEnabled(verticalResize)
|
|
709
|
+
const contentClassName = resolveSurfaceContentClassName({
|
|
710
|
+
className: resolveStringOption(
|
|
711
|
+
options.surface?.contentClassName,
|
|
712
|
+
context,
|
|
713
|
+
),
|
|
714
|
+
isVerticallyResizable,
|
|
715
|
+
view,
|
|
716
|
+
})
|
|
717
|
+
|
|
718
|
+
return (
|
|
719
|
+
<ProjectedViewSurface
|
|
720
|
+
action={renderPresentationViewActionFallback({ context, options, view })}
|
|
721
|
+
className={resolveStringOption(options.surface?.className, context)}
|
|
722
|
+
componentSystem={resolveRequiredValueOption(options.componentSystem, context)}
|
|
723
|
+
contentClassName={contentClassName}
|
|
724
|
+
contentTopInset={resolveValueOption(options.surface?.contentTopInset, context)}
|
|
725
|
+
eyebrow={resolveStringOption(options.surface?.eyebrow, context)}
|
|
726
|
+
renderChromeSlot={createPresentationViewChromeSlotRenderer({
|
|
727
|
+
context,
|
|
728
|
+
options,
|
|
729
|
+
resource: dataSource?.data,
|
|
730
|
+
})}
|
|
731
|
+
title={resolveStringOption(options.surface?.title, context)}
|
|
732
|
+
verticalResize={verticalResize}
|
|
733
|
+
view={view}
|
|
734
|
+
>
|
|
735
|
+
{renderSurfaceRegionViews({
|
|
736
|
+
regions: orderSurfaceRegions(view.Regions),
|
|
737
|
+
renderView,
|
|
738
|
+
stretchPrimaryRegions: isVerticallyResizable,
|
|
739
|
+
})}
|
|
740
|
+
</ProjectedViewSurface>
|
|
741
|
+
)
|
|
742
|
+
}
|
|
743
|
+
}
|
|
744
|
+
|
|
745
|
+
function createTabsRenderer<TContext>(
|
|
746
|
+
options: PresentationStandardRendererOptions<TContext>,
|
|
747
|
+
) {
|
|
748
|
+
return function renderTabs(context: PresentationViewRenderContext<TContext>) {
|
|
749
|
+
const { dataSourceResolver, renderView, view } = context
|
|
750
|
+
const dataSource = dataSourceResolver.resolveViewPrimary(view)
|
|
751
|
+
const componentSystem = resolveRequiredValueOption(options.componentSystem, context)
|
|
752
|
+
|
|
753
|
+
return (
|
|
754
|
+
<ProjectedTabsView
|
|
755
|
+
componentSystem={componentSystem}
|
|
756
|
+
iconByRegionId={resolveValueOption(options.tabs?.iconByRegionId, context)}
|
|
757
|
+
renderChromeSlot={createPresentationViewChromeSlotRenderer({
|
|
758
|
+
context,
|
|
759
|
+
options,
|
|
760
|
+
resource: dataSource?.data,
|
|
761
|
+
})}
|
|
762
|
+
renderView={renderView}
|
|
763
|
+
view={view}
|
|
764
|
+
viewId={view.Id}
|
|
765
|
+
/>
|
|
766
|
+
)
|
|
767
|
+
}
|
|
768
|
+
}
|
|
769
|
+
|
|
770
|
+
function createCollectionRenderer<TContext>(
|
|
771
|
+
options: PresentationStandardRendererOptions<TContext>,
|
|
772
|
+
) {
|
|
773
|
+
return function renderCollection(
|
|
774
|
+
context: PresentationViewRenderContext<TContext>,
|
|
775
|
+
) {
|
|
776
|
+
const { dataSourceResolver, view } = context
|
|
777
|
+
const dataSource = dataSourceResolver.resolveViewPrimary(view)
|
|
778
|
+
const items = readPresentationDataSourceItems(dataSource)
|
|
779
|
+
const chromeSlotRenderers = resolveValueOption(
|
|
780
|
+
options.collection?.chromeSlotRenderers,
|
|
781
|
+
context,
|
|
782
|
+
)
|
|
783
|
+
const componentSystem = resolveRequiredValueOption(options.componentSystem, context)
|
|
784
|
+
const collectionContext = {
|
|
785
|
+
...context,
|
|
786
|
+
dataSource,
|
|
787
|
+
items,
|
|
788
|
+
} satisfies PresentationCollectionRenderContext<TContext>
|
|
789
|
+
|
|
790
|
+
return (
|
|
791
|
+
<ProjectedActivityStateBoundary
|
|
792
|
+
state={createPresentationViewActivityState({ dataSourceResolver, view })}
|
|
793
|
+
>
|
|
794
|
+
<ProjectedCollectionView
|
|
795
|
+
actionRuntimeBindings={resolveValueOption(
|
|
796
|
+
options.collection?.actionRuntimeBindings,
|
|
797
|
+
context,
|
|
798
|
+
)}
|
|
799
|
+
componentSet={resolveStandardPresentationComponentSet(options, context)}
|
|
800
|
+
componentSystem={componentSystem}
|
|
801
|
+
data={items}
|
|
802
|
+
detailFieldRenderers={resolveValueOption(
|
|
803
|
+
options.collection?.detailFieldRenderers,
|
|
804
|
+
context,
|
|
805
|
+
)}
|
|
806
|
+
emptyMessage={
|
|
807
|
+
resolveStringOption(options.collection?.emptyMessage, context) ??
|
|
808
|
+
dataSource?.emptyMessage ??
|
|
809
|
+
`No ${view.Name.toLocaleLowerCase()} records are visible.`
|
|
810
|
+
}
|
|
811
|
+
fieldRenderers={resolveValueOption(
|
|
812
|
+
options.collection?.fieldRenderers,
|
|
813
|
+
context,
|
|
814
|
+
)}
|
|
815
|
+
footer={options.collection?.renderFooter
|
|
816
|
+
? (collectionRuntime) =>
|
|
817
|
+
options.collection?.renderFooter?.({
|
|
818
|
+
...collectionContext,
|
|
819
|
+
collectionRuntime: collectionRuntime as ProjectedCollectionRuntime<object>,
|
|
820
|
+
})
|
|
821
|
+
: null}
|
|
822
|
+
pagination={options.collection?.pagination?.(collectionContext)}
|
|
823
|
+
renderChromeSlot={({ collectionRuntime, slot, ...slotContext }) =>
|
|
824
|
+
renderPresentationCollectionChromeSlot({
|
|
825
|
+
context: {
|
|
826
|
+
...collectionContext,
|
|
827
|
+
...slotContext,
|
|
828
|
+
collectionRuntime: collectionRuntime as ProjectedCollectionRuntime<object>,
|
|
829
|
+
module: collectionContext.module,
|
|
830
|
+
renderQueryFormSlot: (slot) =>
|
|
831
|
+
renderPresentationCollectionQueryFormSlot({
|
|
832
|
+
context: collectionContext,
|
|
833
|
+
options,
|
|
834
|
+
slot,
|
|
835
|
+
}),
|
|
836
|
+
renderSummarySlot: (slot) =>
|
|
837
|
+
renderPresentationCollectionSummarySlot({
|
|
838
|
+
context: collectionContext,
|
|
839
|
+
options,
|
|
840
|
+
slot,
|
|
841
|
+
}),
|
|
842
|
+
slot,
|
|
843
|
+
},
|
|
844
|
+
registry: chromeSlotRenderers,
|
|
845
|
+
renderFallback: options.collection?.renderChromeSlot,
|
|
846
|
+
})}
|
|
847
|
+
viewId={view.Id}
|
|
848
|
+
/>
|
|
849
|
+
</ProjectedActivityStateBoundary>
|
|
850
|
+
)
|
|
851
|
+
}
|
|
852
|
+
}
|
|
853
|
+
|
|
854
|
+
function renderPresentationCollectionChromeSlot<TContext>({
|
|
855
|
+
context,
|
|
856
|
+
registry,
|
|
857
|
+
renderFallback,
|
|
858
|
+
}: {
|
|
859
|
+
readonly context: PresentationCollectionChromeSlotRenderContext<TContext>
|
|
860
|
+
readonly registry:
|
|
861
|
+
| CollectionChromeSlotRendererRegistry<
|
|
862
|
+
PresentationCollectionChromeSlotRenderContext<TContext>,
|
|
863
|
+
ReactNode
|
|
864
|
+
>
|
|
865
|
+
| undefined
|
|
866
|
+
readonly renderFallback?: (
|
|
867
|
+
context: PresentationCollectionChromeSlotRenderContext<TContext>,
|
|
868
|
+
) => ReactNode
|
|
869
|
+
}) {
|
|
870
|
+
const renderer = resolveCollectionChromeSlotRenderer(registry, context.slot)
|
|
871
|
+
return renderer?.(context) ??
|
|
872
|
+
renderStandardCollectionChromeSlot(context) ??
|
|
873
|
+
renderFallback?.(context) ??
|
|
874
|
+
null
|
|
875
|
+
}
|
|
876
|
+
|
|
877
|
+
function renderPresentationCollectionQueryFormSlot<TContext>({
|
|
878
|
+
context,
|
|
879
|
+
options,
|
|
880
|
+
slot,
|
|
881
|
+
}: {
|
|
882
|
+
readonly context: PresentationCollectionRenderContext<TContext>
|
|
883
|
+
readonly options: PresentationStandardRendererOptions<TContext>
|
|
884
|
+
readonly slot: CollectionChromeSlotDefinition
|
|
885
|
+
}) {
|
|
886
|
+
const { dataSourceResolver, module, view } = context
|
|
887
|
+
const queryForm = slot.QueryFormId
|
|
888
|
+
? findPresentationQueryForm(module, slot.QueryFormId)
|
|
889
|
+
: findPresentationQueryFormForView(module, view)
|
|
890
|
+
|
|
891
|
+
return (
|
|
892
|
+
<ProjectedQueryForm
|
|
893
|
+
choiceToggleClassName={resolveValueOption(
|
|
894
|
+
options.queryForm?.choiceToggleClassName,
|
|
895
|
+
context,
|
|
896
|
+
)}
|
|
897
|
+
choiceTone={resolveValueOption(options.queryForm?.choiceTone, context)}
|
|
898
|
+
className={resolveStringOption(options.queryForm?.className, context)}
|
|
899
|
+
componentSet={resolveStandardPresentationComponentSet(options, context)}
|
|
900
|
+
componentSystem={resolveRequiredValueOption(options.componentSystem, context)}
|
|
901
|
+
contentClassName={resolveStringOption(options.queryForm?.contentClassName, context)}
|
|
902
|
+
dataSourceResolver={dataSourceResolver}
|
|
903
|
+
designSystem={resolveRequiredValueOption(options.designSystem, context)}
|
|
904
|
+
fieldRenderers={resolveValueOption(options.queryForm?.fieldRenderers, context)}
|
|
905
|
+
module={module}
|
|
906
|
+
queryForm={queryForm}
|
|
907
|
+
runtime={options.queryForm?.runtime(context) ?? null}
|
|
908
|
+
view={view}
|
|
909
|
+
/>
|
|
910
|
+
)
|
|
911
|
+
}
|
|
912
|
+
|
|
913
|
+
function resolveSurfaceContentClassName({
|
|
914
|
+
className,
|
|
915
|
+
isVerticallyResizable,
|
|
916
|
+
view,
|
|
917
|
+
}: {
|
|
918
|
+
readonly className?: string
|
|
919
|
+
readonly isVerticallyResizable: boolean
|
|
920
|
+
readonly view: ViewDefinition
|
|
921
|
+
}) {
|
|
922
|
+
if (hasSidecarSurfaceRegions(view.Regions)) {
|
|
923
|
+
return cn(
|
|
924
|
+
'grid min-h-0 flex-1 gap-y-4 lg:grid-cols-[minmax(0,1fr)_auto] lg:items-start lg:gap-x-0 lg:has-[>[data-surface-region-kind=sidecar]:not(:empty)]:gap-x-4',
|
|
925
|
+
className,
|
|
926
|
+
)
|
|
927
|
+
}
|
|
928
|
+
|
|
929
|
+
if (isVerticallyResizable) {
|
|
930
|
+
return cn(
|
|
931
|
+
'flex min-h-0 flex-1 flex-col gap-4 overflow-hidden',
|
|
932
|
+
className,
|
|
933
|
+
)
|
|
934
|
+
}
|
|
935
|
+
|
|
936
|
+
return className ?? (view.Regions.length > 0 ? 'grid w-full min-w-0 gap-4' : undefined)
|
|
937
|
+
}
|
|
938
|
+
|
|
939
|
+
function orderSurfaceRegions(
|
|
940
|
+
regions: readonly ViewRegionDefinition[],
|
|
941
|
+
): readonly ViewRegionDefinition[] {
|
|
942
|
+
if (!hasSidecarSurfaceRegions(regions)) {
|
|
943
|
+
return regions
|
|
944
|
+
}
|
|
945
|
+
|
|
946
|
+
return [
|
|
947
|
+
...regions.filter((region) => isPrimarySurfaceRegionKind(region.Kind)),
|
|
948
|
+
...regions.filter((region) => isSidecarSurfaceRegionKind(region.Kind)),
|
|
949
|
+
...regions.filter((region) =>
|
|
950
|
+
!isPrimarySurfaceRegionKind(region.Kind) &&
|
|
951
|
+
!isSidecarSurfaceRegionKind(region.Kind)),
|
|
952
|
+
]
|
|
953
|
+
}
|
|
954
|
+
|
|
955
|
+
function renderSurfaceRegionViews({
|
|
956
|
+
regions,
|
|
957
|
+
renderView,
|
|
958
|
+
stretchPrimaryRegions,
|
|
959
|
+
}: {
|
|
960
|
+
readonly regions: readonly ViewRegionDefinition[]
|
|
961
|
+
readonly renderView: (viewId: string) => ReactNode
|
|
962
|
+
readonly stretchPrimaryRegions?: boolean
|
|
963
|
+
}) {
|
|
964
|
+
return regions.flatMap((region) =>
|
|
965
|
+
getRegionViewIds(region).map((childViewId) => (
|
|
966
|
+
<div
|
|
967
|
+
className={resolveSurfaceRegionClassName(region, { stretchPrimaryRegions })}
|
|
968
|
+
data-surface-region-kind={resolveSurfaceRegionLayoutKind(region)}
|
|
969
|
+
key={`${region.Id}:${childViewId}`}
|
|
970
|
+
>
|
|
971
|
+
{renderView(childViewId)}
|
|
972
|
+
</div>
|
|
973
|
+
)),
|
|
974
|
+
)
|
|
975
|
+
}
|
|
976
|
+
|
|
977
|
+
function hasSidecarSurfaceRegions(regions: readonly ViewRegionDefinition[]) {
|
|
978
|
+
if (regions.length < 2) {
|
|
979
|
+
return false
|
|
980
|
+
}
|
|
981
|
+
|
|
982
|
+
return regions.some((region) => isPrimarySurfaceRegionKind(region.Kind)) &&
|
|
983
|
+
regions.some((region) => isSidecarSurfaceRegionKind(region.Kind))
|
|
984
|
+
}
|
|
985
|
+
|
|
986
|
+
function resolveSurfaceRegionClassName(
|
|
987
|
+
region: ViewRegionDefinition,
|
|
988
|
+
options: { readonly stretchPrimaryRegions?: boolean } = {},
|
|
989
|
+
) {
|
|
990
|
+
const layoutKind = resolveSurfaceRegionLayoutKind(region)
|
|
991
|
+
if (layoutKind === 'sidecar') {
|
|
992
|
+
return 'min-h-0 min-w-0 empty:hidden lg:w-[clamp(18rem,25vw,24rem)]'
|
|
993
|
+
}
|
|
994
|
+
|
|
995
|
+
if (layoutKind === 'primary' && options.stretchPrimaryRegions) {
|
|
996
|
+
return 'flex min-h-0 w-full min-w-0 flex-1 flex-col overflow-hidden'
|
|
997
|
+
}
|
|
998
|
+
|
|
999
|
+
return 'min-h-0 w-full min-w-0'
|
|
1000
|
+
}
|
|
1001
|
+
|
|
1002
|
+
function resolveSurfaceRegionLayoutKind(region: ViewRegionDefinition) {
|
|
1003
|
+
if (isSidecarSurfaceRegionKind(region.Kind)) {
|
|
1004
|
+
return 'sidecar'
|
|
1005
|
+
}
|
|
1006
|
+
|
|
1007
|
+
if (isPrimarySurfaceRegionKind(region.Kind)) {
|
|
1008
|
+
return 'primary'
|
|
1009
|
+
}
|
|
1010
|
+
|
|
1011
|
+
return 'supporting'
|
|
1012
|
+
}
|
|
1013
|
+
|
|
1014
|
+
function isPrimarySurfaceRegionKind(kind: string | number) {
|
|
1015
|
+
return matchesViewRegionKind(kind, viewRegionKinds.primary) ||
|
|
1016
|
+
matchesViewRegionKind(kind, viewRegionKinds.content) ||
|
|
1017
|
+
matchesViewRegionKind(kind, viewRegionKinds.surface) ||
|
|
1018
|
+
matchesViewRegionKind(kind, viewRegionKinds.collection) ||
|
|
1019
|
+
matchesViewRegionKind(kind, viewRegionKinds.detail)
|
|
1020
|
+
}
|
|
1021
|
+
|
|
1022
|
+
function isSidecarSurfaceRegionKind(kind: string | number) {
|
|
1023
|
+
return matchesViewRegionKind(kind, viewRegionKinds.sidebar) ||
|
|
1024
|
+
matchesViewRegionKind(kind, viewRegionKinds.statusList) ||
|
|
1025
|
+
matchesViewRegionKind(kind, viewRegionKinds.list) ||
|
|
1026
|
+
matchesViewRegionKind(kind, viewRegionKinds.inspector) ||
|
|
1027
|
+
matchesViewRegionKind(kind, viewRegionKinds.panel)
|
|
1028
|
+
}
|
|
1029
|
+
|
|
1030
|
+
function matchesViewRegionKind(kind: string | number, expected: string | number) {
|
|
1031
|
+
const expectedLabel =
|
|
1032
|
+
viewRegionKindLabels[expected as keyof typeof viewRegionKindLabels] ?? expected
|
|
1033
|
+
return kind === expected ||
|
|
1034
|
+
normalizeEnumDiscriminator(kind) === normalizeEnumDiscriminator(expectedLabel)
|
|
1035
|
+
}
|
|
1036
|
+
|
|
1037
|
+
function renderPresentationCollectionSummarySlot<TContext>({
|
|
1038
|
+
context,
|
|
1039
|
+
options,
|
|
1040
|
+
slot,
|
|
1041
|
+
}: {
|
|
1042
|
+
readonly context: PresentationCollectionRenderContext<TContext>
|
|
1043
|
+
readonly options: PresentationStandardRendererOptions<TContext>
|
|
1044
|
+
readonly slot: CollectionChromeSlotDefinition
|
|
1045
|
+
}) {
|
|
1046
|
+
const fieldIds = resolveCollectionSummaryFieldIds(context.module, slot)
|
|
1047
|
+
if (fieldIds.length === 0) {
|
|
1048
|
+
return null
|
|
1049
|
+
}
|
|
1050
|
+
|
|
1051
|
+
return (
|
|
1052
|
+
<ProjectedMetricStrip
|
|
1053
|
+
className={resolveStringOption(options.collection?.summaryClassName, context)}
|
|
1054
|
+
componentSystem={resolveRequiredValueOption(options.componentSystem, context)}
|
|
1055
|
+
dataSourceResolver={context.dataSourceResolver}
|
|
1056
|
+
fieldIds={fieldIds}
|
|
1057
|
+
iconByFieldId={resolveValueOption(options.metricDashboard?.iconByFieldId, context)}
|
|
1058
|
+
/>
|
|
1059
|
+
)
|
|
1060
|
+
}
|
|
1061
|
+
|
|
1062
|
+
function resolveCollectionSummaryFieldIds(
|
|
1063
|
+
module: PresentationCollectionRenderContext<unknown>['module'],
|
|
1064
|
+
slot: CollectionChromeSlotDefinition,
|
|
1065
|
+
) {
|
|
1066
|
+
if (slot.FieldIds.length > 0) {
|
|
1067
|
+
return slot.FieldIds
|
|
1068
|
+
}
|
|
1069
|
+
|
|
1070
|
+
const slotDataSourceIds = new Set(slot.DataSourceIds)
|
|
1071
|
+
return module.Fields
|
|
1072
|
+
.filter((field) =>
|
|
1073
|
+
field.Source?.DataSourceId &&
|
|
1074
|
+
slotDataSourceIds.has(field.Source.DataSourceId) &&
|
|
1075
|
+
isMetricField(field.DisplayKind))
|
|
1076
|
+
.map((field) => field.Id)
|
|
1077
|
+
}
|
|
1078
|
+
|
|
1079
|
+
function isMetricField(displayKind: unknown) {
|
|
1080
|
+
return displayKind === fieldDisplayKinds.metric ||
|
|
1081
|
+
String(displayKind).toLocaleLowerCase() === 'metric'
|
|
1082
|
+
}
|
|
1083
|
+
|
|
1084
|
+
function createPresentationViewChromeSlotRenderer<TContext>({
|
|
1085
|
+
context,
|
|
1086
|
+
options,
|
|
1087
|
+
resource,
|
|
1088
|
+
}: {
|
|
1089
|
+
readonly context: PresentationViewRenderContext<TContext>
|
|
1090
|
+
readonly options: PresentationStandardRendererOptions<TContext>
|
|
1091
|
+
readonly resource?: unknown
|
|
1092
|
+
}) {
|
|
1093
|
+
return (slot: ViewChromeSlotDefinition, view: ViewDefinition | null) =>
|
|
1094
|
+
renderStandardViewChromeSlot({
|
|
1095
|
+
actionContext: context.context,
|
|
1096
|
+
actionGroupOptions: options.actionGroup,
|
|
1097
|
+
componentSystem: resolveRequiredValueOption(options.componentSystem, context),
|
|
1098
|
+
dataSourceResolver: context.dataSourceResolver,
|
|
1099
|
+
designSystem: resolveRequiredValueOption(options.designSystem, context),
|
|
1100
|
+
documentViewIds: slot.ViewIds,
|
|
1101
|
+
module: context.module,
|
|
1102
|
+
resource,
|
|
1103
|
+
slot,
|
|
1104
|
+
view: view ?? context.view,
|
|
1105
|
+
workspaceView: view ?? context.view,
|
|
1106
|
+
})
|
|
1107
|
+
}
|
|
1108
|
+
|
|
1109
|
+
function renderPresentationViewActionFallback<TContext>({
|
|
1110
|
+
context,
|
|
1111
|
+
options,
|
|
1112
|
+
view,
|
|
1113
|
+
}: {
|
|
1114
|
+
readonly context: PresentationViewRenderContext<TContext>
|
|
1115
|
+
readonly options: PresentationStandardRendererOptions<TContext>
|
|
1116
|
+
readonly view: ViewDefinition
|
|
1117
|
+
}) {
|
|
1118
|
+
if (!options.actionGroup || hasViewActionsChromeSlot(view)) {
|
|
1119
|
+
return null
|
|
1120
|
+
}
|
|
1121
|
+
|
|
1122
|
+
return (
|
|
1123
|
+
<PresentationActionGroup
|
|
1124
|
+
context={context.context}
|
|
1125
|
+
dataSourceResolver={context.dataSourceResolver}
|
|
1126
|
+
module={context.module}
|
|
1127
|
+
options={options.actionGroup}
|
|
1128
|
+
view={view}
|
|
1129
|
+
/>
|
|
1130
|
+
)
|
|
1131
|
+
}
|
|
1132
|
+
|
|
1133
|
+
function hasViewActionsChromeSlot(view: ViewDefinition) {
|
|
1134
|
+
return view.Chrome?.Slots.some((slot) =>
|
|
1135
|
+
isViewChromeSlotKind(slot, viewChromeSlotKinds.actions)) ?? false
|
|
1136
|
+
}
|
|
1137
|
+
|
|
1138
|
+
function createRecordDetailRenderer<TContext>(
|
|
1139
|
+
options: PresentationStandardRendererOptions<TContext>,
|
|
1140
|
+
) {
|
|
1141
|
+
return function renderRecordDetail(context: PresentationViewRenderContext<TContext>) {
|
|
1142
|
+
const { dataSourceResolver, view } = context
|
|
1143
|
+
const dataSource = dataSourceResolver.resolveViewPrimary(view)
|
|
1144
|
+
const data = dataSource?.data
|
|
1145
|
+
const componentSystem = resolveRequiredValueOption(options.componentSystem, context)
|
|
1146
|
+
|
|
1147
|
+
return (
|
|
1148
|
+
<ProjectedActivityStateBoundary
|
|
1149
|
+
state={createPresentationViewActivityState({ dataSourceResolver, view })}
|
|
1150
|
+
>
|
|
1151
|
+
<ProjectedViewSurface
|
|
1152
|
+
action={renderPresentationViewActionFallback({ context, options, view })}
|
|
1153
|
+
className={resolveStringOption(options.recordDetail?.className, context)}
|
|
1154
|
+
componentSystem={componentSystem}
|
|
1155
|
+
contentClassName={
|
|
1156
|
+
resolveStringOption(options.recordDetail?.contentClassName, context) ??
|
|
1157
|
+
'grid gap-4'
|
|
1158
|
+
}
|
|
1159
|
+
renderChromeSlot={createPresentationViewChromeSlotRenderer({
|
|
1160
|
+
context,
|
|
1161
|
+
options,
|
|
1162
|
+
resource: data,
|
|
1163
|
+
})}
|
|
1164
|
+
title={resolveStringOption(options.recordDetail?.title, context) ?? view.Name}
|
|
1165
|
+
view={view}
|
|
1166
|
+
>
|
|
1167
|
+
{data && typeof data === 'object' ? (
|
|
1168
|
+
<ProjectedRecordDetails
|
|
1169
|
+
componentSystem={componentSystem}
|
|
1170
|
+
data={data as object}
|
|
1171
|
+
emptyMessage={
|
|
1172
|
+
resolveStringOption(options.recordDetail?.emptyMessage, context) ??
|
|
1173
|
+
dataSource?.emptyMessage
|
|
1174
|
+
}
|
|
1175
|
+
fieldRenderers={resolveValueOption(
|
|
1176
|
+
options.recordDetail?.fieldRenderers,
|
|
1177
|
+
context,
|
|
1178
|
+
)}
|
|
1179
|
+
hiddenFieldLabels={
|
|
1180
|
+
resolveValueOption(options.recordDetail?.hiddenFieldLabels, context)
|
|
1181
|
+
}
|
|
1182
|
+
viewId={view.Id}
|
|
1183
|
+
/>
|
|
1184
|
+
) : (
|
|
1185
|
+
<ProjectedStatusBlock
|
|
1186
|
+
label={
|
|
1187
|
+
resolveStringOption(options.recordDetail?.emptyMessage, context) ??
|
|
1188
|
+
dataSource?.emptyMessage ??
|
|
1189
|
+
'No details are available.'
|
|
1190
|
+
}
|
|
1191
|
+
/>
|
|
1192
|
+
)}
|
|
1193
|
+
</ProjectedViewSurface>
|
|
1194
|
+
</ProjectedActivityStateBoundary>
|
|
1195
|
+
)
|
|
1196
|
+
}
|
|
1197
|
+
}
|
|
1198
|
+
|
|
1199
|
+
function createInlineListRenderer<TContext>(
|
|
1200
|
+
options: PresentationStandardRendererOptions<TContext>,
|
|
1201
|
+
) {
|
|
1202
|
+
return function renderInlineList(context: PresentationViewRenderContext<TContext>) {
|
|
1203
|
+
const { dataSourceResolver, view } = context
|
|
1204
|
+
const dataSource = dataSourceResolver.resolveViewPrimary(view)
|
|
1205
|
+
const items = readPresentationDataSourceItems(dataSource)
|
|
1206
|
+
const componentSystem = resolveRequiredValueOption(options.componentSystem, context)
|
|
1207
|
+
|
|
1208
|
+
return (
|
|
1209
|
+
<ProjectedActivityStateBoundary
|
|
1210
|
+
state={createPresentationViewActivityState({ dataSourceResolver, view })}
|
|
1211
|
+
>
|
|
1212
|
+
{items.length === 0 && options.inlineList?.renderItems ? (
|
|
1213
|
+
resolveStringOption(options.inlineList?.emptyMessage, context) ??
|
|
1214
|
+
dataSource?.emptyMessage ??
|
|
1215
|
+
null
|
|
1216
|
+
) : (
|
|
1217
|
+
options.inlineList?.renderItems?.({ ...context, dataSource, items }) ?? (
|
|
1218
|
+
<ProjectedInlineList
|
|
1219
|
+
actionRuntimeBindings={resolveValueOption(
|
|
1220
|
+
options.collection?.actionRuntimeBindings,
|
|
1221
|
+
context,
|
|
1222
|
+
)}
|
|
1223
|
+
componentSet={resolveStandardPresentationComponentSet(options, context)}
|
|
1224
|
+
componentSystem={componentSystem}
|
|
1225
|
+
data={items}
|
|
1226
|
+
emptyMessage={
|
|
1227
|
+
resolveStringOption(options.inlineList?.emptyMessage, context) ??
|
|
1228
|
+
dataSource?.emptyMessage
|
|
1229
|
+
}
|
|
1230
|
+
fieldRenderers={resolveValueOption(
|
|
1231
|
+
options.collection?.fieldRenderers,
|
|
1232
|
+
context,
|
|
1233
|
+
)}
|
|
1234
|
+
title={view.Name}
|
|
1235
|
+
viewId={view.Id}
|
|
1236
|
+
/>
|
|
1237
|
+
)
|
|
1238
|
+
)}
|
|
1239
|
+
</ProjectedActivityStateBoundary>
|
|
1240
|
+
)
|
|
1241
|
+
}
|
|
1242
|
+
}
|
|
1243
|
+
|
|
1244
|
+
function resolveStandardPresentationComponentSet<TContext>(
|
|
1245
|
+
options: PresentationStandardRendererOptions<TContext>,
|
|
1246
|
+
context: PresentationViewRenderContext<TContext>,
|
|
1247
|
+
) {
|
|
1248
|
+
return resolveStringOption(options.componentSet, context) ??
|
|
1249
|
+
defaultPresentationComponentSet
|
|
1250
|
+
}
|
|
1251
|
+
|
|
1252
|
+
function resolveStringOption<TContext>(
|
|
1253
|
+
option: PresentationStringOption<TContext> | undefined,
|
|
1254
|
+
context: PresentationViewRenderContext<TContext>,
|
|
1255
|
+
) {
|
|
1256
|
+
return resolveValueOption(option, context)
|
|
1257
|
+
}
|
|
1258
|
+
|
|
1259
|
+
function resolveRequiredValueOption<TContext, TValue>(
|
|
1260
|
+
option: PresentationRequiredValueOption<TContext, TValue>,
|
|
1261
|
+
context: PresentationViewRenderContext<TContext>,
|
|
1262
|
+
) {
|
|
1263
|
+
return typeof option === 'function'
|
|
1264
|
+
? (option as (context: PresentationViewRenderContext<TContext>) => TValue)(context)
|
|
1265
|
+
: option
|
|
1266
|
+
}
|
|
1267
|
+
|
|
1268
|
+
function resolveValueOption<TContext, TValue>(
|
|
1269
|
+
option: PresentationValueOption<TContext, TValue> | undefined,
|
|
1270
|
+
context: PresentationViewRenderContext<TContext>,
|
|
1271
|
+
) {
|
|
1272
|
+
return typeof option === 'function'
|
|
1273
|
+
? (option as (context: PresentationViewRenderContext<TContext>) => TValue | undefined)(context)
|
|
1274
|
+
: option
|
|
1275
|
+
}
|
|
1276
|
+
|
|
1277
|
+
function normalizeEnumDiscriminator(value: string | number) {
|
|
1278
|
+
return String(value).replace(/[-_\s]/g, '').toLocaleLowerCase()
|
|
1279
|
+
}
|
|
1280
|
+
|
|
1281
|
+
function isSurfaceVerticalResizeEnabled(
|
|
1282
|
+
value: boolean | ProjectedViewSurfaceVerticalResizeOptions | null | undefined,
|
|
1283
|
+
) {
|
|
1284
|
+
return value === true ||
|
|
1285
|
+
(typeof value === 'object' && value !== null && value.enabled !== false)
|
|
1286
|
+
}
|
|
1287
|
+
|
|
1288
|
+
function cn(...values: readonly (false | null | string | undefined)[]) {
|
|
1289
|
+
return values.filter(Boolean).join(' ')
|
|
1290
|
+
}
|