@manta-eu/react 0.7.0 → 0.8.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 (439) hide show
  1. package/dist/action-plan-changes/ActionPlanChangesTable.js +1 -1
  2. package/dist/action-plan-changes/build-change-tree.js.map +1 -1
  3. package/dist/ad-preview/AdPluralDisplay.js +1 -1
  4. package/dist/ad-preview/GoogleAdGroupAdSingularDisplay.js +1 -3
  5. package/dist/ad-preview/GoogleAdGroupAdSingularDisplay.js.map +1 -1
  6. package/dist/ad-preview/MetaAdPreview.js +1 -1
  7. package/dist/ad-preview/meta-ad-copy.d.ts.map +1 -1
  8. package/dist/ad-preview/meta-ad-model.js.map +1 -1
  9. package/dist/components/ErrorBoundary.d.ts.map +1 -1
  10. package/dist/components/ad-preview/business-avatar.d.ts.map +1 -1
  11. package/dist/components/ad-preview/business-identity.d.ts.map +1 -1
  12. package/dist/components/ad-preview/business-info.d.ts.map +1 -1
  13. package/dist/components/ad-preview/facebook/carousel.d.ts.map +1 -1
  14. package/dist/components/ad-preview/facebook/constants.d.ts.map +1 -1
  15. package/dist/components/ad-preview/facebook/header.js +1 -1
  16. package/dist/components/ad-preview/facebook/instream-reels.d.ts.map +1 -1
  17. package/dist/components/ad-preview/facebook/marketplace.d.ts.map +1 -1
  18. package/dist/components/ad-preview/google/search.js +1 -1
  19. package/dist/components/ad-preview/instagram/feed.js +1 -1
  20. package/dist/components/ad-preview/instagram/search-result.d.ts.map +1 -1
  21. package/dist/components/ad-preview/use-scroll-navigation.d.ts.map +1 -1
  22. package/dist/components/ai-elements/conversation.js +1 -1
  23. package/dist/components/badge/index.d.ts.map +1 -1
  24. package/dist/components/badge/index.js +1 -1
  25. package/dist/components/banner/index.d.ts.map +1 -1
  26. package/dist/components/branding/MantaGridAnimation.js +1 -1
  27. package/dist/components/breadcrumbs/index.js +1 -1
  28. package/dist/components/button/index.d.ts.map +1 -1
  29. package/dist/components/calendar/index.js +2 -2
  30. package/dist/components/card/index.d.ts.map +1 -1
  31. package/dist/components/chart/ForecastChart.d.ts +41 -0
  32. package/dist/components/chart/ForecastChart.d.ts.map +1 -0
  33. package/dist/components/chart/ForecastChart.js +110 -0
  34. package/dist/components/chart/ForecastChart.js.map +1 -0
  35. package/dist/components/chart/ForecastEventCard.d.ts +28 -0
  36. package/dist/components/chart/ForecastEventCard.d.ts.map +1 -0
  37. package/dist/components/chart/ForecastEventCard.js +56 -0
  38. package/dist/components/chart/ForecastEventCard.js.map +1 -0
  39. package/dist/components/chart/ForecastHoverCard.d.ts +23 -0
  40. package/dist/components/chart/ForecastHoverCard.d.ts.map +1 -0
  41. package/dist/components/chart/ForecastHoverCard.js +22 -0
  42. package/dist/components/chart/ForecastHoverCard.js.map +1 -0
  43. package/dist/components/chart/ForecastLegend.d.ts +33 -0
  44. package/dist/components/chart/ForecastLegend.d.ts.map +1 -0
  45. package/dist/components/chart/ForecastLegend.js +38 -0
  46. package/dist/components/chart/ForecastLegend.js.map +1 -0
  47. package/dist/components/chart/annotations.d.ts.map +1 -1
  48. package/dist/components/chart/chart-colors.d.ts.map +1 -1
  49. package/dist/components/chart/chart-schemas.d.ts +599 -599
  50. package/dist/components/chart/chart-schemas.d.ts.map +1 -1
  51. package/dist/components/chart/chart-schemas.js.map +1 -1
  52. package/dist/components/chart/chart.js +1 -1
  53. package/dist/components/chart/forecast-model.d.ts +70 -0
  54. package/dist/components/chart/forecast-model.d.ts.map +1 -0
  55. package/dist/components/chart/forecast-model.js +89 -0
  56. package/dist/components/chart/forecast-model.js.map +1 -0
  57. package/dist/components/chart/forecast.d.ts +62 -0
  58. package/dist/components/chart/forecast.d.ts.map +1 -0
  59. package/dist/components/chart/forecast.js +90 -0
  60. package/dist/components/chart/forecast.js.map +1 -0
  61. package/dist/components/chart/index.d.ts +3 -0
  62. package/dist/components/chart/index.d.ts.map +1 -1
  63. package/dist/components/chart/index.js +1 -0
  64. package/dist/components/chart/index.js.map +1 -1
  65. package/dist/components/chat/chat-input/index.d.ts +1 -1
  66. package/dist/components/chat/chat-input/index.js +1 -1
  67. package/dist/components/chat/chat-input-footer/index.js +1 -1
  68. package/dist/components/chat/chat-reasoning/index.js +1 -1
  69. package/dist/components/chat-view/Chat.js +1 -1
  70. package/dist/components/chat-view/FileMessagePart.js +1 -1
  71. package/dist/components/chat-view/GraphContextPanel.js +1 -1
  72. package/dist/components/chat-view/MessageItem.js +1 -1
  73. package/dist/components/command/index.d.ts +15 -15
  74. package/dist/components/command/index.d.ts.map +1 -1
  75. package/dist/components/command/index.js +1 -1
  76. package/dist/components/dropdown/index.js +1 -1
  77. package/dist/components/graph/AgentsGraphListRow.js +1 -1
  78. package/dist/components/input/ai-action-buttons.js +1 -1
  79. package/dist/components/input/input-date-range.js +1 -1
  80. package/dist/components/input/input-field.d.ts.map +1 -1
  81. package/dist/components/input/input-field.js +1 -1
  82. package/dist/components/input/textarea.d.ts.map +1 -1
  83. package/dist/components/input/textarea.js +2 -2
  84. package/dist/components/input-otp/index.d.ts +6 -6
  85. package/dist/components/input-otp/index.d.ts.map +1 -1
  86. package/dist/components/layouts/InstallPrompt.js +1 -1
  87. package/dist/components/layouts/KnowledgeGraphStartupGate.d.ts +1 -1
  88. package/dist/components/layouts/RouteLayout.js +1 -1
  89. package/dist/components/layouts/page/PageHeaderActions.js +1 -1
  90. package/dist/components/loader/index.d.ts.map +1 -1
  91. package/dist/components/manta-logo/index.d.ts.map +1 -1
  92. package/dist/components/modal/index.d.ts.map +1 -1
  93. package/dist/components/onboarding/SidebarSpotlight.js +1 -1
  94. package/dist/components/pill/index.d.ts.map +1 -1
  95. package/dist/components/planning/ActionPlanDetailView.js +1 -1
  96. package/dist/components/planning/ManualActionList.d.ts +1 -1
  97. package/dist/components/planning/PlanDetailFooter.js +1 -1
  98. package/dist/components/popover/index.d.ts +2 -1
  99. package/dist/components/popover/index.d.ts.map +1 -1
  100. package/dist/components/popover/index.js +2 -1
  101. package/dist/components/popover/index.js.map +1 -1
  102. package/dist/components/progress/index.d.ts.map +1 -1
  103. package/dist/components/radio/index.d.ts.map +1 -1
  104. package/dist/components/rdf-insights/CampaignPerformanceSummary.js +1 -1
  105. package/dist/components/rdf-insights/InsightCard.js +1 -1
  106. package/dist/components/rdf-insights/ProductProfitability.js +1 -1
  107. package/dist/components/rdf-insights/ProductSalesRanking.js +1 -1
  108. package/dist/components/rdf-insights/ProductVariantsTable.js +1 -1
  109. package/dist/components/rdf-insights/RoasBenchmark.js +1 -1
  110. package/dist/components/select/index.d.ts.map +1 -1
  111. package/dist/components/sheet/index.d.ts.map +1 -1
  112. package/dist/components/sidebar/company-picker.js +1 -1
  113. package/dist/components/sidebar/nav-menu.js +1 -1
  114. package/dist/components/skeleton/index.d.ts +4 -4
  115. package/dist/components/skeleton/index.d.ts.map +1 -1
  116. package/dist/components/status/index.d.ts.map +1 -1
  117. package/dist/components/table/index.d.ts.map +1 -1
  118. package/dist/components/table/index.js.map +1 -1
  119. package/dist/components/table/use-table-state.js.map +1 -1
  120. package/dist/components/table-skeleton/index.js +1 -1
  121. package/dist/components/tabs/index.d.ts.map +1 -1
  122. package/dist/components/thinking/index.d.ts.map +1 -1
  123. package/dist/components/toast/index.d.ts.map +1 -1
  124. package/dist/components/tool-invocation-card/DefaultResultDisplay.js +1 -1
  125. package/dist/components/tool-invocation-card/ToolOutputRenderer.js +1 -1
  126. package/dist/components/tree-multi-select/tree-multi-select-rows.js.map +1 -1
  127. package/dist/datastore-picker/DatastoreRow.js +1 -1
  128. package/dist/easing.d.ts.map +1 -1
  129. package/dist/entity-tree/EntityRelationTree.js +1 -1
  130. package/dist/explain-fact/EntityChip.js +1 -1
  131. package/dist/explain-fact/conclusion/ConclusionSubtitle.js +1 -1
  132. package/dist/explain-fact/inspector/InspectorBindings.js +1 -1
  133. package/dist/explain-fact/inspector/SupportsSection.js +1 -1
  134. package/dist/explain-fact/proof-tree/ProofRowContent.js +1 -1
  135. package/dist/explain-fact/proof-tree/ProofRowValue.js +1 -1
  136. package/dist/globals.css +64 -0
  137. package/dist/graph/GraphContextPanel.js +1 -1
  138. package/dist/graph/GraphControls.d.ts +1 -1
  139. package/dist/graph/GraphControls.d.ts.map +1 -1
  140. package/dist/graph/GraphControls.js +1 -1
  141. package/dist/graph/GraphErrorBoundary.d.ts +1 -1
  142. package/dist/graph/GraphErrorBoundary.d.ts.map +1 -1
  143. package/dist/graph/NodeContextMenu.d.ts +1 -1
  144. package/dist/graph/NodeContextMenu.d.ts.map +1 -1
  145. package/dist/graph/NodeContextMenu.js +1 -1
  146. package/dist/graph/NodeDetailPanel/PropertyDiffView.js +1 -1
  147. package/dist/graph/custom-nodes.d.ts +4 -4
  148. package/dist/graph/custom-nodes.d.ts.map +1 -1
  149. package/dist/graph/custom-nodes.js +1 -1
  150. package/dist/graph/graph-layout.js.map +1 -1
  151. package/dist/graph/graph-list-utils.js.map +1 -1
  152. package/dist/graph/graph-model.js.map +1 -1
  153. package/dist/graph/graph-store.js.map +1 -1
  154. package/dist/graph/nodes/AdsDailyReportTemplateView.d.ts +1 -1
  155. package/dist/graph/nodes/AdsDailyReportTemplateView.d.ts.map +1 -1
  156. package/dist/graph/nodes/AttioCallRecordingView.d.ts +1 -1
  157. package/dist/graph/nodes/AttioCallRecordingView.d.ts.map +1 -1
  158. package/dist/graph/nodes/AttioCompanyView.d.ts +1 -1
  159. package/dist/graph/nodes/AttioCompanyView.d.ts.map +1 -1
  160. package/dist/graph/nodes/AttioDealView.d.ts +1 -1
  161. package/dist/graph/nodes/AttioDealView.d.ts.map +1 -1
  162. package/dist/graph/nodes/AttioMeetingView.d.ts +1 -1
  163. package/dist/graph/nodes/AttioMeetingView.d.ts.map +1 -1
  164. package/dist/graph/nodes/AttioNoteView.d.ts +1 -1
  165. package/dist/graph/nodes/AttioNoteView.d.ts.map +1 -1
  166. package/dist/graph/nodes/AttioTaskView.d.ts +1 -1
  167. package/dist/graph/nodes/AttioTaskView.d.ts.map +1 -1
  168. package/dist/graph/nodes/BrandAssetAnalysisActionView.d.ts +1 -1
  169. package/dist/graph/nodes/BrandAssetAnalysisActionView.d.ts.map +1 -1
  170. package/dist/graph/nodes/BrandAssetAnalysisView.d.ts +1 -1
  171. package/dist/graph/nodes/BrandAssetAnalysisView.d.ts.map +1 -1
  172. package/dist/graph/nodes/BrandFontSuggestionView.d.ts +1 -1
  173. package/dist/graph/nodes/BrandFontSuggestionView.d.ts.map +1 -1
  174. package/dist/graph/nodes/BrandGuidelinesView.d.ts +1 -1
  175. package/dist/graph/nodes/BrandGuidelinesView.d.ts.map +1 -1
  176. package/dist/graph/nodes/ConnectedAccountCard.d.ts +1 -1
  177. package/dist/graph/nodes/ConnectedAccountCard.d.ts.map +1 -1
  178. package/dist/graph/nodes/CoresignalCompanyView.d.ts +1 -1
  179. package/dist/graph/nodes/CoresignalCompanyView.d.ts.map +1 -1
  180. package/dist/graph/nodes/CoresignalEmployeeView.d.ts +1 -1
  181. package/dist/graph/nodes/CoresignalEmployeeView.d.ts.map +1 -1
  182. package/dist/graph/nodes/CoresignalExperienceView.d.ts +1 -1
  183. package/dist/graph/nodes/CoresignalExperienceView.d.ts.map +1 -1
  184. package/dist/graph/nodes/CoresignalJobView.d.ts +1 -1
  185. package/dist/graph/nodes/CoresignalJobView.d.ts.map +1 -1
  186. package/dist/graph/nodes/CoresignalKeyExecutiveDepartureView.d.ts +1 -1
  187. package/dist/graph/nodes/CoresignalKeyExecutiveDepartureView.d.ts.map +1 -1
  188. package/dist/graph/nodes/EntityCardShell.d.ts +1 -1
  189. package/dist/graph/nodes/EntityCardShell.d.ts.map +1 -1
  190. package/dist/graph/nodes/Ga4DailyOverviewView.d.ts +1 -1
  191. package/dist/graph/nodes/Ga4DailyOverviewView.d.ts.map +1 -1
  192. package/dist/graph/nodes/Ga4FunnelEventCountView.d.ts +1 -1
  193. package/dist/graph/nodes/Ga4FunnelEventCountView.d.ts.map +1 -1
  194. package/dist/graph/nodes/Ga4TrafficSourceView.d.ts +1 -1
  195. package/dist/graph/nodes/Ga4TrafficSourceView.d.ts.map +1 -1
  196. package/dist/graph/nodes/GoogleAdGroupAdView.d.ts +1 -1
  197. package/dist/graph/nodes/GoogleAdGroupAdView.d.ts.map +1 -1
  198. package/dist/graph/nodes/GoogleAdGroupCriterionView.d.ts +1 -1
  199. package/dist/graph/nodes/GoogleAdGroupCriterionView.d.ts.map +1 -1
  200. package/dist/graph/nodes/GoogleAdGroupView.d.ts +1 -1
  201. package/dist/graph/nodes/GoogleAdGroupView.d.ts.map +1 -1
  202. package/dist/graph/nodes/GoogleCampaignBudgetView.d.ts +1 -1
  203. package/dist/graph/nodes/GoogleCampaignBudgetView.d.ts.map +1 -1
  204. package/dist/graph/nodes/GoogleCampaignCriterionView.d.ts +1 -1
  205. package/dist/graph/nodes/GoogleCampaignCriterionView.d.ts.map +1 -1
  206. package/dist/graph/nodes/GoogleCampaignInsightView.d.ts +1 -1
  207. package/dist/graph/nodes/GoogleCampaignInsightView.d.ts.map +1 -1
  208. package/dist/graph/nodes/GoogleCampaignView.d.ts +1 -1
  209. package/dist/graph/nodes/GoogleCampaignView.d.ts.map +1 -1
  210. package/dist/graph/nodes/GoogleCustomerClientView.d.ts +1 -1
  211. package/dist/graph/nodes/GoogleCustomerClientView.d.ts.map +1 -1
  212. package/dist/graph/nodes/GoogleCustomerView.d.ts +1 -1
  213. package/dist/graph/nodes/GoogleCustomerView.d.ts.map +1 -1
  214. package/dist/graph/nodes/GoogleSearchTermInsightView.d.ts +1 -1
  215. package/dist/graph/nodes/GoogleSearchTermInsightView.d.ts.map +1 -1
  216. package/dist/graph/nodes/LinkedinAdAccountView.d.ts +1 -1
  217. package/dist/graph/nodes/LinkedinAdAccountView.d.ts.map +1 -1
  218. package/dist/graph/nodes/MetaAdAccountActivityView.d.ts +1 -1
  219. package/dist/graph/nodes/MetaAdAccountActivityView.d.ts.map +1 -1
  220. package/dist/graph/nodes/MetaAdAccountView.d.ts +1 -1
  221. package/dist/graph/nodes/MetaAdAccountView.d.ts.map +1 -1
  222. package/dist/graph/nodes/MetaAdImageView.d.ts +1 -1
  223. package/dist/graph/nodes/MetaAdImageView.d.ts.map +1 -1
  224. package/dist/graph/nodes/MetaAdSetView.d.ts +1 -1
  225. package/dist/graph/nodes/MetaAdSetView.d.ts.map +1 -1
  226. package/dist/graph/nodes/MetaAdView.d.ts +1 -1
  227. package/dist/graph/nodes/MetaAdView.d.ts.map +1 -1
  228. package/dist/graph/nodes/MetaCampaignView.d.ts +1 -1
  229. package/dist/graph/nodes/MetaCampaignView.d.ts.map +1 -1
  230. package/dist/graph/nodes/MetaInsightView.d.ts +1 -1
  231. package/dist/graph/nodes/MetaInsightView.d.ts.map +1 -1
  232. package/dist/graph/nodes/RenderedTemplateView.d.ts +1 -1
  233. package/dist/graph/nodes/RenderedTemplateView.d.ts.map +1 -1
  234. package/dist/graph/nodes/SchemaActionView.d.ts +1 -1
  235. package/dist/graph/nodes/SchemaActionView.d.ts.map +1 -1
  236. package/dist/graph/nodes/ShopifyShopView.d.ts +1 -1
  237. package/dist/graph/nodes/ShopifyShopView.d.ts.map +1 -1
  238. package/dist/graph/nodes/SlackChannelView.d.ts +1 -1
  239. package/dist/graph/nodes/SlackChannelView.d.ts.map +1 -1
  240. package/dist/graph/nodes/SlackMessageView.d.ts +1 -1
  241. package/dist/graph/nodes/SlackMessageView.d.ts.map +1 -1
  242. package/dist/graph/nodes/SlackUserView.d.ts +1 -1
  243. package/dist/graph/nodes/SlackUserView.d.ts.map +1 -1
  244. package/dist/graph/nodes/SlackWorkspaceView.d.ts +1 -1
  245. package/dist/graph/nodes/SlackWorkspaceView.d.ts.map +1 -1
  246. package/dist/graph/nodes/attio-shared.d.ts +1 -1
  247. package/dist/graph/nodes/attio-shared.d.ts.map +1 -1
  248. package/dist/graph/nodes/attio-shared.js +1 -1
  249. package/dist/graph/nodes/brand-shared.d.ts.map +1 -1
  250. package/dist/graph/nodes/card-rows.js +1 -1
  251. package/dist/graph/nodes/google-campaign-utils.d.ts.map +1 -1
  252. package/dist/graph/nodes/insight-shared.d.ts +1 -1
  253. package/dist/graph/nodes/insight-shared.d.ts.map +1 -1
  254. package/dist/graph/special-nodes/BaseNode.d.ts +2 -2
  255. package/dist/graph/special-nodes/BaseNode.d.ts.map +1 -1
  256. package/dist/graph/special-nodes/BaseNode.js +1 -1
  257. package/dist/graph/special-nodes/DynamicNode.d.ts +1 -1
  258. package/dist/graph/special-nodes/DynamicNode.d.ts.map +1 -1
  259. package/dist/graph/special-nodes/EntityValueChip.js +1 -1
  260. package/dist/graph/special-nodes/GenericNode.d.ts +1 -1
  261. package/dist/graph/special-nodes/GenericNode.d.ts.map +1 -1
  262. package/dist/graph/special-nodes/GenericView.d.ts +1 -1
  263. package/dist/graph/special-nodes/GenericView.d.ts.map +1 -1
  264. package/dist/graph/special-nodes/NodeFrame.d.ts +1 -1
  265. package/dist/graph/special-nodes/NodeFrame.d.ts.map +1 -1
  266. package/dist/graph/special-nodes/NodeFrame.js +1 -1
  267. package/dist/graph/special-nodes/TypeSummaryNode.d.ts +1 -1
  268. package/dist/graph/special-nodes/TypeSummaryNode.d.ts.map +1 -1
  269. package/dist/graph/special-nodes/TypeSummaryNode.js +1 -1
  270. package/dist/graph/special-nodes/card-facts.js.map +1 -1
  271. package/dist/hooks/resolved-terms.d.ts +1 -0
  272. package/dist/hooks/resolved-terms.d.ts.map +1 -1
  273. package/dist/hooks/resolved-terms.js +2 -1
  274. package/dist/hooks/resolved-terms.js.map +1 -1
  275. package/dist/hooks/use-action-plans-list.d.ts.map +1 -1
  276. package/dist/hooks/use-action-plans-list.js.map +1 -1
  277. package/dist/hooks/use-activity-feed.js.map +1 -1
  278. package/dist/hooks/use-connection-problems.d.ts.map +1 -1
  279. package/dist/hooks/use-conversation-starters.d.ts +2 -2
  280. package/dist/hooks/use-entity-relations.d.ts.map +1 -1
  281. package/dist/hooks/use-entity.d.ts.map +1 -1
  282. package/dist/hooks/use-latest-rendered-template.d.ts.map +1 -1
  283. package/dist/hooks/use-manual-actions.d.ts.map +1 -1
  284. package/dist/hooks/use-manual-actions.js.map +1 -1
  285. package/dist/hooks/useActionGraph.d.ts.map +1 -1
  286. package/dist/hooks/useActionGraph.js.map +1 -1
  287. package/dist/hooks/useActionPlanDetail.d.ts +2 -2
  288. package/dist/hooks/useActionPlanDetail.d.ts.map +1 -1
  289. package/dist/hooks/useAuth.d.ts +2 -1
  290. package/dist/hooks/useAuth.d.ts.map +1 -1
  291. package/dist/hooks/useAuth.js +4 -1
  292. package/dist/hooks/useAuth.js.map +1 -1
  293. package/dist/hooks/useConversationGraphContext.js.map +1 -1
  294. package/dist/hooks/useConversations.js.map +1 -1
  295. package/dist/hooks/useDatastoreSelection.js.map +1 -1
  296. package/dist/hooks/useValidateActionPlan.d.ts.map +1 -1
  297. package/dist/lib/build-config.js.map +1 -1
  298. package/dist/lib/default-map.d.ts.map +1 -1
  299. package/dist/lib/default-map.js.map +1 -1
  300. package/dist/lib/merge-refs.d.ts.map +1 -1
  301. package/dist/lib/rdf/insights.js.map +1 -1
  302. package/dist/lib/structured-data/schema-converter.d.ts +2 -2
  303. package/dist/lib/structured-data/schema-converter.d.ts.map +1 -1
  304. package/dist/lib/structured-data/schema-converter.js.map +1 -1
  305. package/dist/lib/tanstack-query.js +1 -1
  306. package/dist/lib/tanstack-query.js.map +1 -1
  307. package/dist/lib/term-batcher.d.ts +3 -1
  308. package/dist/lib/term-batcher.d.ts.map +1 -1
  309. package/dist/lib/term-batcher.js +2 -2
  310. package/dist/lib/term-batcher.js.map +1 -1
  311. package/dist/lib/use-can-scroll.d.ts.map +1 -1
  312. package/dist/lib/use-color-palette.d.ts.map +1 -1
  313. package/dist/lib/use-toggle-set.js.map +1 -1
  314. package/dist/lib/utils.js +1 -1
  315. package/dist/ontology/OntologyTermText.js +1 -1
  316. package/dist/providers/ActiveChatProvider.d.ts +1 -1
  317. package/dist/providers/ActiveDatastoreProvider.js.map +1 -1
  318. package/dist/providers/AuthContext.d.ts +1 -0
  319. package/dist/providers/AuthContext.d.ts.map +1 -1
  320. package/dist/providers/AuthContext.js.map +1 -1
  321. package/dist/providers/ChatManagerProvider.js.map +1 -1
  322. package/dist/providers/commands/CommandContext.js +1 -1
  323. package/dist/routes/activity/components/ActivityTable.js +1 -1
  324. package/dist/routes/activity/detail/ActivityDetail.d.ts.map +1 -1
  325. package/dist/routes/activity/detail/ActivityDetail.js +1 -1
  326. package/dist/routes/activity/detail/ActivityStepsRail.js +1 -1
  327. package/dist/routes/activity/detail/ActivityTimeline.js +1 -1
  328. package/dist/routes/data-explorer/class-properties.js.map +1 -1
  329. package/dist/routes/data-explorer/class-relations.d.ts +2 -2
  330. package/dist/routes/data-explorer/components/DetailHeader.js +1 -1
  331. package/dist/routes/data-explorer/components/DetailHeader.js.map +1 -1
  332. package/dist/routes/data-explorer/components/SegmentBuilder.js +1 -1
  333. package/dist/routes/data-explorer/components/class-detail/ClassDetail.js +1 -1
  334. package/dist/routes/data-explorer/components/class-detail/CreateRecordAction.js +1 -1
  335. package/dist/routes/data-explorer/components/class-detail/Overview.js +1 -1
  336. package/dist/routes/data-explorer/components/ontology-coverage/CoverageNamespaceRail.js +1 -1
  337. package/dist/routes/data-explorer/components/ontology-coverage/CoverageSkeleton.js +1 -1
  338. package/dist/routes/data-explorer/components/record-detail/CreateAction.js +1 -1
  339. package/dist/routes/data-explorer/components/record-detail/RecordActions.d.ts.map +1 -1
  340. package/dist/routes/data-explorer/components/record-detail/RecordActions.js +12 -9
  341. package/dist/routes/data-explorer/components/record-detail/RecordActions.js.map +1 -1
  342. package/dist/routes/data-explorer/components/record-detail/RecordDetail.js +1 -1
  343. package/dist/routes/data-explorer/components/record-detail/RecordRefresh.d.ts +7 -0
  344. package/dist/routes/data-explorer/components/record-detail/RecordRefresh.d.ts.map +1 -0
  345. package/dist/routes/data-explorer/components/record-detail/RecordRefresh.js +104 -0
  346. package/dist/routes/data-explorer/components/record-detail/RecordRefresh.js.map +1 -0
  347. package/dist/routes/data-explorer/coverage.d.ts.map +1 -1
  348. package/dist/routes/data-explorer/sparql-client.js.map +1 -1
  349. package/dist/routes/datastores/components/DatastoreTableSkeleton.js +1 -1
  350. package/dist/routes/datastores/components/DatastoresToolbar.js +1 -1
  351. package/dist/routes/datastores/components/LinkUnlinkedDatastoreDialog.js +1 -1
  352. package/dist/routes/datastores/components/UnlinkedDatastoresPanel.js +1 -1
  353. package/dist/routes/datastores/hooks/useDatastoreColumns.d.ts +2 -2
  354. package/dist/routes/datastores/hooks/useDatastoreColumns.d.ts.map +1 -1
  355. package/dist/routes/datastores/hooks/useDatastoreColumns.js +2 -4
  356. package/dist/routes/datastores/hooks/useDatastoreColumns.js.map +1 -1
  357. package/dist/routes/datastores/index.js +1 -1
  358. package/dist/routes/integrations/catalog-shape.js.map +1 -1
  359. package/dist/routes/integrations/components/ConnectionRow.js +1 -1
  360. package/dist/routes/integrations/components/ProviderLogo.d.ts.map +1 -1
  361. package/dist/routes/integrations/components/connect-forms/DashConnectForm.js.map +1 -1
  362. package/dist/routes/integrations/components/connect-forms/MetaAdsConnectForm.js.map +1 -1
  363. package/dist/routes/integrations/components/connect-forms/MicrosoftAdsConnectForm.js.map +1 -1
  364. package/dist/routes/integrations/components/connect-forms/google-ads-account-tree.js.map +1 -1
  365. package/dist/routes/integrations/components/connect-forms/google-analytics-property-tree.js.map +1 -1
  366. package/dist/routes/integrations/types.d.ts.map +1 -1
  367. package/dist/routes/memories/components/ChangeScopeDialog.js +1 -1
  368. package/dist/routes/memories/components/ConflictMemoryCard.js +1 -1
  369. package/dist/routes/memories/components/ConsolidationReviewDialog.js +1 -1
  370. package/dist/routes/memories/components/LoadingSkeleton.js +1 -1
  371. package/dist/routes/memories/components/MemoriesFilters.js +1 -1
  372. package/dist/routes/memories/components/MemoriesTabPanel.js +1 -1
  373. package/dist/routes/memories/components/MemoryActions.js +1 -1
  374. package/dist/routes/memories/components/MemoryFields.js +1 -1
  375. package/dist/routes/memories/components/MemoryFormDialog.js +1 -1
  376. package/dist/routes/memories/expiry-utils.js.map +1 -1
  377. package/dist/routes/memories/hooks/useDuplicateDetection.js.map +1 -1
  378. package/dist/routes/memories/hooks/useLiveContext.d.ts.map +1 -1
  379. package/dist/routes/memories/hooks/useMemoryColumns.d.ts.map +1 -1
  380. package/dist/routes/memories/hooks/useMemoryColumns.js +1 -1
  381. package/dist/routes/memories/hooks/useMemoryTable.js.map +1 -1
  382. package/dist/routes/plans/components/ActionPlanPage.js +1 -1
  383. package/dist/routes/plans/components/ActionPlansFilters.js +1 -1
  384. package/dist/routes/plans/components/ActionPlansPage.js +1 -1
  385. package/dist/routes/plans/components/ActionPlansTableBody.js +1 -1
  386. package/dist/routes/plans/components/actionPlansTableConfig.d.ts +7 -7
  387. package/dist/routes/plans/components/actionPlansTableConfig.d.ts.map +1 -1
  388. package/dist/routes/plans/index.js +1 -1
  389. package/dist/routes/rules/components/RuleAffectedActionPlansSection.js +1 -1
  390. package/dist/routes/rules/components/RuleDetailsPage.js +1 -1
  391. package/dist/routes/rules/components/RuleProducersSection.js +1 -1
  392. package/dist/routes/rules/components/RuleSetup.js +1 -1
  393. package/dist/routes/rules/components/RulesOverviewPage.js +1 -1
  394. package/dist/routes/rules/components/datalog-editor/FactsPreview.js +1 -1
  395. package/dist/routes/rules/components/datalog-editor/SparqlQueryPanel.js +1 -1
  396. package/dist/routes/rules/components/rule-actionability.js.map +1 -1
  397. package/dist/rules/RuleNarrativeSegments.js +1 -1
  398. package/dist/rules/datalog-ast/DatalogAtomComponent.js +1 -1
  399. package/dist/rules/datalog-ast/DatalogBodyFormulaComponent.js +1 -1
  400. package/dist/rules/datalog-ast/DatalogExpressionRenderer.js +1 -1
  401. package/dist/rules/datalog-ast/DatalogTermComponent.js +1 -1
  402. package/dist/rules/datalog-cache.js.map +1 -1
  403. package/dist/rules/rule-narrative-format.d.ts.map +1 -1
  404. package/dist/rules/rule-narrative-renderer.js.map +1 -1
  405. package/dist/style.js +1 -1
  406. package/dist/templates/slack-to-markdown.js +1 -1
  407. package/package.json +14 -14
  408. package/src/components/badge/index.tsx +1 -1
  409. package/src/components/calendar/index.tsx +2 -2
  410. package/src/components/chart/ForecastChart.tsx +383 -0
  411. package/src/components/chart/ForecastEventCard.tsx +163 -0
  412. package/src/components/chart/ForecastHoverCard.tsx +73 -0
  413. package/src/components/chart/ForecastLegend.tsx +97 -0
  414. package/src/components/chart/forecast-model.ts +130 -0
  415. package/src/components/chart/forecast.ts +144 -0
  416. package/src/components/chart/index.tsx +3 -0
  417. package/src/components/input/input-field.tsx +1 -1
  418. package/src/components/input/textarea.tsx +1 -1
  419. package/src/components/popover/index.tsx +2 -1
  420. package/src/components/table/index.tsx +0 -1
  421. package/src/globals.css +2 -0
  422. package/src/hooks/resolved-terms.ts +6 -1
  423. package/src/hooks/useAuth.ts +5 -1
  424. package/src/lib/chat-types.ts +1 -1
  425. package/src/lib/tanstack-query.ts +2 -2
  426. package/src/lib/term-batcher.ts +3 -3
  427. package/src/lib/utils.ts +1 -1
  428. package/src/providers/AuthContext.ts +1 -0
  429. package/src/routes/data-explorer/components/DetailHeader.tsx +4 -4
  430. package/src/routes/data-explorer/components/record-detail/RecordActions.tsx +22 -16
  431. package/src/routes/data-explorer/components/record-detail/RecordRefresh.tsx +150 -0
  432. package/src/rules/datalog-ast/DatalogBodyFormulaComponent.tsx +1 -1
  433. package/src/rules/datalog-ast/DatalogTermComponent.tsx +1 -1
  434. package/src/shacl/shacl-form-types.ts +1 -1
  435. package/src/style.ts +1 -1
  436. package/src/templates/slack-to-markdown.ts +1 -1
  437. package/src/themes/manta-dark.css +2 -0
  438. package/src/themes/manta.css +2 -0
  439. package/src/themes/standard.css +2 -0
