@manta-eu/react 0.2.0 → 0.3.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 (324) hide show
  1. package/dist/components/channel-icon/index.d.ts +1 -0
  2. package/dist/components/channel-icon/index.d.ts.map +1 -1
  3. package/dist/components/channel-icon/index.js +1 -1
  4. package/dist/components/channel-icon/index.js.map +1 -1
  5. package/dist/components/datastore-management/tree.d.ts +1 -1
  6. package/dist/components/datastore-management/tree.d.ts.map +1 -1
  7. package/dist/components/datastore-management/tree.js +5 -5
  8. package/dist/components/datastore-management/tree.js.map +1 -1
  9. package/dist/components/explain-fact/ExplainFact.js +3 -3
  10. package/dist/components/explain-fact/ExplainFact.js.map +1 -1
  11. package/dist/components/planning/ActioningView.d.ts +1 -2
  12. package/dist/components/planning/ActioningView.d.ts.map +1 -1
  13. package/dist/components/planning/ActioningView.js +19 -44
  14. package/dist/components/planning/ActioningView.js.map +1 -1
  15. package/dist/components/planning/ManualActionCard.d.ts +4 -0
  16. package/dist/components/planning/ManualActionCard.d.ts.map +1 -1
  17. package/dist/components/planning/ManualActionCard.js +7 -5
  18. package/dist/components/planning/ManualActionCard.js.map +1 -1
  19. package/dist/components/planning/ManualActionList.d.ts +4 -0
  20. package/dist/components/planning/ManualActionList.d.ts.map +1 -1
  21. package/dist/components/planning/ManualActionList.js +8 -2
  22. package/dist/components/planning/ManualActionList.js.map +1 -1
  23. package/dist/components/planning/actioning-view-utils.d.ts +9 -0
  24. package/dist/components/planning/actioning-view-utils.d.ts.map +1 -1
  25. package/dist/components/planning/actioning-view-utils.js +19 -1
  26. package/dist/components/planning/actioning-view-utils.js.map +1 -1
  27. package/dist/components/planning/plan-detail-utils.d.ts.map +1 -1
  28. package/dist/components/planning/plan-detail-utils.js +2 -0
  29. package/dist/components/planning/plan-detail-utils.js.map +1 -1
  30. package/dist/components/tool-invocation-card/ListRulesResultDisplay.d.ts +2 -2
  31. package/dist/components/tool-invocation-card/ListRulesResultDisplay.d.ts.map +1 -1
  32. package/dist/components/tool-invocation-card/ToolOutputRenderer.d.ts.map +1 -1
  33. package/dist/components/tool-invocation-card/ToolOutputRenderer.js +7 -4
  34. package/dist/components/tool-invocation-card/ToolOutputRenderer.js.map +1 -1
  35. package/dist/components/tool-invocation-card/types.d.ts +5 -5
  36. package/dist/components/tool-invocation-card/types.d.ts.map +1 -1
  37. package/dist/components/tool-invocation-card/types.js +5 -5
  38. package/dist/components/tool-invocation-card/types.js.map +1 -1
  39. package/dist/components/tooltip/index.d.ts +7 -0
  40. package/dist/components/tooltip/index.d.ts.map +1 -1
  41. package/dist/components/tooltip/index.js +10 -1
  42. package/dist/components/tooltip/index.js.map +1 -1
  43. package/dist/explain-fact/rule-presentation.js +2 -2
  44. package/dist/explain-fact/rule-presentation.js.map +1 -1
  45. package/dist/explain-fact/tree-model.js +2 -2
  46. package/dist/explain-fact/tree-model.js.map +1 -1
  47. package/dist/globals.css +19 -6
  48. package/dist/graph/entity-link.d.ts +14 -0
  49. package/dist/graph/entity-link.d.ts.map +1 -0
  50. package/dist/graph/entity-link.js +12 -0
  51. package/dist/graph/entity-link.js.map +1 -0
  52. package/dist/graph/graph-list-utils.d.ts +1 -0
  53. package/dist/graph/graph-list-utils.d.ts.map +1 -1
  54. package/dist/graph/graph-list-utils.js +1 -0
  55. package/dist/graph/graph-list-utils.js.map +1 -1
  56. package/dist/graph/graph-model.d.ts.map +1 -1
  57. package/dist/graph/graph-model.js +14 -5
  58. package/dist/graph/graph-model.js.map +1 -1
  59. package/dist/graph/nodes/BrandAssetAnalysisView.d.ts.map +1 -1
  60. package/dist/graph/nodes/BrandAssetAnalysisView.js +2 -1
  61. package/dist/graph/nodes/BrandAssetAnalysisView.js.map +1 -1
  62. package/dist/graph/nodes/BrandFontSuggestionView.d.ts.map +1 -1
  63. package/dist/graph/nodes/BrandFontSuggestionView.js +2 -1
  64. package/dist/graph/nodes/BrandFontSuggestionView.js.map +1 -1
  65. package/dist/graph/nodes/BrandGuidelinesView.js +1 -1
  66. package/dist/graph/nodes/BrandGuidelinesView.js.map +1 -1
  67. package/dist/graph/nodes/NodePropertyTable.d.ts +4 -2
  68. package/dist/graph/nodes/NodePropertyTable.d.ts.map +1 -1
  69. package/dist/graph/nodes/NodePropertyTable.js +12 -59
  70. package/dist/graph/nodes/NodePropertyTable.js.map +1 -1
  71. package/dist/graph/nodes/node-property-row.d.ts +30 -0
  72. package/dist/graph/nodes/node-property-row.d.ts.map +1 -0
  73. package/dist/graph/nodes/node-property-row.js +35 -0
  74. package/dist/graph/nodes/node-property-row.js.map +1 -0
  75. package/dist/graph/property-formatters.d.ts +1 -0
  76. package/dist/graph/property-formatters.d.ts.map +1 -1
  77. package/dist/graph/property-formatters.js +4 -1
  78. package/dist/graph/property-formatters.js.map +1 -1
  79. package/dist/graph/special-nodes/AttributeList.d.ts +27 -0
  80. package/dist/graph/special-nodes/AttributeList.d.ts.map +1 -0
  81. package/dist/graph/special-nodes/AttributeList.js +57 -0
  82. package/dist/graph/special-nodes/AttributeList.js.map +1 -0
  83. package/dist/graph/special-nodes/EntityPreview.d.ts +5 -0
  84. package/dist/graph/special-nodes/EntityPreview.d.ts.map +1 -0
  85. package/dist/graph/special-nodes/EntityPreview.js +19 -0
  86. package/dist/graph/special-nodes/EntityPreview.js.map +1 -0
  87. package/dist/graph/special-nodes/EntityValueChip.d.ts +11 -0
  88. package/dist/graph/special-nodes/EntityValueChip.d.ts.map +1 -0
  89. package/dist/graph/special-nodes/EntityValueChip.js +40 -0
  90. package/dist/graph/special-nodes/EntityValueChip.js.map +1 -0
  91. package/dist/graph/special-nodes/GenericView.d.ts +2 -1
  92. package/dist/graph/special-nodes/GenericView.d.ts.map +1 -1
  93. package/dist/graph/special-nodes/GenericView.js +23 -69
  94. package/dist/graph/special-nodes/GenericView.js.map +1 -1
  95. package/dist/graph/special-nodes/card-facts.d.ts +52 -0
  96. package/dist/graph/special-nodes/card-facts.d.ts.map +1 -0
  97. package/dist/graph/special-nodes/card-facts.js +189 -0
  98. package/dist/graph/special-nodes/card-facts.js.map +1 -0
  99. package/dist/graph/special-nodes/property-icons.d.ts +9 -0
  100. package/dist/graph/special-nodes/property-icons.d.ts.map +1 -0
  101. package/dist/graph/special-nodes/property-icons.js +39 -0
  102. package/dist/graph/special-nodes/property-icons.js.map +1 -0
  103. package/dist/graph/status-utils.d.ts +16 -0
  104. package/dist/graph/status-utils.d.ts.map +1 -1
  105. package/dist/graph/status-utils.js +35 -0
  106. package/dist/graph/status-utils.js.map +1 -1
  107. package/dist/graph/types.d.ts +5 -0
  108. package/dist/graph/types.d.ts.map +1 -1
  109. package/dist/hooks/use-approve-anyway.d.ts +12 -0
  110. package/dist/hooks/use-approve-anyway.d.ts.map +1 -0
  111. package/dist/hooks/use-approve-anyway.js +81 -0
  112. package/dist/hooks/use-approve-anyway.js.map +1 -0
  113. package/dist/hooks/use-connection-problems.d.ts.map +1 -1
  114. package/dist/hooks/useValidateActionPlan.d.ts.map +1 -1
  115. package/dist/ldo-ui.d.ts +2 -1
  116. package/dist/ldo-ui.d.ts.map +1 -1
  117. package/dist/ldo-ui.js +1 -0
  118. package/dist/ldo-ui.js.map +1 -1
  119. package/dist/lib/find-latest-staged-rule.js +1 -1
  120. package/dist/lib/find-latest-staged-rule.js.map +1 -1
  121. package/dist/lib/manual-actions.d.ts +2 -1
  122. package/dist/lib/manual-actions.d.ts.map +1 -1
  123. package/dist/lib/manual-actions.js +3 -2
  124. package/dist/lib/manual-actions.js.map +1 -1
  125. package/dist/lib/tool-icons.js +6 -6
  126. package/dist/lib/tool-icons.js.map +1 -1
  127. package/dist/lib/tool-names.d.ts.map +1 -1
  128. package/dist/lib/tool-names.js +0 -1
  129. package/dist/lib/tool-names.js.map +1 -1
  130. package/dist/ontology/skolem.js +2 -2
  131. package/dist/ontology/skolem.js.map +1 -1
  132. package/dist/providers/ActiveChatProvider.js +3 -1
  133. package/dist/providers/ActiveChatProvider.js.map +1 -1
  134. package/dist/providers/ChatManagerProvider.d.ts.map +1 -1
  135. package/dist/providers/ChatManagerProvider.js +3 -1
  136. package/dist/providers/ChatManagerProvider.js.map +1 -1
  137. package/dist/providers/KnowledgeGraphStateProvider.js +1 -1
  138. package/dist/providers/KnowledgeGraphStateProvider.js.map +1 -1
  139. package/dist/providers/chat-socket-auth.d.ts +7 -2
  140. package/dist/providers/chat-socket-auth.d.ts.map +1 -1
  141. package/dist/providers/chat-socket-auth.js +87 -16
  142. package/dist/providers/chat-socket-auth.js.map +1 -1
  143. package/dist/providers/index.d.ts.map +1 -1
  144. package/dist/providers/index.js +8 -1
  145. package/dist/providers/index.js.map +1 -1
  146. package/dist/routes/activity/detail/ActivityChanges.d.ts +2 -0
  147. package/dist/routes/activity/detail/ActivityChanges.d.ts.map +1 -1
  148. package/dist/routes/activity/detail/ActivityChanges.js +8 -7
  149. package/dist/routes/activity/detail/ActivityChanges.js.map +1 -1
  150. package/dist/routes/activity/detail/ActivityDetail.d.ts +1 -0
  151. package/dist/routes/activity/detail/ActivityDetail.d.ts.map +1 -1
  152. package/dist/routes/activity/detail/ActivityDetail.js +5 -4
  153. package/dist/routes/activity/detail/ActivityDetail.js.map +1 -1
  154. package/dist/routes/activity/detail/ActivityStepsRail.d.ts +1 -0
  155. package/dist/routes/activity/detail/ActivityStepsRail.d.ts.map +1 -1
  156. package/dist/routes/activity/detail/ActivityStepsRail.js +3 -2
  157. package/dist/routes/activity/detail/ActivityStepsRail.js.map +1 -1
  158. package/dist/routes/activity/detail/ActivityTimeline.js +2 -2
  159. package/dist/routes/activity/detail/ActivityTimeline.js.map +1 -1
  160. package/dist/routes/activity/detail/NoChangesMessage.d.ts +6 -0
  161. package/dist/routes/activity/detail/NoChangesMessage.d.ts.map +1 -0
  162. package/dist/routes/activity/detail/NoChangesMessage.js +10 -0
  163. package/dist/routes/activity/detail/NoChangesMessage.js.map +1 -0
  164. package/dist/routes/data-explorer/class-properties.js +2 -2
  165. package/dist/routes/data-explorer/class-properties.js.map +1 -1
  166. package/dist/routes/data-explorer/classes.js +2 -2
  167. package/dist/routes/data-explorer/classes.js.map +1 -1
  168. package/dist/routes/data-explorer/components/RawTriples.js +1 -1
  169. package/dist/routes/data-explorer/components/RawTriples.js.map +1 -1
  170. package/dist/routes/data-explorer/components/RecentTypes.js +1 -1
  171. package/dist/routes/data-explorer/components/RecentTypes.js.map +1 -1
  172. package/dist/routes/data-explorer/components/class-detail/Instances.js +1 -1
  173. package/dist/routes/data-explorer/components/class-detail/Instances.js.map +1 -1
  174. package/dist/routes/data-explorer/components/namespace-detail/NamespaceClassRow.js +1 -1
  175. package/dist/routes/data-explorer/components/namespace-detail/NamespaceClassRow.js.map +1 -1
  176. package/dist/routes/data-explorer/components/ontology-coverage/CoverageTermColumns.js +1 -1
  177. package/dist/routes/data-explorer/components/ontology-coverage/CoverageTermColumns.js.map +1 -1
  178. package/dist/routes/data-explorer/components/ontology-coverage/UnobservedRuleVocabulary.js +1 -1
  179. package/dist/routes/data-explorer/components/ontology-coverage/UnobservedRuleVocabulary.js.map +1 -1
  180. package/dist/routes/data-explorer/components/record-detail/ChatPreview.js +2 -2
  181. package/dist/routes/data-explorer/components/record-detail/ChatPreview.js.map +1 -1
  182. package/dist/routes/data-explorer/recents.js +1 -1
  183. package/dist/routes/data-explorer/recents.js.map +1 -1
  184. package/dist/routes/data-explorer/shapes.js +2 -2
  185. package/dist/routes/data-explorer/shapes.js.map +1 -1
  186. package/dist/routes/integrations/components/connect-forms/CanvaConnectForm.d.ts +3 -0
  187. package/dist/routes/integrations/components/connect-forms/CanvaConnectForm.d.ts.map +1 -0
  188. package/dist/routes/integrations/components/connect-forms/CanvaConnectForm.js +12 -0
  189. package/dist/routes/integrations/components/connect-forms/CanvaConnectForm.js.map +1 -0
  190. package/dist/routes/integrations/components/connect-forms/DataConnectionConnectForm.d.ts.map +1 -1
  191. package/dist/routes/integrations/components/connect-forms/DataConnectionConnectForm.js +13 -6
  192. package/dist/routes/integrations/components/connect-forms/DataConnectionConnectForm.js.map +1 -1
  193. package/dist/routes/integrations/components/connect-forms/data-connection-fields.d.ts +3 -0
  194. package/dist/routes/integrations/components/connect-forms/data-connection-fields.d.ts.map +1 -1
  195. package/dist/routes/integrations/components/connect-forms/data-connection-fields.js +9 -2
  196. package/dist/routes/integrations/components/connect-forms/data-connection-fields.js.map +1 -1
  197. package/dist/routes/integrations/connect-forms.d.ts +1 -0
  198. package/dist/routes/integrations/connect-forms.d.ts.map +1 -1
  199. package/dist/routes/integrations/connect-forms.js +1 -0
  200. package/dist/routes/integrations/connect-forms.js.map +1 -1
  201. package/dist/routes/integrations/connection-view.d.ts.map +1 -1
  202. package/dist/routes/integrations/connection-view.js +1 -0
  203. package/dist/routes/integrations/connection-view.js.map +1 -1
  204. package/dist/routes/integrations/types.d.ts +2 -1
  205. package/dist/routes/integrations/types.d.ts.map +1 -1
  206. package/dist/routes/integrations/types.js +1 -0
  207. package/dist/routes/integrations/types.js.map +1 -1
  208. package/dist/routes/plans/components/ActionPlanPage.d.ts.map +1 -1
  209. package/dist/routes/plans/components/ActionPlanPage.js +4 -7
  210. package/dist/routes/plans/components/ActionPlanPage.js.map +1 -1
  211. package/dist/routes/plans/components/PlanDetailRouteContent.d.ts.map +1 -1
  212. package/dist/routes/plans/components/PlanDetailRouteContent.js +2 -1
  213. package/dist/routes/plans/components/PlanDetailRouteContent.js.map +1 -1
  214. package/dist/routes/rules/hooks/useRuleFactsPreview.js +4 -4
  215. package/dist/routes/rules/hooks/useRuleFactsPreview.js.map +1 -1
  216. package/dist/shacl/form-appearance.d.ts +1 -1
  217. package/dist/shacl/form-appearance.d.ts.map +1 -1
  218. package/dist/shacl/form-appearance.js +1 -1
  219. package/dist/shacl/form-appearance.js.map +1 -1
  220. package/dist/shared/graph-derived-queries.js +2 -2
  221. package/dist/shared/graph-derived-queries.js.map +1 -1
  222. package/package.json +12 -7
  223. package/src/app-subpaths.json +1 -0
  224. package/src/components/channel-icon/index.tsx +1 -1
  225. package/src/components/datastore-management/tree.ts +5 -5
  226. package/src/components/explain-fact/ExplainFact.tsx +3 -3
  227. package/src/components/planning/ActioningView.tsx +62 -70
  228. package/src/components/planning/ManualActionCard.tsx +66 -14
  229. package/src/components/planning/ManualActionList.tsx +30 -11
  230. package/src/components/planning/actioning-view-utils.ts +27 -1
  231. package/src/components/planning/plan-detail-utils.tsx +2 -0
  232. package/src/components/tool-invocation-card/ListRulesResultDisplay.tsx +2 -2
  233. package/src/components/tool-invocation-card/ToolOutputRenderer.tsx +10 -8
  234. package/src/components/tool-invocation-card/types.ts +8 -8
  235. package/src/components/tooltip/index.tsx +35 -2
  236. package/src/explain-fact/rule-presentation.ts +2 -2
  237. package/src/explain-fact/tree-model.ts +2 -2
  238. package/src/graph/entity-link.tsx +20 -0
  239. package/src/graph/graph-list-utils.ts +2 -0
  240. package/src/graph/graph-model.ts +15 -6
  241. package/src/graph/nodes/BrandAssetAnalysisView.tsx +3 -1
  242. package/src/graph/nodes/BrandFontSuggestionView.tsx +7 -1
  243. package/src/graph/nodes/BrandGuidelinesView.tsx +1 -1
  244. package/src/graph/nodes/NodePropertyTable.tsx +32 -143
  245. package/src/graph/nodes/node-property-row.tsx +154 -0
  246. package/src/graph/property-formatters.ts +5 -1
  247. package/src/graph/special-nodes/AttributeList.tsx +177 -0
  248. package/src/graph/special-nodes/EntityPreview.tsx +27 -0
  249. package/src/graph/special-nodes/EntityValueChip.tsx +85 -0
  250. package/src/graph/special-nodes/GenericView.tsx +49 -139
  251. package/src/graph/special-nodes/card-facts.ts +278 -0
  252. package/src/graph/special-nodes/property-icons.ts +59 -0
  253. package/src/graph/status-utils.ts +40 -0
  254. package/src/graph/types.ts +4 -0
  255. package/src/hooks/use-approve-anyway.ts +100 -0
  256. package/src/ldo-ui.ts +8 -0
  257. package/src/lib/find-latest-staged-rule.ts +1 -1
  258. package/src/lib/manual-actions.ts +3 -2
  259. package/src/lib/tool-icons.ts +6 -6
  260. package/src/lib/tool-names.ts +0 -1
  261. package/src/ontology/skolem.ts +2 -2
  262. package/src/providers/ActiveChatProvider.tsx +3 -1
  263. package/src/providers/ChatManagerProvider.tsx +3 -1
  264. package/src/providers/KnowledgeGraphStateProvider.tsx +1 -1
  265. package/src/providers/chat-socket-auth.ts +95 -16
  266. package/src/providers/index.tsx +16 -1
  267. package/src/routes/activity/detail/ActivityChanges.tsx +21 -5
  268. package/src/routes/activity/detail/ActivityDetail.tsx +24 -5
  269. package/src/routes/activity/detail/ActivityStepsRail.tsx +4 -2
  270. package/src/routes/activity/detail/ActivityTimeline.tsx +2 -2
  271. package/src/routes/activity/detail/NoChangesMessage.tsx +20 -0
  272. package/src/routes/data-explorer/class-properties.ts +2 -2
  273. package/src/routes/data-explorer/classes.ts +2 -2
  274. package/src/routes/data-explorer/components/RawTriples.tsx +1 -1
  275. package/src/routes/data-explorer/components/RecentTypes.tsx +1 -1
  276. package/src/routes/data-explorer/components/class-detail/Instances.tsx +1 -1
  277. package/src/routes/data-explorer/components/namespace-detail/NamespaceClassRow.tsx +1 -1
  278. package/src/routes/data-explorer/components/ontology-coverage/CoverageTermColumns.tsx +1 -1
  279. package/src/routes/data-explorer/components/ontology-coverage/UnobservedRuleVocabulary.tsx +1 -1
  280. package/src/routes/data-explorer/components/record-detail/ChatPreview.tsx +2 -2
  281. package/src/routes/data-explorer/recents.ts +1 -1
  282. package/src/routes/data-explorer/shapes.ts +2 -2
  283. package/src/routes/datastores/flatten.ts +1 -1
  284. package/src/routes/integrations/components/connect-forms/CanvaConnectForm.tsx +26 -0
  285. package/src/routes/integrations/components/connect-forms/DataConnectionConnectForm.tsx +38 -12
  286. package/src/routes/integrations/components/connect-forms/data-connection-fields.ts +11 -2
  287. package/src/routes/integrations/connect-forms.ts +1 -0
  288. package/src/routes/integrations/connection-view.ts +1 -0
  289. package/src/routes/integrations/types.ts +2 -0
  290. package/src/routes/plans/components/ActionPlanPage.tsx +9 -8
  291. package/src/routes/plans/components/PlanDetailRouteContent.tsx +4 -3
  292. package/src/routes/rules/hooks/useRuleFactsPreview.ts +4 -4
  293. package/src/shacl/form-appearance.ts +1 -1
  294. package/src/shared/graph-derived-queries.ts +2 -2
  295. package/dist/components/planning/ExecutionActivityRow.d.ts +0 -9
  296. package/dist/components/planning/ExecutionActivityRow.d.ts.map +0 -1
  297. package/dist/components/planning/ExecutionActivityRow.js +0 -53
  298. package/dist/components/planning/ExecutionActivityRow.js.map +0 -1
  299. package/dist/components/planning/ExecutionSectionItem.d.ts +0 -20
  300. package/dist/components/planning/ExecutionSectionItem.d.ts.map +0 -1
  301. package/dist/components/planning/ExecutionSectionItem.js +0 -66
  302. package/dist/components/planning/ExecutionSectionItem.js.map +0 -1
  303. package/dist/components/planning/ExecutionSections.d.ts +0 -16
  304. package/dist/components/planning/ExecutionSections.d.ts.map +0 -1
  305. package/dist/components/planning/ExecutionSections.js +0 -32
  306. package/dist/components/planning/ExecutionSections.js.map +0 -1
  307. package/dist/components/planning/action-plan-icons.d.ts +0 -3
  308. package/dist/components/planning/action-plan-icons.d.ts.map +0 -1
  309. package/dist/components/planning/action-plan-icons.js +0 -25
  310. package/dist/components/planning/action-plan-icons.js.map +0 -1
  311. package/dist/components/planning/execution-section-model.d.ts +0 -24
  312. package/dist/components/planning/execution-section-model.d.ts.map +0 -1
  313. package/dist/components/planning/execution-section-model.js +0 -150
  314. package/dist/components/planning/execution-section-model.js.map +0 -1
  315. package/dist/routes/data-explorer/components/TruncateTooltip.d.ts +0 -7
  316. package/dist/routes/data-explorer/components/TruncateTooltip.d.ts.map +0 -1
  317. package/dist/routes/data-explorer/components/TruncateTooltip.js +0 -9
  318. package/dist/routes/data-explorer/components/TruncateTooltip.js.map +0 -1
  319. package/src/components/planning/ExecutionActivityRow.tsx +0 -89
  320. package/src/components/planning/ExecutionSectionItem.tsx +0 -184
  321. package/src/components/planning/ExecutionSections.tsx +0 -97
  322. package/src/components/planning/action-plan-icons.tsx +0 -27
  323. package/src/components/planning/execution-section-model.ts +0 -190
  324. package/src/routes/data-explorer/components/TruncateTooltip.tsx +0 -25
