@gntik-ai/blocks 0.0.0-stage → 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (397) hide show
  1. package/dist/index.d.ts +3626 -0
  2. package/dist/index.js +15417 -0
  3. package/dist/index.js.map +1 -0
  4. package/package.json +62 -3
  5. package/src/ai/AssistantCardGrid/AssistantCardGrid.test.tsx +32 -0
  6. package/src/ai/AssistantCardGrid/AssistantCardGrid.tsx +98 -0
  7. package/src/ai/AssistantCardGrid/block.meta.ts +10 -0
  8. package/src/ai/AssistantCardGrid/fixtures.ts +72 -0
  9. package/src/ai/EvaluationScorecard/EvaluationScorecard.test.tsx +39 -0
  10. package/src/ai/EvaluationScorecard/EvaluationScorecard.tsx +233 -0
  11. package/src/ai/EvaluationScorecard/block.meta.ts +10 -0
  12. package/src/ai/EvaluationScorecard/fixtures.ts +79 -0
  13. package/src/ai/ModelKeysList/ModelKeysList.test.tsx +44 -0
  14. package/src/ai/ModelKeysList/ModelKeysList.tsx +203 -0
  15. package/src/ai/ModelKeysList/block.meta.ts +10 -0
  16. package/src/ai/ModelKeysList/fixtures.ts +44 -0
  17. package/src/ai/PromptEditor/PromptEditor.test.tsx +97 -0
  18. package/src/ai/PromptEditor/PromptEditor.tsx +202 -0
  19. package/src/ai/PromptEditor/block.meta.ts +10 -0
  20. package/src/ai/PromptEditor/examples/controlled-variables.tsx +23 -0
  21. package/src/ai/PromptEditor/fixtures.ts +12 -0
  22. package/src/ai/TokenCostCard/TokenCostCard.test.tsx +36 -0
  23. package/src/ai/TokenCostCard/TokenCostCard.tsx +130 -0
  24. package/src/ai/TokenCostCard/block.meta.ts +9 -0
  25. package/src/ai/TokenCostCard/fixtures.ts +18 -0
  26. package/src/ai/TraceWaterfall/TraceWaterfall.test.tsx +119 -0
  27. package/src/ai/TraceWaterfall/TraceWaterfall.tsx +317 -0
  28. package/src/ai/TraceWaterfall/block.meta.ts +10 -0
  29. package/src/ai/TraceWaterfall/examples/no-details.tsx +6 -0
  30. package/src/ai/TraceWaterfall/examples/running.tsx +16 -0
  31. package/src/ai/TraceWaterfall/fixtures.ts +133 -0
  32. package/src/ai/TraceWaterfall/span-details.tsx +51 -0
  33. package/src/ai/index.ts +13 -0
  34. package/src/auth/ForgotPasswordForm/ForgotPasswordForm.test.tsx +209 -0
  35. package/src/auth/ForgotPasswordForm/ForgotPasswordForm.tsx +211 -0
  36. package/src/auth/ForgotPasswordForm/block.meta.ts +10 -0
  37. package/src/auth/ForgotPasswordForm/examples/UsernameOrEmail.tsx +24 -0
  38. package/src/auth/MfaChallenge/MfaChallenge.test.tsx +35 -0
  39. package/src/auth/MfaChallenge/MfaChallenge.tsx +170 -0
  40. package/src/auth/MfaChallenge/block.meta.ts +9 -0
  41. package/src/auth/ResetPasswordForm/ResetPasswordForm.test.tsx +27 -0
  42. package/src/auth/ResetPasswordForm/ResetPasswordForm.tsx +100 -0
  43. package/src/auth/ResetPasswordForm/block.meta.ts +10 -0
  44. package/src/auth/SignInForm/SignInForm.test.tsx +222 -0
  45. package/src/auth/SignInForm/SignInForm.tsx +226 -0
  46. package/src/auth/SignInForm/block.meta.ts +22 -0
  47. package/src/auth/SignInForm/examples/Username.tsx +26 -0
  48. package/src/auth/SignUpForm/SignUpForm.configured.test.tsx +316 -0
  49. package/src/auth/SignUpForm/SignUpForm.test.tsx +33 -0
  50. package/src/auth/SignUpForm/SignUpForm.tsx +298 -0
  51. package/src/auth/SignUpForm/block.meta.ts +22 -0
  52. package/src/auth/SignUpForm/examples/CustomFields.tsx +56 -0
  53. package/src/auth/SignUpForm/examples/Error.tsx +5 -0
  54. package/src/auth/SignUpForm/examples/Loading.tsx +6 -0
  55. package/src/auth/SignUpForm/examples/NoTerms.tsx +6 -0
  56. package/src/auth/SignUpForm/examples/Submitting.tsx +5 -0
  57. package/src/auth/SignUpForm/examples/Unavailable.tsx +15 -0
  58. package/src/auth/SsoButtons/SsoButtons.test.tsx +23 -0
  59. package/src/auth/SsoButtons/SsoButtons.tsx +52 -0
  60. package/src/auth/SsoButtons/block.meta.ts +9 -0
  61. package/src/auth/SsoButtons/fixtures.ts +15 -0
  62. package/src/auth/index.ts +16 -0
  63. package/src/auth/shared.tsx +147 -0
  64. package/src/billing/CostBreakdown/CostBreakdown.test.tsx +24 -0
  65. package/src/billing/CostBreakdown/CostBreakdown.tsx +95 -0
  66. package/src/billing/CostBreakdown/block.meta.ts +10 -0
  67. package/src/billing/CostBreakdown/fixtures.ts +9 -0
  68. package/src/billing/InvoiceTable/InvoiceTable.test.tsx +29 -0
  69. package/src/billing/InvoiceTable/InvoiceTable.tsx +130 -0
  70. package/src/billing/InvoiceTable/block.meta.ts +10 -0
  71. package/src/billing/InvoiceTable/fixtures.ts +38 -0
  72. package/src/billing/PaymentMethodCard/PaymentMethodCard.test.tsx +28 -0
  73. package/src/billing/PaymentMethodCard/PaymentMethodCard.tsx +103 -0
  74. package/src/billing/PaymentMethodCard/block.meta.ts +10 -0
  75. package/src/billing/PaymentMethodCard/fixtures.ts +12 -0
  76. package/src/billing/PlanCard/PlanCard.baseline.test.tsx +26 -0
  77. package/src/billing/PlanCard/PlanCard.summary.test.tsx +227 -0
  78. package/src/billing/PlanCard/PlanCard.test.tsx +27 -0
  79. package/src/billing/PlanCard/PlanCard.tsx +140 -0
  80. package/src/billing/PlanCard/PlanSummary.tsx +101 -0
  81. package/src/billing/PlanCard/README.md +23 -0
  82. package/src/billing/PlanCard/__snapshots__/PlanCard.baseline.test.tsx.snap +5 -0
  83. package/src/billing/PlanCard/block.meta.ts +60 -0
  84. package/src/billing/PlanCard/examples/SummaryActionsOnly.tsx +12 -0
  85. package/src/billing/PlanCard/examples/SummaryFeaturesOnly.tsx +14 -0
  86. package/src/billing/PlanCard/examples/SummaryFull.tsx +28 -0
  87. package/src/billing/PlanCard/examples/SummaryMinimal.tsx +5 -0
  88. package/src/billing/PlanCard/examples/SummaryPriceOnly.tsx +15 -0
  89. package/src/billing/PlanCard/examples/SummaryRenewalOnly.tsx +14 -0
  90. package/src/billing/PlanCard/examples/SummaryUnassigned.tsx +5 -0
  91. package/src/billing/PlanCard/examples/SummaryUnassignedNoLabel.tsx +5 -0
  92. package/src/billing/PlanCard/examples/SummaryZeroPrice.tsx +15 -0
  93. package/src/billing/PlanCard/fixtures.ts +19 -0
  94. package/src/billing/PlanDefinitionCard/PlanDefinitionCard.test.tsx +111 -0
  95. package/src/billing/PlanDefinitionCard/PlanDefinitionCard.tsx +86 -0
  96. package/src/billing/PlanDefinitionCard/README.md +29 -0
  97. package/src/billing/PlanDefinitionCard/block.meta.ts +46 -0
  98. package/src/billing/PlanDefinitionCard/examples/Compact.tsx +23 -0
  99. package/src/billing/PlanDefinitionCard/examples/Full.tsx +23 -0
  100. package/src/billing/PlanDefinitionCard/fixtures.ts +12 -0
  101. package/src/billing/QuotaMeters/QuotaMeters.test.tsx +23 -0
  102. package/src/billing/QuotaMeters/QuotaMeters.tsx +92 -0
  103. package/src/billing/QuotaMeters/block.meta.ts +10 -0
  104. package/src/billing/QuotaMeters/fixtures.ts +9 -0
  105. package/src/billing/SpendVsBudget/SpendVsBudget.test.tsx +24 -0
  106. package/src/billing/SpendVsBudget/SpendVsBudget.tsx +105 -0
  107. package/src/billing/SpendVsBudget/block.meta.ts +10 -0
  108. package/src/billing/SpendVsBudget/fixtures.ts +18 -0
  109. package/src/billing/format.ts +42 -0
  110. package/src/billing/index.ts +21 -0
  111. package/src/builders/CodePanel/CodePanel.test.tsx +280 -0
  112. package/src/builders/CodePanel/CodePanel.tsx +239 -0
  113. package/src/builders/CodePanel/block.meta.ts +10 -0
  114. package/src/builders/CodePanel/examples/controlled.tsx +15 -0
  115. package/src/builders/CodePanel/examples/diagnostics.tsx +40 -0
  116. package/src/builders/CodePanel/fixtures.ts +95 -0
  117. package/src/builders/CodePanel/marker-store.ts +90 -0
  118. package/src/builders/CodePanel/markers.ts +62 -0
  119. package/src/builders/FlowBuilder/FlowBuilder.test.tsx +480 -0
  120. package/src/builders/FlowBuilder/FlowBuilder.tsx +343 -0
  121. package/src/builders/FlowBuilder/block.meta.ts +20 -0
  122. package/src/builders/FlowBuilder/connections.ts +67 -0
  123. package/src/builders/FlowBuilder/decorated-nodes.ts +80 -0
  124. package/src/builders/FlowBuilder/examples/extensions.tsx +120 -0
  125. package/src/builders/FlowBuilder/extensions.ts +37 -0
  126. package/src/builders/FlowBuilder/fixtures.ts +80 -0
  127. package/src/builders/FlowBuilder/parts.tsx +196 -0
  128. package/src/builders/FlowBuilder/problems.tsx +40 -0
  129. package/src/builders/LogViewer/LogViewer.test.tsx +97 -0
  130. package/src/builders/LogViewer/LogViewer.tsx +253 -0
  131. package/src/builders/LogViewer/block.meta.ts +10 -0
  132. package/src/builders/LogViewer/fixtures.ts +49 -0
  133. package/src/builders/index.ts +15 -0
  134. package/src/data-display/ActivityFeed/ActivityFeed.test.tsx +62 -0
  135. package/src/data-display/ActivityFeed/ActivityFeed.tsx +118 -0
  136. package/src/data-display/ActivityFeed/block.meta.ts +10 -0
  137. package/src/data-display/ActivityFeed/fixtures.ts +29 -0
  138. package/src/data-display/ChartCard/ChartCard.ranges.test.tsx +282 -0
  139. package/src/data-display/ChartCard/ChartCard.test.tsx +54 -0
  140. package/src/data-display/ChartCard/ChartCard.tsx +218 -0
  141. package/src/data-display/ChartCard/block.meta.ts +10 -0
  142. package/src/data-display/ChartCard/examples/custom-ranges.tsx +37 -0
  143. package/src/data-display/ChartCard/examples/heatmap.tsx +20 -0
  144. package/src/data-display/ChartCard/examples/toolbar-owned-range.tsx +34 -0
  145. package/src/data-display/ChartCard/fixtures.ts +82 -0
  146. package/src/data-display/CommentThread/CommentThread.test.tsx +29 -0
  147. package/src/data-display/CommentThread/CommentThread.tsx +120 -0
  148. package/src/data-display/CommentThread/block.meta.ts +10 -0
  149. package/src/data-display/CommentThread/fixtures.ts +28 -0
  150. package/src/data-display/DescriptionListCard/DescriptionListCard.test.tsx +28 -0
  151. package/src/data-display/DescriptionListCard/DescriptionListCard.tsx +120 -0
  152. package/src/data-display/DescriptionListCard/block.meta.ts +9 -0
  153. package/src/data-display/DescriptionListCard/fixtures.ts +12 -0
  154. package/src/data-display/KpiRow/KpiRow.test.tsx +29 -0
  155. package/src/data-display/KpiRow/KpiRow.tsx +101 -0
  156. package/src/data-display/KpiRow/block.meta.ts +10 -0
  157. package/src/data-display/KpiRow/fixtures.ts +34 -0
  158. package/src/data-display/ResourceCardGrid/ResourceCardGrid.test.tsx +22 -0
  159. package/src/data-display/ResourceCardGrid/ResourceCardGrid.tsx +98 -0
  160. package/src/data-display/ResourceCardGrid/block.meta.ts +10 -0
  161. package/src/data-display/ResourceCardGrid/fixtures.ts +72 -0
  162. package/src/data-display/StatCard/StatCard.test.tsx +30 -0
  163. package/src/data-display/StatCard/StatCard.tsx +138 -0
  164. package/src/data-display/StatCard/block.meta.ts +10 -0
  165. package/src/data-display/StatCard/fixtures.ts +26 -0
  166. package/src/data-display/StatusTimeline/StatusTimeline.test.tsx +153 -0
  167. package/src/data-display/StatusTimeline/StatusTimeline.tsx +114 -0
  168. package/src/data-display/StatusTimeline/block.meta.ts +10 -0
  169. package/src/data-display/StatusTimeline/examples/Empty.tsx +6 -0
  170. package/src/data-display/StatusTimeline/fixtures.ts +62 -0
  171. package/src/data-display/index.ts +34 -0
  172. package/src/data-display/shared/TrendDelta.tsx +60 -0
  173. package/src/feedback/ConfirmDestructive/ConfirmDestructive.test.tsx +47 -0
  174. package/src/feedback/ConfirmDestructive/ConfirmDestructive.tsx +145 -0
  175. package/src/feedback/ConfirmDestructive/block.meta.ts +10 -0
  176. package/src/feedback/EmptyStates/EmptyStates.test.tsx +48 -0
  177. package/src/feedback/EmptyStates/EmptyStates.tsx +191 -0
  178. package/src/feedback/EmptyStates/block.meta.ts +10 -0
  179. package/src/feedback/EmptyStates/fixtures.ts +6 -0
  180. package/src/feedback/ErrorPanel/ErrorPanel.test.tsx +37 -0
  181. package/src/feedback/ErrorPanel/ErrorPanel.tsx +146 -0
  182. package/src/feedback/ErrorPanel/block.meta.ts +10 -0
  183. package/src/feedback/InlineCallout/InlineCallout.test.tsx +33 -0
  184. package/src/feedback/InlineCallout/InlineCallout.tsx +81 -0
  185. package/src/feedback/InlineCallout/block.meta.ts +9 -0
  186. package/src/feedback/Skeletons/Skeletons.test.tsx +25 -0
  187. package/src/feedback/Skeletons/Skeletons.tsx +142 -0
  188. package/src/feedback/Skeletons/block.meta.ts +10 -0
  189. package/src/feedback/SystemBanner/SystemBanner.test.tsx +29 -0
  190. package/src/feedback/SystemBanner/SystemBanner.tsx +105 -0
  191. package/src/feedback/SystemBanner/block.meta.ts +9 -0
  192. package/src/feedback/index.ts +14 -0
  193. package/src/feedback/types.ts +13 -0
  194. package/src/forms/CreateApiKeyDialog/CreateApiKeyDialog.test.tsx +36 -0
  195. package/src/forms/CreateApiKeyDialog/CreateApiKeyDialog.tsx +197 -0
  196. package/src/forms/CreateApiKeyDialog/block.meta.ts +10 -0
  197. package/src/forms/CreateApiKeyDialog/fixtures.ts +31 -0
  198. package/src/forms/CredentialDisclosureDialog/CredentialDisclosureDialog.test.tsx +339 -0
  199. package/src/forms/CredentialDisclosureDialog/CredentialDisclosureDialog.tsx +193 -0
  200. package/src/forms/CredentialDisclosureDialog/block.meta.ts +10 -0
  201. package/src/forms/CredentialDisclosureDialog/examples/Fresh.tsx +32 -0
  202. package/src/forms/CredentialDisclosureDialog/examples/ResponseGating.tsx +69 -0
  203. package/src/forms/CredentialDisclosureDialog/examples/Stored.tsx +32 -0
  204. package/src/forms/CredentialDisclosureDialog/fixtures.ts +14 -0
  205. package/src/forms/DangerZone/ConfirmDestructiveDialog.tsx +101 -0
  206. package/src/forms/DangerZone/DangerZone.test.tsx +28 -0
  207. package/src/forms/DangerZone/DangerZone.tsx +86 -0
  208. package/src/forms/DangerZone/block.meta.ts +10 -0
  209. package/src/forms/DangerZone/fixtures.ts +36 -0
  210. package/src/forms/DateRangeFilter/DateRangeFilter.test.tsx +26 -0
  211. package/src/forms/DateRangeFilter/DateRangeFilter.tsx +83 -0
  212. package/src/forms/DateRangeFilter/block.meta.ts +9 -0
  213. package/src/forms/DialogWizard/DialogWizard.test.tsx +95 -0
  214. package/src/forms/DialogWizard/DialogWizard.tsx +39 -0
  215. package/src/forms/DialogWizard/block.meta.ts +10 -0
  216. package/src/forms/DialogWizard/examples/CreateResource.tsx +65 -0
  217. package/src/forms/DialogWizard/fixtures.ts +20 -0
  218. package/src/forms/FileUploadPanel/FileUploadPanel.test.tsx +43 -0
  219. package/src/forms/FileUploadPanel/FileUploadPanel.tsx +244 -0
  220. package/src/forms/FileUploadPanel/block.meta.ts +10 -0
  221. package/src/forms/FileUploadPanel/fixtures.ts +66 -0
  222. package/src/forms/FormSection/FormSection.test.tsx +34 -0
  223. package/src/forms/FormSection/FormSection.tsx +77 -0
  224. package/src/forms/FormSection/block.meta.ts +9 -0
  225. package/src/forms/InviteMembersDialog/InviteMembersDialog.test.tsx +37 -0
  226. package/src/forms/InviteMembersDialog/InviteMembersDialog.tsx +183 -0
  227. package/src/forms/InviteMembersDialog/block.meta.ts +10 -0
  228. package/src/forms/InviteMembersDialog/fixtures.ts +14 -0
  229. package/src/forms/SettingsRow/SettingsRow.test.tsx +50 -0
  230. package/src/forms/SettingsRow/SettingsRow.tsx +74 -0
  231. package/src/forms/SettingsRow/block.meta.ts +9 -0
  232. package/src/forms/ValidationSummary/ValidationSummary.test.tsx +46 -0
  233. package/src/forms/ValidationSummary/ValidationSummary.tsx +75 -0
  234. package/src/forms/ValidationSummary/block.meta.ts +9 -0
  235. package/src/forms/ValidationSummary/fixtures.ts +13 -0
  236. package/src/forms/index.ts +27 -0
  237. package/src/index.ts +14 -0
  238. package/src/marketing/ComparisonTable/ComparisonTable.test.tsx +69 -0
  239. package/src/marketing/ComparisonTable/ComparisonTable.tsx +245 -0
  240. package/src/marketing/ComparisonTable/block.meta.ts +10 -0
  241. package/src/marketing/ComparisonTable/examples/options.tsx +48 -0
  242. package/src/marketing/ComparisonTable/fixtures.ts +83 -0
  243. package/src/marketing/Faq/Faq.test.tsx +25 -0
  244. package/src/marketing/Faq/Faq.tsx +68 -0
  245. package/src/marketing/Faq/block.meta.ts +10 -0
  246. package/src/marketing/Faq/fixtures.ts +32 -0
  247. package/src/marketing/FeatureGrid/FeatureGrid.test.tsx +19 -0
  248. package/src/marketing/FeatureGrid/FeatureGrid.tsx +79 -0
  249. package/src/marketing/FeatureGrid/block.meta.ts +10 -0
  250. package/src/marketing/FeatureGrid/fixtures.ts +36 -0
  251. package/src/marketing/Hero/Hero.test.tsx +33 -0
  252. package/src/marketing/Hero/Hero.tsx +107 -0
  253. package/src/marketing/Hero/block.meta.ts +10 -0
  254. package/src/marketing/PricingTable/PricingTable.test.tsx +92 -0
  255. package/src/marketing/PricingTable/PricingTable.tsx +323 -0
  256. package/src/marketing/PricingTable/block.meta.ts +10 -0
  257. package/src/marketing/PricingTable/fixtures.ts +34 -0
  258. package/src/marketing/actions.tsx +40 -0
  259. package/src/marketing/index.ts +15 -0
  260. package/src/meta.ts +25 -0
  261. package/src/page-chrome/BulkActionBar/BulkActionBar.test.tsx +34 -0
  262. package/src/page-chrome/BulkActionBar/BulkActionBar.tsx +76 -0
  263. package/src/page-chrome/BulkActionBar/block.meta.ts +9 -0
  264. package/src/page-chrome/PageHeader/PageHeader.test.tsx +68 -0
  265. package/src/page-chrome/PageHeader/PageHeader.tsx +152 -0
  266. package/src/page-chrome/PageHeader/block.meta.ts +10 -0
  267. package/src/page-chrome/PageHeader/fixtures.ts +29 -0
  268. package/src/page-chrome/PageToolbar/PageToolbar.test.tsx +38 -0
  269. package/src/page-chrome/PageToolbar/PageToolbar.tsx +138 -0
  270. package/src/page-chrome/PageToolbar/block.meta.ts +10 -0
  271. package/src/page-chrome/PageToolbar/fixtures.ts +8 -0
  272. package/src/page-chrome/SectionHeader/SectionHeader.test.tsx +28 -0
  273. package/src/page-chrome/SectionHeader/SectionHeader.tsx +73 -0
  274. package/src/page-chrome/SectionHeader/block.meta.ts +9 -0
  275. package/src/page-chrome/StickyActionBar/StickyActionBar.test.tsx +29 -0
  276. package/src/page-chrome/StickyActionBar/StickyActionBar.tsx +66 -0
  277. package/src/page-chrome/StickyActionBar/block.meta.ts +9 -0
  278. package/src/page-chrome/index.ts +13 -0
  279. package/src/page-chrome/types.ts +25 -0
  280. package/src/scheduling/AgendaList/AgendaList.test.tsx +28 -0
  281. package/src/scheduling/AgendaList/AgendaList.tsx +165 -0
  282. package/src/scheduling/AgendaList/block.meta.ts +10 -0
  283. package/src/scheduling/MonthCalendar/MonthCalendar.test.tsx +32 -0
  284. package/src/scheduling/MonthCalendar/MonthCalendar.tsx +223 -0
  285. package/src/scheduling/MonthCalendar/block.meta.ts +10 -0
  286. package/src/scheduling/TimeSlotPicker/TimeSlotPicker.test.tsx +26 -0
  287. package/src/scheduling/TimeSlotPicker/TimeSlotPicker.tsx +115 -0
  288. package/src/scheduling/TimeSlotPicker/block.meta.ts +10 -0
  289. package/src/scheduling/TimeSlotPicker/fixtures.ts +10 -0
  290. package/src/scheduling/WeekCalendar/WeekCalendar.test.tsx +27 -0
  291. package/src/scheduling/WeekCalendar/WeekCalendar.tsx +274 -0
  292. package/src/scheduling/WeekCalendar/block.meta.ts +10 -0
  293. package/src/scheduling/index.ts +11 -0
  294. package/src/scheduling/shared/CalendarHeader.tsx +54 -0
  295. package/src/scheduling/shared/EventTile.tsx +21 -0
  296. package/src/scheduling/shared/dates.ts +98 -0
  297. package/src/scheduling/shared/events.ts +90 -0
  298. package/src/scheduling/shared/fixtures.ts +54 -0
  299. package/src/shell/AppSidebar/AppSidebar.test.tsx +38 -0
  300. package/src/shell/AppSidebar/AppSidebar.tsx +226 -0
  301. package/src/shell/AppSidebar/block.meta.ts +10 -0
  302. package/src/shell/AppSidebar/fixtures.ts +58 -0
  303. package/src/shell/AppTopbar/AppTopbar.test.tsx +41 -0
  304. package/src/shell/AppTopbar/AppTopbar.tsx +82 -0
  305. package/src/shell/AppTopbar/block.meta.ts +19 -0
  306. package/src/shell/AppTopbar/fixtures.ts +22 -0
  307. package/src/shell/EnvironmentBadge/EnvironmentBadge.test.tsx +22 -0
  308. package/src/shell/EnvironmentBadge/EnvironmentBadge.tsx +55 -0
  309. package/src/shell/EnvironmentBadge/block.meta.ts +10 -0
  310. package/src/shell/GlobalSearch/GlobalSearch.test.tsx +28 -0
  311. package/src/shell/GlobalSearch/GlobalSearch.tsx +80 -0
  312. package/src/shell/GlobalSearch/block.meta.ts +10 -0
  313. package/src/shell/GlobalSearch/fixtures.ts +64 -0
  314. package/src/shell/index.ts +11 -0
  315. package/src/styles.css +2 -0
  316. package/src/tables/DataTable/DataTable.edit-views.test.tsx +249 -0
  317. package/src/tables/DataTable/DataTable.labels.test.tsx +291 -0
  318. package/src/tables/DataTable/DataTable.layout.test.tsx +188 -0
  319. package/src/tables/DataTable/DataTable.overflow-labels.test.tsx +59 -0
  320. package/src/tables/DataTable/DataTable.single-select.test.tsx +501 -0
  321. package/src/tables/DataTable/DataTable.test.tsx +268 -0
  322. package/src/tables/DataTable/DataTable.tsx +531 -0
  323. package/src/tables/DataTable/block.meta.ts +129 -0
  324. package/src/tables/DataTable/column-menu.tsx +112 -0
  325. package/src/tables/DataTable/column-sizing.ts +166 -0
  326. package/src/tables/DataTable/data-table-body.tsx +195 -0
  327. package/src/tables/DataTable/data-table-props.ts +159 -0
  328. package/src/tables/DataTable/data-table-row.tsx +231 -0
  329. package/src/tables/DataTable/data-table-utils.ts +195 -0
  330. package/src/tables/DataTable/density-toggle.tsx +33 -0
  331. package/src/tables/DataTable/editable-cell.tsx +287 -0
  332. package/src/tables/DataTable/examples/editable.tsx +71 -0
  333. package/src/tables/DataTable/examples/grouped.tsx +18 -0
  334. package/src/tables/DataTable/examples/resizable-pinned.tsx +20 -0
  335. package/src/tables/DataTable/examples/saved-views.tsx +61 -0
  336. package/src/tables/DataTable/examples/single-selection.tsx +55 -0
  337. package/src/tables/DataTable/examples/virtualized.tsx +20 -0
  338. package/src/tables/DataTable/fixtures.ts +119 -0
  339. package/src/tables/DataTable/header-cell.tsx +90 -0
  340. package/src/tables/DataTable/labels.ts +54 -0
  341. package/src/tables/DataTable/resize-handle.tsx +91 -0
  342. package/src/tables/DataTable/single-selection.tsx +149 -0
  343. package/src/tables/DataTable/use-table-views.ts +79 -0
  344. package/src/tables/DataTable/use-virtual-rows.ts +83 -0
  345. package/src/tables/DataTable/views.tsx +193 -0
  346. package/src/tables/FilterBar/FilterBar.labels.test.tsx +69 -0
  347. package/src/tables/FilterBar/FilterBar.test.tsx +43 -0
  348. package/src/tables/FilterBar/FilterBar.tsx +232 -0
  349. package/src/tables/FilterBar/block.meta.ts +32 -0
  350. package/src/tables/FilterBar/fixtures.ts +32 -0
  351. package/src/tables/InlineEditRow/InlineEditRow.test.tsx +41 -0
  352. package/src/tables/InlineEditRow/InlineEditRow.tsx +215 -0
  353. package/src/tables/InlineEditRow/block.meta.ts +10 -0
  354. package/src/tables/InlineEditRow/fixtures.ts +28 -0
  355. package/src/tables/PaginationFooter/PaginationFooter.labels.test.tsx +57 -0
  356. package/src/tables/PaginationFooter/PaginationFooter.test.tsx +29 -0
  357. package/src/tables/PaginationFooter/PaginationFooter.tsx +118 -0
  358. package/src/tables/PaginationFooter/block.meta.ts +33 -0
  359. package/src/tables/SubordinateList/SubordinateList.test.tsx +351 -0
  360. package/src/tables/SubordinateList/SubordinateList.tsx +140 -0
  361. package/src/tables/SubordinateList/block.meta.ts +10 -0
  362. package/src/tables/SubordinateList/examples/ResourceForm.tsx +129 -0
  363. package/src/tables/SubordinateList/examples/empty.tsx +5 -0
  364. package/src/tables/SubordinateList/examples/error.tsx +5 -0
  365. package/src/tables/SubordinateList/examples/loading.tsx +5 -0
  366. package/src/tables/TruncatedCollectionFooter/TruncatedCollectionFooter.test.tsx +159 -0
  367. package/src/tables/TruncatedCollectionFooter/TruncatedCollectionFooter.tsx +60 -0
  368. package/src/tables/TruncatedCollectionFooter/block.meta.ts +10 -0
  369. package/src/tables/TruncatedCollectionFooter/examples/exact.tsx +6 -0
  370. package/src/tables/TruncatedCollectionFooter/examples/has-more.tsx +12 -0
  371. package/src/tables/TruncatedCollectionFooter/fixtures.ts +2 -0
  372. package/src/tables/index.ts +45 -0
  373. package/src/team/MembersTable/MembersTable.test.tsx +29 -0
  374. package/src/team/MembersTable/MembersTable.tsx +141 -0
  375. package/src/team/MembersTable/block.meta.ts +9 -0
  376. package/src/team/MembersTable/fixtures.ts +19 -0
  377. package/src/team/NotificationMatrix/NotificationMatrix.test.tsx +36 -0
  378. package/src/team/NotificationMatrix/NotificationMatrix.tsx +144 -0
  379. package/src/team/NotificationMatrix/block.meta.ts +9 -0
  380. package/src/team/NotificationMatrix/fixtures.ts +43 -0
  381. package/src/team/PendingInvitations/PendingInvitations.test.tsx +30 -0
  382. package/src/team/PendingInvitations/PendingInvitations.tsx +132 -0
  383. package/src/team/PendingInvitations/block.meta.ts +9 -0
  384. package/src/team/PendingInvitations/fixtures.ts +39 -0
  385. package/src/team/ProfileHeader/ProfileHeader.test.tsx +29 -0
  386. package/src/team/ProfileHeader/ProfileHeader.tsx +106 -0
  387. package/src/team/ProfileHeader/block.meta.ts +10 -0
  388. package/src/team/ProfileHeader/fixtures.ts +28 -0
  389. package/src/team/SessionsDevices/SessionsDevices.test.tsx +30 -0
  390. package/src/team/SessionsDevices/SessionsDevices.tsx +126 -0
  391. package/src/team/SessionsDevices/block.meta.ts +10 -0
  392. package/src/team/SessionsDevices/fixtures.ts +58 -0
  393. package/src/team/index.ts +15 -0
  394. package/src/test/a11y.ts +18 -0
  395. package/src/test/heading-levels.test.tsx +69 -0
  396. package/src/test/setup.ts +36 -0
  397. package/README.md +0 -3
