@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,475 @@
|
|
|
1
|
+
import { useMemo, type ReactNode } from 'react'
|
|
2
|
+
|
|
3
|
+
import type {
|
|
4
|
+
PresentationShadcnComponentSystem as PresentationComponentSystem,
|
|
5
|
+
} from './presentation-shadcn-component-system'
|
|
6
|
+
import {
|
|
7
|
+
type PresentationActionButtonSize,
|
|
8
|
+
type PresentationActionButtonVariant,
|
|
9
|
+
type PresentationDesignSystem,
|
|
10
|
+
} from '@cohesivesystems/presentation-tailwind'
|
|
11
|
+
import {
|
|
12
|
+
defaultPresentationComponentSet,
|
|
13
|
+
findPresentationAction,
|
|
14
|
+
getPresentationViewProjectedActionPlacements,
|
|
15
|
+
isPresentationViewFetching,
|
|
16
|
+
presentationActionIconIds,
|
|
17
|
+
projectPresentationActionRuntimeBindingDiagnostics,
|
|
18
|
+
createPresentationTestAttributes,
|
|
19
|
+
resolvePresentationViewDataSourceIds,
|
|
20
|
+
type ActionDefinition,
|
|
21
|
+
type ActionPlacementDefinition,
|
|
22
|
+
type PresentationDataSourceResolver,
|
|
23
|
+
type PresentationModuleDefinition,
|
|
24
|
+
type PresentationActionRuntimeRegistry,
|
|
25
|
+
type ViewDefinition,
|
|
26
|
+
} from '@cohesivesystems/presentation-core'
|
|
27
|
+
import {
|
|
28
|
+
renderPresentationIcon,
|
|
29
|
+
standardLucidePresentationIconRegistry,
|
|
30
|
+
type PresentationIconRegistry,
|
|
31
|
+
} from './presentation-icon-registry'
|
|
32
|
+
import {
|
|
33
|
+
projectPresentationActionIconDiagnostics,
|
|
34
|
+
projectPresentationIconDiagnostics,
|
|
35
|
+
} from './presentation-icon-diagnostics'
|
|
36
|
+
import {
|
|
37
|
+
useRegisterPresentationProjectionDiagnostics,
|
|
38
|
+
} from '@cohesivesystems/presentation-react'
|
|
39
|
+
|
|
40
|
+
export interface PresentationActionGroupOptions<TContext> {
|
|
41
|
+
/** Default button size used when no per-action resolver or design rule applies. */
|
|
42
|
+
readonly buttonSize?: PresentationActionButtonSize
|
|
43
|
+
|
|
44
|
+
/** Default button variant used when no per-action resolver or design rule applies. */
|
|
45
|
+
readonly buttonVariant?: PresentationActionButtonVariant
|
|
46
|
+
|
|
47
|
+
/** Host predicate that decides whether a projected action can execute. */
|
|
48
|
+
readonly canExecuteAction?: (context: PresentationActionRenderContext<TContext>) => boolean
|
|
49
|
+
|
|
50
|
+
/** CSS class applied to the action group container. */
|
|
51
|
+
readonly className?: string
|
|
52
|
+
|
|
53
|
+
/** Component set identifier used for icon and diagnostic projection. */
|
|
54
|
+
readonly componentSet?: string
|
|
55
|
+
|
|
56
|
+
/** Concrete component system that supplies the action button implementation. */
|
|
57
|
+
readonly componentSystem?: PresentationComponentSystem
|
|
58
|
+
|
|
59
|
+
/** Design system used to resolve default action button presentation. */
|
|
60
|
+
readonly designSystem?: PresentationDesignSystem
|
|
61
|
+
|
|
62
|
+
/** Host executor invoked when an enabled action button is clicked. */
|
|
63
|
+
readonly executeAction?: (context: PresentationActionRenderContext<TContext>) => Promise<void> | void
|
|
64
|
+
|
|
65
|
+
/** Icon registry used to render action and pending-state icons. */
|
|
66
|
+
readonly iconRegistry?: PresentationIconRegistry<ActionPlacementDefinition>
|
|
67
|
+
|
|
68
|
+
/** Host predicate that reports whether an action has an executable runtime binding. */
|
|
69
|
+
readonly isActionRuntimeBound?: (context: PresentationActionRenderContext<TContext>) => boolean
|
|
70
|
+
|
|
71
|
+
/** Optional override for rendering the icon portion of each action button. */
|
|
72
|
+
readonly renderActionIcon?: (context: PresentationActionRenderContext<TContext>) => ReactNode
|
|
73
|
+
|
|
74
|
+
/** Optional override for rendering the label portion of each action button. */
|
|
75
|
+
readonly renderActionLabel?: (context: PresentationActionRenderContext<TContext>) => ReactNode
|
|
76
|
+
|
|
77
|
+
/** Optional content rendered before the projected action buttons. */
|
|
78
|
+
readonly renderLeading?: (context: PresentationActionGroupRenderContext<TContext>) => ReactNode
|
|
79
|
+
|
|
80
|
+
/** Resolves transient render state such as hidden, disabled, pending, or label override. */
|
|
81
|
+
readonly resolveActionState?: (
|
|
82
|
+
context: PresentationActionRenderContext<TContext>,
|
|
83
|
+
) => PresentationActionRenderState | null | undefined
|
|
84
|
+
|
|
85
|
+
/** Resolves a per-action button size override. */
|
|
86
|
+
readonly resolveButtonSize?: (
|
|
87
|
+
context: PresentationActionRenderContext<TContext>,
|
|
88
|
+
) => PresentationActionButtonSize | undefined
|
|
89
|
+
|
|
90
|
+
/** Resolves a per-action button variant override. */
|
|
91
|
+
readonly resolveButtonVariant?: (
|
|
92
|
+
context: PresentationActionRenderContext<TContext>,
|
|
93
|
+
) => PresentationActionButtonVariant | undefined
|
|
94
|
+
|
|
95
|
+
/** Resolves data sources that block this action while they are busy. */
|
|
96
|
+
readonly resolveInvalidatedDataSourceIds?: (context: PresentationActionRenderContext<TContext>) => readonly string[]
|
|
97
|
+
|
|
98
|
+
/** Runtime registry used for projection diagnostics and host execution binding. */
|
|
99
|
+
readonly runtimes?: PresentationActionRuntimeRegistry<
|
|
100
|
+
PresentationActionRenderContext<TContext>,
|
|
101
|
+
ReactNode
|
|
102
|
+
>
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* Host-resolved render state for a projected action button.
|
|
107
|
+
*/
|
|
108
|
+
export interface PresentationActionRenderState {
|
|
109
|
+
/** Tooltip text or richer node explaining why the action is disabled. */
|
|
110
|
+
readonly disabledReason?: ReactNode
|
|
111
|
+
|
|
112
|
+
/** Whether the action should render disabled even if runtime checks pass. */
|
|
113
|
+
readonly isDisabled?: boolean
|
|
114
|
+
|
|
115
|
+
/** Whether the action should be omitted from the group. */
|
|
116
|
+
readonly isHidden?: boolean
|
|
117
|
+
|
|
118
|
+
/** Whether the action is currently pending host work. */
|
|
119
|
+
readonly isPending?: boolean
|
|
120
|
+
|
|
121
|
+
/** Label override for the action button. */
|
|
122
|
+
readonly label?: ReactNode
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* Shared render context for the whole action group.
|
|
127
|
+
*/
|
|
128
|
+
export interface PresentationActionGroupRenderContext<TContext> {
|
|
129
|
+
/** Host-specific context threaded through action rendering and execution. */
|
|
130
|
+
readonly context: TContext
|
|
131
|
+
|
|
132
|
+
/** Resolver used to inspect data-source fetch and block state. */
|
|
133
|
+
readonly dataSourceResolver: PresentationDataSourceResolver
|
|
134
|
+
|
|
135
|
+
/** Module fragment used to resolve actions and targets. */
|
|
136
|
+
readonly module: Pick<PresentationModuleDefinition, 'Actions' | 'Targets'>
|
|
137
|
+
|
|
138
|
+
/** View whose projected actions are rendered by the group. */
|
|
139
|
+
readonly view: ViewDefinition
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* Render and execution context for a single projected action placement.
|
|
144
|
+
*/
|
|
145
|
+
export interface PresentationActionRenderContext<TContext>
|
|
146
|
+
extends PresentationActionGroupRenderContext<TContext> {
|
|
147
|
+
/** Resolved module action for the placement, or null when the module is incomplete. */
|
|
148
|
+
readonly action: ActionDefinition | null
|
|
149
|
+
|
|
150
|
+
/** Data sources invalidated by the action or implied by the view. */
|
|
151
|
+
readonly invalidatedDataSourceIds: readonly string[]
|
|
152
|
+
|
|
153
|
+
/** Whether the action is blocked by active view/data-source fetch state. */
|
|
154
|
+
readonly isFetching: boolean
|
|
155
|
+
|
|
156
|
+
/** View-local placement that introduced this action button. */
|
|
157
|
+
readonly placement: ActionPlacementDefinition
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
/**
|
|
161
|
+
* Props for rendering a group of actions projected by a presentation view.
|
|
162
|
+
*/
|
|
163
|
+
export interface PresentationActionGroupProps<TContext>
|
|
164
|
+
extends PresentationActionGroupRenderContext<TContext> {
|
|
165
|
+
/** Optional host integration and rendering overrides. */
|
|
166
|
+
readonly options?: PresentationActionGroupOptions<TContext>
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
/**
|
|
170
|
+
* Renders the view-scoped action placements declared by Cohesive presentation
|
|
171
|
+
* IR. The component keeps module action semantics, host runtime binding, design
|
|
172
|
+
* defaults, diagnostics, and data-source blocking in a single reusable action
|
|
173
|
+
* surface.
|
|
174
|
+
*/
|
|
175
|
+
export function PresentationActionGroup<TContext>({
|
|
176
|
+
context,
|
|
177
|
+
dataSourceResolver,
|
|
178
|
+
module,
|
|
179
|
+
options,
|
|
180
|
+
view,
|
|
181
|
+
}: PresentationActionGroupProps<TContext>) {
|
|
182
|
+
const ActionButton = options?.componentSystem?.actions.ActionButton
|
|
183
|
+
const designSystem = options?.designSystem
|
|
184
|
+
const actionPlacements = useMemo(
|
|
185
|
+
() => getPresentationViewProjectedActionPlacements(view),
|
|
186
|
+
[view],
|
|
187
|
+
)
|
|
188
|
+
const iconRegistry =
|
|
189
|
+
options?.iconRegistry ??
|
|
190
|
+
(standardLucidePresentationIconRegistry as PresentationIconRegistry<ActionPlacementDefinition>)
|
|
191
|
+
const componentSet = options?.componentSet ?? defaultPresentationComponentSet
|
|
192
|
+
const actionIconDiagnostics = useMemo(
|
|
193
|
+
() => [
|
|
194
|
+
...projectPresentationActionIconDiagnostics({
|
|
195
|
+
actionPlacements,
|
|
196
|
+
module,
|
|
197
|
+
componentSet,
|
|
198
|
+
registry: iconRegistry,
|
|
199
|
+
source: `presentation-action-group-icons:${view.Id}`,
|
|
200
|
+
surfaceId: view.Id,
|
|
201
|
+
surfaceName: view.Name,
|
|
202
|
+
}),
|
|
203
|
+
...projectPresentationIconDiagnostics({
|
|
204
|
+
icons: actionPlacements.length === 0
|
|
205
|
+
? []
|
|
206
|
+
: [{
|
|
207
|
+
icon: presentationActionIconIds.pending,
|
|
208
|
+
id: `${view.Id}:pending`,
|
|
209
|
+
kind: 'action-state-icon',
|
|
210
|
+
label: 'Pending action',
|
|
211
|
+
}],
|
|
212
|
+
module,
|
|
213
|
+
componentSet,
|
|
214
|
+
source: `presentation-action-group-icons:${view.Id}`,
|
|
215
|
+
surfaceId: view.Id,
|
|
216
|
+
surfaceName: view.Name,
|
|
217
|
+
}),
|
|
218
|
+
],
|
|
219
|
+
[
|
|
220
|
+
actionPlacements,
|
|
221
|
+
componentSet,
|
|
222
|
+
iconRegistry,
|
|
223
|
+
module,
|
|
224
|
+
view.Id,
|
|
225
|
+
view.Name,
|
|
226
|
+
],
|
|
227
|
+
)
|
|
228
|
+
useRegisterPresentationProjectionDiagnostics(
|
|
229
|
+
`presentation-action-group-icons:${view.Id}`,
|
|
230
|
+
actionIconDiagnostics,
|
|
231
|
+
)
|
|
232
|
+
|
|
233
|
+
const actionRuntimeDiagnostics = useMemo(
|
|
234
|
+
() => {
|
|
235
|
+
if (!options?.isActionRuntimeBound) {
|
|
236
|
+
return []
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
const runtimes: Record<
|
|
240
|
+
string,
|
|
241
|
+
NonNullable<PresentationActionRuntimeRegistry<
|
|
242
|
+
PresentationActionRenderContext<TContext>,
|
|
243
|
+
ReactNode
|
|
244
|
+
>[string]>
|
|
245
|
+
> = {}
|
|
246
|
+
for (const [actionId, runtime] of Object.entries(options.runtimes ?? {})) {
|
|
247
|
+
if (runtime) {
|
|
248
|
+
runtimes[actionId] = runtime
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
for (const placement of actionPlacements) {
|
|
252
|
+
const actionContext = createActionRenderContext({
|
|
253
|
+
context,
|
|
254
|
+
dataSourceResolver,
|
|
255
|
+
module,
|
|
256
|
+
placement,
|
|
257
|
+
view,
|
|
258
|
+
})
|
|
259
|
+
if (options.isActionRuntimeBound(actionContext)) {
|
|
260
|
+
runtimes[placement.ActionId] ??= { execute: () => undefined }
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
return projectPresentationActionRuntimeBindingDiagnostics({
|
|
265
|
+
actionPlacements,
|
|
266
|
+
module,
|
|
267
|
+
runtimes,
|
|
268
|
+
source: `presentation-action-group-runtime:${view.Id}`,
|
|
269
|
+
})
|
|
270
|
+
},
|
|
271
|
+
[
|
|
272
|
+
actionPlacements,
|
|
273
|
+
context,
|
|
274
|
+
dataSourceResolver,
|
|
275
|
+
module,
|
|
276
|
+
options,
|
|
277
|
+
view,
|
|
278
|
+
],
|
|
279
|
+
)
|
|
280
|
+
useRegisterPresentationProjectionDiagnostics(
|
|
281
|
+
`presentation-action-group-runtime:${view.Id}`,
|
|
282
|
+
actionRuntimeDiagnostics,
|
|
283
|
+
)
|
|
284
|
+
|
|
285
|
+
if (!ActionButton || !designSystem) {
|
|
286
|
+
return null
|
|
287
|
+
}
|
|
288
|
+
if (actionPlacements.length === 0) {
|
|
289
|
+
return null
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
const groupContext = {
|
|
293
|
+
context,
|
|
294
|
+
dataSourceResolver,
|
|
295
|
+
module,
|
|
296
|
+
view,
|
|
297
|
+
} satisfies PresentationActionGroupRenderContext<TContext>
|
|
298
|
+
const leading = options?.renderLeading?.(groupContext)
|
|
299
|
+
|
|
300
|
+
return (
|
|
301
|
+
<div className={options?.className ?? 'flex flex-wrap items-center gap-2'}>
|
|
302
|
+
{leading}
|
|
303
|
+
{actionPlacements.map((placement) => {
|
|
304
|
+
const actionContext = createActionRenderContext({
|
|
305
|
+
context,
|
|
306
|
+
dataSourceResolver,
|
|
307
|
+
groupContext,
|
|
308
|
+
module,
|
|
309
|
+
placement,
|
|
310
|
+
view,
|
|
311
|
+
})
|
|
312
|
+
const { action, invalidatedDataSourceIds, isFetching } = actionContext
|
|
313
|
+
const resolvedInvalidatedDataSourceIds =
|
|
314
|
+
options?.resolveInvalidatedDataSourceIds?.(actionContext) ??
|
|
315
|
+
invalidatedDataSourceIds
|
|
316
|
+
const isBlocked = resolvedInvalidatedDataSourceIds.some(
|
|
317
|
+
(dataSourceId) => dataSourceResolver.resolve(dataSourceId)?.isBlocked,
|
|
318
|
+
)
|
|
319
|
+
const resolvedActionContext = {
|
|
320
|
+
...actionContext,
|
|
321
|
+
invalidatedDataSourceIds: resolvedInvalidatedDataSourceIds,
|
|
322
|
+
} satisfies PresentationActionRenderContext<TContext>
|
|
323
|
+
const isRuntimeBound =
|
|
324
|
+
options?.isActionRuntimeBound?.(resolvedActionContext) ??
|
|
325
|
+
Boolean(options?.executeAction)
|
|
326
|
+
const canExecute = options?.canExecuteAction?.(resolvedActionContext) ?? true
|
|
327
|
+
const actionState = options?.resolveActionState?.(resolvedActionContext) ?? {}
|
|
328
|
+
if (actionState.isHidden) {
|
|
329
|
+
return null
|
|
330
|
+
}
|
|
331
|
+
const isPending = Boolean(actionState.isPending)
|
|
332
|
+
const disabledTitle = typeof actionState.disabledReason === 'string'
|
|
333
|
+
? actionState.disabledReason
|
|
334
|
+
: undefined
|
|
335
|
+
const renderedLabel =
|
|
336
|
+
actionState.label ??
|
|
337
|
+
options?.renderActionLabel?.(resolvedActionContext) ??
|
|
338
|
+
placement.Label ??
|
|
339
|
+
action?.Name ??
|
|
340
|
+
placement.ActionId
|
|
341
|
+
|
|
342
|
+
return (
|
|
343
|
+
<ActionButton
|
|
344
|
+
aria-label={action?.Accessibility?.Label ?? String(renderedLabel)}
|
|
345
|
+
{...createPresentationTestAttributes({
|
|
346
|
+
actionId: placement.ActionId,
|
|
347
|
+
viewId: view.Id,
|
|
348
|
+
})}
|
|
349
|
+
disabled={
|
|
350
|
+
!options?.executeAction ||
|
|
351
|
+
!isRuntimeBound ||
|
|
352
|
+
!canExecute ||
|
|
353
|
+
Boolean(actionState.isDisabled) ||
|
|
354
|
+
isBlocked ||
|
|
355
|
+
isFetching ||
|
|
356
|
+
isPending
|
|
357
|
+
}
|
|
358
|
+
key={`${placement.Region}:${placement.ActionId}`}
|
|
359
|
+
onClick={() => {
|
|
360
|
+
void options?.executeAction?.(resolvedActionContext)
|
|
361
|
+
}}
|
|
362
|
+
size={
|
|
363
|
+
options?.resolveButtonSize?.(resolvedActionContext) ??
|
|
364
|
+
options?.buttonSize ??
|
|
365
|
+
designSystem.components.actionButton.size({
|
|
366
|
+
action,
|
|
367
|
+
placement,
|
|
368
|
+
})
|
|
369
|
+
}
|
|
370
|
+
title={disabledTitle}
|
|
371
|
+
type="button"
|
|
372
|
+
variant={
|
|
373
|
+
options?.resolveButtonVariant?.(resolvedActionContext) ??
|
|
374
|
+
options?.buttonVariant ??
|
|
375
|
+
designSystem.components.actionButton.variant({
|
|
376
|
+
action,
|
|
377
|
+
placement,
|
|
378
|
+
})
|
|
379
|
+
}
|
|
380
|
+
>
|
|
381
|
+
{options?.renderActionIcon?.(resolvedActionContext) ??
|
|
382
|
+
renderDefaultActionIcon({
|
|
383
|
+
iconRegistry: options?.iconRegistry,
|
|
384
|
+
isPending: isFetching || isPending,
|
|
385
|
+
componentSet,
|
|
386
|
+
module,
|
|
387
|
+
placement,
|
|
388
|
+
})}
|
|
389
|
+
{renderedLabel}
|
|
390
|
+
</ActionButton>
|
|
391
|
+
)
|
|
392
|
+
})}
|
|
393
|
+
</div>
|
|
394
|
+
)
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
function createActionRenderContext<TContext>({
|
|
398
|
+
context,
|
|
399
|
+
dataSourceResolver,
|
|
400
|
+
groupContext,
|
|
401
|
+
module,
|
|
402
|
+
placement,
|
|
403
|
+
view,
|
|
404
|
+
}: {
|
|
405
|
+
readonly context: TContext
|
|
406
|
+
readonly dataSourceResolver: PresentationDataSourceResolver
|
|
407
|
+
readonly groupContext?: PresentationActionGroupRenderContext<TContext>
|
|
408
|
+
readonly module: Pick<PresentationModuleDefinition, 'Actions' | 'Targets'>
|
|
409
|
+
readonly placement: ActionPlacementDefinition
|
|
410
|
+
readonly view: ViewDefinition
|
|
411
|
+
}): PresentationActionRenderContext<TContext> {
|
|
412
|
+
const action = findPresentationAction<ActionDefinition>(
|
|
413
|
+
module,
|
|
414
|
+
placement.ActionId,
|
|
415
|
+
)
|
|
416
|
+
const invalidatedDataSourceIds =
|
|
417
|
+
action?.Result?.InvalidateDataSourceIds ??
|
|
418
|
+
resolvePresentationViewDataSourceIds(view)
|
|
419
|
+
const isFetching = isPresentationViewFetching(
|
|
420
|
+
{
|
|
421
|
+
...view,
|
|
422
|
+
DataSourceIds: invalidatedDataSourceIds,
|
|
423
|
+
},
|
|
424
|
+
dataSourceResolver,
|
|
425
|
+
)
|
|
426
|
+
|
|
427
|
+
return {
|
|
428
|
+
...(groupContext ?? {
|
|
429
|
+
context,
|
|
430
|
+
dataSourceResolver,
|
|
431
|
+
module,
|
|
432
|
+
view,
|
|
433
|
+
}),
|
|
434
|
+
action,
|
|
435
|
+
invalidatedDataSourceIds,
|
|
436
|
+
isFetching,
|
|
437
|
+
placement,
|
|
438
|
+
} satisfies PresentationActionRenderContext<TContext>
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
function renderDefaultActionIcon({
|
|
442
|
+
componentSet = defaultPresentationComponentSet,
|
|
443
|
+
iconRegistry = standardLucidePresentationIconRegistry as PresentationIconRegistry<ActionPlacementDefinition>,
|
|
444
|
+
isPending,
|
|
445
|
+
module,
|
|
446
|
+
placement,
|
|
447
|
+
}: {
|
|
448
|
+
readonly componentSet?: string
|
|
449
|
+
readonly iconRegistry?: PresentationIconRegistry<ActionPlacementDefinition>
|
|
450
|
+
readonly isPending: boolean
|
|
451
|
+
readonly module: Pick<PresentationModuleDefinition, 'Targets'>
|
|
452
|
+
readonly placement: ActionPlacementDefinition
|
|
453
|
+
}) {
|
|
454
|
+
return isPending ? (
|
|
455
|
+
renderPresentationIcon({
|
|
456
|
+
className: 'size-3.5 animate-spin',
|
|
457
|
+
componentSet,
|
|
458
|
+
icon: presentationActionIconIds.pending,
|
|
459
|
+
module,
|
|
460
|
+
registry: iconRegistry,
|
|
461
|
+
subject: placement,
|
|
462
|
+
}) ?? renderPresentationIcon({
|
|
463
|
+
className: 'size-3.5 animate-spin',
|
|
464
|
+
icon: 'loader-circle',
|
|
465
|
+
registry: iconRegistry,
|
|
466
|
+
subject: placement,
|
|
467
|
+
})
|
|
468
|
+
) : renderPresentationIcon({
|
|
469
|
+
componentSet,
|
|
470
|
+
icon: placement.Icon,
|
|
471
|
+
module,
|
|
472
|
+
registry: iconRegistry,
|
|
473
|
+
subject: placement,
|
|
474
|
+
})
|
|
475
|
+
}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import type { ReactNode } from 'react'
|
|
2
|
+
|
|
3
|
+
import type {
|
|
4
|
+
PresentationBadgeDefinition,
|
|
5
|
+
PresentationModuleDefinition,
|
|
6
|
+
ProjectedDocumentFieldDefinitionLike,
|
|
7
|
+
ResolvedPresentationBadge,
|
|
8
|
+
} from '@cohesivesystems/presentation-core'
|
|
9
|
+
import type {
|
|
10
|
+
PresentationShadcnComponentSystem as PresentationComponentSystem,
|
|
11
|
+
} from './presentation-shadcn-component-system'
|
|
12
|
+
import type {
|
|
13
|
+
PresentationDesignSystem,
|
|
14
|
+
} from '@cohesivesystems/presentation-tailwind'
|
|
15
|
+
|
|
16
|
+
export interface PresentationBadgeTargetInterpretationContext {
|
|
17
|
+
readonly badge: PresentationBadgeDefinition
|
|
18
|
+
readonly componentSystem: PresentationComponentSystem
|
|
19
|
+
readonly designSystem: PresentationDesignSystem
|
|
20
|
+
readonly field: ProjectedDocumentFieldDefinitionLike | null
|
|
21
|
+
readonly fieldId: string
|
|
22
|
+
readonly module: PresentationModuleDefinition | null
|
|
23
|
+
readonly resolvedBadge: ResolvedPresentationBadge | null
|
|
24
|
+
readonly resource: unknown
|
|
25
|
+
readonly value: unknown
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export type PresentationBadgeTargetInterpreter = (
|
|
29
|
+
context: PresentationBadgeTargetInterpretationContext,
|
|
30
|
+
) => ReactNode | undefined
|
|
31
|
+
|
|
32
|
+
export type PresentationBadgeTargetInterpreterRegistry =
|
|
33
|
+
readonly PresentationBadgeTargetInterpreter[]
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Applies target-specific badge interpretations in registry order.
|
|
37
|
+
*
|
|
38
|
+
* Returning `undefined` means an interpreter does not handle the badge.
|
|
39
|
+
* Returning `null` means the interpreter handled the badge and intentionally
|
|
40
|
+
* suppresses rendering.
|
|
41
|
+
*/
|
|
42
|
+
export function interpretPresentationBadgeTarget(
|
|
43
|
+
registry: PresentationBadgeTargetInterpreterRegistry | null | undefined,
|
|
44
|
+
context: PresentationBadgeTargetInterpretationContext,
|
|
45
|
+
) {
|
|
46
|
+
for (const interpreter of registry ?? []) {
|
|
47
|
+
const rendered = interpreter(context)
|
|
48
|
+
if (rendered !== undefined) {
|
|
49
|
+
return rendered
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
return undefined
|
|
54
|
+
}
|