@@ -1,15 +1,16 @@
1
- import { isPresent } from "@manta-eu/lib/present";
2
- import { Check, ChevronDown, ChevronRight, X } from "lucide-react";
3
- import { useMemo, useState } from "react";
4
- import { match, P } from "ts-pattern";
1
+ import { useCallback, useMemo } from "react";
5
2
  import { shouldHidePreviewField } from "../graph-list-utils";
6
- import { ontologyTermIrisForProperties, withOntologyLabels } from "../ontology-labels";
7
- import { formatDisplayValue } from "../property-formatters";
8
- import type { NodeProperty } from "../types";
9
- import { classifyPropertyDisplay, type PropertyDisplay } from "./node-property-display";
10
- import { useOntologyTerms } from "#hooks/use-ontology-terms";
11
- import { formatPropertyLabel } from "#lib/iri-labels";
12
- import { cn } from "#style";
3
+ import { AttributeList, useAttributeFacts } from "../special-nodes/AttributeList";
4
+ import type { NodeProperty, NodeRelation } from "../types";
5
+
6
+ export {
7
+ NodePropertyExpander,
8
+ NodePropertyList,
9
+ NodePropertyRow,
10
+ PropertyValue,
11
+ type NodePropertyExpanderProps,
12
+ type NodePropertyRowProps,
13
+ } from "./node-property-row";
13
14
 