@@ -0,0 +1,239 @@
1
+ import { useRef, useState } from 'react';
2
+ import { CircleX, FileCode, Info, TriangleAlert } from '@gntik-ai/icons';
3
+ import { CodeEditor, DiffEditor, type CodeEditorProps, type MonacoLoader, type Monaco } from '@gntik-ai/editor';
4
+ import { Tabs, TabsList, TabsPanel, TabsTab, Toggle, ToggleGroup, cn } from '@gntik-ai/ui';
5
+ import { NO_MARKERS, usePanelMarkers, useValidity, type CodePanelMarker, type MonacoReady } from './markers';
6
+ import { codeFiles, codeProblems, type CodeFile, type CodeProblem, type ProblemSeverity } from './fixtures';
7
+
8
+ export type { CodePanelMarker, MonacoReady } from './markers';
9
+ export type { CodeFile, CodeProblem, ProblemSeverity } from './fixtures';
10
+
11
+ type CodeEditorInstance = Parameters<NonNullable<CodeEditorProps['onMount']>>[0];
12
+ type View = 'code' | 'diff';
13
+
14
+ const SEVERITY: Record<ProblemSeverity, { label: string; icon: typeof CircleX; className: string }> = {
15
+ error: { label: 'Error', icon: CircleX, className: 'text-destructive-text' },
16
+ warning: { label: 'Warning', icon: TriangleAlert, className: 'text-warning-text' },
17
+ info: { label: 'Info', icon: Info, className: 'text-muted-foreground' },
18
+ };
19
+
20
+ export interface CodePanelProps {
21
+ files?: CodeFile[];
22
+ readOnly?: boolean;
23
+ markers?: readonly CodePanelMarker[];
24
+ /** Fires when the merged error count crosses zero (warnings do not invalidate). */
25
+ onValidityChange?: (valid: boolean) => void;
26
+ /** Configure consumer language services; optionally return their cleanup function. */
27
+ onMonacoReady?: MonacoReady;
28
+ problems?: CodeProblem[];
29
+ /** Path of the file opened first (uncontrolled; defaults to the first file). */
30
+ defaultFile?: string;
31
+ /** Path of the open file (controlled). Pair with `onActiveFileChange`. */
32
+ activeFile?: string;
33
+ /** Called with the path of the file to open (tab click, arrow keys, or a problem in another file). */
34
+ onActiveFileChange?: (path: string) => void;
35
+ /** Heading level of the "Problems" heading, to fit the page outline (default 3). */
36
+ headingLevel?: 2 | 3 | 4 | 5 | 6;
37
+ defaultView?: View;
38
+ /** Editor height (px or CSS length). */
39
+ height?: number | string;
40
+ /** Called with the file path and its new text on every edit. */
41
+ onChange?: (path: string, value: string) => void;
42
+ /** Called when a problem is picked in the list (the editor also jumps to it). */
43
+ onProblemSelect?: (problem: CodeProblem) => void;
44
+ /** Monaco loader passed to the editors (self-hosting, tests). Monaco loads lazily by default. */
45
+ loader?: MonacoLoader;
46
+ className?: string;
47
+ }
48
+
49
+ function basename(path: string) {
50
+ return path.split('/').pop() ?? path;
51
+ }
52
+
53
+ /**
54
+ * Multi-file code panel: file tabs, Monaco editor (or diff against the previous version) and
55
+ * a problems list that jumps to the reported line. Monaco is loaded lazily by @gntik-ai/editor.
56
+ */
57
+ export function CodePanel({
58
+ files = codeFiles,
59
+ problems: suppliedProblems = codeProblems,
60
+ readOnly,
61
+ markers = NO_MARKERS,
62
+ onValidityChange,
63
+ onMonacoReady,
64
+ defaultFile,
65
+ activeFile: activeProp,
66
+ onActiveFileChange,
67
+ headingLevel = 3,
68
+ defaultView = 'code',
69
+ height = 360,
70
+ onChange,
71
+ onProblemSelect,
72
+ loader,
73
+ className,
74
+ }: CodePanelProps) {
75
+ const collectMarkers = markers !== NO_MARKERS || onMonacoReady !== undefined || onValidityChange !== undefined;
76
+ const markerState = usePanelMarkers(markers, onMonacoReady, collectMarkers);
77
+ const problems = [...suppliedProblems, ...markers, ...markerState.problems];
78
+ const [innerActive, setInnerActive] = useState(defaultFile ?? files[0]?.path ?? '');
79
+ const active = activeProp ?? innerActive;
80
+ const setActive = (path: string) => {
81
+ if (path === active) return;
82
+ setInnerActive(path);
83
+ onActiveFileChange?.(path);
84
+ };
85
+ const ProblemsHeading = `h${headingLevel}` as const;
86
+ const [view, setView] = useState<View>(defaultView);
87
+ const [values, setValues] = useState<Record<string, string>>({});
88
+ const editors = useRef(new Map<string, CodeEditorInstance>());
89
+ const pending = useRef<CodeProblem | null>(null);
90
+
91
+ const currentFile = files.find((f) => f.path === active);
92
+ const canDiff = currentFile?.original !== undefined;
93
+ const effectiveView: View = canDiff ? view : 'code';
94
+ const errors = problems.filter((p) => p.severity === 'error').length;
95
+ useValidity(errors, onValidityChange);
96
+ const warnings = problems.filter((p) => p.severity === 'warning').length;
97
+
98
+ const reveal = (ed: CodeEditorInstance, problem: CodeProblem) => {
99
+ try {
100
+ ed.setPosition({ lineNumber: problem.line, column: problem.column ?? 1 });
101
+ ed.revealLineInCenter(problem.line);
102
+ ed.focus();
103
+ } catch {
104
+ /* editor not ready or disposed */
105
+ }
106
+ };
107
+
108
+ const selectProblem = (problem: CodeProblem) => {
109
+ onProblemSelect?.(problem);
110
+ setActive(problem.file);
111
+ setView('code');
112
+ const ed = editors.current.get(problem.file);
113
+ if (ed && ed.getModel() && problem.file === active && effectiveView === 'code') reveal(ed, problem);
114
+ else pending.current = problem;
115
+ };
116
+
117
+ const onMount = (path: string) => (ed: CodeEditorInstance, monaco: Monaco) => {
118
+ markerState.mount(path, ed, monaco);
119
+ editors.current.set(path, ed);
120
+ const p = pending.current;
121
+ if (p && p.file === path) {
122
+ pending.current = null;
123
+ reveal(ed, p);
124
+ }
125
+ };
126
+
127
+ const valueOf = (f: CodeFile) => values[f.path] ?? f.content;
128
+
129
+ return (
130
+ <section
131
+ aria-label="Code panel"
132
+ className={cn('flex flex-col overflow-hidden rounded-lg border border-border bg-card shadow-sm', className)}
133
+ >
134
+ <Tabs value={active} onValueChange={(v) => setActive(String(v))} className="gap-0">
135
+ <div className="flex flex-col gap-2 border-b border-border bg-secondary/35 px-3 pt-1 sm:flex-row sm:items-end sm:justify-between">
136
+ <TabsList aria-label="Open files" className="-mb-px gap-4 overflow-x-auto border-b-0">
137
+ {files.map((f) => {
138
+ const count = problems.filter((p) => p.file === f.path).length;
139
+ return (
140
+ <TabsTab
141
+ key={f.path}
142
+ value={f.path}
143
+ icon={FileCode}
144
+ count={count || undefined}
145
+ className="font-mono text-[12px]"
146
+ >
147
+ {basename(f.path)}
148
+ </TabsTab>
149
+ );
150
+ })}
151
+ </TabsList>
152
+ <ToggleGroup
153
+ aria-label="Editor view"
154
+ size="sm"
155
+ value={[effectiveView]}
156
+ onValueChange={(v) => v[0] && setView(v[0] as View)}
157
+ className="mb-2 self-start sm:self-auto"
158
+ >
159
+ <Toggle value="code">Edit</Toggle>
160
+ <Toggle value="diff" disabled={!canDiff}>
161
+ Diff
162
+ </Toggle>
163
+ </ToggleGroup>
164
+ </div>
165
+ {files.map((f) => (
166
+ <TabsPanel key={f.path} value={f.path} className="rounded-none">
167
+ {effectiveView === 'diff' && f.original !== undefined ? (
168
+ <DiffEditor
169
+ original={f.original}
170
+ modified={valueOf(f)}
171
+ language={f.language}
172
+ height={height}
173
+ aria-label={`${f.path} changes`}
174
+ loader={loader}
175
+ readOnly={readOnly}
176
+ onMount={(diff, monaco) => {
177
+ const editor = diff.getModifiedEditor?.();
178
+ if (editor) onMount(f.path)(editor, monaco);
179
+ }}
180
+ />
181
+ ) : (
182
+ <CodeEditor
183
+ value={valueOf(f)}
184
+ language={f.language}
185
+ height={height}
186
+ aria-label={f.path}
187
+ loader={loader}
188
+ readOnly={readOnly}
189
+ onMount={onMount(f.path)}
190
+ onChange={(v) => {
191
+ setValues((prev) => ({ ...prev, [f.path]: v }));
192
+ onChange?.(f.path, v);
193
+ }}
194
+ />
195
+ )}
196
+ </TabsPanel>
197
+ ))}
198
+ </Tabs>
199
+ <div className="border-t border-border">
200
+ <div className="flex items-center gap-3 bg-secondary/35 px-3 py-2">
201
+ <ProblemsHeading className="text-[12px] font-semibold tracking-wide text-foreground uppercase">
202
+ Problems
203
+ </ProblemsHeading>
204
+ <span className="font-mono text-[11px] text-muted-foreground">
205
+ {errors} {errors === 1 ? 'error' : 'errors'} · {warnings} {warnings === 1 ? 'warning' : 'warnings'}
206
+ </span>
207
+ </div>
208
+ {problems.length === 0 ? (
209
+ <p className="px-3 py-3 text-[12.5px] text-muted-foreground">No problems detected.</p>
210
+ ) : (
211
+ <ul aria-label="Problems" className="max-h-40 overflow-y-auto py-1">
212
+ {problems.map((p) => {
213
+ const sev = SEVERITY[p.severity];
214
+ const SevIcon = sev.icon;
215
+ return (
216
+ <li key={p.id}>
217
+ <button
218
+ type="button"
219
+ onClick={() => selectProblem(p)}
220
+ className="flex w-full items-start gap-2 px-3 py-1.5 text-start text-[12.5px] hover:bg-secondary/60 focus-visible:outline-2 focus-visible:-outline-offset-2 focus-visible:outline-focus-ring"
221
+ >
222
+ <SevIcon size={14} aria-hidden className={cn('mt-0.5 shrink-0', sev.className)} />
223
+ <span className="sr-only">{sev.label}:</span>
224
+ <span className="min-w-0 flex-1 text-foreground">{p.message}</span>
225
+ <span className="shrink-0 font-mono text-[11px] text-muted-foreground">
226
+ {basename(p.file)}:{p.line}
227
+ {p.column !== undefined ? `:${p.column}` : ''}
228
+ {p.source ? ` · ${p.source}` : ''}
229
+ </span>
230
+ </button>
231
+ </li>
232
+ );
233
+ })}
234
+ </ul>
235
+ )}
236
+ </div>
237
+ </section>
238
+ );
239
+ }
@@ -0,0 +1,10 @@
1
+ import type { BlockMeta } from '../../meta';
2
+
3
+ export const meta: BlockMeta = {
4
+ name: 'Code panel',
5
+ family: 'builders',
6
+ status: 'beta',
7
+ description:
8
+ 'Multi-file code panel with optional readOnly, owned line markers, onValidityChange and onMonacoReady, merging every Monaco marker owner into Problems; the lazy loader example injects inline YAML schemas and same-origin yaml workers under CSP. The open file can be controlled (activeFile, onActiveFileChange) and the heading level set (headingLevel). Optional readOnly prevents editor edits. markers accepts CodePanelMarker entries {id,owner,file,line,column?,endLine?,endColumn?,severity,message,source?}; each owner is reserved for its consumer diagnostics service. The Problems list merges problems, consumer markers, and Monaco model markers from every owner, including worker-backed YAML schema errors. onValidityChange(valid) fires only when errors cross zero (initially clean emits nothing); warnings do not invalidate. onMonacoReady(monaco) configures consumer services once per Monaco instance and may return cleanup. loader can configure monaco-yaml before mounting; the only supported YAML path is consumer-injected, with enableSchemaRequest:false and an inline schema. examples/diagnostics.tsx demonstrates a semantic-worker owner next to schema diagnostics. See packages/editor/README.md for the lazy Vite yaml.worker recipe, Monaco 0.57 compatibility alias, and CSP worker-src self blob: with same-origin scripts and assets. Supplying markers (including []), onMonacoReady or onValidityChange enables model-marker collection; readOnly controls editing independently. Omitting diagnostics extensions preserves the original supplied-problems-only view. No kit runtime dependency on monaco-yaml.',
9
+ uses: ['Tabs', 'ToggleGroup', 'Toggle', 'CodeEditor', 'DiffEditor'],
10
+ };
@@ -0,0 +1,15 @@
1
+ import { useState } from 'react';
2
+ import { CodePanel } from '../CodePanel';
3
+
4
+ /** The page owns the open file (e.g. to sync it with the URL) and places the panel under an h2. */
5
+ export default function ControlledCodePanel() {
6
+ const [file, setFile] = useState('deploy.yaml');
7
+ return (
8
+ <div className="flex flex-col gap-2">
9
+ <p className="text-[12.5px] text-muted-foreground">
10
+ Open file: <span className="font-mono text-foreground">{file}</span>
11
+ </p>
12
+ <CodePanel activeFile={file} onActiveFileChange={setFile} headingLevel={4} />
13
+ </div>
14
+ );
15
+ }
@@ -0,0 +1,40 @@
1
+ import type { MonacoLoader } from '@gntik-ai/editor';
2
+ import { CodePanel, type CodePanelMarker, type MonacoReady } from '../CodePanel';
3
+
4
+ /** Inject the lazy same-origin loader from the editor README; the kit adds no YAML dependency. */
5
+ export default function YamlDiagnosticsExample({
6
+ loader,
7
+ onMonacoReady,
8
+ markers,
9
+ readOnly = false,
10
+ onValidityChange,
11
+ }: {
12
+ loader: MonacoLoader;
13
+ onMonacoReady?: MonacoReady;
14
+ markers?: readonly CodePanelMarker[];
15
+ readOnly?: boolean;
16
+ onValidityChange?: (valid: boolean) => void;
17
+ }) {
18
+ return (
19
+ <CodePanel
20
+ files={[{ path: 'flow.yaml', language: 'yaml', content: 'count: wrong\n' }]}
21
+ problems={[]}
22
+ loader={loader}
23
+ onMonacoReady={onMonacoReady}
24
+ markers={
25
+ markers ?? [
26
+ {
27
+ id: 'terminal',
28
+ owner: 'semantic-worker',
29
+ severity: 'warning',
30
+ file: 'flow.yaml',
31
+ line: 1,
32
+ message: 'Review the terminal step.',
33
+ },
34
+ ]
35
+ }
36
+ readOnly={readOnly}
37
+ onValidityChange={onValidityChange}
38
+ />
39
+ );
40
+ }
@@ -0,0 +1,95 @@
1
+ export interface CodeFile {
2
+ /** File path, shown as the tab label. */
3
+ path: string;
4
+ /** Monaco language id. */
5
+ language: string;
6
+ content: string;
7
+ /** Previous version; enables the diff view for this file. */
8
+ original?: string;
9
+ }
10
+
11
+ export type ProblemSeverity = 'error' | 'warning' | 'info';
12
+
13
+ export interface CodeProblem {
14
+ id: string;
15
+ severity: ProblemSeverity;
16
+ message: string;
17
+ /** Path of the file the problem belongs to. */
18
+ file: string;
19
+ line: number;
20
+ column?: number;
21
+ /** Tool that reported it, e.g. "tsc" or "schema". */
22
+ source?: string;
23
+ }
24
+
25
+ const handlerBefore = `import { listProjects } from './store';
26
+
27
+ export async function handler(req: Request) {
28
+ const projects = await listProjects();
29
+ return Response.json(projects);
30
+ }
31
+ `;
32
+
33
+ const handlerAfter = `import { listProjects } from './store';
34
+
35
+ export async function handler(req: Request) {
36
+ const limit = Number(new URL(req.url).searchParams.get('limit') ?? 20);
37
+ const projects = await listProjects({ limit });
38
+ return Response.json({ items: projects, limit });
39
+ }
40
+ `;
41
+
42
+ export const codeFiles: CodeFile[] = [
43
+ { path: 'src/handler.ts', language: 'typescript', content: handlerAfter, original: handlerBefore },
44
+ {
45
+ path: 'deploy.yaml',
46
+ language: 'yaml',
47
+ content: `name: projects-api
48
+ region: eu-west
49
+ replicas: 2
50
+ resources:
51
+ cpu: 500m
52
+ memory: 512Mi
53
+ `,
54
+ },
55
+ {
56
+ path: 'settings.json',
57
+ language: 'json',
58
+ content: `{
59
+ "timeoutMs": 30000,
60
+ "retries": 3,
61
+ "logLevel": "info"
62
+ }
63
+ `,
64
+ },
65
+ ];
66
+
67
+ export const codeProblems: CodeProblem[] = [
68
+ {
69
+ id: 'p1',
70
+ severity: 'error',
71
+ message: 'Expected 0 arguments, but got 1.',
72
+ file: 'src/handler.ts',
73
+ line: 5,
74
+ column: 43,
75
+ source: 'tsc',
76
+ },
77
+ {
78
+ id: 'p2',
79
+ severity: 'warning',
80
+ message: "'req' is declared but only read once; consider a typed query parser.",
81
+ file: 'src/handler.ts',
82
+ line: 3,
83
+ column: 31,
84
+ source: 'lint',
85
+ },
86
+ {
87
+ id: 'p3',
88
+ severity: 'info',
89
+ message: 'replicas: 2 is below the recommended minimum of 3 for production.',
90
+ file: 'deploy.yaml',
91
+ line: 3,
92
+ column: 1,
93
+ source: 'schema',
94
+ },
95
+ ];
@@ -0,0 +1,90 @@
1
+ import type { CodeEditorProps, Monaco } from '@gntik-ai/editor';
2
+ import type { CodePanelMarker } from './markers';
3
+ import type { CodeProblem } from './fixtures';
4
+
5
+ type Editor = Parameters<NonNullable<CodeEditorProps['onMount']>>[0];
6
+ const SEVERITY = { error: 8, warning: 4, info: 2 } as const;
7
+
8
+ /** A cached external-store snapshot for Monaco's asynchronously produced diagnostics. */
9
+ export function createMarkerStore() {
10
+ const models = new Map<string, ReturnType<Editor['getModel']>>();
11
+ const owners = new Map<string, Set<string>>();
12
+ const listeners = new Set<() => void>();
13
+ let api: Monaco | null = null;
14
+ let markers: readonly CodePanelMarker[] = [];
15
+ let snapshot: CodeProblem[] = [];
16
+ const refresh = () => {
17
+ if (!api?.editor.getModelMarkers) return;
18
+ const paths = new Map<string, string>();
19
+ for (const [path, model] of models) if (model?.uri) paths.set(model.uri.toString(), path);
20
+ const injectedOwners = new Set(markers.map((m) => m.owner));
21
+ const next: CodeProblem[] = [];
22
+ for (const marker of api.editor.getModelMarkers({})) {
23
+ const file = paths.get(marker.resource.toString());
24
+ if (!file || injectedOwners.has(marker.owner)) continue;
25
+ next.push({
26
+ id: `monaco:${marker.owner}:${file}:${marker.startLineNumber}:${marker.startColumn}:${next.length}`,
27
+ file,
28
+ line: marker.startLineNumber,
29
+ column: marker.startColumn,
30
+ message: marker.message,
31
+ severity: marker.severity === 8 ? 'error' : marker.severity === 4 ? 'warning' : 'info',
32
+ source: marker.source ?? marker.owner,
33
+ });
34
+ }
35
+ if (JSON.stringify(next) === JSON.stringify(snapshot)) return;
36
+ snapshot = next;
37
+ listeners.forEach((listener) => listener());
38
+ };
39
+ const clear = () => {
40
+ if (!api?.editor.setModelMarkers) return;
41
+ for (const [path, model] of models) {
42
+ if (!model || model.isDisposed?.()) continue;
43
+ for (const owner of owners.get(path) ?? []) api.editor.setModelMarkers(model, owner, []);
44
+ }
45
+ };
46
+ const apply = (next: readonly CodePanelMarker[]) => {
47
+ markers = next;
48
+ if (!api?.editor.setModelMarkers) return;
49
+ for (const [path, model] of models) {
50
+ if (!model || model.isDisposed?.()) continue;
51
+ const groups = new Map<string, CodePanelMarker[]>();
52
+ for (const marker of markers)
53
+ if (marker.file === path) groups.set(marker.owner, [...(groups.get(marker.owner) ?? []), marker]);
54
+ const previous = owners.get(path) ?? new Set<string>();
55
+ for (const owner of new Set([...previous, ...groups.keys()])) {
56
+ api.editor.setModelMarkers(
57
+ model,
58
+ owner,
59
+ (groups.get(owner) ?? []).map((marker) => ({
60
+ severity: SEVERITY[marker.severity],
61
+ message: marker.message,
62
+ source: marker.source ?? owner,
63
+ startLineNumber: marker.line,
64
+ startColumn: marker.column ?? 1,
65
+ endLineNumber: marker.endLine ?? marker.line,
66
+ endColumn: marker.endColumn ?? (marker.column ?? 1) + 1,
67
+ })),
68
+ );
69
+ }
70
+ owners.set(path, new Set(groups.keys()));
71
+ }
72
+ refresh();
73
+ };
74
+ return {
75
+ refresh,
76
+ clear,
77
+ apply,
78
+ mount(path: string, editor: Editor, monaco: Monaco) {
79
+ api = monaco;
80
+ models.set(path, editor.getModel());
81
+ },
82
+ getSnapshot: () => snapshot,
83
+ subscribe(listener: () => void) {
84
+ listeners.add(listener);
85
+ return () => {
86
+ listeners.delete(listener);
87
+ };
88
+ },
89
+ };
90
+ }
@@ -0,0 +1,62 @@
1
+ import { useEffect, useLayoutEffect, useRef, useState, useSyncExternalStore } from 'react';
2
+ import type { CodeEditorProps, Monaco } from '@gntik-ai/editor';
3
+ import type { CodeProblem } from './fixtures';
4
+ import { createMarkerStore } from './marker-store';
5
+
6
+ /** Consumer line marker. Use a distinct owner for each external diagnostics service. */
7
+ export interface CodePanelMarker extends CodeProblem {
8
+ owner: string;
9
+ endLine?: number;
10
+ endColumn?: number;
11
+ }
12
+
13
+ export type MonacoReady = (monaco: Monaco) => void | (() => void);
14
+ type Editor = Parameters<NonNullable<CodeEditorProps['onMount']>>[0];
15
+ export const NO_MARKERS: readonly CodePanelMarker[] = [];
16
+
17
+ /** Observe Monaco's public marker API; schemas and their workers remain consumer-owned. */
18
+ export function usePanelMarkers(
19
+ markers: readonly CodePanelMarker[],
20
+ onReady: MonacoReady | undefined,
21
+ enabled: boolean,
22
+ ) {
23
+ const [store] = useState(createMarkerStore);
24
+ const problems = useSyncExternalStore(store.subscribe, store.getSnapshot, store.getSnapshot);
25
+ const [monaco, setMonaco] = useState<Monaco | null>(null);
26
+ const [revision, setRevision] = useState(0);
27
+ const ready = useRef(onReady);
28
+ useLayoutEffect(() => {
29
+ ready.current = onReady;
30
+ });
31
+ useEffect(() => {
32
+ if (!monaco || !enabled) return;
33
+ const subscription = monaco.editor.onDidChangeMarkers?.(store.refresh);
34
+ const cleanup = ready.current?.(monaco);
35
+ store.refresh();
36
+ return () => {
37
+ subscription?.dispose();
38
+ cleanup?.();
39
+ store.clear();
40
+ };
41
+ }, [monaco, store, enabled]);
42
+ useEffect(() => {
43
+ if (enabled) store.apply(markers);
44
+ }, [store, markers, monaco, revision, enabled]);
45
+ const mount = (path: string, editor: Editor, api: Monaco) => {
46
+ store.mount(path, editor, api);
47
+ setMonaco(api);
48
+ setRevision((v) => v + 1);
49
+ };
50
+ return { problems: enabled ? problems : [], mount };
51
+ }
52
+
53
+ export function useValidity(errors: number, onChange: ((valid: boolean) => void) | undefined) {
54
+ const wasValid = useRef(true);
55
+ useEffect(() => {
56
+ const valid = errors === 0;
57
+ if (wasValid.current !== valid) {
58
+ wasValid.current = valid;
59
+ onChange?.(valid);
60
+ }
61
+ }, [errors, onChange]);
62
+ }