@@ -0,0 +1,163 @@
1
+ import { isPresent } from "@manta-eu/lib/present";
2
+ import { ArrowUpRight } from "lucide-react";
3
+ import type { FocusEvent, KeyboardEvent, ReactNode } from "react";
4
+ import type { ForecastEvent } from "./forecast";
5
+ import { PopoverArrow, PopoverContent } from "#components/popover/index";
6
+ import { cn } from "#style";
7
+
8
+ const eventLabels: Record<ForecastEvent["status"], string> = {
9
+ applied: "Applied",
10
+ waiting: "Waiting for your approval",
11
+ };
12
+
13
+ export function eventLabel(event: ForecastEvent): string {
14
+ return event.label ?? eventLabels[event.status];
15
+ }
16
+
17
+ type ForecastEventDotProps = {
18
+ event: ForecastEvent;
19
+ color: string;
20
+ cx?: number;
21
+ cy?: number;
22
+ active: boolean;
23
+ cardId: string;
24
+ onSelect?: (event: ForecastEvent) => void;
25
+ onShow: (cx: number, cy: number) => void;
26
+ onLeave: () => void;
27
+ onBlur: (next: EventTarget | null) => void;
28
+ };
29
+
30
+ /** A dot on a metric's line. With `onSelect` it acts on click or Enter; otherwise an `href` makes it a plain link. */
31
+ export function ForecastEventDot(props: ForecastEventDotProps) {
32
+ const { event, color, cx, cy, active, cardId, onSelect, onShow, onLeave, onBlur } = props;
33
+ if (cx === undefined || cy === undefined) {
34
+ return null;
35
+ }
36
+ const label = `${eventLabel(event)}: ${event.title}`;
37
+ const waiting = event.status === "waiting";
38
+ const circles = (
39
+ <>
40
+ <circle cx={cx} cy={cy} r={14} fill="transparent" />
41
+ <circle
42
+ cx={cx}
43
+ cy={cy}
44
+ r={10}
45
+ fill={color}
46
+ className={cn(
47
+ "opacity-0 transition-opacity group-hover/event:opacity-20 group-focus-visible/event:opacity-35",
48
+ active && "opacity-20",
49
+ )}
50
+ />
51
+ <circle
52
+ cx={cx}
53
+ cy={cy}
54
+ r={active ? 6.5 : 5}
55
+ fill={waiting ? "var(--color-card)" : color}
56
+ stroke={waiting ? color : "var(--color-card)"}
57
+ strokeWidth={2}
58
+ />
59
+ </>
60
+ );
61
+ const shared = {
62
+ "aria-label": label,
63
+ "aria-describedby": active ? cardId : undefined,
64
+ className: "group/event cursor-pointer outline-none",
65
+ onMouseEnter: () => onShow(cx, cy),
66
+ onMouseLeave: onLeave,
67
+ onFocus: () => onShow(cx, cy),
68
+ onBlur: (focusEvent: FocusEvent) => onBlur(focusEvent.relatedTarget),
69
+ };
70
+
71
+ if (onSelect === undefined && isPresent(event.href)) {
72
+ return (
73
+ <a href={event.href} {...shared}>
74
+ {circles}
75
+ </a>
76
+ );
77
+ }
78
+
79
+ if (onSelect === undefined) {
80
+ return (
81
+ <g role="img" tabIndex={0} {...shared} className="group/event outline-none">
82
+ {circles}
83
+ </g>
84
+ );
85
+ }
86
+
87
+ function handleKeyDown(keyEvent: KeyboardEvent<SVGGElement>) {
88
+ if (keyEvent.key === "Enter" || keyEvent.key === " ") {
89
+ keyEvent.preventDefault();
90
+ onSelect?.(event);
91
+ }
92
+ }
93
+
94
+ return (
95
+ <g role="button" tabIndex={0} {...shared} onClick={() => onSelect(event)} onKeyDown={handleKeyDown}>
96
+ {circles}
97
+ </g>
98
+ );
99
+ }
100
+
101
+ type ForecastEventCardProps = {
102
+ event: ForecastEvent;
103
+ id: string;
104
+ onSelect?: (event: ForecastEvent) => void;
105
+ onEnter: () => void;
106
+ onLeave: () => void;
107
+ onBlur: (next: EventTarget | null) => void;
108
+ };
109
+
110
+ /** The dark card over a dot: its label, title, value and, with an `href`, an "Open plan" link. */
111
+ export function ForecastEventCard(props: ForecastEventCardProps) {
112
+ const { event, id, onSelect, onEnter, onLeave, onBlur } = props;
113
+ const link: ReactNode = isPresent(event.href) ? (
114
+ <a
115
+ href={event.href}
116
+ onClick={(clickEvent) => {
117
+ if (onSelect) {
118
+ clickEvent.preventDefault();
119
+ onSelect(event);
120
+ }
121
+ }}
122
+ className="mt-1 inline-flex items-center gap-1 self-start typography-small underline underline-offset-2"
123
+ >
124
+ {event.linkLabel ?? "Open plan"}
125
+ <ArrowUpRight className="size-3.5" aria-hidden="true" />
126
+ </a>
127
+ ) : null;
128
+ return (
129
+ <PopoverContent
130
+ id={id}
131
+ role={isPresent(event.href) ? undefined : "tooltip"}
132
+ side="top"
133
+ sideOffset={12}
134
+ collisionPadding={8}
135
+ onOpenAutoFocus={(focusEvent) => focusEvent.preventDefault()}
136
+ onCloseAutoFocus={(focusEvent) => focusEvent.preventDefault()}
137
+ className={cn(
138
+ "flex w-max min-w-50 max-w-65 flex-col gap-1 rounded-md-v4 border-0 px-3.5 pt-2.5 pb-3",
139
+ "bg-inverse text-inverse-foreground shadow-xl ring-1 ring-inverse-foreground/10",
140
+ !isPresent(event.href) && "pointer-events-none",
141
+ )}
142
+ onMouseEnter={onEnter}
143
+ onMouseLeave={onLeave}
144
+ onBlur={(focusEvent) => onBlur(focusEvent.relatedTarget)}
145
+ >
146
+ <span className="typography-tiny opacity-70">{eventLabel(event)}</span>
147
+ <strong className="typography-body-medium">{event.title}</strong>
148
+ {isPresent(event.value) ? (
149
+ <span
150
+ className="typography-small-semibold tabular-nums"
151
+ style={{ color: "color-mix(in srgb, var(--color-accent-foreground) 55%, var(--color-inverse-foreground))" }}
152
+ >
153
+ {event.value}
154
+ {isPresent(event.valueNote) ? (
155
+ <small className="ml-1 typography-tiny opacity-70">{event.valueNote}</small>
156
+ ) : null}
157
+ </span>
158
+ ) : null}
159
+ {link}
160
+ <PopoverArrow className="fill-inverse" width={12} height={6} />
161
+ </PopoverContent>
162
+ );
163
+ }
@@ -0,0 +1,73 @@
1
+ import { isPresent } from "@manta-eu/lib/present";
2
+ import { plansAt, projectedKey, signedChange, type ForecastPlanShare } from "./forecast";
3
+ import { cn } from "#style";
4
+
5
+ export type ForecastHoverMetric = { key: string; label: string; withoutKey?: string; lowerIsBetter: boolean };
6
+
7
+ type ForecastHoverCardProps = {
8
+ metric: ForecastHoverMetric | undefined;
9
+ formatDetail: (value: number) => string;
10
+ changeLabel: string;
11
+ projectedLabel: string;
12
+ planShares: readonly ForecastPlanShare[];
13
+ active?: boolean;
14
+ label?: string | number;
15
+ payload?: { payload?: Record<string, unknown> }[];
16
+ };
17
+
18
+ /** The card for the line under the pointer: its figure and, when projected, the gap and the plans behind it. */
19
+ export function ForecastHoverCard(props: ForecastHoverCardProps) {
20
+ const { metric, formatDetail, changeLabel, projectedLabel, planShares, active, label, payload } = props;
21
+ const row = payload?.[0]?.payload;
22
+ const value = metric === undefined ? undefined : row?.[metric.key];
23
+ if (active !== true || row === undefined || metric === undefined || typeof value !== "number") {
24
+ return null;
25
+ }
26
+ const projected = row[projectedKey] === true;
27
+ const without = isPresent(metric.withoutKey) ? row[metric.withoutKey] : undefined;
28
+ const x = row.x;
29
+ function helps(change: number) {
30
+ return metric?.lowerIsBetter === true ? change <= 0 : change >= 0;
31
+ }
32
+ const plans =
33
+ projected && (typeof x === "string" || typeof x === "number") ? plansAt(planShares, x, metric.key).slice(0, 2) : [];
34
+ return (
35
+ <div className="min-w-50 max-w-75 rounded-md-v4 border border-default-border bg-card px-3 py-2.5 text-default-foreground shadow-xl">
36
+ <p className="mb-1.5 typography-tiny text-muted-foreground">
37
+ {label}
38
+ {projected ? ` · ${projectedLabel}` : ""}
39
+ </p>
40
+ <p className="flex items-baseline justify-between gap-4 typography-small text-muted-foreground">
41
+ <span>{metric.label}</span>
42
+ <strong className="typography-body-semibold tabular-nums text-default-foreground">{formatDetail(value)}</strong>
43
+ </p>
44
+ {projected && typeof without === "number" ? (
45
+ <p
46
+ className={cn(
47
+ "typography-small-medium tabular-nums",
48
+ helps(value - without) ? "text-accent-foreground" : "text-muted-foreground",
49
+ )}
50
+ >
51
+ {signedChange(value, without, formatDetail)} {changeLabel}
52
+ </p>
53
+ ) : null}
54
+ {isPresent(plans) ? (
55
+ <div className="mt-2 grid gap-0.5 border-t border-default-border pt-2">
56
+ {plans.map((plan) => (
57
+ <p key={plan.label} className="flex items-baseline justify-between gap-3 typography-tiny">
58
+ <span className="min-w-0">{plan.label}</span>
59
+ <strong
60
+ className={cn(
61
+ "flex-none typography-tiny-semibold tabular-nums",
62
+ helps(plan.value) ? "text-accent-foreground" : "text-muted-foreground",
63
+ )}
64
+ >
65
+ {signedChange(plan.value, 0, formatDetail)}
66
+ </strong>
67
+ </p>
68
+ ))}
69
+ </div>
70
+ ) : null}
71
+ </div>
72
+ );
73
+ }
@@ -0,0 +1,97 @@
1
+ import { cn } from "#style";
2
+
3
+ export type ForecastLegendItem = {
4
+ label: string;
5
+ color: string;
6
+ kind: "line" | "dotted-line" | "thin-line" | "fill" | "faint-fill";
7
+ };
8
+
9
+ type LegendSource = {
10
+ metrics: { label: string; color: string }[];
11
+ withoutLabels: string[];
12
+ /** The metrics with a `withoutPlans` line and the color their gain is shaded in. */
13
+ gains: { metric: string; color: string }[];
14
+ gainLabel: string;
15
+ betweenLabels: string[];
16
+ firstColor: string;
17
+ withoutColor: string;
18
+ hasProjection: boolean;
19
+ legendLabels?: { historic?: string; projected?: string };
20
+ };
21
+
22
+ /** Two metrics are named per line; a single metric is split into its historic and projected parts instead. */
23
+ export function forecastLegendItems(source: LegendSource): ForecastLegendItem[] {
24
+ const {
25
+ metrics,
26
+ withoutLabels,
27
+ gains,
28
+ gainLabel,
29
+ betweenLabels,
30
+ firstColor,
31
+ withoutColor,
32
+ hasProjection,
33
+ legendLabels,
34
+ } = source;
35
+ const withoutItems = [...new Set(withoutLabels)].map(
36
+ (label): ForecastLegendItem => ({ label, color: withoutColor, kind: "thin-line" }),
37
+ );
38
+ const oneGainColor = new Set(gains.map((gain) => gain.color)).size === 1;
39
+ const gainItems = (oneGainColor ? gains.slice(0, 1) : gains).map(
40
+ (gain): ForecastLegendItem => ({
41
+ label: oneGainColor ? gainLabel : `${gainLabel} · ${gain.metric}`,
42
+ color: gain.color,
43
+ kind: "fill",
44
+ }),
45
+ );
46
+ const betweenItems = betweenLabels.map(
47
+ (label): ForecastLegendItem => ({ label, color: firstColor, kind: "faint-fill" }),
48
+ );
49
+ if (metrics.length > 1) {
50
+ return [
51
+ ...metrics.map((metric): ForecastLegendItem => ({ label: metric.label, color: metric.color, kind: "line" })),
52
+ ...betweenItems,
53
+ ...gainItems,
54
+ ...withoutItems,
55
+ ];
56
+ }
57
+ return [
58
+ { label: legendLabels?.historic ?? "Historic results", color: firstColor, kind: "line" },
59
+ ...(hasProjection
60
+ ? [{ label: legendLabels?.projected ?? "Projected results", color: firstColor, kind: "dotted-line" as const }]
61
+ : []),
62
+ ...withoutItems,
63
+ ...gainItems,
64
+ ...betweenItems,
65
+ ];
66
+ }
67
+
68
+ export function ForecastLegend(props: { items: ForecastLegendItem[] }) {
69
+ const { items } = props;
70
+ return (
71
+ <ul className="m-0 mb-3 flex list-none flex-wrap gap-x-6 gap-y-2 p-0 typography-small text-muted-foreground">
72
+ {items.map((item) => (
73
+ <li key={item.label} className="inline-flex items-center gap-2">
74
+ {item.kind === "fill" || item.kind === "faint-fill" ? (
75
+ <span
76
+ className="h-2.5 w-4 rounded-xs-v4"
77
+ style={{
78
+ background: `color-mix(in srgb, ${item.color} ${item.kind === "fill" ? 42 : 10}%, transparent)`,
79
+ }}
80
+ />
81
+ ) : (
82
+ <span
83
+ className={cn(
84
+ "w-5 rounded-sm",
85
+ item.kind === "line" && "border-t-[2.5px]",
86
+ item.kind === "dotted-line" && "border-t-[3px] border-dotted",
87
+ item.kind === "thin-line" && "border-t-2",
88
+ )}
89
+ style={{ borderColor: item.color }}
90
+ />
91
+ )}
92
+ {item.label}
93
+ </li>
94
+ ))}
95
+ </ul>
96
+ );
97
+ }
@@ -0,0 +1,130 @@
1
+ import { isPresent } from "@manta-eu/lib/present";
2
+ import type { ChartConfig } from "./chart";
3
+ import { chartColorAt } from "./chart-colors";
4
+ import { forecastDomain, partKey, splitAtToday, type ForecastPart, type ForecastRange } from "./forecast";
5
+ import type { ForecastHoverMetric } from "./ForecastHoverCard";
6
+ import { forecastLegendItems } from "./ForecastLegend";
7
+
8
+ export type ForecastMetric = {
9
+ key: string;
10
+ label: string;
11
+ color?: string;
12
+ /** For costs: a drop with the plans shows as a gain in the hover card. */
13
+ lowerIsBetter?: boolean;
14
+ /** The same metric if the plans are not approved; the gap between the two is shaded as what the plans add. */
15
+ withoutPlans?: { key: string; label: string };
16
+ };
17
+
18
+ export type ForecastBetween = { from: string; to: string; label: string };
19
+
20
+ export const forecastParts = ["past", "ahead"] as const;
21
+ export const withoutColor = "color-mix(in srgb, var(--color-muted-foreground) 82%, var(--color-card))";
22
+ const metricColors = [
23
+ "var(--color-accent-foreground)",
24
+ "color-mix(in srgb, var(--color-accent-foreground) 45%, var(--color-muted-foreground))",
25
+ ];
26
+
27
+ export function metricColor(metric: ForecastMetric, index: number): string {
28
+ return metric.color ?? metricColors[index] ?? chartColorAt(index);
29
+ }
30
+
31
+ export function gainName(index: number): string {
32
+ return `gain-${index}`;
33
+ }
34
+
35
+ export function betweenName(index: number): string {
36
+ return `between-${index}`;
37
+ }
38
+
39
+ type ModelInput = {
40
+ data: Record<string, unknown>[];
41
+ today?: string | number;
42
+ metrics: ForecastMetric[];
43
+ between: ForecastBetween[];
44
+ goal?: { value: number };
45
+ gainLabel: string;
46
+ legendLabels?: { historic?: string; projected?: string };
47
+ };
48
+
49
+ /** Everything the chart draws, derived once from its props: split rows, axis, fades, legend and hover metrics. */
50
+ export function buildForecastModel(input: ModelInput) {
51
+ const { data, today, metrics, between, goal, gainLabel, legendLabels } = input;
52
+ const overlay = metrics.length > 1;
53
+ const todayIndex = today === undefined ? -1 : data.findIndex((row) => row.x === today);
54
+ const withPlans = metrics.flatMap((metric, index) =>
55
+ isPresent(metric.withoutPlans) ? [{ metric, index, without: metric.withoutPlans }] : [],
56
+ );
57
+ const ranges: Record<string, ForecastRange> = {
58
+ ...Object.fromEntries(
59
+ withPlans.map((entry) => [gainName(entry.index), { from: entry.without.key, to: entry.metric.key }]),
60
+ ),
61
+ ...Object.fromEntries(between.map((range, index) => [betweenName(index), range])),
62
+ };
63
+ const lineKeys = [...metrics.map((metric) => metric.key), ...withPlans.map((entry) => entry.without.key)];
64
+ const emptyKeys = lineKeys.filter((key) => !data.some((row) => typeof row[key] === "number"));
65
+ const rows = splitAtToday(data, todayIndex, lineKeys, ranges);
66
+ const values = data.flatMap((row) => lineKeys.map((key) => row[key])).filter((value) => typeof value === "number");
67
+ const { domain, ticks } = forecastDomain(isPresent(goal) ? [...values, goal.value] : values);
68
+
69
+ function meanOf(key: string) {
70
+ const numbers = data.map((row) => row[key]).filter((value) => typeof value === "number");
71
+ return numbers.reduce((sum, value) => sum + value, 0) / Math.max(numbers.length, 1);
72
+ }
73
+ const lowestIndex = metrics.reduce(
74
+ (lowest, metric, index) => (meanOf(metric.key) < meanOf(metrics[lowest]?.key ?? "") ? index : lowest),
75
+ 0,
76
+ );
77
+ const lowestMetric = metrics[lowestIndex];
78
+ const onlyWithout = withPlans[0]?.without;
79
+ function drawsIn(key: string, part: ForecastPart) {
80
+ return rows.filter((row) => typeof row[partKey(key, part)] === "number").length > 1;
81
+ }
82
+ const fadeKeys = forecastParts.flatMap((part) => {
83
+ const key = overlay
84
+ ? lowestMetric?.key
85
+ : onlyWithout && drawsIn(onlyWithout.key, part)
86
+ ? onlyWithout.key
87
+ : metrics[0]?.key;
88
+ return key === undefined ? [] : [{ part, key }];
89
+ });
90
+ const firstColor = metrics[0] ? metricColor(metrics[0], 0) : withoutColor;
91
+
92
+ return {
93
+ emptyKeys,
94
+ todayMissing: today !== undefined && todayIndex < 0 && isPresent(data),
95
+ overlay,
96
+ todayIndex,
97
+ withPlans,
98
+ rows,
99
+ domain,
100
+ ticks,
101
+ fadeKeys,
102
+ fadeColor: overlay && lowestMetric ? metricColor(lowestMetric, lowestIndex) : withoutColor,
103
+ firstColor,
104
+ config: Object.fromEntries(
105
+ [...metrics, ...withPlans.map((entry) => entry.without)].map((line) => [line.key, { label: line.label }]),
106
+ ) satisfies ChartConfig,
107
+ hoverMetrics: metrics.map(
108
+ (metric): ForecastHoverMetric => ({
109
+ key: metric.key,
110
+ label: metric.label,
111
+ lowerIsBetter: metric.lowerIsBetter === true,
112
+ ...(isPresent(metric.withoutPlans) ? { withoutKey: metric.withoutPlans.key } : {}),
113
+ }),
114
+ ),
115
+ legendItems: forecastLegendItems({
116
+ metrics: metrics.map((metric, index) => ({ label: metric.label, color: metricColor(metric, index) })),
117
+ withoutLabels: withPlans.map((entry) => entry.without.label),
118
+ gains: withPlans.map((entry) => ({
119
+ metric: entry.metric.label,
120
+ color: metricColor(entry.metric, entry.index),
121
+ })),
122
+ gainLabel,
123
+ betweenLabels: between.map((range) => range.label),
124
+ firstColor,
125
+ withoutColor,
126
+ hasProjection: todayIndex >= 0,
127
+ ...(legendLabels ? { legendLabels } : {}),
128
+ }),
129
+ };
130
+ }
@@ -0,0 +1,144 @@
1
+ import { isPresent } from "@manta-eu/lib/present";
2
+
3
+ export type ForecastPart = "past" | "ahead";
4
+
5
+ export type ForecastRange = { from: string; to: string };
6
+
7
+ export function partKey(key: string, part: ForecastPart): string {
8
+ return `${key}~${part}`;
9
+ }
10
+
11
+ export function rangeKey(name: string, part: ForecastPart): string {
12
+ return `${name}~range~${part}`;
13
+ }
14
+
15
+ export const projectedKey = "~projected";
16
+
17
+ function rangeOf(row: Record<string, unknown>, range: ForecastRange): [number, number] | null {
18
+ const from = row[range.from];
19
+ const to = row[range.to];
20
+ return typeof from === "number" && typeof to === "number" ? [Math.min(from, to), Math.max(from, to)] : null;
21
+ }
22
+
23
+ /** Splits each line and range at Today: the past part runs up to and including Today, the part ahead starts there. */
24
+ export function splitAtToday(
25
+ rows: readonly Record<string, unknown>[],
26
+ todayIndex: number,
27
+ lineKeys: readonly string[],
28
+ ranges: Readonly<Record<string, ForecastRange>>,
29
+ ): Record<string, unknown>[] {
30
+ return rows.map((row, index) => {
31
+ const inPast = todayIndex < 0 || index <= todayIndex;
32
+ const ahead = todayIndex >= 0 && index >= todayIndex;
33
+ const split: Record<string, unknown> = { ...row, [projectedKey]: todayIndex >= 0 && index > todayIndex };
34
+ lineKeys.forEach((key) => {
35
+ split[partKey(key, "past")] = inPast ? (row[key] ?? null) : null;
36
+ split[partKey(key, "ahead")] = ahead ? (row[key] ?? null) : null;
37
+ });
38
+ Object.entries(ranges).forEach(([name, range]) => {
39
+ const value = rangeOf(row, range);
40
+ split[rangeKey(name, "past")] = inPast ? value : null;
41
+ split[rangeKey(name, "ahead")] = ahead ? value : null;
42
+ });
43
+ return split;
44
+ });
45
+ }
46
+
47
+ function niceStep(rough: number): number {
48
+ const magnitude = 10 ** Math.floor(Math.log10(rough));
49
+ const step = [1, 2, 2.5, 5, 10].find((multiple) => multiple * magnitude >= rough) ?? 10;
50
+ return step * magnitude;
51
+ }
52
+
53
+ /** A y range that hugs the values with a little air and round ticks, never dipping below zero for positive data. */
54
+ export function forecastDomain(values: number[], tickCount = 5): { domain: [number, number]; ticks: number[] } {
55
+ if (!isPresent(values)) {
56
+ return { domain: [0, 1], ticks: [0, 1] };
57
+ }
58
+ const min = Math.min(...values);
59
+ const max = Math.max(...values);
60
+ const spread = max - min || Math.abs(max) || 1;
61
+ const step = niceStep((spread * 1.2) / (tickCount - 1));
62
+ const low = Math.floor((min - spread * 0.1) / step) * step;
63
+ const high = Math.ceil((max + spread * 0.1) / step) * step;
64
+ const domainLow = min >= 0 ? Math.max(0, low) : low;
65
+ const ticks = Array.from({ length: Math.round((high - domainLow) / step) + 1 }, (_, index) =>
66
+ Number((domainLow + index * step).toFixed(10)),
67
+ );
68
+ return { domain: [domainLow, high], ticks };
69
+ }
70
+
71
+ const compact = new Intl.NumberFormat("en-US", { notation: "compact", maximumFractionDigits: 1 });
72
+
73
+ export function formatCompact(value: number): string {
74
+ return compact.format(value);
75
+ }
76
+
77
+ const whole = new Intl.NumberFormat("en-US", { maximumFractionDigits: 0 });
78
+
79
+ export function formatWhole(value: number): string {
80
+ return whole.format(value);
81
+ }
82
+
83
+ /** "+$2,664 with the plans": the signed gap between a metric and its line without plans. */
84
+ export function signedChange(value: number, without: number, format: (value: number) => string): string {
85
+ const change = value - without;
86
+ return `${change < 0 ? "-" : "+"}${format(Math.abs(change))}`;
87
+ }
88
+
89
+ /** The margin and x-axis height the chart passes to recharts; the plot geometry below is derived from them. */
90
+ export const forecastMargin = { top: 24, right: 12, left: 8, bottom: 0 };
91
+ export const forecastXAxisHeight = 30;
92
+
93
+ /** Where the plot area sits inside a chart of this height, so a pointer's y maps back to a value. */
94
+ export function plotGeometry(chartHeight: number): { top: number; height: number } {
95
+ return {
96
+ top: forecastMargin.top,
97
+ height: chartHeight - forecastMargin.top - forecastMargin.bottom - forecastXAxisHeight,
98
+ };
99
+ }
100
+
101
+ /** The value at a pointer's height in the plot, with `domain[0]` at its bottom and `domain[1]` at its top. */
102
+ export function valueAtY(y: number, plotTop: number, plotHeight: number, domain: [number, number]): number {
103
+ return domain[1] - ((y - plotTop) / plotHeight) * (domain[1] - domain[0]);
104
+ }
105
+
106
+ /** The metric whose line passes closest to a value at one point: the hover card follows that line. */
107
+ export function nearestMetric(
108
+ row: Record<string, unknown>,
109
+ keys: readonly string[],
110
+ value: number,
111
+ ): string | undefined {
112
+ const distances = keys.flatMap((key) => {
113
+ const metricValue = row[key];
114
+ return typeof metricValue === "number" ? [{ key, distance: Math.abs(metricValue - value) }] : [];
115
+ });
116
+ return distances.reduce<{ key: string; distance: number } | undefined>(
117
+ (nearest, candidate) => (nearest === undefined || candidate.distance < nearest.distance ? candidate : nearest),
118
+ undefined,
119
+ )?.key;
120
+ }
121
+
122
+ /** An action already applied (a filled dot) or a plan waiting for approval (a hollow dot), on a metric's line. */
123
+ export type ForecastEvent = {
124
+ x: string | number;
125
+ metric: string;
126
+ status: "applied" | "waiting";
127
+ title: string;
128
+ /** The small line above the title; defaults to "Applied" or "Waiting for your approval". */
129
+ label?: string;
130
+ value?: string;
131
+ valueNote?: string;
132
+ /** Rendered as a plain link in the card (and on the dot when the chart has no `onEventSelect`). */
133
+ href?: string;
134
+ linkLabel?: string;
135
+ };
136
+
137
+ export type ForecastPointPlan = { label: string; value: number };
138
+
139
+ /** The plans behind one metric's projected value at one point, as the chart's data carries them. */
140
+ export type ForecastPlanShare = { x: string | number; metric: string; plans: ForecastPointPlan[] };
141
+
142
+ export function plansAt(shares: readonly ForecastPlanShare[], x: string | number, metric: string): ForecastPointPlan[] {
143
+ return shares.find((share) => share.x === x && share.metric === metric)?.plans ?? [];
144
+ }
@@ -19,6 +19,9 @@ export { ChartFrame, type ChartFrameProps } from "./ChartFrame";
19
19
  export { AreaChart, type AreaChartProps } from "./AreaChart";
