@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.
Files changed (262) hide show
  1. package/LICENSE +55 -0
  2. package/dist/document-workspace-surface-slot-renderers.d.ts +58 -0
  3. package/dist/document-workspace-surface-slot-renderers.d.ts.map +1 -0
  4. package/dist/document-workspace-surface-slot-renderers.js +206 -0
  5. package/dist/document-workspace-surface-slot-renderers.js.map +1 -0
  6. package/dist/index.d.ts +53 -0
  7. package/dist/index.d.ts.map +1 -0
  8. package/dist/index.js +53 -0
  9. package/dist/index.js.map +1 -0
  10. package/dist/navigation-shell-frame-renderer-registry.d.ts +8 -0
  11. package/dist/navigation-shell-frame-renderer-registry.d.ts.map +1 -0
  12. package/dist/navigation-shell-frame-renderer-registry.js +2 -0
  13. package/dist/navigation-shell-frame-renderer-registry.js.map +1 -0
  14. package/dist/navigation-shell-slot-renderer-registry.d.ts +9 -0
  15. package/dist/navigation-shell-slot-renderer-registry.d.ts.map +1 -0
  16. package/dist/navigation-shell-slot-renderer-registry.js +2 -0
  17. package/dist/navigation-shell-slot-renderer-registry.js.map +1 -0
  18. package/dist/page-host-unavailable-renderer.d.ts +10 -0
  19. package/dist/page-host-unavailable-renderer.d.ts.map +1 -0
  20. package/dist/page-host-unavailable-renderer.js +27 -0
  21. package/dist/page-host-unavailable-renderer.js.map +1 -0
  22. package/dist/presentation-action-group.d.ts +99 -0
  23. package/dist/presentation-action-group.d.ts.map +1 -0
  24. package/dist/presentation-action-group.js +214 -0
  25. package/dist/presentation-action-group.js.map +1 -0
  26. package/dist/presentation-badge-target-interpreter.d.ts +26 -0
  27. package/dist/presentation-badge-target-interpreter.d.ts.map +1 -0
  28. package/dist/presentation-badge-target-interpreter.js +17 -0
  29. package/dist/presentation-badge-target-interpreter.js.map +1 -0
  30. package/dist/presentation-component-groups.d.ts +968 -0
  31. package/dist/presentation-component-groups.d.ts.map +1 -0
  32. package/dist/presentation-component-groups.js +505 -0
  33. package/dist/presentation-component-groups.js.map +1 -0
  34. package/dist/presentation-component-system-diagnostics.d.ts +27 -0
  35. package/dist/presentation-component-system-diagnostics.d.ts.map +1 -0
  36. package/dist/presentation-component-system-diagnostics.js +399 -0
  37. package/dist/presentation-component-system-diagnostics.js.map +1 -0
  38. package/dist/presentation-component-system.d.ts +31 -0
  39. package/dist/presentation-component-system.d.ts.map +1 -0
  40. package/dist/presentation-component-system.js +61 -0
  41. package/dist/presentation-component-system.js.map +1 -0
  42. package/dist/presentation-icon-diagnostics.d.ts +12 -0
  43. package/dist/presentation-icon-diagnostics.d.ts.map +1 -0
  44. package/dist/presentation-icon-diagnostics.js +17 -0
  45. package/dist/presentation-icon-diagnostics.js.map +1 -0
  46. package/dist/presentation-icon-registry.d.ts +28 -0
  47. package/dist/presentation-icon-registry.d.ts.map +1 -0
  48. package/dist/presentation-icon-registry.js +80 -0
  49. package/dist/presentation-icon-registry.js.map +1 -0
  50. package/dist/presentation-projection-trace-panel.d.ts +10 -0
  51. package/dist/presentation-projection-trace-panel.d.ts.map +1 -0
  52. package/dist/presentation-projection-trace-panel.js +48 -0
  53. package/dist/presentation-projection-trace-panel.js.map +1 -0
  54. package/dist/presentation-routed-surface-host.d.ts +19 -0
  55. package/dist/presentation-routed-surface-host.d.ts.map +1 -0
  56. package/dist/presentation-routed-surface-host.js +12 -0
  57. package/dist/presentation-routed-surface-host.js.map +1 -0
  58. package/dist/presentation-shadcn-component-system.d.ts +22 -0
  59. package/dist/presentation-shadcn-component-system.d.ts.map +1 -0
  60. package/dist/presentation-shadcn-component-system.js +2 -0
  61. package/dist/presentation-shadcn-component-system.js.map +1 -0
  62. package/dist/presentation-standard-renderers.d.ts +168 -0
  63. package/dist/presentation-standard-renderers.d.ts.map +1 -0
  64. package/dist/presentation-standard-renderers.js +440 -0
  65. package/dist/presentation-standard-renderers.js.map +1 -0
  66. package/dist/presentation-surface-renderer.d.ts +23 -0
  67. package/dist/presentation-surface-renderer.d.ts.map +1 -0
  68. package/dist/presentation-surface-renderer.js +119 -0
  69. package/dist/presentation-surface-renderer.js.map +1 -0
  70. package/dist/presentation-value-renderers.d.ts +10 -0
  71. package/dist/presentation-value-renderers.d.ts.map +1 -0
  72. package/dist/presentation-value-renderers.js +14 -0
  73. package/dist/presentation-value-renderers.js.map +1 -0
  74. package/dist/process-task-icons.d.ts +49 -0
  75. package/dist/process-task-icons.d.ts.map +1 -0
  76. package/dist/process-task-icons.js +154 -0
  77. package/dist/process-task-icons.js.map +1 -0
  78. package/dist/projected-activity-state.d.ts +17 -0
  79. package/dist/projected-activity-state.d.ts.map +1 -0
  80. package/dist/projected-activity-state.js +22 -0
  81. package/dist/projected-activity-state.js.map +1 -0
  82. package/dist/projected-collection-action-runtime-diagnostics.d.ts +4 -0
  83. package/dist/projected-collection-action-runtime-diagnostics.d.ts.map +1 -0
  84. package/dist/projected-collection-action-runtime-diagnostics.js +9 -0
  85. package/dist/projected-collection-action-runtime-diagnostics.js.map +1 -0
  86. package/dist/projected-collection-view.d.ts +90 -0
  87. package/dist/projected-collection-view.d.ts.map +1 -0
  88. package/dist/projected-collection-view.js +532 -0
  89. package/dist/projected-collection-view.js.map +1 -0
  90. package/dist/projected-document-action-status-notices.d.ts +15 -0
  91. package/dist/projected-document-action-status-notices.d.ts.map +1 -0
  92. package/dist/projected-document-action-status-notices.js +33 -0
  93. package/dist/projected-document-action-status-notices.js.map +1 -0
  94. package/dist/projected-document-badges.d.ts +24 -0
  95. package/dist/projected-document-badges.d.ts.map +1 -0
  96. package/dist/projected-document-badges.js +53 -0
  97. package/dist/projected-document-badges.js.map +1 -0
  98. package/dist/projected-document-editor-surface.d.ts +46 -0
  99. package/dist/projected-document-editor-surface.d.ts.map +1 -0
  100. package/dist/projected-document-editor-surface.js +399 -0
  101. package/dist/projected-document-editor-surface.js.map +1 -0
  102. package/dist/projected-document-workspace-notices.d.ts +24 -0
  103. package/dist/projected-document-workspace-notices.d.ts.map +1 -0
  104. package/dist/projected-document-workspace-notices.js +14 -0
  105. package/dist/projected-document-workspace-notices.js.map +1 -0
  106. package/dist/projected-document-workspace-prompt-child-view-registry.d.ts +25 -0
  107. package/dist/projected-document-workspace-prompt-child-view-registry.d.ts.map +1 -0
  108. package/dist/projected-document-workspace-prompt-child-view-registry.js +41 -0
  109. package/dist/projected-document-workspace-prompt-child-view-registry.js.map +1 -0
  110. package/dist/projected-document-workspace-prompt-child-view-renderers.d.ts +32 -0
  111. package/dist/projected-document-workspace-prompt-child-view-renderers.d.ts.map +1 -0
  112. package/dist/projected-document-workspace-prompt-child-view-renderers.js +77 -0
  113. package/dist/projected-document-workspace-prompt-child-view-renderers.js.map +1 -0
  114. package/dist/projected-document-workspace-shell.d.ts +100 -0
  115. package/dist/projected-document-workspace-shell.d.ts.map +1 -0
  116. package/dist/projected-document-workspace-shell.js +153 -0
  117. package/dist/projected-document-workspace-shell.js.map +1 -0
  118. package/dist/projected-document-workspace.d.ts +39 -0
  119. package/dist/projected-document-workspace.d.ts.map +1 -0
  120. package/dist/projected-document-workspace.js +63 -0
  121. package/dist/projected-document-workspace.js.map +1 -0
  122. package/dist/projected-field-value-rendering.d.ts +94 -0
  123. package/dist/projected-field-value-rendering.d.ts.map +1 -0
  124. package/dist/projected-field-value-rendering.js +377 -0
  125. package/dist/projected-field-value-rendering.js.map +1 -0
  126. package/dist/projected-inline-list.d.ts +20 -0
  127. package/dist/projected-inline-list.d.ts.map +1 -0
  128. package/dist/projected-inline-list.js +149 -0
  129. package/dist/projected-inline-list.js.map +1 -0
  130. package/dist/projected-input-form.d.ts +143 -0
  131. package/dist/projected-input-form.d.ts.map +1 -0
  132. package/dist/projected-input-form.js +612 -0
  133. package/dist/projected-input-form.js.map +1 -0
  134. package/dist/projected-metric-dashboard.d.ts +26 -0
  135. package/dist/projected-metric-dashboard.d.ts.map +1 -0
  136. package/dist/projected-metric-dashboard.js +20 -0
  137. package/dist/projected-metric-dashboard.js.map +1 -0
  138. package/dist/projected-metric-strip.d.ts +20 -0
  139. package/dist/projected-metric-strip.d.ts.map +1 -0
  140. package/dist/projected-metric-strip.js +131 -0
  141. package/dist/projected-metric-strip.js.map +1 -0
  142. package/dist/projected-navigation-shell-view-host.d.ts +34 -0
  143. package/dist/projected-navigation-shell-view-host.d.ts.map +1 -0
  144. package/dist/projected-navigation-shell-view-host.js +75 -0
  145. package/dist/projected-navigation-shell-view-host.js.map +1 -0
  146. package/dist/projected-navigation-shell.d.ts +33 -0
  147. package/dist/projected-navigation-shell.d.ts.map +1 -0
  148. package/dist/projected-navigation-shell.js +112 -0
  149. package/dist/projected-navigation-shell.js.map +1 -0
  150. package/dist/projected-presentation-badges.d.ts +34 -0
  151. package/dist/projected-presentation-badges.d.ts.map +1 -0
  152. package/dist/projected-presentation-badges.js +22 -0
  153. package/dist/projected-presentation-badges.js.map +1 -0
  154. package/dist/projected-presentation-diagnostics.d.ts +10 -0
  155. package/dist/projected-presentation-diagnostics.d.ts.map +1 -0
  156. package/dist/projected-presentation-diagnostics.js +40 -0
  157. package/dist/projected-presentation-diagnostics.js.map +1 -0
  158. package/dist/projected-presentation-flow-layer.d.ts +33 -0
  159. package/dist/projected-presentation-flow-layer.d.ts.map +1 -0
  160. package/dist/projected-presentation-flow-layer.js +71 -0
  161. package/dist/projected-presentation-flow-layer.js.map +1 -0
  162. package/dist/projected-process-task-notices.d.ts +37 -0
  163. package/dist/projected-process-task-notices.d.ts.map +1 -0
  164. package/dist/projected-process-task-notices.js +225 -0
  165. package/dist/projected-process-task-notices.js.map +1 -0
  166. package/dist/projected-prompt-child-view-renderer.d.ts +101 -0
  167. package/dist/projected-prompt-child-view-renderer.d.ts.map +1 -0
  168. package/dist/projected-prompt-child-view-renderer.js +442 -0
  169. package/dist/projected-prompt-child-view-renderer.js.map +1 -0
  170. package/dist/projected-prompt-document-preview.d.ts +39 -0
  171. package/dist/projected-prompt-document-preview.d.ts.map +1 -0
  172. package/dist/projected-prompt-document-preview.js +50 -0
  173. package/dist/projected-prompt-document-preview.js.map +1 -0
  174. package/dist/projected-prompt-view.d.ts +35 -0
  175. package/dist/projected-prompt-view.d.ts.map +1 -0
  176. package/dist/projected-prompt-view.js +292 -0
  177. package/dist/projected-prompt-view.js.map +1 -0
  178. package/dist/projected-query-form.d.ts +56 -0
  179. package/dist/projected-query-form.d.ts.map +1 -0
  180. package/dist/projected-query-form.js +100 -0
  181. package/dist/projected-query-form.js.map +1 -0
  182. package/dist/projected-record-details.d.ts +20 -0
  183. package/dist/projected-record-details.d.ts.map +1 -0
  184. package/dist/projected-record-details.js +60 -0
  185. package/dist/projected-record-details.js.map +1 -0
  186. package/dist/projected-routed-surface-runtime.d.ts +86 -0
  187. package/dist/projected-routed-surface-runtime.d.ts.map +1 -0
  188. package/dist/projected-routed-surface-runtime.js +332 -0
  189. package/dist/projected-routed-surface-runtime.js.map +1 -0
  190. package/dist/projected-tabs-view.d.ts +21 -0
  191. package/dist/projected-tabs-view.d.ts.map +1 -0
  192. package/dist/projected-tabs-view.js +140 -0
  193. package/dist/projected-tabs-view.js.map +1 -0
  194. package/dist/projected-view-chrome.d.ts +15 -0
  195. package/dist/projected-view-chrome.d.ts.map +1 -0
  196. package/dist/projected-view-chrome.js +67 -0
  197. package/dist/projected-view-chrome.js.map +1 -0
  198. package/dist/projected-view-surface.d.ts +34 -0
  199. package/dist/projected-view-surface.d.ts.map +1 -0
  200. package/dist/projected-view-surface.js +40 -0
  201. package/dist/projected-view-surface.js.map +1 -0
  202. package/dist/standard-collection-chrome-slot-renderers.d.ts +26 -0
  203. package/dist/standard-collection-chrome-slot-renderers.d.ts.map +1 -0
  204. package/dist/standard-collection-chrome-slot-renderers.js +250 -0
  205. package/dist/standard-collection-chrome-slot-renderers.js.map +1 -0
  206. package/dist/standard-view-chrome-slot-renderers.d.ts +57 -0
  207. package/dist/standard-view-chrome-slot-renderers.d.ts.map +1 -0
  208. package/dist/standard-view-chrome-slot-renderers.js +614 -0
  209. package/dist/standard-view-chrome-slot-renderers.js.map +1 -0
  210. package/package.json +68 -0
  211. package/src/document-workspace-surface-slot-renderers.tsx +395 -0
  212. package/src/index.ts +53 -0
  213. package/src/navigation-shell-frame-renderer-registry.ts +29 -0
  214. package/src/navigation-shell-slot-renderer-registry.ts +46 -0
  215. package/src/page-host-unavailable-renderer.tsx +79 -0
  216. package/src/presentation-action-group.tsx +475 -0
  217. package/src/presentation-badge-target-interpreter.ts +54 -0
  218. package/src/presentation-component-groups.ts +2505 -0
  219. package/src/presentation-component-system-diagnostics.ts +848 -0
  220. package/src/presentation-component-system.ts +365 -0
  221. package/src/presentation-icon-diagnostics.ts +53 -0
  222. package/src/presentation-icon-registry.tsx +181 -0
  223. package/src/presentation-projection-trace-panel.tsx +140 -0
  224. package/src/presentation-routed-surface-host.tsx +48 -0
  225. package/src/presentation-shadcn-component-system.ts +102 -0
  226. package/src/presentation-standard-renderers.tsx +1290 -0
  227. package/src/presentation-surface-renderer.tsx +263 -0
  228. package/src/presentation-value-renderers.tsx +40 -0
  229. package/src/process-task-icons.tsx +258 -0
  230. package/src/projected-activity-state.tsx +63 -0
  231. package/src/projected-collection-action-runtime-diagnostics.ts +22 -0
  232. package/src/projected-collection-view.tsx +1273 -0
  233. package/src/projected-document-action-status-notices.tsx +66 -0
  234. package/src/projected-document-badges.tsx +134 -0
  235. package/src/projected-document-editor-surface.tsx +808 -0
  236. package/src/projected-document-workspace-notices.tsx +77 -0
  237. package/src/projected-document-workspace-prompt-child-view-registry.ts +99 -0
  238. package/src/projected-document-workspace-prompt-child-view-renderers.tsx +205 -0
  239. package/src/projected-document-workspace-shell.tsx +427 -0
  240. package/src/projected-document-workspace.tsx +216 -0
  241. package/src/projected-field-value-rendering.tsx +704 -0
  242. package/src/projected-inline-list.tsx +434 -0
  243. package/src/projected-input-form.tsx +1218 -0
  244. package/src/projected-metric-dashboard.tsx +106 -0
  245. package/src/projected-metric-strip.tsx +244 -0
  246. package/src/projected-navigation-shell-view-host.tsx +177 -0
  247. package/src/projected-navigation-shell.tsx +219 -0
  248. package/src/projected-presentation-badges.tsx +95 -0
  249. package/src/projected-presentation-diagnostics.tsx +120 -0
  250. package/src/projected-presentation-flow-layer.tsx +186 -0
  251. package/src/projected-process-task-notices.tsx +501 -0
  252. package/src/projected-prompt-child-view-renderer.tsx +698 -0
  253. package/src/projected-prompt-document-preview.tsx +197 -0
  254. package/src/projected-prompt-view.tsx +592 -0
  255. package/src/projected-query-form.tsx +286 -0
  256. package/src/projected-record-details.tsx +133 -0
  257. package/src/projected-routed-surface-runtime.tsx +713 -0
  258. package/src/projected-tabs-view.tsx +308 -0
  259. package/src/projected-view-chrome.tsx +148 -0
  260. package/src/projected-view-surface.tsx +131 -0
  261. package/src/standard-collection-chrome-slot-renderers.tsx +391 -0
  262. package/src/standard-view-chrome-slot-renderers.tsx +1064 -0