14
15
  export type NodePropertyTableProps = {
15
16
  properties: NodeProperty[];
@@ -17,145 +18,33 @@ export type NodePropertyTableProps = {
17
18
  jsonLd?: Record<string, unknown>;
18
19
  // Rendered above the table by the card itself, so the table skips them.
19
20
  omitPredicates?: readonly string[];
21
+ relations?: NodeRelation[];
20
22
  };
21
23
 
22
- function Tag(props: { children: string }) {
23
- return (
24
- <span className="rounded bg-faint px-1.5 py-[1px] typography-tiny text-default-foreground">{props.children}</span>
25
- );
26
- }
27
-
28
- function PropertyValue(props: { display: PropertyDisplay }) {
29
- return match(props.display)
30
- .with({ kind: "tags" }, ({ values }) => (
31
- <div className="flex flex-wrap gap-1">
32
- {values.map((value) => (
33
- <Tag key={value}>{value}</Tag>
34
- ))}
35
- </div>
36
- ))
37
- .with({ kind: "color" }, ({ hex }) => (
38
- <span className="flex items-center gap-1.5">
39
- <span
40
- aria-hidden
41
- className="size-3.5 shrink-0 rounded-sm border border-default-border"
42
- style={{ backgroundColor: hex }}
43
- />
44
- <span className="tabular-nums">{hex}</span>
45
- </span>
46
- ))
47
- .with({ kind: "ratio" }, ({ fraction, text }) => (
48
- <span className="flex items-center gap-1.5">
49
- <span aria-hidden className="h-1 w-12 shrink-0 overflow-hidden rounded-full bg-faint">
50
- <span className="block h-full rounded-full bg-accent-foreground" style={{ width: `${fraction * 100}%` }} />
51
- </span>
52
- <span className="tabular-nums">{text}</span>
53
- </span>
54
- ))
55
- .with({ kind: "number" }, ({ text }) => <span className="tabular-nums">{text}</span>)
56
- .with({ kind: "boolean" }, ({ value }) =>
57
- value ? (
58
- <span className="flex items-center gap-1">
59
- <Check aria-hidden className="size-3.5 shrink-0 text-success-foreground" />
60
- true
61
- </span>
62
- ) : (
63
- <span className="flex items-center gap-1">
64
- <X aria-hidden className="size-3.5 shrink-0 text-muted-foreground" />
65
- false
66
- </span>
67
- ),
68
- )
69
- .with(P.union({ kind: "prose" }, { kind: "text" }), ({ text }) => <span>{text}</span>)
70
- .exhaustive();
71
- }
72
-
73
- type Row = { key: string; label: string; display: PropertyDisplay };
74
-
75
- function PropertyRow(props: { row: Row }) {
76
- const { row } = props;
77
-
78
- return (
79
- <div className="-mx-1 grid grid-cols-[minmax(0,7rem)_minmax(0,1fr)] items-baseline gap-x-3 gap-y-1 rounded-md border-t border-muted-border/50 px-1 py-1.5 transition-colors first:border-t-0 hover:bg-muted/30">
80
- <span className="typography-tiny min-w-0 break-words text-muted-foreground first-letter:uppercase">
81
- {row.label}
82
- </span>
83
- <div
84
- className={cn(
85
- "typography-tiny min-w-0 break-words text-default-foreground",
86
- // A long description reads better as its own full-width block under the label.
87
- row.display.kind === "prose" && "col-span-2",
88
- )}
89
- >
90
- <PropertyValue display={row.display} />
91
- </div>
92
- </div>
93
- );
94
- }
24
+ const noJsonLd: Record<string, unknown> = {};
95
25
 
96
- // Every property the node carries, laid out like the record-detail field list. Rule-derived
26
+ // Every property the node carries, in the same attribute list the fallback card uses. Rule-derived
97
27
  // properties are included: they are real on the instance even though no shape declares them.
98
- // Short values keep the compact two-column rhythm; prose paragraphs collapse behind the same
99
- // "Show more" expander AttioNodeBody uses, so the card stays a summary until asked.
100
28
  export function NodePropertyTable(props: NodePropertyTableProps) {
101
- const { properties, jsonLd, omitPredicates = [] } = props;
29
+ const { properties, jsonLd = noJsonLd, omitPredicates, relations } = props;
102
30
 
103
- const [expanded, setExpanded] = useState(false);
104
-
105
- const terms = useOntologyTerms(useMemo(() => ontologyTermIrisForProperties(properties), [properties]));
106
-
107
- const rows = useMemo(() => {
108
- const omitted = new Set(omitPredicates);
109
-
110
- return withOntologyLabels(properties, terms)
111
- .filter(
112
- (property) =>
113
- !omitted.has(property.iri ?? "") && !shouldHidePreviewField(property.label ?? "", property.iri ?? ""),
114
- )
115
- .map((property): Row => {
116
- const label = property.label || formatPropertyLabel(property.iri ?? property.key);
117
- const formatted = formatDisplayValue(property.value, {
118
- predicate: property.iri,
119
- predicateLabel: property.label,
120
- valueScale: property.valueScale,
121
- });
122
-
123
- return {
124
- key: property.iri ?? property.key,
125
- label,
126
- display: classifyPropertyDisplay({ label, formatted, raw: jsonLd?.[property.iri ?? ""] ?? property.value }),
127
- };
128
- });
129
- }, [properties, terms, jsonLd, omitPredicates]);
130
-
131
- const compactRows = rows.filter((row) => row.display.kind !== "prose");
132
- const proseRows = rows.filter((row) => row.display.kind === "prose");
31
+ const include = useCallback(
32
+ (property: NodeProperty) =>
33
+ !(omitPredicates ?? []).includes(property.iri ?? "") &&
34
+ !shouldHidePreviewField(property.label ?? "", property.iri ?? ""),
35
+ [omitPredicates],
36
+ );
133
37
 
134
- if (!isPresent(rows)) return null;
38
+ const visibleRelations = useMemo(
39
+ () =>
40
+ relations?.filter(
41
+ (relation) =>
42
+ !(omitPredicates ?? []).includes(relation.predicate) && !shouldHidePreviewField("", relation.predicate),
43
+ ),
44
+ [relations, omitPredicates],
45
+ );
135
46
 
136
- return (
137
- <div className="flex flex-col">
138
- {compactRows.map((row) => (
139
- <PropertyRow key={row.key} row={row} />
140
- ))}
47
+ const { facts, previewCount } = useAttributeFacts({ properties, relations: visibleRelations, jsonLd, include });
141
48
 
142
- {isPresent(proseRows) && (
143
- <>
144
- {expanded && proseRows.map((row) => <PropertyRow key={row.key} row={row} />)}
145
- <button
146
- type="button"
147
- onClick={() => setExpanded((value) => !value)}
148
- className="nodrag flex items-center gap-1 pt-1.5 typography-tiny-medium text-muted-foreground hover:text-default-foreground"
149
- >
150
- {expanded ? (
151
- <ChevronDown size={11} className="shrink-0" />
152
- ) : (
153
- <ChevronRight size={11} className="shrink-0" />
154
- )}
155
- {expanded ? "Show less" : `Show ${proseRows.length} more`}
156
- </button>
157
- </>
158
- )}
159
- </div>
160
- );
49
+ return <AttributeList facts={facts} previewCount={previewCount} showAll />;
161
50
  }
@@ -0,0 +1,154 @@
1
+ import { Check, ChevronDown, ChevronRight, type LucideIcon, X } from "lucide-react";
2
+ import type { ReactNode } from "react";
3
+ import { match, P } from "ts-pattern";
4
+ import type { PropertyDisplay } from "./node-property-display";
5
+ import { TruncateTooltip } from "#components/tooltip/index";
6
+ import { cn } from "#style";
7
+
8
+ function Tag(props: { children: string }) {
9
+ return (
10
+ <span className="rounded bg-faint px-1.5 py-[1px] typography-tiny text-default-foreground">{props.children}</span>
11
+ );
12
+ }
13
+
14
+ export function PropertyValue(props: { display: PropertyDisplay }) {
15
+ return match(props.display)
16
+ .with({ kind: "tags" }, ({ values }) => (
17
+ <div className="flex flex-wrap gap-1">
18
+ {values.map((value) => (
19
+ <Tag key={value}>{value}</Tag>
20
+ ))}
21
+ </div>
22
+ ))
23
+ .with({ kind: "color" }, ({ hex }) => (
24
+ <span className="flex items-center gap-1.5">
25
+ <span
26
+ aria-hidden
27
+ className="size-3.5 shrink-0 rounded-sm border border-default-border"
28
+ style={{ backgroundColor: hex }}
29
+ />
30
+ <span className="tabular-nums">{hex}</span>
31
+ </span>
32
+ ))
33
+ .with({ kind: "ratio" }, ({ fraction, text }) => (
34
+ <span className="flex items-center gap-1.5">
35
+ <span aria-hidden className="h-1 w-12 shrink-0 overflow-hidden rounded-full bg-faint">
36
+ <span className="block h-full rounded-full bg-accent-foreground" style={{ width: `${fraction * 100}%` }} />
37
+ </span>
38
+ <span className="tabular-nums">{text}</span>
39
+ </span>
40
+ ))
41
+ .with({ kind: "number" }, ({ text }) => <span className="tabular-nums">{text}</span>)
42
+ .with({ kind: "boolean" }, ({ value }) =>
43
+ value ? (
44
+ <span className="flex items-center gap-1">
45
+ <Check aria-hidden className="size-3.5 shrink-0 text-success-foreground" />
46
+ true
47
+ </span>
48
+ ) : (
49
+ <span className="flex items-center gap-1">
50
+ <X aria-hidden className="size-3.5 shrink-0 text-muted-foreground" />
51
+ false
52
+ </span>
53
+ ),
54
+ )
55
+ .with(P.union({ kind: "prose" }, { kind: "text" }), ({ text }) => <span>{text}</span>)
56
+ .exhaustive();
57
+ }
58
+
59
+ export function NodePropertyList(props: { children: ReactNode }) {
60
+ return <dl className="flex flex-col">{props.children}</dl>;
61
+ }
62
+
63
+ export type NodePropertyRowProps = {
64
+ label: string;
65
+ icon?: LucideIcon;
66
+ labelPrefix?: ReactNode;
67
+ children: ReactNode;
68
+ fullWidth?: boolean;
69
+ overflow?: "wrap" | "truncate" | "clamp";
70
+ valueTitle?: string;
71
+ divided?: boolean;
72
+ wideLabel?: boolean;
73
+ emphasized?: boolean;
74
+ valueClassName?: string;
75
+ };
76
+
77
+ // Render inside NodePropertyList so the dt/dd pairs sit in a dl.
78
+ export function NodePropertyRow(props: NodePropertyRowProps) {
79
+ const {
80
+ label,
81
+ icon: Icon,
82
+ labelPrefix,
83
+ children,
84
+ fullWidth = false,
85
+ overflow = "wrap",
86
+ valueTitle,
87
+ divided = true,
88
+ wideLabel = false,
89
+ emphasized = false,
90
+ valueClassName,
91
+ } = props;
92
+
93
+ const clipped = overflow !== "wrap";
94
+ const spansRow = fullWidth || overflow === "clamp";
95
+
96
+ return (
97
+ <div
98
+ className={cn(
99
+ "grid items-baseline gap-x-3 gap-y-1",
100
+ // The wide label column grows with the card, never with the rows shown, so Show all never shifts it.
101
+ wideLabel ? "grid-cols-[minmax(8rem,40%)_minmax(0,1fr)]" : "grid-cols-[minmax(0,7rem)_minmax(0,1fr)]",
102
+ divided ? "border-t border-muted-border/50 py-1.5 first:border-t-0" : "py-1",
103
+ )}
104
+ >
105
+ <dt className={cn("flex min-w-0 items-baseline gap-1.5 text-muted-foreground", spansRow && "col-span-2")}>
106
+ {Icon && <Icon aria-hidden className="size-3 shrink-0 self-center" />}
107
+ {labelPrefix}
108
+ {overflow === "truncate" ? (
109
+ <TruncateTooltip text={label} className="typography-tiny min-w-0 truncate first-letter:uppercase" />
110
+ ) : (
111
+ <span className="typography-tiny min-w-0 break-words first-letter:uppercase">{label}</span>
112
+ )}
113
+ </dt>
114
+ <dd
115
+ className={cn(
116
+ emphasized ? "typography-tiny-medium" : "typography-tiny",
117
+ "min-w-0 text-default-foreground",
118
+ overflow === "wrap" && "break-words",
119
+ spansRow && "col-span-2",
120
+ valueClassName,
121
+ )}
122
+ >
123
+ {clipped && valueTitle !== undefined ? (
124
+ <TruncateTooltip
125
+ text={valueTitle}
126
+ className={cn("block min-w-0", overflow === "truncate" ? "truncate" : "line-clamp-4 break-words")}
127
+ >
128
+ {children}
129
+ </TruncateTooltip>
130
+ ) : (
131
+ children
132
+ )}
133
+ </dd>
134
+ </div>
135
+ );
136
+ }
137
+
138
+ export type NodePropertyExpanderProps = { expanded: boolean; collapsedLabel: string; onToggle: () => void };
139
+
140
+ export function NodePropertyExpander(props: NodePropertyExpanderProps) {
141
+ const { expanded, collapsedLabel, onToggle } = props;
142
+
143
+ return (
144
+ <button
145
+ type="button"
146
+ onClick={onToggle}
147
+ aria-expanded={expanded}
148
+ className="nodrag flex items-center gap-1 pt-1.5 typography-tiny-medium text-muted-foreground hover:text-default-foreground"
149
+ >
150
+ {expanded ? <ChevronDown size={11} className="shrink-0" /> : <ChevronRight size={11} className="shrink-0" />}
151
+ {expanded ? "Show less" : collapsedLabel}
152
+ </button>
153
+ );
154
+ }
@@ -135,6 +135,10 @@ function humanizeToken(value: string): string {
135
135
  return value;
136
136
  }
137
137
 
138
+ export function isIsoDateTime(value: string): boolean {
139
+ return /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}/.test(value);
140
+ }
141
+
138
142
  export function formatDisplayValue(
139
143
  value: string,
140
144
  options?: {
@@ -162,7 +166,7 @@ export function formatDisplayValue(
162
166
 
163
167
  if (combinedLabel.includes("currency")) return value;
164
168
 
165
- if (/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}/.test(value)) {
169
+ if (isIsoDateTime(value)) {
166
170
  const date = parseISO(value);
167
171
 
168
172
  if (isValid(date)) return format(date, "MMM d, yyyy");
@@ -0,0 +1,177 @@
1
+ import { isFullIri } from "@manta-eu/client/shared/rdf-namespaces";
2
+ import { isPresent } from "@manta-eu/lib/present";
3
+ import { Search } from "lucide-react";
4
+ import { useMemo, useState } from "react";
5
+ import type { PreviewFieldHints } from "../graph-list-utils";
6
+ import { NodePropertyExpander, NodePropertyList, NodePropertyRow, PropertyValue } from "../nodes/node-property-row";
7
+ import { ontologyTermIrisForProperties, withOntologyLabels } from "../ontology-labels";
8
+ import type { NodeProperty, NodeRelation } from "../types";
9
+ import { buildCardFacts, type CardFact, isAttributeSearchable, searchFacts, visibleChips } from "./card-facts";
10
+ import { EntityValueChip } from "./EntityValueChip";
11
+ import { ChannelIcon, channelDisplayName } from "#components/channel-icon/index";
12
+ import { useOntologyTerms } from "#hooks/use-ontology-terms";
13
+ import { cn } from "#style";
14
+
15
+ export type UseAttributeFactsArgs = {
16
+ properties: NodeProperty[];
17
+ relations?: NodeRelation[];
18
+ jsonLd: Record<string, unknown>;
19
+ title?: string;
20
+ type?: string;
21
+ prefixLabels?: boolean;
22
+ previewHints?: PreviewFieldHints;
23
+ // Applied after ontology labels resolve, so a filter can match on the label too. Keep it stable (useCallback).
24
+ include?: (property: NodeProperty) => boolean;
25
+ };
26
+
27
+ export function useAttributeFacts(args: UseAttributeFactsArgs): { facts: CardFact[]; previewCount: number } {
28
+ const { properties, jsonLd, title, type, prefixLabels, previewHints, include } = args;
29
+
30
+ const relations = useMemo(() => args.relations ?? [], [args.relations]);
31
+
32
+ const terms = useOntologyTerms(
33
+ useMemo(
34
+ () => [
35
+ ...ontologyTermIrisForProperties(properties),
36
+ ...relations.flatMap((relation) => [relation.predicate, relation.target]).filter(isFullIri),
37
+ ],
38
+ [properties, relations],
39
+ ),
40
+ );
41
+
42
+ return useMemo(() => {
43
+ const labeled = withOntologyLabels(properties, terms);
44
+
45
+ return buildCardFacts({
46
+ properties: include ? labeled.filter(include) : labeled,
47
+ relations,
48
+ jsonLd,
49
+ terms,
50
+ title,
51
+ type,
52
+ prefixLabels,
53
+ previewHints,
54
+ });
55
+ }, [properties, terms, include, relations, jsonLd, title, type, prefixLabels, previewHints]);
56
+ }
57
+
58
+ type EntityChipsProps = { iris: string[]; color?: string; expanded: boolean };
59
+
60
+ function EntityChips(props: EntityChipsProps) {
61
+ const { iris, color, expanded } = props;
62
+
63
+ const { shown, hiddenCount } = visibleChips(iris, expanded);
64
+
65
+ return (
66
+ <span className="flex min-w-0 flex-wrap items-center gap-1">
67
+ {shown.map((iri) => (
68
+ <EntityValueChip key={iri} iri={iri} color={color} />
69
+ ))}
70
+ {hiddenCount > 0 && <span className="typography-tiny text-muted-foreground">+{hiddenCount}</span>}
71
+ </span>
72
+ );
73
+ }
74
+
75
+ export type AttributeListProps = {
76
+ facts: CardFact[];
77
+ previewCount: number;
78
+ searchClassName?: string;
79
+ bodyClassName?: string;
80
+ // Lists every attribute with no preview, so a card that promises the whole record keeps that promise.
81
+ showAll?: boolean;
82
+ defaultExpanded?: boolean;
83
+ };
84
+
85
+ export function AttributeList(props: AttributeListProps) {
86
+ const { facts, previewCount, searchClassName, bodyClassName, showAll = false, defaultExpanded = false } = props;
87
+
88
+ const [expandedByUser, setExpanded] = useState(defaultExpanded);
89
+ const expanded = showAll || expandedByUser;
90
+ const [query, setQuery] = useState("");
91
+
92
+ const searchable = isAttributeSearchable(expanded, facts.length);
93
+ const searching = searchable && isPresent(query.trim());
94
+ const matchingFacts = useMemo(
95
+ () => (searching ? searchFacts(facts, query.trim()) : facts),
96
+ [searching, facts, query],
97
+ );
98
+
99
+ const visibleFacts = searching || expanded ? matchingFacts : facts.slice(0, previewCount);
100
+ const hasHiddenChips = visibleFacts.some((fact) => visibleChips(fact.entityIris, expanded).hiddenCount > 0);
101
+ const hiddenCount = facts.length - previewCount;
102
+
103
+ if (!isPresent(facts)) return null;
104
+
105
+ return (
106
+ <div className="flex flex-col">
107
+ {searchable && (
108
+ <label
109
+ className={cn(
110
+ "nodrag nopan flex items-center gap-2 border-b border-muted-border py-2 text-muted-foreground",
111
+ searchClassName,
112
+ )}
113
+ >
114
+ <Search aria-hidden className="size-3.5 shrink-0" />
115
+ <input
116
+ type="search"
117
+ value={query}
118
+ onChange={(event) => setQuery(event.target.value)}
119
+ onKeyDown={(event) => event.stopPropagation()}
120
+ placeholder="Search attributes…"
121
+ aria-label="Search attributes"
122
+ className="typography-tiny min-w-0 flex-1 bg-transparent text-default-foreground outline-none placeholder:text-muted-foreground"
123
+ />
124
+ </label>
125
+ )}
126
+
127
+ <div className={cn("flex flex-col", bodyClassName)}>
128
+ <NodePropertyList>
129
+ {visibleFacts.map(({ key, label, value, display, icon, entityIris, entityColor, highlighted, channel }) => (
130
+ <NodePropertyRow
131
+ key={key}
132
+ label={label}
133
+ icon={channel ? undefined : icon}
134
+ labelPrefix={
135
+ channel && (
136
+ <span
137
+ role="img"
138
+ aria-label={channelDisplayName[channel]}
139
+ title={channelDisplayName[channel]}
140
+ className="shrink-0 self-center"
141
+ >
142
+ <ChannelIcon channel={channel} iconClassName="size-3" />
143
+ </span>
144
+ )
145
+ }
146
+ overflow={isPresent(entityIris) ? "wrap" : expanded && display.kind === "prose" ? "clamp" : "truncate"}
147
+ valueTitle={value}
148
+ divided={false}
149
+ wideLabel
150
+ emphasized={highlighted}
151
+ valueClassName={cn("tabular-nums", highlighted && "text-primary")}
152
+ >
153
+ {isPresent(entityIris) ? (
154
+ <EntityChips iris={entityIris} color={entityColor} expanded={expanded} />
155
+ ) : (
156
+ <PropertyValue display={display} />
157
+ )}
158
+ </NodePropertyRow>
159
+ ))}
160
+ </NodePropertyList>
161
+ {searching && !isPresent(visibleFacts) && (
162
+ <span className="typography-tiny py-1 text-muted-foreground">No matching attributes.</span>
163
+ )}
164
+ {!showAll && (hiddenCount > 0 || hasHiddenChips || expanded) && (
165
+ <NodePropertyExpander
166
+ expanded={expanded}
167
+ collapsedLabel={hiddenCount > 0 ? `Show all ${facts.length}` : "Show all"}
168
+ onToggle={() => {
169
+ setExpanded((value) => !value);
170
+ setQuery("");
171
+ }}
172
+ />
173
+ )}
174
+ </div>
175
+ </div>
176
+ );
177
+ }
@@ -0,0 +1,27 @@
1
+ import { useMemo } from "react";
2
+ import { stubNodeData } from "../stub-node";
3
+ import { InsideEntityPreview } from "./EntityValueChip";
4
+ import { GenericView } from "./GenericView";
5
+ import { getEntityView } from "./router";
6
+ import { useEntityNodes } from "#hooks/use-entity-nodes";
7
+
8
+ export type EntityPreviewProps = { iri: string };
9
+
10
+ // Loaded lazily from EntityValueChip: a static import would cycle through the node router back to GenericView.
11
+ export function EntityPreview(props: EntityPreviewProps) {
12
+ const { iri } = props;
13
+
14
+ const iris = useMemo(() => [iri], [iri]);
15
+ const { nodesByIri, isLoading } = useEntityNodes(iris);
16
+
17
+ if (isLoading) return <div className="typography-tiny px-3 py-2 text-muted-foreground">Loading…</div>;
18
+
19
+ const node = nodesByIri.get(iri);
20
+ const View = (node && getEntityView(node.data.type, node.data.actionShape)) ?? GenericView;
21
+
22
+ return (
23
+ <InsideEntityPreview.Provider value={true}>
24
+ <View data={node?.data ?? stubNodeData(iri)} />
25
+ </InsideEntityPreview.Provider>
26
+ );
27
+ }
@@ -0,0 +1,85 @@
1
+ import { humanizeEntityName } from "@manta-eu/client/shared/agent-mode";
2
+ import { iriLocalName } from "@manta-eu/client/shared/rdf-namespaces";
3
+ import { isPresent } from "@manta-eu/lib/present";
4
+ import { createContext, lazy, Suspense, useContext } from "react";
5
+ import { useEntityLink } from "../entity-link";
6
+ import { iriChannel } from "./card-facts";
7
+ import { ChannelIcon, channelDisplayName } from "#components/channel-icon/index";
8
+ import { Tooltip, TooltipContent, TooltipTrigger } from "#components/tooltip/index";
9
+ import { useInstanceLabel } from "#hooks/use-instance-labels";
10
+ import { useOntologyTerm } from "#hooks/use-ontology-terms";
11
+ import { cn } from "#style";
12
+
13
+ const EntityPreview = lazy(() => import("./EntityPreview").then((module) => ({ default: module.EntityPreview })));
14
+
15
+ // A preview already shows one entity card; its own chips skip the hover so previews never stack.
16
+ export const InsideEntityPreview = createContext(false);
17
+
18
+ // An ontology term (e.g. an enum concept) has a label but no record of its own to open or preview.
19
+ export function useEntityValueLabel(iri: string): { label: string; isOntologyTerm: boolean } {
20
+ const term = useOntologyTerm(iri);
21
+ const instanceLabel = useInstanceLabel(term?.label ? undefined : iri);
22
+
23
+ return {
24
+ label: term?.label ?? instanceLabel ?? humanizeEntityName(iriLocalName(iri)),
25
+ isOntologyTerm: isPresent(term?.label),
26
+ };
27
+ }
28
+
29
+ export type EntityValueChipProps = { iri: string; color?: string };
30
+
31
+ export function EntityValueChip(props: EntityValueChipProps) {
32
+ const { iri, color } = props;
33
+
34
+ const { label, isOntologyTerm } = useEntityValueLabel(iri);
35
+ const EntityLink = useEntityLink();
36
+ const insidePreview = useContext(InsideEntityPreview);
37
+ const channel = iriChannel(iri);
38
+
39
+ if (isOntologyTerm) return <span className="min-w-0 truncate">{label}</span>;
40
+
41
+ const chipClassName = cn(
42
+ "nodrag inline-flex min-w-0 max-w-full items-center gap-1.5 rounded bg-faint px-1.5 py-px text-default-foreground",
43
+ EntityLink && "transition-colors hover:bg-accent hover:text-primary",
44
+ );
45
+ const content = (
46
+ <>
47
+ {channel ? (
48
+ <span role="img" aria-label={channelDisplayName[channel]} className="shrink-0">
49
+ <ChannelIcon channel={channel} iconClassName="size-3" />
50
+ </span>
51
+ ) : (
52
+ color && <span aria-hidden className="size-1.5 shrink-0 rounded-full" style={{ backgroundColor: color }} />
53
+ )}
54
+ <span className="min-w-0 truncate">{label}</span>
55
+ </>
56
+ );
57
+ const chip = EntityLink ? (
58
+ <EntityLink iri={iri} className={chipClassName}>
59
+ {content}
60
+ </EntityLink>
61
+ ) : (
62
+ <span className={chipClassName}>{content}</span>
63
+ );
64
+
65
+ if (insidePreview) return chip;
66
+
67
+ return (
68
+ <Tooltip>
69
+ <TooltipTrigger asChild>
70
+ <span className="inline-flex min-w-0 max-w-full">{chip}</span>
71
+ </TooltipTrigger>
72
+ <TooltipContent
73
+ side="bottom"
74
+ align="start"
75
+ collisionPadding={8}
76
+ showArrow={false}
77
+ className="rounded-lg-v4 border border-default-border bg-card p-1.5 shadow-v4"
78
+ >
79
+ <Suspense fallback={null}>
80
+ <EntityPreview iri={iri} />
81
+ </Suspense>
82
+ </TooltipContent>
83
+ </Tooltip>
84
+ );
85
+ }