20
20
  export { BarChart, type BarChartProps } from "./BarChart";
21
21
  export { ComposedChart, type ComposedChartProps } from "./ComposedChart";
22
+ export { ForecastChart, type ForecastChartProps } from "./ForecastChart";
23
+ export type { ForecastBetween, ForecastMetric } from "./forecast-model";
24
+ export type { ForecastEvent, ForecastPlanShare, ForecastPointPlan } from "./forecast";
22
25
  export { LineChart, type LineChartProps } from "./LineChart";
23
26
  export { PieChart, type PieChartProps } from "./PieChart";
24
27
  export { RadarChart, type RadarChartProps } from "./RadarChart";
@@ -170,7 +170,7 @@ export const Input = React.forwardRef<HTMLInputElement, InputArgs>(function Inpu
170
170
  inputRef.current.value = next;
171
171
  setInternalCount(next.length);
172
172
  onChange?.({ target: inputRef.current } as ChangeEvent<HTMLInputElement>);
173
- // eslint-disable-next-line no-useless-catch
173
+ // oxlint-disable-next-line no-useless-catch
174
174
  } catch (error) {
175
175
  throw error;
176
176
  } finally {
@@ -178,7 +178,7 @@ export const Textarea = React.forwardRef<HTMLTextAreaElement, TextareaArgs>(func
178
178
  textareaRef.current.value = next;
179
179
  setInternalCount(next.length);
180
180
  onChange?.({ target: textareaRef.current } as ChangeEvent<HTMLTextAreaElement>);
181
- // eslint-disable-next-line no-useless-catch
181
+ // oxlint-disable-next-line no-useless-catch
182
182
  } catch (error) {
183
183
  throw error;
184
184
  } finally {
@@ -8,6 +8,7 @@ const Popover = PopoverPrimitive.Root;
8
8
  const PopoverTrigger = PopoverPrimitive.Trigger;
9
9
  const PopoverAnchor = PopoverPrimitive.Anchor;
10
10
  const PopoverClose = PopoverPrimitive.Close;
11
+ const PopoverArrow = PopoverPrimitive.Arrow;
11
12
 
12
13
  const PopoverContent = React.forwardRef<
13
14
  React.ElementRef<typeof PopoverPrimitive.Content>,
@@ -81,4 +82,4 @@ const PopoverItem = React.forwardRef<HTMLButtonElement, PopoverItemProps>((props
81
82
  });
82
83
  PopoverItem.displayName = "PopoverItem";
83
84
 
84
- export { Popover, PopoverAnchor, PopoverClose, PopoverContent, PopoverItem, PopoverTrigger };
85
+ export { Popover, PopoverAnchor, PopoverArrow, PopoverClose, PopoverContent, PopoverItem, PopoverTrigger };
@@ -120,7 +120,6 @@ export enum SortingHandlerPlacement {
120
120
  }
121
121
 
122
122
  declare module "@tanstack/react-table" {
123
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
124
123
  interface ColumnMeta<TData, TValue> {
125
124
  /**
126
125
  * Placement of the sorting handler relative to the cell header
package/src/globals.css CHANGED
@@ -381,6 +381,8 @@
381
381
  --color-rank-3: #ffe4d6;
382
382
 
383
383
  --color-default-foreground: var(--color-neutral-900);
384
+ --color-inverse: var(--color-neutral-900);
385
+ --color-inverse-foreground: #ffffff;
384
386
  --color-body-foreground: rgba(23, 23, 23, 0.85);
385
387
  --color-muted-foreground: var(--color-neutral-500);
386
388
  --color-disabled-foreground: var(--color-neutral-400);