@@ -0,0 +1,2505 @@
1
+ import { clsx, type ClassValue } from 'clsx'
2
+ import {
3
+ type ChangeEvent,
4
+ createElement,
5
+ type ExoticComponent,
6
+ Fragment,
7
+ Suspense,
8
+ type ComponentType,
9
+ type CSSProperties,
10
+ type MouseEventHandler,
11
+ type ReactNode,
12
+ } from 'react'
13
+ import { twMerge } from 'tailwind-merge'
14
+
15
+ import type {
16
+ InputFormDefinition,
17
+ InputFormFieldDefinition,
18
+ InputFormGroupDefinition,
19
+ ViewChromeSlotDefinition,
20
+ ViewRegionDefinition,
21
+ } from '@cohesivesystems/presentation-contracts'
22
+ import {
23
+ createPresentationTestAttributes,
24
+ } from '@cohesivesystems/presentation-core'
25
+ import type {
26
+ PresentationActionButtonSize,
27
+ PresentationActionButtonVariant,
28
+ } from '@cohesivesystems/presentation-tailwind'
29
+
30
+ /** Props accepted by action buttons projected from presentation actions. */
31
+ export interface PresentationActionButtonProps {
32
+ readonly 'aria-label'?: string
33
+ readonly 'aria-pressed'?: boolean
34
+ readonly 'data-presentation-action-id'?: string
35
+ readonly 'data-presentation-collection-slot-id'?: string
36
+ readonly 'data-presentation-view-id'?: string
37
+ readonly children?: ReactNode
38
+ readonly className?: string
39
+ readonly disabled?: boolean
40
+ readonly onClick?: MouseEventHandler<HTMLButtonElement>
41
+ readonly size?: PresentationActionButtonSize
42
+ readonly title?: string
43
+ readonly type?: 'button' | 'reset' | 'submit'
44
+ readonly variant?: PresentationActionButtonVariant
45
+ }
46
+
47
+ /** Action component group used by renderers that need command or intent buttons. */
48
+ export interface PresentationActionComponentSystemComponents {
49
+ readonly ActionButton: (props: PresentationActionButtonProps) => ReactNode
50
+ }
51
+
52
+ /** Visual variants supported by badge primitives in the shadcn adapter layer. */
53
+ export type PresentationBadgeVariant =
54
+ 'default' | 'destructive' | 'ghost' | 'link' | 'outline' | 'secondary'
55
+
56
+ /** Props accepted by semantic badge renderers. */
57
+ export interface PresentationBadgeProps {
58
+ readonly children?: ReactNode
59
+ readonly className?: string
60
+ readonly variant?: PresentationBadgeVariant
61
+ }
62
+
63
+ /** Badge component group shared by presentation renderers that need compact labels. */
64
+ export interface PresentationBadgeComponentSystemComponents {
65
+ readonly Badge: (props: PresentationBadgeProps) => ReactNode
66
+ }
67
+
68
+ /** Props for navigation links after route targets have been projected to frontend paths. */
69
+ export interface PresentationNavigationLinkProps {
70
+ readonly children?: ReactNode
71
+ readonly className?: string
72
+ readonly isActive?: boolean
73
+ readonly to: string
74
+ }
75
+
76
+ /** Navigation component group used to render projected route links. */
77
+ export interface PresentationNavigationComponentSystemComponents {
78
+ readonly NavigationLink: (props: PresentationNavigationLinkProps) => ReactNode
79
+ }
80
+
81
+ /** Minimal router link contract required by the navigation adapter. */
82
+ export interface PresentationNavigationRouterLinkProps {
83
+ readonly children?: ReactNode
84
+ readonly className?: string
85
+ readonly to: string
86
+ }
87
+
88
+ /** Button style options used to derive class names for navigation links. */
89
+ export interface PresentationNavigationButtonClassNameOptions {
90
+ readonly size: 'sm'
91
+ readonly variant: 'ghost' | 'secondary'
92
+ }
93
+
94
+ /** Primitive dependencies required to build the action component group. */
95
+ export interface CreateShadcnActionComponentsOptions {
96
+ readonly Button: ComponentType<PresentationActionButtonProps>
97
+ }
98
+
99
+ /** Primitive dependencies required to build the badge component group. */
100
+ export interface CreateShadcnBadgeComponentsOptions {
101
+ readonly Badge: ComponentType<PresentationBadgeProps>
102
+ }
103
+
104
+ /** Primitive dependencies required to build the navigation component group. */
105
+ export interface CreateShadcnNavigationComponentsOptions {
106
+ readonly Link: ComponentType<PresentationNavigationRouterLinkProps>
107
+ readonly buttonClassName: (options: PresentationNavigationButtonClassNameOptions) => string
108
+ }
109
+
110
+ /** Adapter contract for the underlying tabs root primitive. */
111
+ export interface PresentationTabsRootPrimitiveProps {
112
+ readonly children?: ReactNode
113
+ readonly className?: string
114
+ readonly 'data-presentation-view-id'?: string
115
+ readonly onValueChange: (value: string) => void
116
+ readonly value: string
117
+ }
118
+
119
+ /** Adapter contract for the underlying tabs list primitive. */
120
+ export interface PresentationTabsListPrimitiveProps {
121
+ readonly children?: ReactNode
122
+ readonly className?: string
123
+ readonly 'data-presentation-view-id'?: string
124
+ }
125
+
126
+ /** Adapter contract for an underlying tabs content primitive. */
127
+ export interface PresentationTabsContentPrimitiveProps {
128
+ readonly children?: ReactNode
129
+ readonly className?: string
130
+ readonly 'data-presentation-region-id'?: string
131
+ readonly 'data-presentation-view-id'?: string
132
+ readonly forceMount?: true
133
+ readonly value: string
134
+ }
135
+
136
+ /** Adapter contract for an underlying tabs trigger primitive. */
137
+ export interface PresentationTabsTriggerPrimitiveProps {
138
+ readonly children?: ReactNode
139
+ readonly className?: string
140
+ readonly 'data-presentation-region-id'?: string
141
+ readonly 'data-presentation-view-id'?: string
142
+ readonly value: string
143
+ }
144
+
145
+ /** Primitive dependencies required to build semantic tab components. */
146
+ export interface CreateShadcnTabsComponentsOptions {
147
+ readonly Tabs: ComponentType<PresentationTabsRootPrimitiveProps>
148
+ readonly TabsContent: ComponentType<PresentationTabsContentPrimitiveProps>
149
+ readonly TabsList: ComponentType<PresentationTabsListPrimitiveProps>
150
+ readonly TabsTrigger: ComponentType<PresentationTabsTriggerPrimitiveProps>
151
+ }
152
+
153
+ /** Props for a semantic multi-choice toggle group control. */
154
+ export interface PresentationChoiceToggleGroupProps {
155
+ readonly 'aria-label'?: string
156
+ readonly children?: ReactNode
157
+ readonly className?: string
158
+ readonly onValueChange?: (value: string[]) => void
159
+ readonly value?: readonly string[]
160
+ }
161
+
162
+ /** Props for an individual semantic choice toggle option. */
163
+ export interface PresentationChoiceToggleItemProps {
164
+ readonly 'aria-label'?: string
165
+ readonly children?: ReactNode
166
+ readonly className?: string
167
+ readonly value: string
168
+ }
169
+
170
+ /** Props for a boolean input control projected from a presentation field. */
171
+ export interface PresentationCheckboxControlProps {
172
+ readonly 'aria-label': string
173
+ readonly checked: boolean
174
+ readonly className?: string
175
+ readonly onCheckedChange: (checked: boolean) => void
176
+ }
177
+
178
+ /** Props for date-time filter controls exposed to presentation form renderers. */
179
+ export interface PresentationDateTimeFilterControlProps<
180
+ TDateTimeFilterValue = unknown,
181
+ > {
182
+ readonly emptyLabel?: string
183
+ readonly incrementMinutes?: number
184
+ readonly label?: string
185
+ readonly onValueChange: (value: TDateTimeFilterValue) => void
186
+ readonly showTimezone?: boolean
187
+ readonly value: TDateTimeFilterValue
188
+ }
189
+
190
+ /** Adapter contract for the date-time primitive consumed by form controls. */
191
+ export interface PresentationDateTimeFilterPrimitiveProps<
192
+ TDateTimeFilterValue,
193
+ > {
194
+ readonly emptyLabel?: string
195
+ readonly incrementMinutes?: number
196
+ readonly label?: string
197
+ readonly onChange: (value: TDateTimeFilterValue) => void
198
+ readonly showTimezone?: boolean
199
+ readonly value: TDateTimeFilterValue
200
+ }
201
+
202
+ /** Props for labels rendered next to projected form fields. */
203
+ export interface PresentationFormFieldLabelProps {
204
+ readonly children?: ReactNode
205
+ readonly className?: string
206
+ }
207
+
208
+ /** Props for the root element of an input form projected from backend presentation IR. */
209
+ export interface PresentationInputFormProps {
210
+ readonly children?: ReactNode
211
+ readonly className?: string
212
+ readonly form: InputFormDefinition
213
+ readonly viewId?: string | null
214
+ }
215
+
216
+ /** Props for a form action row bound to a projected input form. */
217
+ export interface PresentationInputFormActionRowProps {
218
+ readonly children?: ReactNode
219
+ readonly className?: string
220
+ readonly form: InputFormDefinition
221
+ }
222
+
223
+ /** Props for grouping one field's control content. */
224
+ export interface PresentationInputFormControlGroupProps {
225
+ readonly children?: ReactNode
226
+ readonly className?: string
227
+ readonly field: InputFormFieldDefinition
228
+ }
229
+
230
+ /** Props for a slot that receives a projected form control. */
231
+ export interface PresentationInputFormControlSlotProps {
232
+ readonly children?: ReactNode
233
+ readonly className?: string
234
+ readonly field: InputFormFieldDefinition
235
+ }
236
+
237
+ /** Props for the composed label, control, and message of one input field. */
238
+ export interface PresentationInputFormFieldProps {
239
+ readonly className?: string
240
+ readonly control: ReactNode
241
+ readonly field: InputFormFieldDefinition
242
+ readonly label: ReactNode
243
+ readonly message?: ReactNode
244
+ }
245
+
246
+ /** Props for validation or helper text associated with a projected field. */
247
+ export interface PresentationInputFormFieldMessageProps {
248
+ readonly children?: ReactNode
249
+ readonly className?: string
250
+ readonly field: InputFormFieldDefinition
251
+ readonly tone?: 'default' | 'error' | 'warning'
252
+ }
253
+
254
+ /** Props for a named group within a projected input form. */
255
+ export interface PresentationInputFormGroupProps {
256
+ readonly children?: ReactNode
257
+ readonly className?: string
258
+ readonly group: InputFormGroupDefinition
259
+ }
260
+
261
+ /** Props for the container that renders all groups in a projected input form. */
262
+ export interface PresentationInputFormGroupsProps {
263
+ readonly children?: ReactNode
264
+ readonly className?: string
265
+ readonly form: InputFormDefinition
266
+ }
267
+
268
+ /** Option contract for select controls projected from presentation choices. */
269
+ export interface PresentationSelectControlOption {
270
+ readonly label: string
271
+ readonly value: string
272
+ }
273
+
274
+ /** Props for a select control bound to a string presentation field value. */
275
+ export interface PresentationSelectControlProps {
276
+ readonly 'aria-label': string
277
+ readonly className?: string
278
+ readonly disabled?: boolean
279
+ readonly onValueChange: (value: string) => void
280
+ readonly options: readonly PresentationSelectControlOption[]
281
+ readonly value: string
282
+ }
283
+
284
+ /** Props for a text-like input control bound to a presentation field value. */
285
+ export interface PresentationTextInputControlProps {
286
+ readonly 'aria-label': string
287
+ readonly className?: string
288
+ readonly onValueChange: (value: string) => void
289
+ readonly placeholder?: string
290
+ readonly type?: string
291
+ readonly value: string
292
+ }
293
+
294
+ /** Adapter contract for the underlying multi-select toggle group primitive. */
295
+ export interface PresentationChoiceToggleGroupPrimitiveProps {
296
+ readonly 'aria-label'?: string
297
+ readonly children?: ReactNode
298
+ readonly className?: string
299
+ readonly onValueChange?: (value: string[]) => void
300
+ readonly type: 'multiple'
301
+ readonly value: string[]
302
+ }
303
+
304
+ /** Adapter contract for the underlying text input primitive. */
305
+ export interface PresentationInputPrimitiveProps {
306
+ readonly 'aria-label': string
307
+ readonly className?: string
308
+ readonly onChange: (event: ChangeEvent<HTMLInputElement>) => void
309
+ readonly placeholder?: string
310
+ readonly type?: string
311
+ readonly value: string
312
+ }
313
+
314
+ /** Primitive dependencies required to build semantic form components. */
315
+ export interface CreateShadcnFormComponentsOptions<
316
+ TDateTimeFilterValue = unknown,
317
+ > {
318
+ readonly Button: ComponentType<PresentationActionButtonProps>
319
+ readonly DateTimeFilter: ComponentType<
320
+ PresentationDateTimeFilterPrimitiveProps<TDateTimeFilterValue>
321
+ >
322
+ readonly Input: ComponentType<PresentationInputPrimitiveProps>
323
+ readonly Label: ComponentType<PresentationFormFieldLabelProps>
324
+ readonly ToggleGroup: ComponentType<PresentationChoiceToggleGroupPrimitiveProps>
325
+ readonly ToggleGroupItem: ComponentType<PresentationChoiceToggleItemProps>
326
+ }
327
+
328
+ /** Props for collection chrome regions such as summaries, details, and query slots. */
329
+ export interface PresentationCollectionChromeSlotProps {
330
+ readonly children?: ReactNode
331
+ readonly className?: string
332
+ readonly slotId?: string
333
+ readonly viewId?: string | null
334
+ }
335
+
336
+ /** Props for collection pagination state and navigation actions. */
337
+ export interface PresentationCollectionPaginationBarProps {
338
+ readonly canGoNextPage: boolean
339
+ readonly canGoPreviousPage: boolean
340
+ readonly className?: string
341
+ readonly firstIcon?: ReactNode
342
+ readonly isFetching: boolean
343
+ readonly loadingIcon?: ReactNode
344
+ readonly nextIcon?: ReactNode
345
+ readonly onFirstPage: () => void
346
+ readonly onNextPage: () => void
347
+ readonly onPreviousPage: () => void
348
+ readonly pageLabel: string
349
+ readonly pageSizeLabel: string
350
+ readonly previousIcon?: ReactNode
351
+ readonly shownLabel: string
352
+ readonly slotId?: string | null
353
+ readonly totalLabel: string
354
+ readonly viewId?: string | null
355
+ }
356
+
357
+ /** Props for row-level action containers in collection projections. */
358
+ export interface PresentationCollectionRowActionsProps {
359
+ readonly children?: ReactNode
360
+ readonly className?: string
361
+ readonly rowLabel?: string | null
362
+ readonly slotId?: string
363
+ }
364
+
365
+ /** Props for action toolbars shown when collection rows are selected. */
366
+ export interface PresentationCollectionSelectionActionToolbarProps {
367
+ readonly actions?: ReactNode
368
+ readonly className?: string
369
+ readonly selectedCount: number
370
+ readonly selectedLabel: string
371
+ readonly slotId?: string | null
372
+ }
373
+
374
+ /** Collection chrome component group for projected query, summary, body, detail, and action slots. */
375
+ export interface PresentationCollectionChromeComponentSystemComponents {
376
+ readonly CollectionBodySlot: (props: PresentationCollectionChromeSlotProps) => ReactNode
377
+ readonly CollectionDetailSlot: (props: PresentationCollectionChromeSlotProps) => ReactNode
378
+ readonly CollectionPaginationBar: (props: PresentationCollectionPaginationBarProps) => ReactNode
379
+ readonly CollectionQueryFormSlot: (props: PresentationCollectionChromeSlotProps) => ReactNode
380
+ readonly CollectionRowActions: (props: PresentationCollectionRowActionsProps) => ReactNode
381
+ readonly CollectionSelectionActionToolbar: (
382
+ props: PresentationCollectionSelectionActionToolbarProps
383
+ ) => ReactNode
384
+ readonly CollectionSummarySlot: (props: PresentationCollectionChromeSlotProps) => ReactNode
385
+ }
386
+
387
+ /** Primitive dependencies required to build collection chrome components. */
388
+ export interface CreateShadcnCollectionChromeComponentsOptions {
389
+ readonly Button: ComponentType<PresentationActionButtonProps>
390
+ }
391
+
392
+ /** Supported layout modes for rendering collection tables with optional detail content. */
393
+ export type PresentationCollectionDetailLayoutMode =
394
+ 'drawer' | 'none' | 'side-panel' | 'stack'
395
+
396
+ /** Props for arranging a collection table with its projected detail view. */
397
+ export interface PresentationCollectionDetailLayoutProps {
398
+ readonly detail: ReactNode
399
+ readonly mode: PresentationCollectionDetailLayoutMode
400
+ readonly table: ReactNode
401
+ }
402
+
403
+ /** Generic data table renderer contract supplied by collection adapters. */
404
+ export type PresentationDataTableRenderer = <TData extends object>(
405
+ props: never & { readonly __data?: TData },
406
+ ) => ReactNode
407
+
408
+ /** Props for a row action menu wrapper and trigger. */
409
+ export interface PresentationRowActionMenuProps {
410
+ readonly children?: ReactNode
411
+ readonly trigger: ReactNode
412
+ }
413
+
414
+ /** Props for the interactive trigger of a row action menu. */
415
+ export interface PresentationRowActionMenuTriggerProps {
416
+ readonly 'aria-label': string
417
+ readonly children?: ReactNode
418
+ }
419
+
420
+ /** Props for one executable item in a row action menu. */
421
+ export interface PresentationRowActionMenuItemProps {
422
+ readonly actionId?: string | null
423
+ readonly children?: ReactNode
424
+ readonly collectionSlotId?: string | null
425
+ readonly disabled?: boolean
426
+ readonly onClick?: MouseEventHandler<HTMLButtonElement>
427
+ readonly viewId?: string | null
428
+ }
429
+
430
+ /** Style options used to derive row action menu trigger classes. */
431
+ export interface PresentationRowActionMenuTriggerClassNameOptions {
432
+ readonly size: 'icon-sm'
433
+ readonly variant: 'ghost'
434
+ }
435
+
436
+ /** Collection component group for tables, detail layout, and row actions. */
437
+ export interface PresentationCollectionComponentSystemComponents<
438
+ TDataTableRenderer extends PresentationDataTableRenderer =
439
+ PresentationDataTableRenderer,
440
+ > {
441
+ readonly CollectionDetailLayout: (props: PresentationCollectionDetailLayoutProps) => ReactNode
442
+ readonly DataTable: TDataTableRenderer
443
+ readonly RowActionMenu: (props: PresentationRowActionMenuProps) => ReactNode
444
+ readonly RowActionMenuItem: (props: PresentationRowActionMenuItemProps) => ReactNode
445
+ readonly RowActionMenuTrigger: (props: PresentationRowActionMenuTriggerProps) => ReactNode
446
+ }
447
+
448
+ /** Primitive dependencies required to build collection components. */
449
+ export interface CreateShadcnCollectionComponentsOptions<
450
+ TDataTableRenderer extends PresentationDataTableRenderer =
451
+ PresentationDataTableRenderer,
452
+ > {
453
+ readonly CollectionDetailLayout: (props: PresentationCollectionDetailLayoutProps) => ReactNode
454
+ readonly DataTable: TDataTableRenderer
455
+ readonly rowActionMenuTriggerClassName: (
456
+ options: PresentationRowActionMenuTriggerClassNameOptions
457
+ ) => string
458
+ }
459
+
460
+ /** Props for a view surface that frames projected presentation content. */
461
+ export interface PresentationViewSurfaceProps {
462
+ readonly action?: ReactNode
463
+ readonly children?: ReactNode
464
+ readonly className?: string
465
+ readonly collapsible?: boolean
466
+ readonly collapsed?: boolean
467
+ readonly collapseLabel?: string
468
+ readonly contentClassName?: string
469
+ readonly contentTopInset?: PresentationViewSurfaceContentTopInset | null
470
+ readonly defaultCollapsed?: boolean
471
+ readonly description?: string
472
+ readonly eyebrow?: string
473
+ readonly onCollapsedChange?: (collapsed: boolean) => void
474
+ readonly title?: string
475
+ readonly verticalResize?: boolean | PresentationViewSurfaceVerticalResizeOptions | null
476
+ readonly viewId?: string | null
477
+ }
478
+
479
+ /** Controls the top inset applied between view surface chrome and content. */
480
+ export type PresentationViewSurfaceContentTopInset =
481
+ | 'default'
482
+ | 'none'
483
+
484
+ /** Defines vertical resize behavior for projected view surfaces. */
485
+ export interface PresentationViewSurfaceVerticalResizeOptions {
486
+ /** Selects one resize affordance for changing the surface height. */
487
+ readonly control?: PresentationViewSurfaceVerticalResizeControl
488
+ readonly defaultHeightRem?: number
489
+ readonly enabled?: boolean
490
+ readonly maxHeightRem?: number
491
+ readonly minHeightRem?: number
492
+ readonly stepRem?: number
493
+ }
494
+
495
+ /** Mutually exclusive resize controls exposed by projected view surfaces. */
496
+ export type PresentationViewSurfaceVerticalResizeControl =
497
+ | 'drag-handle'
498
+ | 'header-buttons'
499
+
500
+ /** Props for chrome content placed around a view surface by semantic placement. */
501
+ export interface PresentationViewSurfaceChromePlacementProps {
502
+ readonly children?: ReactNode
503
+ readonly className?: string
504
+ readonly placement: string | number
505
+ readonly viewId?: string | null
506
+ }
507
+
508
+ /** Props for composing main content with before, after, and footer chrome. */
509
+ export interface PresentationViewSurfaceContentProps {
510
+ readonly afterContentChrome?: ReactNode
511
+ readonly beforeContentChrome?: ReactNode
512
+ readonly children?: ReactNode
513
+ readonly footerChrome?: ReactNode
514
+ readonly viewId?: string | null
515
+ }
516
+
517
+ /** Props for merging primary view actions with additional header chrome. */
518
+ export interface PresentationViewSurfaceHeaderActionsProps {
519
+ readonly action?: ReactNode
520
+ readonly chrome?: ReactNode
521
+ readonly className?: string
522
+ readonly viewId?: string | null
523
+ }
524
+
525
+ /** Surface component group used to frame projected views and their chrome. */
526
+ export interface PresentationSurfaceComponentSystemComponents {
527
+ readonly ViewSurface: (props: PresentationViewSurfaceProps) => ReactNode
528
+ readonly ViewSurfaceChromePlacement: (
529
+ props: PresentationViewSurfaceChromePlacementProps
530
+ ) => ReactNode
531
+ readonly ViewSurfaceContent: (props: PresentationViewSurfaceContentProps) => ReactNode
532
+ readonly ViewSurfaceHeaderActions: (
533
+ props: PresentationViewSurfaceHeaderActionsProps
534
+ ) => ReactNode
535
+ }
536
+
537
+ /** Primitive dependencies required to build view surface components. */
538
+ export interface CreateShadcnSurfaceComponentsOptions {
539
+ readonly Surface: ComponentType<PresentationViewSurfaceProps>
540
+ }
541
+
542
+ /** Props for the document workspace detail panel shown beside a tree or surface. */
543
+ export interface PresentationDocumentWorkspaceDetailPanelProps {
544
+ readonly children?: ReactNode
545
+ readonly className?: string
546
+ readonly contentClassName?: string
547
+ readonly emptyClassName?: string
548
+ readonly emptyLabel?: string
549
+ readonly headerClassName?: string
550
+ readonly headerContentClassName?: string
551
+ readonly icon?: ReactNode
552
+ readonly subtitle?: string
553
+ readonly subtitleClassName?: string
554
+ readonly title?: string
555
+ readonly titleClassName?: string
556
+ }
557
+
558
+ /** Props for the root document workspace shell. */
559
+ export interface PresentationDocumentWorkspaceShellProps {
560
+ readonly children?: ReactNode
561
+ readonly className?: string
562
+ readonly contentClassName?: string
563
+ readonly viewId?: string | null
564
+ }
565
+
566
+ /** Resolved rendering options for a document workspace surface slot. */
567
+ export interface PresentationDocumentWorkspaceSurfaceSlotRenderOptions {
568
+ readonly chromeHeaderClassName?: string
569
+ readonly className?: string
570
+ readonly collapsible?: boolean
571
+ readonly contentClassName?: string
572
+ }
573
+
574
+ /** Props for a named document workspace surface slot declared by backend presentation IR. */
575
+ export interface PresentationDocumentWorkspaceSurfaceSlotProps {
576
+ readonly children?: ReactNode
577
+ readonly regionId?: string | null
578
+ readonly renderSurface?: (
579
+ options: PresentationDocumentWorkspaceSurfaceSlotRenderOptions,
580
+ ) => ReactNode
581
+ readonly role?: string | number | null
582
+ readonly slot: string
583
+ readonly viewId?: string | null
584
+ }
585
+
586
+ /** Props for a document workspace layout group projected from layout semantics. */
587
+ export interface PresentationDocumentWorkspaceLayoutGroupProps {
588
+ readonly children?: ReactNode
589
+ readonly className?: string
590
+ readonly layoutNodeId?: string | null
591
+ readonly orientation?: string | number | null
592
+ readonly style?: CSSProperties
593
+ readonly workspaceViewId?: string | null
594
+ }
595
+
596
+ /** Props for one pane in a projected document workspace layout. */
597
+ export interface PresentationDocumentWorkspaceLayoutPaneProps {
598
+ readonly children?: ReactNode
599
+ readonly className?: string
600
+ readonly contentClassName?: string
601
+ readonly layoutNodeId?: string | null
602
+ readonly title: ReactNode
603
+ readonly titleClassName?: string
604
+ readonly viewId?: string | null
605
+ readonly workspaceViewId?: string | null
606
+ }
607
+
608
+ /** Badge metadata rendered inside a document workspace node label. */
609
+ export interface PresentationDocumentWorkspaceNodeLabelBadge {
610
+ readonly className?: string
611
+ readonly label: string
612
+ }
613
+
614
+ /** Props for labels attached to tree or graph nodes in a document workspace. */
615
+ export interface PresentationDocumentWorkspaceNodeLabelProps {
616
+ readonly badges?: readonly PresentationDocumentWorkspaceNodeLabelBadge[]
617
+ readonly className?: string
618
+ readonly icon?: ReactNode
619
+ readonly label: string
620
+ readonly labelClassName?: string
621
+ }
622
+
623
+ /** Props for one item in a document workspace tree. */
624
+ export interface PresentationDocumentWorkspaceTreeItemProps {
625
+ readonly children?: ReactNode
626
+ readonly itemId: string
627
+ readonly label: ReactNode
628
+ }
629
+
630
+ /** Props for lightweight document workspace status content. */
631
+ export interface PresentationDocumentWorkspaceStatusProps {
632
+ readonly children?: ReactNode
633
+ readonly className?: string
634
+ }
635
+
636
+ /** Label-value pair rendered by the document workspace details table. */
637
+ export interface PresentationDocumentWorkspaceTableDetail {
638
+ readonly label: string
639
+ readonly value: ReactNode
640
+ }
641
+
642
+ /** Props for tabular document workspace metadata. */
643
+ export interface PresentationDocumentWorkspaceTableProps {
644
+ readonly details: readonly PresentationDocumentWorkspaceTableDetail[]
645
+ readonly labelCellClassName?: string
646
+ readonly rowClassName?: string
647
+ readonly tableClassName?: string
648
+ readonly valueCellClassName?: string
649
+ readonly valueTextClassName?: string
650
+ }
651
+
652
+ /** Props for split tree/detail layout in document workspaces. */
653
+ export interface PresentationDocumentWorkspaceTreeLayoutProps {
654
+ readonly className?: string
655
+ readonly detail: ReactNode
656
+ readonly detailDefaultSize?: number | string
657
+ readonly detailId: string
658
+ readonly detailMinSize?: number | string
659
+ readonly splitterClassName?: string
660
+ readonly splitterHandleClassName?: string
661
+ readonly tree: ReactNode
662
+ readonly treeDefaultSize?: number | string
663
+ readonly treeId: string
664
+ readonly treeMinSize?: number | string
665
+ }
666
+
667
+ /** Props for controlled tree state in document workspace navigation. */
668
+ export interface PresentationDocumentWorkspaceTreeViewProps {
669
+ readonly ariaLabel: string
670
+ readonly children?: ReactNode
671
+ readonly expandedItemIds: readonly string[]
672
+ readonly onExpandedItemIdsChange: (itemIds: readonly string[]) => void
673
+ readonly onSelectedItemIdChange: (itemId: string | null) => void
674
+ readonly selectedItemId: string | null
675
+ }
676
+
677
+ /** Adapter contract for the split-pane group primitive used by tree layouts. */
678
+ export interface PresentationDocumentWorkspaceTreeLayoutGroupPrimitiveProps {
679
+ readonly children?: ReactNode
680
+ readonly className?: string
681
+ readonly orientation: 'horizontal'
682
+ }
683
+
684
+ /** Adapter contract for split-pane panels used by tree layouts. */
685
+ export interface PresentationDocumentWorkspaceTreeLayoutPanelPrimitiveProps {
686
+ readonly children?: ReactNode
687
+ readonly defaultSize: number | string
688
+ readonly id: string
689
+ readonly minSize: number | string
690
+ }
691
+
692
+ /** Adapter contract for the split-pane separator used by tree layouts. */
693
+ export interface PresentationDocumentWorkspaceTreeLayoutSeparatorPrimitiveProps {
694
+ readonly children?: ReactNode
695
+ readonly className?: string
696
+ }
697
+
698
+ /** Primitive dependencies required to build a document workspace tree layout. */
699
+ export interface CreateShadcnDocumentWorkspaceTreeLayoutOptions {
700
+ readonly Group: ComponentType<PresentationDocumentWorkspaceTreeLayoutGroupPrimitiveProps>
701
+ readonly Panel: ComponentType<PresentationDocumentWorkspaceTreeLayoutPanelPrimitiveProps>
702
+ readonly Separator: ComponentType<
703
+ PresentationDocumentWorkspaceTreeLayoutSeparatorPrimitiveProps
704
+ >
705
+ }
706
+
707
+ /** Adapter contract for the underlying document tree item primitive. */
708
+ export interface PresentationDocumentWorkspaceTreeItemPrimitiveProps {
709
+ readonly children?: ReactNode
710
+ readonly itemId: string
711
+ readonly label: ReactNode
712
+ }
713
+
714
+ /** Primitive dependency required to build document workspace tree items. */
715
+ export interface CreateShadcnDocumentWorkspaceTreeItemOptions {
716
+ readonly TreeItem: ComponentType<PresentationDocumentWorkspaceTreeItemPrimitiveProps>
717
+ }
718
+
719
+ /** Adapter contract for the underlying controlled document tree view primitive. */
720
+ export interface PresentationDocumentWorkspaceTreeViewPrimitiveProps<TSx = unknown> {
721
+ readonly 'aria-label': string
722
+ readonly children?: ReactNode
723
+ readonly expandedItems: string[]
724
+ readonly onExpandedItemsChange: (
725
+ event: unknown,
726
+ itemIds: string[],
727
+ ) => void
728
+ readonly onSelectedItemsChange: (
729
+ event: unknown,
730
+ itemId: string | string[] | null,
731
+ ) => void
732
+ readonly selectedItems: string | null
733
+ readonly sx?: TSx
734
+ }
735
+
736
+ /** Primitive dependency and optional style object for document workspace tree views. */
737
+ export interface CreateShadcnDocumentWorkspaceTreeViewOptions<TSx = unknown> {
738
+ readonly TreeView: ComponentType<PresentationDocumentWorkspaceTreeViewPrimitiveProps<TSx>>
739
+ readonly sx?: TSx
740
+ }
741
+
742
+ /** JSON document component contract that supports regular and exotic React components. */
743
+ export type PresentationDocumentWorkspaceJsonComponent<TProps extends object> =
744
+ | ComponentType<TProps>
745
+ | ExoticComponent<TProps>
746
+
747
+ /** Primitive dependency required to render JSON document diffs. */
748
+ export interface CreateShadcnJsonDocumentDiffOptions<TProps extends object> {
749
+ readonly JsonDocumentDiff: PresentationDocumentWorkspaceJsonComponent<TProps>
750
+ }
751
+
752
+ /** Primitive dependency and fallback configuration for lazy JSON document editors. */
753
+ export interface CreateShadcnJsonDocumentEditorOptions<TProps extends object> {
754
+ readonly fallbackClassName: (props: TProps) => string
755
+ readonly fallbackLabel?: ReactNode
756
+ readonly JsonDocumentEditor: PresentationDocumentWorkspaceJsonComponent<TProps>
757
+ }
758
+
759
+ /** Context used to resolve styling and behavior for a document workspace surface slot. */
760
+ export interface PresentationDocumentWorkspaceSurfaceSlotOptionsContext {
761
+ readonly role?: string | number | null
762
+ readonly slot: string
763
+ }
764
+
765
+ /** Document workspace component group for semantic document navigation, surfaces, and JSON tools. */
766
+ export interface PresentationDocumentWorkspaceComponentSystemComponents<
767
+ TTreeControlsProps extends object = object,
768
+ TJsonDocumentDiffProps extends object = object,
769
+ TJsonDocumentEditorProps extends object = object,
770
+ > {
771
+ readonly DocumentWorkspaceDetailPanel: (
772
+ props: PresentationDocumentWorkspaceDetailPanelProps
773
+ ) => ReactNode
774
+ readonly DocumentWorkspaceLayoutGroup: (
775
+ props: PresentationDocumentWorkspaceLayoutGroupProps
776
+ ) => ReactNode
777
+ readonly DocumentWorkspaceLayoutPane: (
778
+ props: PresentationDocumentWorkspaceLayoutPaneProps
779
+ ) => ReactNode
780
+ readonly DocumentWorkspaceNodeLabel: (
781
+ props: PresentationDocumentWorkspaceNodeLabelProps
782
+ ) => ReactNode
783
+ readonly DocumentWorkspaceShell: (
784
+ props: PresentationDocumentWorkspaceShellProps
785
+ ) => ReactNode
786
+ readonly DocumentWorkspaceSurfaceSlot: (
787
+ props: PresentationDocumentWorkspaceSurfaceSlotProps
788
+ ) => ReactNode
789
+ readonly DocumentWorkspaceTreeControls: (props: TTreeControlsProps) => ReactNode
790
+ readonly DocumentWorkspaceTreeItem: (props: PresentationDocumentWorkspaceTreeItemProps) => ReactNode
791
+ readonly DocumentWorkspaceStatus: (props: PresentationDocumentWorkspaceStatusProps) => ReactNode
792
+ readonly DocumentWorkspaceTable: (props: PresentationDocumentWorkspaceTableProps) => ReactNode
793
+ readonly DocumentWorkspaceTreeLayout: (props: PresentationDocumentWorkspaceTreeLayoutProps) => ReactNode
794
+ readonly DocumentWorkspaceTreeView: (
795
+ props: PresentationDocumentWorkspaceTreeViewProps
796
+ ) => ReactNode
797
+ readonly JsonDocumentDiff: (props: TJsonDocumentDiffProps) => ReactNode
798
+ readonly JsonDocumentEditor: (props: TJsonDocumentEditorProps) => ReactNode
799
+ }
800
+
801
+ /** Dependencies required to build the document workspace component group. */
802
+ export interface CreateShadcnDocumentWorkspaceComponentsOptions<
803
+ TTreeControlsProps extends object = object,
804
+ TJsonDocumentDiffProps extends object = object,
805
+ TJsonDocumentEditorProps extends object = object,
806
+ > {
807
+ readonly Badge: ComponentType<PresentationBadgeProps>
808
+ readonly DocumentWorkspaceTreeControls: (props: TTreeControlsProps) => ReactNode
809
+ readonly DocumentWorkspaceTreeItem: (
810
+ props: PresentationDocumentWorkspaceTreeItemProps
811
+ ) => ReactNode
812
+ readonly DocumentWorkspaceTreeLayout: (
813
+ props: PresentationDocumentWorkspaceTreeLayoutProps
814
+ ) => ReactNode
815
+ readonly DocumentWorkspaceTreeView: (
816
+ props: PresentationDocumentWorkspaceTreeViewProps
817
+ ) => ReactNode
818
+ readonly JsonDocumentDiff: (props: TJsonDocumentDiffProps) => ReactNode
819
+ readonly JsonDocumentEditor: (props: TJsonDocumentEditorProps) => ReactNode
820
+ readonly resolveSurfaceSlotOptions: (
821
+ context: PresentationDocumentWorkspaceSurfaceSlotOptionsContext
822
+ ) => PresentationDocumentWorkspaceSurfaceSlotRenderOptions
823
+ }
824
+
825
+ /** Props for status or empty-state feedback blocks. */
826
+ export interface PresentationStatusBlockProps {
827
+ readonly className?: string
828
+ readonly label: ReactNode
829
+ readonly tone?: 'default' | 'error'
830
+ }
831
+
832
+ /** Feedback component group for status and error messaging. */
833
+ export interface PresentationFeedbackComponentSystemComponents {
834
+ readonly StatusBlock: (props: PresentationStatusBlockProps) => ReactNode
835
+ }
836
+
837
+ /** Props for a single metric projected from view chrome or record data. */
838
+ export interface PresentationMetricItemProps {
839
+ readonly className?: string
840
+ readonly icon?: ReactNode
841
+ readonly id: string
842
+ readonly label: ReactNode
843
+ readonly value: ReactNode
844
+ readonly variant?: 'number' | 'text'
845
+ }
846
+
847
+ /** Props for a container of projected metric items. */
848
+ export interface PresentationMetricStripProps {
849
+ readonly children?: ReactNode
850
+ readonly className?: string
851
+ }
852
+
853
+ /** Metric component group for compact key-value summaries. */
854
+ export interface PresentationMetricComponentSystemComponents {
855
+ readonly MetricItem: (props: PresentationMetricItemProps) => ReactNode
856
+ readonly MetricStrip: (props: PresentationMetricStripProps) => ReactNode
857
+ }
858
+
859
+ /** Semantic color tones available to field value renderers. */
860
+ export type PresentationFieldValueTone =
861
+ 'amber' | 'red' | 'sky' | 'slate' | 'teal' | 'violet'
862
+
863
+ /** Props for rendering code-like field values. */
864
+ export interface PresentationFieldValueCodeProps {
865
+ readonly className?: string
866
+ readonly value: string
867
+ }
868
+
869
+ /** Props for rendering compound field values with badges and supporting lines. */
870
+ export interface PresentationFieldValueCompositeProps {
871
+ readonly className?: string
872
+ readonly inlineBadges?: readonly ReactNode[]
873
+ readonly primaryValue?: ReactNode
874
+ readonly supportingValues?: readonly ReactNode[]
875
+ }
876
+
877
+ /** Props for rendering missing or empty field values. */
878
+ export interface PresentationFieldValueEmptyProps {
879
+ readonly className?: string
880
+ readonly label: ReactNode
881
+ }
882
+
883
+ /** Props for rendering formatted JSON field values. */
884
+ export interface PresentationFieldValueJsonProps {
885
+ readonly className?: string
886
+ readonly formattedValue: string
887
+ readonly tone?: PresentationFieldValueTone
888
+ }
889
+
890
+ /** Props for rendering scalar field values. */
891
+ export interface PresentationFieldValueScalarProps {
892
+ readonly children?: ReactNode
893
+ readonly className?: string
894
+ readonly title?: string
895
+ readonly tone?: PresentationFieldValueTone
896
+ }
897
+
898
+ /** Props for secondary field value lines. */
899
+ export interface PresentationFieldValueSupportingValueProps {
900
+ readonly children?: ReactNode
901
+ readonly className?: string
902
+ }
903
+
904
+ /** Field value component group for scalar, JSON, code, empty, and composite values. */
905
+ export interface PresentationFieldValueComponentSystemComponents {
906
+ readonly FieldValueCode: (props: PresentationFieldValueCodeProps) => ReactNode
907
+ readonly FieldValueComposite: (
908
+ props: PresentationFieldValueCompositeProps
909
+ ) => ReactNode
910
+ readonly FieldValueEmpty: (props: PresentationFieldValueEmptyProps) => ReactNode
911
+ readonly FieldValueJson: (props: PresentationFieldValueJsonProps) => ReactNode
912
+ readonly FieldValueScalar: (props: PresentationFieldValueScalarProps) => ReactNode
913
+ readonly FieldValueSupportingValue: (
914
+ props: PresentationFieldValueSupportingValueProps
915
+ ) => ReactNode
916
+ }
917
+
918
+ /** Props for a record detail container projected from presentation record semantics. */
919
+ export interface PresentationRecordDetailsProps {
920
+ readonly children?: ReactNode
921
+ readonly className?: string
922
+ readonly viewId?: string | null
923
+ }
924
+
925
+ /** Props for empty-state content in record detail views. */
926
+ export interface PresentationRecordDetailEmptyStateProps {
927
+ readonly className?: string
928
+ readonly label: ReactNode
929
+ readonly viewId?: string | null
930
+ }
931
+
932
+ /** Props for one field row in a record detail view. */
933
+ export interface PresentationRecordDetailFieldProps {
934
+ readonly actions?: ReactNode
935
+ readonly className?: string
936
+ readonly fieldId: string
937
+ readonly hideLabel?: boolean
938
+ readonly label: ReactNode
939
+ readonly value: ReactNode
940
+ }
941
+
942
+ /** Record component group for detail tables and field rows. */
943
+ export interface PresentationRecordComponentSystemComponents {
944
+ readonly RecordDetailEmptyState: (
945
+ props: PresentationRecordDetailEmptyStateProps
946
+ ) => ReactNode
947
+ readonly RecordDetailField: (props: PresentationRecordDetailFieldProps) => ReactNode
948
+ readonly RecordDetails: (props: PresentationRecordDetailsProps) => ReactNode
949
+ }
950
+
951
+ /** Form component group for projected input forms and their controls. */
952
+ export interface PresentationFormComponentSystemComponents<
953
+ TDateTimeFilterValue = unknown,
954
+ > {
955
+ readonly CheckboxControl: (props: PresentationCheckboxControlProps) => ReactNode
956
+ readonly ChoiceToggleGroup: (props: PresentationChoiceToggleGroupProps) => ReactNode
957
+ readonly ChoiceToggleItem: (props: PresentationChoiceToggleItemProps) => ReactNode
958
+ readonly DateTimeFilterControl: (
959
+ props: PresentationDateTimeFilterControlProps<TDateTimeFilterValue>
960
+ ) => ReactNode
961
+ readonly FormActionButton: (props: PresentationActionButtonProps) => ReactNode
962
+ readonly FormFieldLabel: (props: PresentationFormFieldLabelProps) => ReactNode
963
+ readonly InputForm: (props: PresentationInputFormProps) => ReactNode
964
+ readonly InputFormActionRow: (props: PresentationInputFormActionRowProps) => ReactNode
965
+ readonly InputFormControlGroup: (
966
+ props: PresentationInputFormControlGroupProps
967
+ ) => ReactNode
968
+ readonly InputFormControlSlot: (props: PresentationInputFormControlSlotProps) => ReactNode
969
+ readonly InputFormField: (props: PresentationInputFormFieldProps) => ReactNode
970
+ readonly InputFormFieldMessage: (
971
+ props: PresentationInputFormFieldMessageProps
972
+ ) => ReactNode
973
+ readonly InputFormGroup: (props: PresentationInputFormGroupProps) => ReactNode
974
+ readonly InputFormGroups: (props: PresentationInputFormGroupsProps) => ReactNode
975
+ readonly SelectControl: (props: PresentationSelectControlProps) => ReactNode
976
+ readonly TextInputControl: (props: PresentationTextInputControlProps) => ReactNode
977
+ }
978
+
979
+ /** Props for the semantic tabs layout projected from view regions. */
980
+ export interface PresentationTabsLayoutProps {
981
+ readonly children?: ReactNode
982
+ readonly className?: string
983
+ readonly onValueChange: (value: string) => void
984
+ readonly value: string
985
+ readonly viewId?: string | null
986
+ }
987
+
988
+ /** Props for the list container of projected tabs. */
989
+ export interface PresentationTabsListProps {
990
+ readonly children?: ReactNode
991
+ readonly className?: string
992
+ readonly viewId?: string | null
993
+ }
994
+
995
+ /** Props for a tab panel bound to a projected view region. */
996
+ export interface PresentationTabsPanelProps {
997
+ readonly children?: ReactNode
998
+ readonly className?: string
999
+ readonly region: ViewRegionDefinition
1000
+ readonly value: string
1001
+ readonly viewId?: string | null
1002
+ }
1003
+
1004
+ /** Props for a tab trigger bound to a projected view region. */
1005
+ export interface PresentationTabsTriggerProps {
1006
+ readonly children?: ReactNode
1007
+ readonly className?: string
1008
+ readonly isActive?: boolean
1009
+ readonly region: ViewRegionDefinition
1010
+ readonly value: string
1011
+ readonly viewId?: string | null
1012
+ }
1013
+
1014
+ /** Tabs component group for rendering view regions as controlled tabs. */
1015
+ export interface PresentationTabsComponentSystemComponents {
1016
+ readonly TabsLayout: (props: PresentationTabsLayoutProps) => ReactNode
1017
+ readonly TabsList: (props: PresentationTabsListProps) => ReactNode
1018
+ readonly TabsPanel: (props: PresentationTabsPanelProps) => ReactNode
1019
+ readonly TabsTrigger: (props: PresentationTabsTriggerProps) => ReactNode
1020
+ }
1021
+
1022
+ /** Props for modal prompt shells projected from presentation flows. */
1023
+ export interface PresentationPromptModalProps {
1024
+ readonly ariaLabelledBy: string
1025
+ readonly children?: ReactNode
1026
+ readonly className?: string
1027
+ readonly description?: ReactNode
1028
+ readonly footer?: ReactNode
1029
+ readonly headerActions?: ReactNode
1030
+ readonly onBackdropMouseDown?: MouseEventHandler<HTMLDivElement>
1031
+ readonly role?: string
1032
+ readonly title: ReactNode
1033
+ readonly titleId: string
1034
+ }
1035
+
1036
+ /** Props for prompt header actions and close affordances. */
1037
+ export interface PresentationPromptHeaderActionsProps {
1038
+ readonly actions?: ReactNode
1039
+ readonly className?: string
1040
+ readonly closeButton?: ReactNode
1041
+ readonly viewId?: string | null
1042
+ }
1043
+
1044
+ /** Props for prompt body content. */
1045
+ export interface PresentationPromptContentProps {
1046
+ readonly children?: ReactNode
1047
+ readonly className?: string
1048
+ readonly viewId?: string | null
1049
+ }
1050
+
1051
+ /** Props for prompt footer content. */
1052
+ export interface PresentationPromptFooterProps {
1053
+ readonly children?: ReactNode
1054
+ readonly className?: string
1055
+ readonly viewId?: string | null
1056
+ }
1057
+
1058
+ /** Props for a projected prompt region. */
1059
+ export interface PresentationPromptRegionProps {
1060
+ readonly children?: ReactNode
1061
+ readonly className?: string
1062
+ readonly region: ViewRegionDefinition
1063
+ readonly viewId?: string | null
1064
+ }
1065
+
1066
+ /** Prompt component group for modal flow and prompt rendering. */
1067
+ export interface PresentationPromptComponentSystemComponents {
1068
+ readonly PromptContent: (props: PresentationPromptContentProps) => ReactNode
1069
+ readonly PromptFooter: (props: PresentationPromptFooterProps) => ReactNode
1070
+ readonly PromptHeaderActions: (props: PresentationPromptHeaderActionsProps) => ReactNode
1071
+ readonly PromptModal: (props: PresentationPromptModalProps) => ReactNode
1072
+ readonly PromptRegion: (props: PresentationPromptRegionProps) => ReactNode
1073
+ }
1074
+
1075
+ /** Props for notices describing process tasks and available actions. */
1076
+ export interface PresentationProcessTaskNoticeProps {
1077
+ readonly actions?: ReactNode
1078
+ readonly className?: string
1079
+ readonly description?: ReactNode
1080
+ readonly icon?: ReactNode
1081
+ readonly title: ReactNode
1082
+ }
1083
+
1084
+ /** Process component group for workflow/task presentation elements. */
1085
+ export interface PresentationProcessComponentSystemComponents {
1086
+ readonly ProcessTaskNotice: (props: PresentationProcessTaskNoticeProps) => ReactNode
1087
+ }
1088
+
1089
+ /** Props for a projected view chrome action slot. */
1090
+ export interface PresentationViewChromeActionSlotProps {
1091
+ readonly children?: ReactNode
1092
+ readonly className?: string
1093
+ readonly slotId?: string
1094
+ readonly viewId?: string | null
1095
+ }
1096
+
1097
+ /** Props for badge strips projected into view chrome. */
1098
+ export interface PresentationViewChromeBadgeStripProps {
1099
+ readonly badges: readonly ReactNode[]
1100
+ readonly className?: string
1101
+ readonly slotId?: string
1102
+ readonly viewId?: string | null
1103
+ }
1104
+
1105
+ /** Props for metric strips projected into view chrome. */
1106
+ export interface PresentationViewChromeMetricStripProps {
1107
+ readonly children?: ReactNode
1108
+ readonly className?: string
1109
+ readonly message?: ReactNode
1110
+ readonly slotId?: string | null
1111
+ readonly viewId?: string | null
1112
+ }
1113
+
1114
+ /** Props for an arbitrary projected view chrome slot. */
1115
+ export interface PresentationViewChromeSlotProps {
1116
+ readonly children?: ReactNode
1117
+ readonly className?: string
1118
+ readonly placement?: string | number | null
1119
+ readonly slot: ViewChromeSlotDefinition
1120
+ readonly viewId?: string | null
1121
+ }
1122
+
1123
+ /** Item contract for layout and view switches rendered in chrome. */
1124
+ export interface PresentationViewChromeSwitchItem {
1125
+ readonly icon?: ReactNode
1126
+ readonly id: string
1127
+ readonly isActive: boolean
1128
+ readonly label: ReactNode
1129
+ readonly onSelect: () => void
1130
+ }
1131
+
1132
+ /** Props for controlled switch groups in view chrome. */
1133
+ export interface PresentationViewChromeSwitchProps {
1134
+ readonly ariaLabel: string
1135
+ readonly className?: string
1136
+ readonly items: readonly PresentationViewChromeSwitchItem[]
1137
+ readonly slotId?: string
1138
+ readonly viewId?: string | null
1139
+ }
1140
+
1141
+ /** View chrome component group for actions, badges, metrics, slots, and switches. */
1142
+ export interface PresentationViewChromeComponentSystemComponents {
1143
+ readonly ActionSlot: (props: PresentationViewChromeActionSlotProps) => ReactNode
1144
+ readonly BadgeStrip: (props: PresentationViewChromeBadgeStripProps) => ReactNode
1145
+ readonly LayoutSwitch: (props: PresentationViewChromeSwitchProps) => ReactNode
1146
+ readonly MetricStripSlot: (props: PresentationViewChromeMetricStripProps) => ReactNode
1147
+ readonly ViewChromeSlot: (props: PresentationViewChromeSlotProps) => ReactNode
1148
+ readonly ViewSwitch: (props: PresentationViewChromeSwitchProps) => ReactNode
1149
+ }
1150
+
1151
+ /** Props required from the button primitive used by view chrome switches. */
1152
+ export interface PresentationViewChromeSwitchButtonProps {
1153
+ readonly 'aria-pressed'?: boolean
1154
+ readonly children?: ReactNode
1155
+ readonly onClick?: () => void
1156
+ readonly size?: 'sm'
1157
+ readonly type?: 'button'
1158
+ readonly variant?: 'ghost' | 'secondary'
1159
+ }
1160
+
1161
+ /** Primitive dependency required to build view chrome components. */
1162
+ export interface CreateShadcnViewChromeComponentsOptions {
1163
+ readonly Button: ComponentType<PresentationViewChromeSwitchButtonProps>
1164
+ }
1165
+
1166
+ /** Creates the action component group from a compatible button primitive. */
1167
+ export function createShadcnActionComponents({
1168
+ Button,
1169
+ }: CreateShadcnActionComponentsOptions):
1170
+ PresentationActionComponentSystemComponents {
1171
+ return {
1172
+ ActionButton: (props) => createElement(Button, props),
1173
+ }
1174
+ }
1175
+
1176
+ /** Creates the badge component group from a compatible badge primitive. */
1177
+ export function createShadcnBadgeComponents({
1178
+ Badge,
1179
+ }: CreateShadcnBadgeComponentsOptions):
1180
+ PresentationBadgeComponentSystemComponents {
1181
+ return {
1182
+ Badge: (props) => createElement(Badge, props),
1183
+ }
1184
+ }
1185
+
1186
+ /** Creates navigation components that style router links as action-like buttons. */
1187
+ export function createShadcnNavigationComponents({
1188
+ buttonClassName,
1189
+ Link,
1190
+ }: CreateShadcnNavigationComponentsOptions):
1191
+ PresentationNavigationComponentSystemComponents {
1192
+ return {
1193
+ NavigationLink: ({ children, className, isActive = false, to }) =>
1194
+ createElement(
1195
+ Link,
1196
+ {
1197
+ className: cn(
1198
+ buttonClassName({
1199
+ size: 'sm',
1200
+ variant: isActive ? 'secondary' : 'ghost',
1201
+ }),
1202
+ className,
1203
+ ),
1204
+ to,
1205
+ },
1206
+ children,
1207
+ ),
1208
+ }
1209
+ }
1210
+
1211
+ /** Creates feedback components with default shadcn/Tailwind styling. */
1212
+ export function createShadcnFeedbackComponents():
1213
+ PresentationFeedbackComponentSystemComponents {
1214
+ return {
1215
+ StatusBlock: ({ className, label, tone = 'default' }) =>
1216
+ createElement(
1217
+ 'div',
1218
+ {
1219
+ className: cn(
1220
+ tone === 'error'
1221
+ ? 'rounded-2xl border border-red-300/60 bg-red-50 px-4 py-3 text-sm text-red-800'
1222
+ : 'rounded-2xl border border-slate-950/8 bg-white/65 px-4 py-3 text-sm text-slate-500',
1223
+ className,
1224
+ ),
1225
+ },
1226
+ label,
1227
+ ),
1228
+ }
1229
+ }
1230
+
1231
+ /** Creates metric components for compact semantic summaries. */
1232
+ export function createShadcnMetricComponents():
1233
+ PresentationMetricComponentSystemComponents {
1234
+ return {
1235
+ MetricItem: ({ className, icon, id, label, value, variant }) =>
1236
+ createElement(
1237
+ 'div',
1238
+ {
1239
+ className: cn(
1240
+ 'grid min-w-0 gap-1 rounded-md border border-slate-950/8 bg-white/70 px-3 py-2',
1241
+ className,
1242
+ ),
1243
+ ...createPresentationTestAttributes({ fieldId: id }),
1244
+ },
1245
+ createElement(
1246
+ 'dt',
1247
+ {
1248
+ className:
1249
+ 'flex min-w-0 items-center gap-1.5 text-[0.68rem] font-medium uppercase tracking-[0.12em] text-slate-500',
1250
+ },
1251
+ icon,
1252
+ label,
1253
+ ),
1254
+ createElement(
1255
+ 'dd',
1256
+ {
1257
+ className: variant === 'text'
1258
+ ? 'break-all text-sm font-medium text-slate-950'
1259
+ : 'text-lg font-semibold leading-6 text-slate-950',
1260
+ },
1261
+ value,
1262
+ ),
1263
+ ),
1264
+ MetricStrip: ({ children, className }) =>
1265
+ createElement(
1266
+ 'dl',
1267
+ {
1268
+ className: cn(
1269
+ 'grid gap-2 sm:grid-cols-[repeat(auto-fit,minmax(7.5rem,1fr))]',
1270
+ className,
1271
+ ),
1272
+ },
1273
+ children,
1274
+ ),
1275
+ }
1276
+ }
1277
+
1278
+ /** Creates form components from shadcn-compatible form primitives. */
1279
+ export function createShadcnFormComponents<TDateTimeFilterValue = unknown>({
1280
+ Button,
1281
+ DateTimeFilter,
1282
+ Input,
1283
+ Label,
1284
+ ToggleGroup,
1285
+ ToggleGroupItem,
1286
+ }: CreateShadcnFormComponentsOptions<TDateTimeFilterValue>):
1287
+ PresentationFormComponentSystemComponents<TDateTimeFilterValue> {
1288
+ return {
1289
+ CheckboxControl: ({ className, onCheckedChange, ...props }) =>
1290
+ createElement('input', {
1291
+ ...props,
1292
+ className: cn('size-4 rounded border border-input', className),
1293
+ onChange: (event: ChangeEvent<HTMLInputElement>) =>
1294
+ onCheckedChange(event.target.checked),
1295
+ type: 'checkbox',
1296
+ }),
1297
+ ChoiceToggleGroup: ({ children, className, value, ...props }) =>
1298
+ createElement(
1299
+ ToggleGroup,
1300
+ {
1301
+ ...props,
1302
+ className: cn('flex flex-wrap justify-start gap-1.5', className),
1303
+ type: 'multiple',
1304
+ value: value ? [...value] : [],
1305
+ },
1306
+ children,
1307
+ ),
1308
+ ChoiceToggleItem: (props) => createElement(ToggleGroupItem, props),
1309
+ DateTimeFilterControl: ({ onValueChange, ...props }) =>
1310
+ createElement(DateTimeFilter, {
1311
+ ...props,
1312
+ onChange: onValueChange,
1313
+ }),
1314
+ FormActionButton: (props) => createElement(Button, props),
1315
+ FormFieldLabel: ({ children, className }) =>
1316
+ createElement(
1317
+ Label,
1318
+ { className: cn('text-xs font-medium text-slate-500', className) },
1319
+ children,
1320
+ ),
1321
+ InputForm: ({ children, className, form, viewId }) =>
1322
+ createElement(
1323
+ 'div',
1324
+ {
1325
+ className,
1326
+ ...createPresentationTestAttributes({ formId: form.Id, viewId }),
1327
+ },
1328
+ children,
1329
+ ),
1330
+ InputFormActionRow: ({ children, className, form }) =>
1331
+ createElement(
1332
+ 'div',
1333
+ {
1334
+ className,
1335
+ ...createPresentationTestAttributes({ formId: form.Id }),
1336
+ },
1337
+ children,
1338
+ ),
1339
+ InputFormControlGroup: ({ children, className, field }) =>
1340
+ createElement(
1341
+ 'div',
1342
+ {
1343
+ className,
1344
+ ...createPresentationTestAttributes({ fieldId: field.FieldId ?? field.Id }),
1345
+ },
1346
+ children,
1347
+ ),
1348
+ InputFormControlSlot: ({ children, className, field }) =>
1349
+ createElement(
1350
+ 'div',
1351
+ {
1352
+ className,
1353
+ ...createPresentationTestAttributes({ fieldId: field.FieldId ?? field.Id }),
1354
+ },
1355
+ children,
1356
+ ),
1357
+ InputFormField: ({ className, control, field, label, message }) =>
1358
+ createElement(
1359
+ 'div',
1360
+ {
1361
+ className,
1362
+ 'data-field-id': field.Id,
1363
+ ...createPresentationTestAttributes({ fieldId: field.FieldId ?? field.Id }),
1364
+ },
1365
+ label,
1366
+ control,
1367
+ message,
1368
+ ),
1369
+ InputFormFieldMessage: ({ children, className, field, tone = 'default' }) =>
1370
+ createElement(
1371
+ 'div',
1372
+ {
1373
+ className: cn(
1374
+ tone === 'error'
1375
+ ? 'text-xs text-red-700'
1376
+ : tone === 'warning'
1377
+ ? 'text-xs text-amber-700'
1378
+ : 'text-xs text-slate-500',
1379
+ className,
1380
+ ),
1381
+ ...createPresentationTestAttributes({ fieldId: field.FieldId ?? field.Id }),
1382
+ },
1383
+ children,
1384
+ ),
1385
+ InputFormGroup: ({ children, className, group }) =>
1386
+ createElement(
1387
+ 'div',
1388
+ {
1389
+ className,
1390
+ 'data-presentation-form-group-id': group.Id,
1391
+ },
1392
+ children,
1393
+ ),
1394
+ InputFormGroups: ({ children, className, form }) =>
1395
+ createElement(
1396
+ 'div',
1397
+ {
1398
+ className,
1399
+ ...createPresentationTestAttributes({ formId: form.Id }),
1400
+ },
1401
+ children,
1402
+ ),
1403
+ SelectControl: ({ className, onValueChange, options, ...props }) =>
1404
+ createElement(
1405
+ 'select',
1406
+ {
1407
+ ...props,
1408
+ className: cn(
1409
+ 'h-8 min-w-0 rounded-lg border border-input bg-transparent px-2.5 py-1 text-sm outline-none transition-colors focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-ring/50 disabled:pointer-events-none disabled:cursor-not-allowed disabled:bg-input/50 disabled:opacity-50',
1410
+ className,
1411
+ ),
1412
+ onChange: (event: ChangeEvent<HTMLSelectElement>) =>
1413
+ onValueChange(event.target.value),
1414
+ },
1415
+ options.map((option) =>
1416
+ createElement('option', { key: option.value, value: option.value }, option.label),
1417
+ ),
1418
+ ),
1419
+ TextInputControl: ({ onValueChange, ...props }) =>
1420
+ createElement(Input, {
1421
+ ...props,
1422
+ onChange: (event: ChangeEvent<HTMLInputElement>) =>
1423
+ onValueChange(event.target.value),
1424
+ }),
1425
+ }
1426
+ }
1427
+
1428
+ /** Creates collection chrome components for query, summary, body, detail, pagination, and selection slots. */
1429
+ export function createShadcnCollectionChromeComponents({
1430
+ Button,
1431
+ }: CreateShadcnCollectionChromeComponentsOptions):
1432
+ PresentationCollectionChromeComponentSystemComponents {
1433
+ return {
1434
+ CollectionBodySlot: ({ children, className, slotId, viewId }) =>
1435
+ createElement(
1436
+ 'div',
1437
+ {
1438
+ className: cn('w-full min-w-0', className),
1439
+ ...createPresentationTestAttributes({ collectionSlotId: slotId, viewId }),
1440
+ },
1441
+ children,
1442
+ ),
1443
+ CollectionDetailSlot: ({ children, className, slotId, viewId }) =>
1444
+ createElement(
1445
+ 'div',
1446
+ {
1447
+ className,
1448
+ ...createPresentationTestAttributes({ collectionSlotId: slotId, viewId }),
1449
+ },
1450
+ children,
1451
+ ),
1452
+ CollectionPaginationBar: ({
1453
+ canGoNextPage,
1454
+ canGoPreviousPage,
1455
+ className,
1456
+ firstIcon,
1457
+ isFetching,
1458
+ loadingIcon,
1459
+ nextIcon,
1460
+ onFirstPage,
1461
+ onNextPage,
1462
+ onPreviousPage,
1463
+ pageLabel,
1464
+ pageSizeLabel,
1465
+ previousIcon,
1466
+ shownLabel,
1467
+ slotId,
1468
+ totalLabel,
1469
+ viewId,
1470
+ }) =>
1471
+ createElement(
1472
+ 'div',
1473
+ {
1474
+ className: cn(
1475
+ 'flex flex-wrap items-center justify-between gap-2 text-xs text-slate-600',
1476
+ className,
1477
+ ),
1478
+ ...createPresentationTestAttributes({ collectionSlotId: slotId, viewId }),
1479
+ },
1480
+ createElement(
1481
+ 'div',
1482
+ { className: 'flex min-w-0 items-center gap-2' },
1483
+ isFetching ? loadingIcon : null,
1484
+ createElement('span', { className: 'font-medium text-slate-800' }, pageLabel),
1485
+ createElement('span', null, shownLabel),
1486
+ createElement('span', null, pageSizeLabel),
1487
+ createElement('span', null, totalLabel),
1488
+ ),
1489
+ createElement(
1490
+ 'div',
1491
+ { className: 'flex items-center gap-1' },
1492
+ createElement(
1493
+ Button,
1494
+ {
1495
+ disabled: isFetching || !canGoPreviousPage,
1496
+ onClick: onFirstPage,
1497
+ size: 'sm',
1498
+ type: 'button',
1499
+ variant: 'outline',
1500
+ },
1501
+ firstIcon,
1502
+ 'First',
1503
+ ),
1504
+ createElement(
1505
+ Button,
1506
+ {
1507
+ disabled: isFetching || !canGoPreviousPage,
1508
+ onClick: onPreviousPage,
1509
+ size: 'sm',
1510
+ type: 'button',
1511
+ variant: 'outline',
1512
+ },
1513
+ previousIcon,
1514
+ 'Previous',
1515
+ ),
1516
+ createElement(
1517
+ Button,
1518
+ {
1519
+ disabled: isFetching || !canGoNextPage,
1520
+ onClick: onNextPage,
1521
+ size: 'sm',
1522
+ type: 'button',
1523
+ variant: 'outline',
1524
+ },
1525
+ 'Next',
1526
+ nextIcon,
1527
+ ),
1528
+ ),
1529
+ ),
1530
+ CollectionQueryFormSlot: ({ children, className, slotId, viewId }) =>
1531
+ createElement(
1532
+ 'div',
1533
+ {
1534
+ className: cn('w-full min-w-0', className),
1535
+ ...createPresentationTestAttributes({ collectionSlotId: slotId, viewId }),
1536
+ },
1537
+ children,
1538
+ ),
1539
+ CollectionRowActions: ({ children, className, slotId }) =>
1540
+ createElement(
1541
+ 'div',
1542
+ {
1543
+ className: cn('flex justify-end gap-1', className),
1544
+ ...createPresentationTestAttributes({ collectionSlotId: slotId }),
1545
+ },
1546
+ children,
1547
+ ),
1548
+ CollectionSelectionActionToolbar: ({
1549
+ actions,
1550
+ className,
1551
+ selectedLabel,
1552
+ slotId,
1553
+ }) =>
1554
+ createElement(
1555
+ 'div',
1556
+ {
1557
+ className: cn(
1558
+ 'flex flex-wrap items-center justify-between gap-2 rounded-lg border border-slate-950/8 bg-slate-50/80 px-3 py-2',
1559
+ className,
1560
+ ),
1561
+ ...createPresentationTestAttributes({ collectionSlotId: slotId }),
1562
+ },
1563
+ createElement('span', { className: 'text-sm font-medium text-slate-600' }, selectedLabel),
1564
+ createElement('div', { className: 'flex flex-wrap items-center gap-2' }, actions),
1565
+ ),
1566
+ CollectionSummarySlot: ({ children, className, slotId, viewId }) =>
1567
+ createElement(
1568
+ 'div',
1569
+ {
1570
+ className: cn('w-full min-w-0', className),
1571
+ ...createPresentationTestAttributes({ collectionSlotId: slotId, viewId }),
1572
+ },
1573
+ children,
1574
+ ),
1575
+ }
1576
+ }
1577
+
1578
+ /** Creates collection components around an injected data table and detail layout. */
1579
+ export function createShadcnCollectionComponents<
1580
+ TDataTableRenderer extends PresentationDataTableRenderer =
1581
+ PresentationDataTableRenderer,
1582
+ >({
1583
+ CollectionDetailLayout,
1584
+ DataTable,
1585
+ rowActionMenuTriggerClassName,
1586
+ }: CreateShadcnCollectionComponentsOptions<TDataTableRenderer>):
1587
+ PresentationCollectionComponentSystemComponents<TDataTableRenderer> {
1588
+ return {
1589
+ CollectionDetailLayout,
1590
+ DataTable,
1591
+ RowActionMenu: ({ children, trigger }) =>
1592
+ createElement(
1593
+ 'div',
1594
+ { className: 'flex justify-end' },
1595
+ createElement(
1596
+ 'details',
1597
+ {
1598
+ className: 'group relative inline-flex justify-end',
1599
+ 'data-row-activation-skip': true,
1600
+ onClick: (event) => {
1601
+ event.stopPropagation()
1602
+ },
1603
+ },
1604
+ trigger,
1605
+ createElement(
1606
+ 'div',
1607
+ {
1608
+ className:
1609
+ 'absolute right-full top-1/2 z-40 mr-1 grid min-w-44 -translate-y-1/2 gap-1 rounded-lg border border-slate-950/10 bg-white p-1 text-left shadow-xl',
1610
+ },
1611
+ children,
1612
+ ),
1613
+ ),
1614
+ ),
1615
+ RowActionMenuItem: ({
1616
+ actionId,
1617
+ children,
1618
+ collectionSlotId,
1619
+ disabled,
1620
+ onClick,
1621
+ viewId,
1622
+ }) =>
1623
+ createElement(
1624
+ 'button',
1625
+ {
1626
+ className:
1627
+ 'flex w-full items-center gap-2 rounded-md px-2 py-1.5 text-left text-sm text-slate-700 outline-none hover:bg-slate-100 focus-visible:bg-slate-100 disabled:pointer-events-none disabled:opacity-50',
1628
+ disabled,
1629
+ onClick,
1630
+ type: 'button',
1631
+ ...createPresentationTestAttributes({
1632
+ actionId,
1633
+ collectionSlotId,
1634
+ viewId,
1635
+ }),
1636
+ },
1637
+ children,
1638
+ ),
1639
+ RowActionMenuTrigger: ({ children, ...props }) =>
1640
+ createElement(
1641
+ 'summary',
1642
+ {
1643
+ ...props,
1644
+ className: cn(
1645
+ rowActionMenuTriggerClassName({
1646
+ size: 'icon-sm',
1647
+ variant: 'ghost',
1648
+ }),
1649
+ 'cursor-pointer list-none [&::-webkit-details-marker]:hidden',
1650
+ ),
1651
+ },
1652
+ children,
1653
+ ),
1654
+ }
1655
+ }
1656
+
1657
+ /** Creates surface components that compose projected view content with chrome. */
1658
+ export function createShadcnSurfaceComponents({
1659
+ Surface,
1660
+ }: CreateShadcnSurfaceComponentsOptions):
1661
+ PresentationSurfaceComponentSystemComponents {
1662
+ return {
1663
+ ViewSurface: (props) => createElement(Surface, props),
1664
+ ViewSurfaceChromePlacement: ({ children, className, placement, viewId }) =>
1665
+ createElement(
1666
+ 'div',
1667
+ {
1668
+ className,
1669
+ 'data-presentation-view-chrome-placement': String(placement),
1670
+ ...createPresentationTestAttributes({ viewId }),
1671
+ },
1672
+ children,
1673
+ ),
1674
+ ViewSurfaceContent: ({
1675
+ afterContentChrome,
1676
+ beforeContentChrome,
1677
+ children,
1678
+ footerChrome,
1679
+ }) => {
1680
+ if (
1681
+ !isRenderableComponentNode(beforeContentChrome) &&
1682
+ !isRenderableComponentNode(afterContentChrome) &&
1683
+ !isRenderableComponentNode(footerChrome)
1684
+ ) {
1685
+ return children
1686
+ }
1687
+
1688
+ return createElement(
1689
+ Fragment,
1690
+ null,
1691
+ beforeContentChrome,
1692
+ children,
1693
+ afterContentChrome,
1694
+ footerChrome,
1695
+ )
1696
+ },
1697
+ ViewSurfaceHeaderActions: ({ action, chrome, className }) => {
1698
+ if (!isRenderableComponentNode(action)) {
1699
+ return chrome
1700
+ }
1701
+
1702
+ if (!isRenderableComponentNode(chrome)) {
1703
+ return action
1704
+ }
1705
+
1706
+ return createElement(
1707
+ 'div',
1708
+ {
1709
+ className: cn(
1710
+ 'flex flex-wrap items-center justify-end gap-2',
1711
+ className,
1712
+ ),
1713
+ },
1714
+ action,
1715
+ chrome,
1716
+ )
1717
+ },
1718
+ }
1719
+ }
1720
+
1721
+ /** Creates document workspace components from tree, layout, badge, and JSON primitives. */
1722
+ export function createShadcnDocumentWorkspaceComponents<
1723
+ TTreeControlsProps extends object = object,
1724
+ TJsonDocumentDiffProps extends object = object,
1725
+ TJsonDocumentEditorProps extends object = object,
1726
+ >({
1727
+ Badge,
1728
+ DocumentWorkspaceTreeControls,
1729
+ DocumentWorkspaceTreeItem,
1730
+ DocumentWorkspaceTreeLayout,
1731
+ DocumentWorkspaceTreeView,
1732
+ JsonDocumentDiff,
1733
+ JsonDocumentEditor,
1734
+ resolveSurfaceSlotOptions,
1735
+ }: CreateShadcnDocumentWorkspaceComponentsOptions<
1736
+ TTreeControlsProps,
1737
+ TJsonDocumentDiffProps,
1738
+ TJsonDocumentEditorProps
1739
+ >):
1740
+ PresentationDocumentWorkspaceComponentSystemComponents<
1741
+ TTreeControlsProps,
1742
+ TJsonDocumentDiffProps,
1743
+ TJsonDocumentEditorProps
1744
+ > {
1745
+ return {
1746
+ DocumentWorkspaceDetailPanel: ({
1747
+ children,
1748
+ className,
1749
+ contentClassName,
1750
+ emptyClassName,
1751
+ emptyLabel,
1752
+ headerClassName,
1753
+ headerContentClassName,
1754
+ icon,
1755
+ subtitle,
1756
+ subtitleClassName,
1757
+ title,
1758
+ titleClassName,
1759
+ }) => {
1760
+ if (!title) {
1761
+ return createElement('div', { className: emptyClassName }, emptyLabel)
1762
+ }
1763
+
1764
+ return createElement(
1765
+ 'aside',
1766
+ { className },
1767
+ createElement(
1768
+ 'div',
1769
+ { className: headerClassName },
1770
+ createElement(
1771
+ 'div',
1772
+ { className: headerContentClassName },
1773
+ icon,
1774
+ createElement(
1775
+ 'div',
1776
+ { className: 'min-w-0' },
1777
+ createElement('p', { className: titleClassName }, title),
1778
+ subtitle
1779
+ ? createElement('p', { className: subtitleClassName }, subtitle)
1780
+ : null,
1781
+ ),
1782
+ ),
1783
+ ),
1784
+ createElement('div', { className: contentClassName }, children),
1785
+ )
1786
+ },
1787
+ DocumentWorkspaceLayoutGroup: ({
1788
+ children,
1789
+ className,
1790
+ layoutNodeId,
1791
+ style,
1792
+ workspaceViewId,
1793
+ }) =>
1794
+ createElement(
1795
+ 'div',
1796
+ {
1797
+ className,
1798
+ 'data-presentation-layout-node-id': layoutNodeId ?? undefined,
1799
+ style,
1800
+ ...createPresentationTestAttributes({ viewId: workspaceViewId }),
1801
+ },
1802
+ children,
1803
+ ),
1804
+ DocumentWorkspaceLayoutPane: ({
1805
+ children,
1806
+ className,
1807
+ contentClassName,
1808
+ layoutNodeId,
1809
+ title,
1810
+ titleClassName,
1811
+ viewId,
1812
+ workspaceViewId,
1813
+ }) =>
1814
+ createElement(
1815
+ 'section',
1816
+ {
1817
+ className: cn('flex h-full min-h-0 flex-col gap-2', className),
1818
+ 'data-presentation-layout-node-id': layoutNodeId ?? undefined,
1819
+ ...createPresentationTestAttributes({ viewId: viewId ?? workspaceViewId }),
1820
+ },
1821
+ createElement(
1822
+ 'h3',
1823
+ {
1824
+ className: cn(
1825
+ 'text-xs font-semibold uppercase tracking-[0.12em] text-slate-500',
1826
+ titleClassName,
1827
+ ),
1828
+ },
1829
+ title,
1830
+ ),
1831
+ createElement(
1832
+ 'div',
1833
+ { className: cn('min-h-0 flex-1 [&>*]:!h-full [&>*]:min-h-170', contentClassName) },
1834
+ children,
1835
+ ),
1836
+ ),
1837
+ DocumentWorkspaceNodeLabel: ({
1838
+ badges = [],
1839
+ className,
1840
+ icon,
1841
+ label,
1842
+ labelClassName,
1843
+ }) =>
1844
+ createElement(
1845
+ 'span',
1846
+ { className },
1847
+ icon,
1848
+ createElement('span', { className: labelClassName }, label),
1849
+ badges.map((badge) =>
1850
+ createElement(
1851
+ Badge,
1852
+ {
1853
+ className: badge.className,
1854
+ key: `${badge.label}:${badge.className ?? ''}`,
1855
+ variant: 'outline',
1856
+ },
1857
+ badge.label,
1858
+ ),
1859
+ ),
1860
+ ),
1861
+ DocumentWorkspaceShell: ({
1862
+ children,
1863
+ className,
1864
+ contentClassName,
1865
+ viewId,
1866
+ }) =>
1867
+ createElement(
1868
+ 'div',
1869
+ {
1870
+ className,
1871
+ ...createPresentationTestAttributes({ viewId }),
1872
+ },
1873
+ createElement('main', { className: contentClassName }, children),
1874
+ ),
1875
+ DocumentWorkspaceSurfaceSlot: ({
1876
+ children,
1877
+ renderSurface,
1878
+ role,
1879
+ slot,
1880
+ viewId,
1881
+ }) =>
1882
+ createElement(
1883
+ 'div',
1884
+ {
1885
+ 'data-presentation-document-workspace-slot-id': slot,
1886
+ ...createPresentationTestAttributes({ viewId }),
1887
+ },
1888
+ renderSurface
1889
+ ? renderSurface(resolveSurfaceSlotOptions({ role, slot }))
1890
+ : children,
1891
+ ),
1892
+ DocumentWorkspaceTreeControls,
1893
+ DocumentWorkspaceTreeItem,
1894
+ DocumentWorkspaceStatus: ({ children, className }) =>
1895
+ createElement('div', { className }, children),
1896
+ DocumentWorkspaceTable: ({
1897
+ details,
1898
+ labelCellClassName,
1899
+ rowClassName,
1900
+ tableClassName,
1901
+ valueCellClassName,
1902
+ valueTextClassName,
1903
+ }) =>
1904
+ createElement(
1905
+ 'table',
1906
+ { className: tableClassName },
1907
+ createElement(
1908
+ 'tbody',
1909
+ null,
1910
+ details.map((detail) =>
1911
+ createElement(
1912
+ 'tr',
1913
+ { className: rowClassName, key: detail.label },
1914
+ createElement('th', { className: labelCellClassName }, detail.label),
1915
+ createElement(
1916
+ 'td',
1917
+ { className: valueCellClassName },
1918
+ createElement('span', { className: valueTextClassName }, detail.value),
1919
+ ),
1920
+ ),
1921
+ ),
1922
+ ),
1923
+ ),
1924
+ DocumentWorkspaceTreeLayout,
1925
+ DocumentWorkspaceTreeView,
1926
+ JsonDocumentDiff,
1927
+ JsonDocumentEditor,
1928
+ }
1929
+ }
1930
+
1931
+ /** Creates a split tree/detail layout adapter for document workspaces. */
1932
+ export function createShadcnDocumentWorkspaceTreeLayout({
1933
+ Group,
1934
+ Panel,
1935
+ Separator,
1936
+ }: CreateShadcnDocumentWorkspaceTreeLayoutOptions) {
1937
+ return ({
1938
+ className,
1939
+ detail,
1940
+ detailDefaultSize = '42%',
1941
+ detailId,
1942
+ detailMinSize = '26%',
1943
+ splitterClassName,
1944
+ splitterHandleClassName,
1945
+ tree,
1946
+ treeDefaultSize = '58%',
1947
+ treeId,
1948
+ treeMinSize = '28%',
1949
+ }: PresentationDocumentWorkspaceTreeLayoutProps) =>
1950
+ createElement(
1951
+ Group,
1952
+ { className, orientation: 'horizontal' },
1953
+ createElement(
1954
+ Panel,
1955
+ { defaultSize: treeDefaultSize, id: treeId, minSize: treeMinSize },
1956
+ tree,
1957
+ ),
1958
+ createElement(
1959
+ Separator,
1960
+ { className: splitterClassName },
1961
+ createElement('div', { className: splitterHandleClassName }),
1962
+ ),
1963
+ createElement(
1964
+ Panel,
1965
+ { defaultSize: detailDefaultSize, id: detailId, minSize: detailMinSize },
1966
+ detail,
1967
+ ),
1968
+ )
1969
+ }
1970
+
1971
+ /** Creates a document workspace tree item adapter. */
1972
+ export function createShadcnDocumentWorkspaceTreeItem({
1973
+ TreeItem,
1974
+ }: CreateShadcnDocumentWorkspaceTreeItemOptions) {
1975
+ return ({ children, itemId, label }: PresentationDocumentWorkspaceTreeItemProps) =>
1976
+ createElement(TreeItem, { itemId, key: itemId, label }, children)
1977
+ }
1978
+
1979
+ /** Creates a controlled document workspace tree view adapter. */
1980
+ export function createShadcnDocumentWorkspaceTreeView<TSx = unknown>({
1981
+ sx,
1982
+ TreeView,
1983
+ }: CreateShadcnDocumentWorkspaceTreeViewOptions<TSx>) {
1984
+ return ({
1985
+ ariaLabel,
1986
+ children,
1987
+ expandedItemIds,
1988
+ onExpandedItemIdsChange,
1989
+ onSelectedItemIdChange,
1990
+ selectedItemId,
1991
+ }: PresentationDocumentWorkspaceTreeViewProps) =>
1992
+ createElement(
1993
+ TreeView,
1994
+ {
1995
+ 'aria-label': ariaLabel,
1996
+ expandedItems: [...expandedItemIds],
1997
+ onExpandedItemsChange: (_event, itemIds) =>
1998
+ onExpandedItemIdsChange(itemIds),
1999
+ onSelectedItemsChange: (_event, itemId) =>
2000
+ onSelectedItemIdChange(Array.isArray(itemId) ? itemId[0] ?? null : itemId),
2001
+ selectedItems: selectedItemId,
2002
+ sx,
2003
+ },
2004
+ children,
2005
+ )
2006
+ }
2007
+
2008
+ /** Wraps a JSON diff component so it fits the document workspace component contract. */
2009
+ export function createShadcnJsonDocumentDiff<TProps extends object>({
2010
+ JsonDocumentDiff,
2011
+ }: CreateShadcnJsonDocumentDiffOptions<TProps>) {
2012
+ return (props: TProps) =>
2013
+ createElement(JsonDocumentDiff as ComponentType<TProps>, props)
2014
+ }
2015
+
2016
+ /** Wraps a lazy JSON editor component in Suspense with a configurable fallback. */
2017
+ export function createShadcnJsonDocumentEditor<TProps extends object>({
2018
+ fallbackClassName,
2019
+ fallbackLabel = 'Loading editor...',
2020
+ JsonDocumentEditor,
2021
+ }: CreateShadcnJsonDocumentEditorOptions<TProps>) {
2022
+ return (props: TProps) =>
2023
+ createElement(
2024
+ Suspense,
2025
+ {
2026
+ fallback: createElement(
2027
+ 'div',
2028
+ { className: fallbackClassName(props) },
2029
+ fallbackLabel,
2030
+ ),
2031
+ },
2032
+ createElement(JsonDocumentEditor as ComponentType<TProps>, props),
2033
+ )
2034
+ }
2035
+
2036
+ /** Creates field value components for record and collection projections. */
2037
+ export function createShadcnFieldValueComponents():
2038
+ PresentationFieldValueComponentSystemComponents {
2039
+ return {
2040
+ FieldValueCode: ({ className, value }) =>
2041
+ createElement(
2042
+ 'code',
2043
+ {
2044
+ className: cn(
2045
+ 'break-all rounded-md bg-slate-100 px-2 py-1 text-xs text-slate-700',
2046
+ className,
2047
+ ),
2048
+ },
2049
+ value,
2050
+ ),
2051
+ FieldValueComposite: ({
2052
+ className,
2053
+ inlineBadges = [],
2054
+ primaryValue,
2055
+ supportingValues = [],
2056
+ }) =>
2057
+ createElement(
2058
+ 'div',
2059
+ { className: cn('grid gap-1', className) },
2060
+ primaryValue || inlineBadges.length > 0
2061
+ ? createElement(
2062
+ 'div',
2063
+ { className: 'flex flex-wrap items-center gap-1.5' },
2064
+ primaryValue
2065
+ ? createElement(
2066
+ 'span',
2067
+ { className: 'font-medium text-slate-950' },
2068
+ primaryValue,
2069
+ )
2070
+ : null,
2071
+ inlineBadges,
2072
+ )
2073
+ : null,
2074
+ supportingValues,
2075
+ ),
2076
+ FieldValueEmpty: ({ className, label }) =>
2077
+ createElement('span', { className: cn('text-slate-400', className) }, label),
2078
+ FieldValueJson: ({ className, formattedValue, tone }) =>
2079
+ createElement(
2080
+ 'pre',
2081
+ {
2082
+ className: cn(
2083
+ tone === 'red'
2084
+ ? 'max-h-96 overflow-auto rounded-lg border border-red-300/60 bg-red-50/40 p-3 text-xs leading-5 text-red-950'
2085
+ : 'max-h-96 overflow-auto rounded-lg border border-slate-950/8 bg-white/72 p-3 text-xs leading-5 text-slate-800',
2086
+ className,
2087
+ ),
2088
+ },
2089
+ createElement('code', null, formattedValue),
2090
+ ),
2091
+ FieldValueScalar: ({ children, className, title, tone }) =>
2092
+ createElement(
2093
+ 'span',
2094
+ {
2095
+ className: cn(
2096
+ tone === 'red' ? 'wrap-break-word text-red-700' : 'wrap-break-word',
2097
+ className,
2098
+ ),
2099
+ title,
2100
+ },
2101
+ children,
2102
+ ),
2103
+ FieldValueSupportingValue: ({ children, className }) =>
2104
+ createElement(
2105
+ 'div',
2106
+ { className: cn('break-all text-xs text-slate-500', className) },
2107
+ children,
2108
+ ),
2109
+ }
2110
+ }
2111
+
2112
+ /** Creates record detail components for projected field/value tables. */
2113
+ export function createShadcnRecordComponents():
2114
+ PresentationRecordComponentSystemComponents {
2115
+ return {
2116
+ RecordDetailEmptyState: ({ className, label, viewId }) =>
2117
+ createElement(
2118
+ 'div',
2119
+ {
2120
+ className: cn(
2121
+ 'rounded-lg border border-slate-950/8 bg-white/65 px-4 py-3 text-sm text-slate-500',
2122
+ className,
2123
+ ),
2124
+ ...createPresentationTestAttributes({ viewId }),
2125
+ },
2126
+ label,
2127
+ ),
2128
+ RecordDetailField: ({ actions, className, fieldId, hideLabel, label, value }) =>
2129
+ createElement(
2130
+ 'tr',
2131
+ {
2132
+ className: cn('border-b border-slate-950/6 last:border-b-0', className),
2133
+ 'data-field-id': fieldId,
2134
+ ...createPresentationTestAttributes({ fieldId }),
2135
+ },
2136
+ hideLabel
2137
+ ? null
2138
+ : createElement(
2139
+ 'th',
2140
+ {
2141
+ className:
2142
+ 'w-44 bg-slate-50 px-3 py-2 text-left text-xs font-semibold uppercase tracking-[0.14em] text-slate-500',
2143
+ },
2144
+ label,
2145
+ ),
2146
+ createElement(
2147
+ 'td',
2148
+ { className: 'break-all px-3 py-2 text-slate-800', colSpan: hideLabel ? 2 : undefined },
2149
+ actions
2150
+ ? createElement(
2151
+ 'div',
2152
+ { className: 'flex min-w-0 items-start justify-between gap-2' },
2153
+ createElement('div', { className: 'min-w-0' }, value),
2154
+ actions,
2155
+ )
2156
+ : value,
2157
+ ),
2158
+ ),
2159
+ RecordDetails: ({ children, className, viewId }) =>
2160
+ createElement(
2161
+ 'div',
2162
+ {
2163
+ className: cn(
2164
+ 'overflow-hidden rounded-lg border border-slate-950/8 bg-white/72',
2165
+ className,
2166
+ ),
2167
+ ...createPresentationTestAttributes({ viewId }),
2168
+ },
2169
+ createElement(
2170
+ 'table',
2171
+ { className: 'w-full text-sm' },
2172
+ createElement('tbody', null, children),
2173
+ ),
2174
+ ),
2175
+ }
2176
+ }
2177
+
2178
+ /** Creates tabs components from shadcn-compatible tabs primitives. */
2179
+ export function createShadcnTabsComponents({
2180
+ Tabs,
2181
+ TabsContent,
2182
+ TabsList,
2183
+ TabsTrigger,
2184
+ }: CreateShadcnTabsComponentsOptions): PresentationTabsComponentSystemComponents {
2185
+ return {
2186
+ TabsLayout: ({ children, className, onValueChange, value, viewId }) =>
2187
+ createElement(
2188
+ Tabs,
2189
+ {
2190
+ className: cn('flex min-h-0 w-full min-w-0 flex-1 flex-col gap-4', className),
2191
+ onValueChange,
2192
+ value,
2193
+ ...createPresentationTestAttributes({ viewId }),
2194
+ },
2195
+ children,
2196
+ ),
2197
+ TabsList: ({ children, className, viewId }) =>
2198
+ createElement(
2199
+ TabsList,
2200
+ {
2201
+ className: cn(
2202
+ 'w-fit rounded-xl border border-slate-950/8 bg-white/75',
2203
+ className,
2204
+ ),
2205
+ ...createPresentationTestAttributes({ viewId }),
2206
+ },
2207
+ children,
2208
+ ),
2209
+ TabsPanel: ({ children, className, region, value, viewId }) =>
2210
+ createElement(
2211
+ TabsContent,
2212
+ {
2213
+ className: cn(
2214
+ 'mt-0 flex min-h-0 w-full min-w-0 flex-1 flex-col overflow-hidden data-[state=inactive]:hidden',
2215
+ className,
2216
+ ),
2217
+ 'data-presentation-region-id': region.Id,
2218
+ forceMount: true,
2219
+ value,
2220
+ ...createPresentationTestAttributes({ viewId }),
2221
+ },
2222
+ children,
2223
+ ),
2224
+ TabsTrigger: ({ children, className, region, value, viewId }) =>
2225
+ createElement(
2226
+ TabsTrigger,
2227
+ {
2228
+ className,
2229
+ 'data-presentation-region-id': region.Id,
2230
+ value,
2231
+ ...createPresentationTestAttributes({ viewId }),
2232
+ },
2233
+ children,
2234
+ ),
2235
+ }
2236
+ }
2237
+
2238
+ /** Creates process components for projected workflow/task notices. */
2239
+ export function createShadcnProcessComponents():
2240
+ PresentationProcessComponentSystemComponents {
2241
+ return {
2242
+ ProcessTaskNotice: ({ actions, className, description, icon, title }) =>
2243
+ createElement(
2244
+ 'div',
2245
+ { className },
2246
+ createElement(
2247
+ 'div',
2248
+ { className: 'flex flex-wrap items-center justify-between gap-3' },
2249
+ createElement(
2250
+ 'div',
2251
+ { className: 'flex min-w-0 items-start gap-2' },
2252
+ icon,
2253
+ createElement(
2254
+ 'div',
2255
+ { className: 'min-w-0' },
2256
+ createElement('p', { className: 'font-medium' }, title),
2257
+ description
2258
+ ? createElement(
2259
+ 'p',
2260
+ { className: 'break-all text-xs opacity-75' },
2261
+ description,
2262
+ )
2263
+ : null,
2264
+ ),
2265
+ ),
2266
+ actions,
2267
+ ),
2268
+ ),
2269
+ }
2270
+ }
2271
+
2272
+ /** Creates prompt components for modal presentation flows. */
2273
+ export function createShadcnPromptComponents():
2274
+ PresentationPromptComponentSystemComponents {
2275
+ return {
2276
+ PromptContent: ({ children, className, viewId }) =>
2277
+ createElement(
2278
+ 'div',
2279
+ {
2280
+ className: cn('grid gap-4', className),
2281
+ ...createPresentationTestAttributes({ viewId }),
2282
+ },
2283
+ children,
2284
+ ),
2285
+ PromptFooter: ({ children, className, viewId }) =>
2286
+ isRenderableComponentNode(children)
2287
+ ? createElement(
2288
+ 'footer',
2289
+ {
2290
+ className: cn('mt-4 flex justify-end border-t border-slate-900/8 pt-4', className),
2291
+ ...createPresentationTestAttributes({ viewId }),
2292
+ },
2293
+ children,
2294
+ )
2295
+ : null,
2296
+ PromptHeaderActions: ({
2297
+ actions,
2298
+ className,
2299
+ closeButton,
2300
+ viewId,
2301
+ }) =>
2302
+ actions || closeButton
2303
+ ? createElement(
2304
+ 'div',
2305
+ {
2306
+ className: cn('flex flex-wrap items-center justify-end gap-2', className),
2307
+ ...createPresentationTestAttributes({ viewId }),
2308
+ },
2309
+ actions,
2310
+ closeButton,
2311
+ )
2312
+ : null,
2313
+ PromptModal: ({
2314
+ ariaLabelledBy,
2315
+ children,
2316
+ className,
2317
+ description,
2318
+ footer,
2319
+ headerActions,
2320
+ onBackdropMouseDown,
2321
+ role,
2322
+ title,
2323
+ titleId,
2324
+ }) =>
2325
+ createElement(
2326
+ 'div',
2327
+ {
2328
+ 'aria-labelledby': ariaLabelledBy,
2329
+ 'aria-modal': 'true',
2330
+ className:
2331
+ 'fixed inset-0 z-50 flex items-center justify-center bg-slate-950/72 p-4 text-slate-950 backdrop-blur-sm',
2332
+ onMouseDown: onBackdropMouseDown,
2333
+ role: role ?? 'dialog',
2334
+ },
2335
+ createElement(
2336
+ 'section',
2337
+ {
2338
+ className: cn(
2339
+ 'flex max-h-full min-h-0 w-full max-w-3xl flex-col overflow-auto rounded-lg border border-white/20 bg-white p-4 shadow-2xl',
2340
+ className,
2341
+ ),
2342
+ },
2343
+ createElement(
2344
+ 'header',
2345
+ {
2346
+ className:
2347
+ 'mb-3 flex flex-wrap items-start justify-between gap-3 border-b border-slate-900/8 pb-3',
2348
+ },
2349
+ createElement(
2350
+ 'div',
2351
+ { className: 'min-w-0' },
2352
+ createElement(
2353
+ 'h2',
2354
+ {
2355
+ className: 'text-sm font-semibold text-slate-950',
2356
+ id: titleId,
2357
+ },
2358
+ title,
2359
+ ),
2360
+ description
2361
+ ? createElement('div', { className: 'mt-1 text-xs text-slate-500' }, description)
2362
+ : null,
2363
+ ),
2364
+ headerActions
2365
+ ? headerActions
2366
+ : null,
2367
+ ),
2368
+ children,
2369
+ footer,
2370
+ ),
2371
+ ),
2372
+ PromptRegion: ({
2373
+ children,
2374
+ className,
2375
+ region,
2376
+ viewId,
2377
+ }) =>
2378
+ isRenderableComponentNode(children)
2379
+ ? createElement(
2380
+ 'div',
2381
+ {
2382
+ className: cn('h-full min-h-0', className),
2383
+ 'data-region-id': region.Id,
2384
+ 'data-presentation-region-id': region.Id,
2385
+ ...createPresentationTestAttributes({ viewId }),
2386
+ },
2387
+ children,
2388
+ )
2389
+ : null,
2390
+ }
2391
+ }
2392
+
2393
+ /** Creates view chrome components for projected actions, badges, metrics, and switches. */
2394
+ export function createShadcnViewChromeComponents({
2395
+ Button,
2396
+ }: CreateShadcnViewChromeComponentsOptions):
2397
+ PresentationViewChromeComponentSystemComponents {
2398
+ return {
2399
+ ActionSlot: ({ children, className, slotId, viewId }) =>
2400
+ createElement(
2401
+ 'div',
2402
+ {
2403
+ className,
2404
+ 'data-presentation-view-chrome-slot-id': slotId,
2405
+ ...createPresentationTestAttributes({ viewId }),
2406
+ },
2407
+ children,
2408
+ ),
2409
+ BadgeStrip: ({ badges, className, slotId, viewId }) =>
2410
+ badges.length === 0
2411
+ ? null
2412
+ : createElement(
2413
+ 'div',
2414
+ {
2415
+ className: cn('flex flex-wrap items-center gap-2', className),
2416
+ 'data-presentation-view-chrome-slot-id': slotId,
2417
+ ...createPresentationTestAttributes({ viewId }),
2418
+ },
2419
+ badges,
2420
+ ),
2421
+ LayoutSwitch: (props) => renderShadcnViewChromeSwitch(props, Button),
2422
+ MetricStripSlot: ({
2423
+ children,
2424
+ className,
2425
+ message,
2426
+ slotId: _slotId,
2427
+ viewId,
2428
+ }) =>
2429
+ createElement(
2430
+ 'div',
2431
+ {
2432
+ className: cn('grid gap-2', className),
2433
+ 'data-presentation-view-chrome-slot-id': _slotId,
2434
+ ...createPresentationTestAttributes({ viewId }),
2435
+ },
2436
+ children,
2437
+ message,
2438
+ ),
2439
+ ViewChromeSlot: ({ children, className, slot, viewId }) =>
2440
+ createElement(
2441
+ 'span',
2442
+ {
2443
+ className: cn('contents', className),
2444
+ 'data-presentation-view-chrome-slot-id': slot.Id,
2445
+ ...createPresentationTestAttributes({ viewId }),
2446
+ },
2447
+ children,
2448
+ ),
2449
+ ViewSwitch: (props) => renderShadcnViewChromeSwitch(props, Button),
2450
+ }
2451
+ }
2452
+
2453
+ function renderShadcnViewChromeSwitch(
2454
+ {
2455
+ ariaLabel,
2456
+ className,
2457
+ items,
2458
+ slotId,
2459
+ viewId,
2460
+ }: PresentationViewChromeSwitchProps,
2461
+ Button: ComponentType<PresentationViewChromeSwitchButtonProps>,
2462
+ ) {
2463
+ if (items.length === 0) {
2464
+ return null
2465
+ }
2466
+
2467
+ return createElement(
2468
+ 'div',
2469
+ {
2470
+ 'aria-label': ariaLabel,
2471
+ className: cn(
2472
+ 'flex items-center gap-1 rounded-lg border border-slate-950/8 bg-white/75 p-0.5',
2473
+ className,
2474
+ ),
2475
+ 'data-presentation-view-chrome-slot-id': slotId,
2476
+ role: 'group',
2477
+ ...createPresentationTestAttributes({ viewId }),
2478
+ },
2479
+ items.map((item) =>
2480
+ createElement(
2481
+ Button,
2482
+ {
2483
+ 'aria-pressed': item.isActive,
2484
+ key: item.id,
2485
+ onClick: item.onSelect,
2486
+ size: 'sm',
2487
+ type: 'button',
2488
+ variant: item.isActive ? 'secondary' : 'ghost',
2489
+ },
2490
+ item.icon,
2491
+ item.label,
2492
+ ),
2493
+ ),
2494
+ )
2495
+ }
2496
+
2497
+ function isRenderableComponentNode(
2498
+ node: ReactNode,
2499
+ ): node is Exclude<ReactNode, null | undefined | false> {
2500
+ return node !== null && node !== undefined && node !== false
2501
+ }
2502
+
2503
+ function cn(...inputs: ClassValue[]) {
2504
+ return twMerge(clsx(inputs))
2505
+ }