@mastra/playground-ui 68.0.0-alpha.2 → 68.0.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 (479) hide show
  1. package/dist/{FilterBar-CQl04O6t.cjs → FilterBar-BSP2UTjc.cjs} +2 -2
  2. package/dist/{FilterBar-CQl04O6t.cjs.map → FilterBar-BSP2UTjc.cjs.map} +1 -1
  3. package/dist/{FilterBar-BgW2dqRQ.js → FilterBar-PSQ1OwqH.js} +2 -2
  4. package/dist/{FilterBar-BgW2dqRQ.js.map → FilterBar-PSQ1OwqH.js.map} +1 -1
  5. package/dist/KnowledgePageGraph.css +55 -0
  6. package/dist/{MarkdownRenderer-2GOXQJEv.js → MarkdownRenderer-CI30RqdB.js} +19 -6
  7. package/dist/MarkdownRenderer-CI30RqdB.js.map +1 -0
  8. package/dist/{MarkdownRenderer-CB8Z_CHc.cjs → MarkdownRenderer-y65WGBhC.cjs} +19 -6
  9. package/dist/MarkdownRenderer-y65WGBhC.cjs.map +1 -0
  10. package/dist/{MetricsCard-CEB-f2sv.cjs → MetricsCard-BEwiS7Pe.cjs} +8 -8
  11. package/dist/MetricsCard-BEwiS7Pe.cjs.map +1 -0
  12. package/dist/{MetricsCard-M8awJ2B_.js → MetricsCard-ua6C6b8a.js} +10 -10
  13. package/dist/MetricsCard-ua6C6b8a.js.map +1 -0
  14. package/dist/{MetricsLineChart-BhHoduO0.js → MetricsLineChart-4SwxBbQx.js} +14 -3
  15. package/dist/MetricsLineChart-4SwxBbQx.js.map +1 -0
  16. package/dist/{MetricsLineChart-CjBm4IXu.cjs → MetricsLineChart-tZxsauau.cjs} +13 -2
  17. package/dist/MetricsLineChart-tZxsauau.cjs.map +1 -0
  18. package/dist/{MetricsStackedBarChart-BdMlKv6G.cjs → MetricsStackedBarChart-CDLE76IB.cjs} +2 -2
  19. package/dist/{MetricsStackedBarChart-BdMlKv6G.cjs.map → MetricsStackedBarChart-CDLE76IB.cjs.map} +1 -1
  20. package/dist/{MetricsStackedBarChart-BRuA6MTE.js → MetricsStackedBarChart-D2QyS4-z.js} +2 -2
  21. package/dist/{MetricsStackedBarChart-BRuA6MTE.js.map → MetricsStackedBarChart-D2QyS4-z.js.map} +1 -1
  22. package/dist/{activity-rJ1NQl_2.js → activity-C8Ql81WM.js} +2 -2
  23. package/dist/{activity-rJ1NQl_2.js.map → activity-C8Ql81WM.js.map} +1 -1
  24. package/dist/{activity-DyB5H3gF.cjs → activity-CcQZeDYi.cjs} +2 -2
  25. package/dist/{activity-DyB5H3gF.cjs.map → activity-CcQZeDYi.cjs.map} +1 -1
  26. package/dist/components/DateTimeRangePicker.cjs.js +1 -1
  27. package/dist/components/DateTimeRangePicker.es.js +1 -1
  28. package/dist/components/FilterBar.cjs.js +2 -2
  29. package/dist/components/FilterBar.es.js +2 -2
  30. package/dist/components/MarkdownRenderer.cjs.js +1 -1
  31. package/dist/components/MarkdownRenderer.es.js +1 -1
  32. package/dist/components/MetricsCard.cjs.js +1 -1
  33. package/dist/components/MetricsCard.es.js +1 -1
  34. package/dist/components/MetricsLineChart.cjs.js +1 -1
  35. package/dist/components/MetricsLineChart.es.js +1 -1
  36. package/dist/components/MetricsStackedBarChart.cjs.js +1 -1
  37. package/dist/components/MetricsStackedBarChart.es.js +1 -1
  38. package/dist/components/SavedViews.cjs.js +1 -1
  39. package/dist/components/SavedViews.es.js +1 -1
  40. package/dist/components/ai/activity.cjs.js +1 -1
  41. package/dist/components/ai/activity.es.js +1 -1
  42. package/dist/components/ai/plan.cjs.js +1 -1
  43. package/dist/components/ai/plan.es.js +1 -1
  44. package/dist/components/ai/tool-approval.cjs.js +1 -1
  45. package/dist/components/ai/tool-approval.es.js +1 -1
  46. package/dist/components/ai/tool-call.cjs.js +2 -2
  47. package/dist/components/ai/tool-call.es.js +2 -2
  48. package/dist/{date-time-range-picker-CTt7Od0P.cjs → date-time-range-picker-CWGjoR3j.cjs} +40 -13
  49. package/dist/date-time-range-picker-CWGjoR3j.cjs.map +1 -0
  50. package/dist/{date-time-range-picker-DKh1K9Iy.js → date-time-range-picker-CdSiXwB4.js} +40 -13
  51. package/dist/date-time-range-picker-CdSiXwB4.js.map +1 -0
  52. package/dist/domains/chat/activity/activity-stretch-line.cjs.js +1 -1
  53. package/dist/domains/chat/activity/activity-stretch-line.es.js +1 -1
  54. package/dist/domains/chat/activity/components/activity-fold.cjs.js +1 -1
  55. package/dist/domains/chat/activity/components/activity-fold.es.js +1 -1
  56. package/dist/domains/chat/activity/components/activity-timed-trigger.cjs.js +1 -1
  57. package/dist/domains/chat/activity/components/activity-timed-trigger.es.js +1 -1
  58. package/dist/domains/chat/activity/components/calls-panel.cjs.js +1 -1
  59. package/dist/domains/chat/activity/components/calls-panel.es.js +1 -1
  60. package/dist/domains/chat/activity/components/stretch-content.cjs.js +1 -1
  61. package/dist/domains/chat/activity/components/stretch-content.es.js +1 -1
  62. package/dist/domains/chat/activity/components/stretch-thought.cjs.js +1 -1
  63. package/dist/domains/chat/activity/components/stretch-thought.es.js +1 -1
  64. package/dist/domains/chat/activity/model/activity-segments.cjs.js +1 -1
  65. package/dist/domains/chat/activity/model/activity-segments.es.js +1 -1
  66. package/dist/domains/chat/activity/model/activity-words.cjs.js +2 -2
  67. package/dist/domains/chat/activity/model/activity-words.es.js +2 -2
  68. package/dist/domains/chat/components/badge-wrapper.cjs.js +1 -1
  69. package/dist/domains/chat/components/badge-wrapper.es.js +1 -1
  70. package/dist/domains/chat/knowledge/knowledge-links.cjs.js +52 -6
  71. package/dist/domains/chat/knowledge/knowledge-links.cjs.js.map +1 -1
  72. package/dist/domains/chat/knowledge/knowledge-links.es.js +53 -9
  73. package/dist/domains/chat/knowledge/knowledge-links.es.js.map +1 -1
  74. package/dist/domains/chat/knowledge/pinned-knowledge-data.cjs.js +10 -3
  75. package/dist/domains/chat/knowledge/pinned-knowledge-data.cjs.js.map +1 -1
  76. package/dist/domains/chat/knowledge/pinned-knowledge-data.es.js +10 -3
  77. package/dist/domains/chat/knowledge/pinned-knowledge-data.es.js.map +1 -1
  78. package/dist/domains/chat/knowledge/pinned-knowledge.cjs.js +8 -3
  79. package/dist/domains/chat/knowledge/pinned-knowledge.cjs.js.map +1 -1
  80. package/dist/domains/chat/knowledge/pinned-knowledge.es.js +8 -3
  81. package/dist/domains/chat/knowledge/pinned-knowledge.es.js.map +1 -1
  82. package/dist/domains/chat/knowledge.cjs.js +2 -0
  83. package/dist/domains/chat/knowledge.es.js +2 -2
  84. package/dist/domains/chat/messages/message-row.cjs.js +3 -3
  85. package/dist/domains/chat/messages/message-row.es.js +3 -3
  86. package/dist/domains/chat/messages/notification-signal-notice.cjs.js +1 -1
  87. package/dist/domains/chat/messages/notification-signal-notice.es.js +1 -1
  88. package/dist/domains/chat/messages/reasoning-content.cjs.js +1 -1
  89. package/dist/domains/chat/messages/reasoning-content.es.js +1 -1
  90. package/dist/domains/chat/messages/renderers/message-text.cjs.js +35 -1
  91. package/dist/domains/chat/messages/renderers/message-text.cjs.js.map +1 -1
  92. package/dist/domains/chat/messages/renderers/message-text.es.js +36 -2
  93. package/dist/domains/chat/messages/renderers/message-text.es.js.map +1 -1
  94. package/dist/domains/chat/messages/renderers/reasoning-part-renderer.cjs.js +1 -1
  95. package/dist/domains/chat/messages/renderers/reasoning-part-renderer.es.js +1 -1
  96. package/dist/domains/chat/messages/signal-badge.cjs.js +1 -1
  97. package/dist/domains/chat/messages/signal-badge.es.js +1 -1
  98. package/dist/domains/chat/messages/skill-message.cjs.js +2 -2
  99. package/dist/domains/chat/messages/skill-message.es.js +2 -2
  100. package/dist/domains/chat/messages/system-reminder-badge.cjs.js +1 -1
  101. package/dist/domains/chat/messages/system-reminder-badge.es.js +1 -1
  102. package/dist/domains/chat/tools/badges/agent-badge-wrapper.cjs.js +1 -1
  103. package/dist/domains/chat/tools/badges/agent-badge-wrapper.es.js +1 -1
  104. package/dist/domains/chat/tools/badges/agent-badge.cjs.js +1 -1
  105. package/dist/domains/chat/tools/badges/agent-badge.es.js +1 -1
  106. package/dist/domains/chat/tools/badges/file-tree-badge.cjs.js +2 -2
  107. package/dist/domains/chat/tools/badges/file-tree-badge.es.js +2 -2
  108. package/dist/domains/chat/tools/badges/knowledge-body-range.cjs.js +80 -0
  109. package/dist/domains/chat/tools/badges/knowledge-body-range.cjs.js.map +1 -0
  110. package/dist/domains/chat/tools/badges/knowledge-body-range.d.ts +1 -0
  111. package/dist/domains/chat/tools/badges/knowledge-body-range.es.js +78 -0
  112. package/dist/domains/chat/tools/badges/knowledge-body-range.es.js.map +1 -0
  113. package/dist/domains/chat/tools/badges/knowledge-tool-badge.cjs.js +163 -13
  114. package/dist/domains/chat/tools/badges/knowledge-tool-badge.cjs.js.map +1 -1
  115. package/dist/domains/chat/tools/badges/knowledge-tool-badge.es.js +165 -15
  116. package/dist/domains/chat/tools/badges/knowledge-tool-badge.es.js.map +1 -1
  117. package/dist/domains/chat/tools/badges/mcp-input-request-badge.cjs.js +51 -0
  118. package/dist/domains/chat/tools/badges/mcp-input-request-badge.cjs.js.map +1 -0
  119. package/dist/domains/chat/tools/badges/mcp-input-request-badge.d.ts +1 -0
  120. package/dist/domains/chat/tools/badges/mcp-input-request-badge.es.js +49 -0
  121. package/dist/domains/chat/tools/badges/mcp-input-request-badge.es.js.map +1 -0
  122. package/dist/domains/chat/tools/badges/mcp-task-chip.cjs.js +7 -2
  123. package/dist/domains/chat/tools/badges/mcp-task-chip.cjs.js.map +1 -1
  124. package/dist/domains/chat/tools/badges/mcp-task-chip.es.js +7 -2
  125. package/dist/domains/chat/tools/badges/mcp-task-chip.es.js.map +1 -1
  126. package/dist/domains/chat/tools/badges/observation-marker-badge.cjs.js +2 -2
  127. package/dist/domains/chat/tools/badges/observation-marker-badge.es.js +2 -2
  128. package/dist/domains/chat/tools/badges/observation-marker-details.cjs.js +2 -2
  129. package/dist/domains/chat/tools/badges/observation-marker-details.es.js +2 -2
  130. package/dist/domains/chat/tools/badges/observation-renderer.cjs.js +1 -1
  131. package/dist/domains/chat/tools/badges/observation-renderer.es.js +1 -1
  132. package/dist/domains/chat/tools/badges/sandbox-execution-badge.cjs.js +2 -2
  133. package/dist/domains/chat/tools/badges/sandbox-execution-badge.es.js +2 -2
  134. package/dist/domains/chat/tools/badges/tool-approval-badge.cjs.js +1 -1
  135. package/dist/domains/chat/tools/badges/tool-approval-badge.es.js +1 -1
  136. package/dist/domains/chat/tools/badges/tool-badge.cjs.js +9 -4
  137. package/dist/domains/chat/tools/badges/tool-badge.cjs.js.map +1 -1
  138. package/dist/domains/chat/tools/badges/tool-badge.es.js +9 -4
  139. package/dist/domains/chat/tools/badges/tool-badge.es.js.map +1 -1
  140. package/dist/domains/chat/tools/badges/use-deferred-input-request.cjs.js +81 -0
  141. package/dist/domains/chat/tools/badges/use-deferred-input-request.cjs.js.map +1 -0
  142. package/dist/domains/chat/tools/badges/use-deferred-input-request.d.ts +1 -0
  143. package/dist/domains/chat/tools/badges/use-deferred-input-request.es.js +77 -0
  144. package/dist/domains/chat/tools/badges/use-deferred-input-request.es.js.map +1 -0
  145. package/dist/domains/chat/tools/badges/use-mcp-task-progress.cjs.js +11 -2
  146. package/dist/domains/chat/tools/badges/use-mcp-task-progress.cjs.js.map +1 -1
  147. package/dist/domains/chat/tools/badges/use-mcp-task-progress.es.js +11 -2
  148. package/dist/domains/chat/tools/badges/use-mcp-task-progress.es.js.map +1 -1
  149. package/dist/domains/chat/tools/badges/workflow-badge.cjs.js +1 -1
  150. package/dist/domains/chat/tools/badges/workflow-badge.es.js +1 -1
  151. package/dist/domains/chat/tools/connect-prompt-tool.cjs.js +79 -4
  152. package/dist/domains/chat/tools/connect-prompt-tool.cjs.js.map +1 -1
  153. package/dist/domains/chat/tools/connect-prompt-tool.es.js +79 -4
  154. package/dist/domains/chat/tools/connect-prompt-tool.es.js.map +1 -1
  155. package/dist/domains/chat/tools/mcp-input-request-tool.cjs.js +238 -0
  156. package/dist/domains/chat/tools/mcp-input-request-tool.cjs.js.map +1 -0
  157. package/dist/domains/chat/tools/mcp-input-request-tool.d.ts +1 -0
  158. package/dist/domains/chat/tools/mcp-input-request-tool.es.js +237 -0
  159. package/dist/domains/chat/tools/mcp-input-request-tool.es.js.map +1 -0
  160. package/dist/domains/chat/tools/mcp-input-request.cjs.js +40 -0
  161. package/dist/domains/chat/tools/mcp-input-request.cjs.js.map +1 -0
  162. package/dist/domains/chat/tools/mcp-input-request.d.ts +1 -0
  163. package/dist/domains/chat/tools/mcp-input-request.es.js +33 -0
  164. package/dist/domains/chat/tools/mcp-input-request.es.js.map +1 -0
  165. package/dist/domains/chat/tools/tool-card-kind.cjs.js +9 -4
  166. package/dist/domains/chat/tools/tool-card-kind.cjs.js.map +1 -1
  167. package/dist/domains/chat/tools/tool-card-kind.es.js +9 -5
  168. package/dist/domains/chat/tools/tool-card-kind.es.js.map +1 -1
  169. package/dist/domains/chat/tools/tool-card.cjs.js +1 -1
  170. package/dist/domains/chat/tools/tool-card.es.js +1 -1
  171. package/dist/domains/chat/tools/tool-groups.cjs.js +1 -1
  172. package/dist/domains/chat/tools/tool-groups.es.js +1 -1
  173. package/dist/domains/chat.cjs.js +5 -3
  174. package/dist/domains/chat.es.js +4 -4
  175. package/dist/domains/connect/types.cjs.js.map +1 -1
  176. package/dist/domains/connect/types.es.js.map +1 -1
  177. package/dist/domains/connect/use-user-connect.cjs.js +19 -2
  178. package/dist/domains/connect/use-user-connect.cjs.js.map +1 -1
  179. package/dist/domains/connect/use-user-connect.es.js +19 -2
  180. package/dist/domains/connect/use-user-connect.es.js.map +1 -1
  181. package/dist/domains/dashboards/components/dashboard-renderer.cjs.js +4 -3
  182. package/dist/domains/dashboards/components/dashboard-renderer.cjs.js.map +1 -1
  183. package/dist/domains/dashboards/components/dashboard-renderer.es.js +4 -3
  184. package/dist/domains/dashboards/components/dashboard-renderer.es.js.map +1 -1
  185. package/dist/domains/dashboards/components/widget-chrome.cjs.js +1 -1
  186. package/dist/domains/dashboards/components/widget-chrome.es.js +1 -1
  187. package/dist/domains/dashboards/components/widget-error.cjs.js +1 -1
  188. package/dist/domains/dashboards/components/widget-error.es.js +1 -1
  189. package/dist/domains/dashboards/hooks/use-widget-views.cjs.js +4 -3
  190. package/dist/domains/dashboards/hooks/use-widget-views.cjs.js.map +1 -1
  191. package/dist/domains/dashboards/hooks/use-widget-views.es.js +4 -3
  192. package/dist/domains/dashboards/hooks/use-widget-views.es.js.map +1 -1
  193. package/dist/domains/dashboards/kinds/scores/scores-widget.cjs.js +9 -6
  194. package/dist/domains/dashboards/kinds/scores/scores-widget.cjs.js.map +1 -1
  195. package/dist/domains/dashboards/kinds/scores/scores-widget.es.js +9 -6
  196. package/dist/domains/dashboards/kinds/scores/scores-widget.es.js.map +1 -1
  197. package/dist/domains/dashboards/kinds/table/table-tabs.cjs.js +2 -2
  198. package/dist/domains/dashboards/kinds/table/table-tabs.es.js +2 -2
  199. package/dist/domains/dashboards/kinds/table/table-widget.cjs.js +1 -1
  200. package/dist/domains/dashboards/kinds/table/table-widget.es.js +1 -1
  201. package/dist/domains/dashboards/kinds/timeseries/timeseries-widget.cjs.js +6 -5
  202. package/dist/domains/dashboards/kinds/timeseries/timeseries-widget.cjs.js.map +1 -1
  203. package/dist/domains/dashboards/kinds/timeseries/timeseries-widget.es.js +6 -5
  204. package/dist/domains/dashboards/kinds/timeseries/timeseries-widget.es.js.map +1 -1
  205. package/dist/domains/dashboards/lib/chrome.cjs.js +9 -2
  206. package/dist/domains/dashboards/lib/chrome.cjs.js.map +1 -1
  207. package/dist/domains/dashboards/lib/chrome.es.js +9 -2
  208. package/dist/domains/dashboards/lib/chrome.es.js.map +1 -1
  209. package/dist/domains/dashboards/widget-kind.cjs.js.map +1 -1
  210. package/dist/domains/dashboards/widget-kind.es.js.map +1 -1
  211. package/dist/domains/knowledge/components/KnowledgePageCard.cjs.js +48 -0
  212. package/dist/domains/knowledge/components/KnowledgePageCard.cjs.js.map +1 -0
  213. package/dist/domains/knowledge/components/KnowledgePageCard.d.ts +1 -0
  214. package/dist/domains/knowledge/components/KnowledgePageCard.es.js +47 -0
  215. package/dist/domains/knowledge/components/KnowledgePageCard.es.js.map +1 -0
  216. package/dist/domains/knowledge/components/KnowledgePageDetail.cjs.js +63 -5
  217. package/dist/domains/knowledge/components/KnowledgePageDetail.cjs.js.map +1 -1
  218. package/dist/domains/knowledge/components/KnowledgePageDetail.es.js +64 -6
  219. package/dist/domains/knowledge/components/KnowledgePageDetail.es.js.map +1 -1
  220. package/dist/domains/knowledge/components/KnowledgePageExplorer.cjs.js +485 -47
  221. package/dist/domains/knowledge/components/KnowledgePageExplorer.cjs.js.map +1 -1
  222. package/dist/domains/knowledge/components/KnowledgePageExplorer.es.js +487 -50
  223. package/dist/domains/knowledge/components/KnowledgePageExplorer.es.js.map +1 -1
  224. package/dist/domains/knowledge/components/KnowledgePageGraph.cjs.js +1051 -123
  225. package/dist/domains/knowledge/components/KnowledgePageGraph.cjs.js.map +1 -1
  226. package/dist/domains/knowledge/components/KnowledgePageGraph.es.js +1054 -126
  227. package/dist/domains/knowledge/components/KnowledgePageGraph.es.js.map +1 -1
  228. package/dist/domains/knowledge/components/KnowledgePageTree.cjs.js +75 -3
  229. package/dist/domains/knowledge/components/KnowledgePageTree.cjs.js.map +1 -1
  230. package/dist/domains/knowledge/components/KnowledgePageTree.es.js +76 -4
  231. package/dist/domains/knowledge/components/KnowledgePageTree.es.js.map +1 -1
  232. package/dist/domains/knowledge/lib/circleText.cjs.js +9 -0
  233. package/dist/domains/knowledge/lib/circleText.cjs.js.map +1 -0
  234. package/dist/domains/knowledge/lib/circleText.d.ts +1 -0
  235. package/dist/domains/knowledge/lib/circleText.es.js +8 -0
  236. package/dist/domains/knowledge/lib/circleText.es.js.map +1 -0
  237. package/dist/domains/knowledge/lib/fitViewport.cjs.js +82 -0
  238. package/dist/domains/knowledge/lib/fitViewport.cjs.js.map +1 -0
  239. package/dist/domains/knowledge/lib/fitViewport.d.ts +1 -0
  240. package/dist/domains/knowledge/lib/fitViewport.es.js +73 -0
  241. package/dist/domains/knowledge/lib/fitViewport.es.js.map +1 -0
  242. package/dist/domains/knowledge/lib/graphShape.cjs.js +524 -0
  243. package/dist/domains/knowledge/lib/graphShape.cjs.js.map +1 -0
  244. package/dist/domains/knowledge/lib/graphShape.d.ts +1 -0
  245. package/dist/domains/knowledge/lib/graphShape.es.js +499 -0
  246. package/dist/domains/knowledge/lib/graphShape.es.js.map +1 -0
  247. package/dist/domains/knowledge/lib/linkCountsText.cjs.js +11 -0
  248. package/dist/domains/knowledge/lib/linkCountsText.cjs.js.map +1 -0
  249. package/dist/domains/knowledge/lib/linkCountsText.d.ts +1 -0
  250. package/dist/domains/knowledge/lib/linkCountsText.es.js +10 -0
  251. package/dist/domains/knowledge/lib/linkCountsText.es.js.map +1 -0
  252. package/dist/domains/knowledge/lib/pageAddress.cjs.js +29 -0
  253. package/dist/domains/knowledge/lib/pageAddress.cjs.js.map +1 -0
  254. package/dist/domains/knowledge/lib/pageAddress.d.ts +1 -0
  255. package/dist/domains/knowledge/lib/pageAddress.es.js +27 -0
  256. package/dist/domains/knowledge/lib/pageAddress.es.js.map +1 -0
  257. package/dist/domains/knowledge/lib/pageGraph.cjs.js +11 -11
  258. package/dist/domains/knowledge/lib/pageGraph.cjs.js.map +1 -1
  259. package/dist/domains/knowledge/lib/pageGraph.es.js +11 -11
  260. package/dist/domains/knowledge/lib/pageGraph.es.js.map +1 -1
  261. package/dist/domains/knowledge/lib/pageRefs.cjs.js +69 -0
  262. package/dist/domains/knowledge/lib/pageRefs.cjs.js.map +1 -0
  263. package/dist/domains/knowledge/lib/pageRefs.d.ts +1 -0
  264. package/dist/domains/knowledge/lib/pageRefs.es.js +66 -0
  265. package/dist/domains/knowledge/lib/pageRefs.es.js.map +1 -0
  266. package/dist/domains/knowledge/lib/pageTree.cjs.js +5 -0
  267. package/dist/domains/knowledge/lib/pageTree.cjs.js.map +1 -1
  268. package/dist/domains/knowledge/lib/pageTree.es.js +5 -1
  269. package/dist/domains/knowledge/lib/pageTree.es.js.map +1 -1
  270. package/dist/domains/knowledge/lib/remarkKnowledgeLinks.cjs.js +82 -0
  271. package/dist/domains/knowledge/lib/remarkKnowledgeLinks.cjs.js.map +1 -0
  272. package/dist/domains/knowledge/lib/remarkKnowledgeLinks.d.ts +1 -0
  273. package/dist/domains/knowledge/lib/remarkKnowledgeLinks.es.js +78 -0
  274. package/dist/domains/knowledge/lib/remarkKnowledgeLinks.es.js.map +1 -0
  275. package/dist/domains/knowledge/lib/tooltipSide.cjs.js +77 -0
  276. package/dist/domains/knowledge/lib/tooltipSide.cjs.js.map +1 -0
  277. package/dist/domains/knowledge/lib/tooltipSide.d.ts +1 -0
  278. package/dist/domains/knowledge/lib/tooltipSide.es.js +75 -0
  279. package/dist/domains/knowledge/lib/tooltipSide.es.js.map +1 -0
  280. package/dist/domains/knowledge/lib/useLeavingNodes.cjs.js +65 -0
  281. package/dist/domains/knowledge/lib/useLeavingNodes.cjs.js.map +1 -0
  282. package/dist/domains/knowledge/lib/useLeavingNodes.d.ts +1 -0
  283. package/dist/domains/knowledge/lib/useLeavingNodes.es.js +62 -0
  284. package/dist/domains/knowledge/lib/useLeavingNodes.es.js.map +1 -0
  285. package/dist/domains/knowledge/lib/useStableWhile.cjs.js +15 -0
  286. package/dist/domains/knowledge/lib/useStableWhile.cjs.js.map +1 -0
  287. package/dist/domains/knowledge/lib/useStableWhile.d.ts +1 -0
  288. package/dist/domains/knowledge/lib/useStableWhile.es.js +14 -0
  289. package/dist/domains/knowledge/lib/useStableWhile.es.js.map +1 -0
  290. package/dist/domains/metrics/components/agent-runs-card.cjs.js +3 -3
  291. package/dist/domains/metrics/components/agent-runs-card.es.js +3 -3
  292. package/dist/domains/metrics/components/breakdown/breakdown-tab-body.cjs.js +1 -1
  293. package/dist/domains/metrics/components/breakdown/breakdown-tab-body.es.js +1 -1
  294. package/dist/domains/metrics/components/breakdown-card.cjs.js +1 -1
  295. package/dist/domains/metrics/components/breakdown-card.es.js +1 -1
  296. package/dist/domains/metrics/components/chart-area.cjs.js +1 -1
  297. package/dist/domains/metrics/components/chart-area.es.js +1 -1
  298. package/dist/domains/metrics/components/chart-card-error.cjs.js +1 -1
  299. package/dist/domains/metrics/components/chart-card-error.es.js +1 -1
  300. package/dist/domains/metrics/components/chart-card.cjs.js +1 -1
  301. package/dist/domains/metrics/components/chart-card.es.js +1 -1
  302. package/dist/domains/metrics/components/date-range-selector.cjs.js +1 -1
  303. package/dist/domains/metrics/components/date-range-selector.es.js +1 -1
  304. package/dist/domains/metrics/components/distinct-ids/distinct-ids-chart.cjs.js +3 -2
  305. package/dist/domains/metrics/components/distinct-ids/distinct-ids-chart.cjs.js.map +1 -1
  306. package/dist/domains/metrics/components/distinct-ids/distinct-ids-chart.es.js +3 -2
  307. package/dist/domains/metrics/components/distinct-ids/distinct-ids-chart.es.js.map +1 -1
  308. package/dist/domains/metrics/components/failure-rate-card.cjs.js +3 -2
  309. package/dist/domains/metrics/components/failure-rate-card.cjs.js.map +1 -1
  310. package/dist/domains/metrics/components/failure-rate-card.es.js +3 -2
  311. package/dist/domains/metrics/components/failure-rate-card.es.js.map +1 -1
  312. package/dist/domains/metrics/components/latency-card.cjs.js +3 -2
  313. package/dist/domains/metrics/components/latency-card.cjs.js.map +1 -1
  314. package/dist/domains/metrics/components/latency-card.es.js +3 -2
  315. package/dist/domains/metrics/components/latency-card.es.js.map +1 -1
  316. package/dist/domains/metrics/components/metrics-time-range-chip.cjs.js +1 -1
  317. package/dist/domains/metrics/components/metrics-time-range-chip.es.js +1 -1
  318. package/dist/domains/metrics/components/scores-card.cjs.js +2 -1
  319. package/dist/domains/metrics/components/scores-card.cjs.js.map +1 -1
  320. package/dist/domains/metrics/components/scores-card.es.js +2 -1
  321. package/dist/domains/metrics/components/scores-card.es.js.map +1 -1
  322. package/dist/domains/metrics/components/token-usage-card.cjs.js +3 -3
  323. package/dist/domains/metrics/components/token-usage-card.es.js +3 -3
  324. package/dist/domains/metrics/components/trace-aggregate-card.cjs.js +1 -1
  325. package/dist/domains/metrics/components/trace-aggregate-card.es.js +1 -1
  326. package/dist/domains/observability/components/observability-histogram.cjs.js +1 -1
  327. package/dist/domains/observability/components/observability-histogram.es.js +1 -1
  328. package/dist/domains/scores/components/trace-scores-list.cjs.js +2 -2
  329. package/dist/domains/scores/components/trace-scores-list.es.js +2 -2
  330. package/dist/domains/skills/skill-simple-form.cjs.js +1 -1
  331. package/dist/domains/skills/skill-simple-form.es.js +1 -1
  332. package/dist/domains/spans/components/spans-filter-bar.cjs.js +2 -2
  333. package/dist/domains/spans/components/spans-filter-bar.es.js +2 -2
  334. package/dist/domains/spans/hooks/use-spans-filter-bar.cjs.js +1 -1
  335. package/dist/domains/spans/hooks/use-spans-filter-bar.es.js +1 -1
  336. package/dist/domains/threads/components/threads-filter-bar.cjs.js +2 -2
  337. package/dist/domains/threads/components/threads-filter-bar.es.js +2 -2
  338. package/dist/domains/threads/hooks/use-threads-filter-bar.cjs.js +1 -1
  339. package/dist/domains/threads/hooks/use-threads-filter-bar.es.js +1 -1
  340. package/dist/domains/traces/components/span-payload/span-error-renderer.cjs.js +1 -1
  341. package/dist/domains/traces/components/span-payload/span-error-renderer.es.js +1 -1
  342. package/dist/domains/traces/components/span-payload/span-input-renderers.cjs.js +1 -1
  343. package/dist/domains/traces/components/span-payload/span-input-renderers.es.js +1 -1
  344. package/dist/domains/traces/components/span-payload/span-output-renderers.cjs.js +2 -2
  345. package/dist/domains/traces/components/span-payload/span-output-renderers.es.js +2 -2
  346. package/dist/domains/traces/components/span-payload/span-payload-messages.cjs.js +2 -2
  347. package/dist/domains/traces/components/span-payload/span-payload-messages.es.js +2 -2
  348. package/dist/domains/traces/components/span-payload/span-payload-primitives.cjs.js +1 -1
  349. package/dist/domains/traces/components/span-payload/span-payload-primitives.es.js +1 -1
  350. package/dist/domains/traces/components/span-payload/span-payload-processor.cjs.js +1 -1
  351. package/dist/domains/traces/components/span-payload/span-payload-processor.es.js +1 -1
  352. package/dist/domains/traces/components/span-payload/span-payload-tool.cjs.js +1 -1
  353. package/dist/domains/traces/components/span-payload/span-payload-tool.es.js +1 -1
  354. package/dist/domains/traces/components/span-payload/span-processor-mutations.cjs.js +1 -1
  355. package/dist/domains/traces/components/span-payload/span-processor-mutations.es.js +1 -1
  356. package/dist/domains/traces/components/span-payload/span-tools-section.cjs.js +1 -1
  357. package/dist/domains/traces/components/span-payload/span-tools-section.es.js +1 -1
  358. package/dist/domains/traces/components/span-timeline-row.cjs.js +1 -1
  359. package/dist/domains/traces/components/span-timeline-row.es.js +1 -1
  360. package/dist/domains/traces/components/span-timing-hover-card.cjs.js +1 -1
  361. package/dist/domains/traces/components/span-timing-hover-card.es.js +1 -1
  362. package/dist/domains/traces/components/trace-data-panel-view.cjs.js +8 -2
  363. package/dist/domains/traces/components/trace-data-panel-view.cjs.js.map +1 -1
  364. package/dist/domains/traces/components/trace-data-panel-view.es.js +8 -2
  365. package/dist/domains/traces/components/trace-data-panel-view.es.js.map +1 -1
  366. package/dist/domains/traces/components/trace-error-cell.cjs.js +1 -1
  367. package/dist/domains/traces/components/trace-error-cell.es.js +1 -1
  368. package/dist/domains/traces/components/traces-explorer/traces-explorer-filter-bar.cjs.js +2 -2
  369. package/dist/domains/traces/components/traces-explorer/traces-explorer-filter-bar.es.js +2 -2
  370. package/dist/domains/traces/components/traces-explorer/use-traces-filter-bar.cjs.js +1 -1
  371. package/dist/domains/traces/components/traces-explorer/use-traces-filter-bar.es.js +1 -1
  372. package/dist/domains/workflows/runs/workflow-run-list.cjs.js +1 -1
  373. package/dist/domains/workflows/runs/workflow-run-list.es.js +1 -1
  374. package/dist/domains/workflows/workflow/input/workflow-processor-input.cjs.js +2 -2
  375. package/dist/domains/workflows/workflow/input/workflow-processor-input.es.js +2 -2
  376. package/dist/domains/workflows/workflow/use-workflow-trigger.cjs.js +3 -3
  377. package/dist/domains/workflows/workflow/use-workflow-trigger.es.js +3 -3
  378. package/dist/domains/workflows/workflow/workflow-input-data.cjs.js +1 -1
  379. package/dist/domains/workflows/workflow/workflow-input-data.es.js +1 -1
  380. package/dist/domains/workflows/workflow/workflow-suspended-steps.cjs.js +2 -2
  381. package/dist/domains/workflows/workflow/workflow-suspended-steps.es.js +2 -2
  382. package/dist/domains/workflows/workflow/workflow-time-travel-form.cjs.js +2 -2
  383. package/dist/domains/workflows/workflow/workflow-time-travel-form.es.js +2 -2
  384. package/dist/domains/workspace/components/workspace-add-skill-dialog.cjs.js +1 -1
  385. package/dist/domains/workspace/components/workspace-add-skill-dialog.es.js +1 -1
  386. package/dist/domains/workspace/components/workspace-markdown-preview.cjs.js +1 -1
  387. package/dist/domains/workspace/components/workspace-markdown-preview.es.js +1 -1
  388. package/dist/{filter-bar-time-range-mg9JeYue.js → filter-bar-time-range-qlV8p7hp.js} +2 -2
  389. package/dist/{filter-bar-time-range-mg9JeYue.js.map → filter-bar-time-range-qlV8p7hp.js.map} +1 -1
  390. package/dist/{filter-bar-time-range-BA-pXMlo.cjs → filter-bar-time-range-zdM024JD.cjs} +2 -2
  391. package/dist/{filter-bar-time-range-BA-pXMlo.cjs.map → filter-bar-time-range-zdM024JD.cjs.map} +1 -1
  392. package/dist/lib/form/dynamic-form.cjs.js +2 -2
  393. package/dist/lib/form/dynamic-form.es.js +2 -2
  394. package/dist/lib/form/json-draft.cjs.js +1 -1
  395. package/dist/lib/form/json-draft.es.js +1 -1
  396. package/dist/lib/form/zod-provider.cjs.js +1 -1
  397. package/dist/lib/form/zod-provider.es.js +1 -1
  398. package/dist/{span-payload-primitives-B3RdahsC.js → span-payload-primitives-CKKIAVPJ.js} +4 -4
  399. package/dist/{span-payload-primitives-B3RdahsC.js.map → span-payload-primitives-CKKIAVPJ.js.map} +1 -1
  400. package/dist/{span-payload-primitives-_2d-pAOD.cjs → span-payload-primitives-D4tHWN2W.cjs} +4 -4
  401. package/dist/{span-payload-primitives-_2d-pAOD.cjs.map → span-payload-primitives-D4tHWN2W.cjs.map} +1 -1
  402. package/dist/src/domains/chat/knowledge/knowledge-links.d.ts +32 -4
  403. package/dist/src/domains/chat/knowledge/pinned-knowledge-data.d.ts +2 -0
  404. package/dist/src/domains/chat/tools/badges/knowledge-body-range.d.ts +12 -0
  405. package/dist/src/domains/chat/tools/badges/knowledge-tool-badge.d.ts +5 -2
  406. package/dist/src/domains/chat/tools/badges/mcp-input-request-badge.d.ts +18 -0
  407. package/dist/src/domains/chat/tools/badges/tool-badge.d.ts +4 -1
  408. package/dist/src/domains/chat/tools/badges/use-deferred-input-request.d.ts +44 -0
  409. package/dist/src/domains/chat/tools/badges/use-mcp-task-progress.d.ts +6 -1
  410. package/dist/src/domains/chat/tools/connect-prompt-tool.d.ts +10 -1
  411. package/dist/src/domains/chat/tools/mcp-input-request-tool.d.ts +18 -0
  412. package/dist/src/domains/chat/tools/mcp-input-request.d.ts +40 -0
  413. package/dist/src/domains/chat/tools/tool-card-kind.d.ts +4 -2
  414. package/dist/src/domains/chat/tools/tool-card.d.ts +1 -1
  415. package/dist/src/domains/connect/types.d.ts +16 -0
  416. package/dist/src/domains/dashboards/components/dashboard-renderer.d.ts +4 -2
  417. package/dist/src/domains/dashboards/hooks/use-widget-views.d.ts +4 -3
  418. package/dist/src/domains/dashboards/index.d.ts +1 -1
  419. package/dist/src/domains/dashboards/kinds/scores/scores-widget.d.ts +1 -1
  420. package/dist/src/domains/dashboards/lib/chrome.d.ts +6 -4
  421. package/dist/src/domains/dashboards/widget-kind.d.ts +12 -0
  422. package/dist/src/domains/knowledge/components/KnowledgePageCard.d.ts +23 -0
  423. package/dist/src/domains/knowledge/components/KnowledgePageExplorer.d.ts +29 -0
  424. package/dist/src/domains/knowledge/components/KnowledgePageGraph.d.ts +27 -1
  425. package/dist/src/domains/knowledge/components/KnowledgePageTree.d.ts +2 -1
  426. package/dist/src/domains/knowledge/lib/circleText.d.ts +2 -0
  427. package/dist/src/domains/knowledge/lib/fitViewport.d.ts +67 -0
  428. package/dist/src/domains/knowledge/lib/graphShape.d.ts +131 -0
  429. package/dist/src/domains/knowledge/lib/linkCountsText.d.ts +5 -0
  430. package/dist/src/domains/knowledge/lib/pageAddress.d.ts +5 -0
  431. package/dist/src/domains/knowledge/lib/pageGraph.d.ts +4 -4
  432. package/dist/src/domains/knowledge/lib/pageRefs.d.ts +15 -0
  433. package/dist/src/domains/knowledge/lib/pageTree.d.ts +2 -0
  434. package/dist/src/domains/knowledge/lib/remarkKnowledgeLinks.d.ts +13 -0
  435. package/dist/src/domains/knowledge/lib/tooltipSide.d.ts +40 -0
  436. package/dist/src/domains/knowledge/lib/useLeavingNodes.d.ts +14 -0
  437. package/dist/src/domains/knowledge/lib/useStableWhile.d.ts +5 -0
  438. package/dist/src/domains/knowledge/pageTypes.d.ts +6 -1
  439. package/dist/src/ds/components/DateTimeRangePicker/date-time-range-picker.d.ts +12 -1
  440. package/dist/src/ds/components/MarkdownRenderer/markdown-renderer.d.ts +8 -1
  441. package/dist/src/ds/components/MetricsCard/metrics-card-headline.d.ts +1 -1
  442. package/dist/src/ds/components/MetricsLineChart/metrics-line-chart.d.ts +8 -0
  443. package/dist/src/ds/components/ai/tool-call/tool-phrases.d.ts +6 -0
  444. package/dist/style.css +73 -2
  445. package/dist/{tool-approval-1qiB4hhG.cjs → tool-approval-CJvPDL7D.cjs} +4 -4
  446. package/dist/{tool-approval-1qiB4hhG.cjs.map → tool-approval-CJvPDL7D.cjs.map} +1 -1
  447. package/dist/{tool-approval-B6MFcaKV.js → tool-approval-DyN11vFA.js} +4 -4
  448. package/dist/{tool-approval-B6MFcaKV.js.map → tool-approval-DyN11vFA.js.map} +1 -1
  449. package/dist/{tool-call-Bu66PkD-.cjs → tool-call-DBn14X-3.cjs} +9 -3
  450. package/dist/{tool-call-Bu66PkD-.cjs.map → tool-call-DBn14X-3.cjs.map} +1 -1
  451. package/dist/{tool-call-Ch9-jjXU.js → tool-call-Dsj43lvJ.js} +9 -3
  452. package/dist/{tool-call-Ch9-jjXU.js.map → tool-call-Dsj43lvJ.js.map} +1 -1
  453. package/dist/{tool-card-DrqPZfPQ.cjs → tool-card-BOLXeKIp.cjs} +167 -126
  454. package/dist/tool-card-BOLXeKIp.cjs.map +1 -0
  455. package/dist/{tool-card-sO6P2Qj4.js → tool-card-HZ5bm7ue.js} +168 -127
  456. package/dist/tool-card-HZ5bm7ue.js.map +1 -0
  457. package/dist/{tool-presentation-DvCsb_kz.js → tool-presentation-CvibOP1J.js} +6 -1
  458. package/dist/tool-presentation-CvibOP1J.js.map +1 -0
  459. package/dist/{tool-presentation-CQlDEwgS.cjs → tool-presentation-D6nzVruN.cjs} +6 -1
  460. package/dist/tool-presentation-D6nzVruN.cjs.map +1 -0
  461. package/package.json +11 -11
  462. package/dist/MarkdownRenderer-2GOXQJEv.js.map +0 -1
  463. package/dist/MarkdownRenderer-CB8Z_CHc.cjs.map +0 -1
  464. package/dist/MetricsCard-CEB-f2sv.cjs.map +0 -1
  465. package/dist/MetricsCard-M8awJ2B_.js.map +0 -1
  466. package/dist/MetricsLineChart-BhHoduO0.js.map +0 -1
  467. package/dist/MetricsLineChart-CjBm4IXu.cjs.map +0 -1
  468. package/dist/date-time-range-picker-CTt7Od0P.cjs.map +0 -1
  469. package/dist/date-time-range-picker-DKh1K9Iy.js.map +0 -1
  470. package/dist/domains/knowledge/lib/pageLayout.cjs.js +0 -49
  471. package/dist/domains/knowledge/lib/pageLayout.cjs.js.map +0 -1
  472. package/dist/domains/knowledge/lib/pageLayout.d.ts +0 -1
  473. package/dist/domains/knowledge/lib/pageLayout.es.js +0 -48
  474. package/dist/domains/knowledge/lib/pageLayout.es.js.map +0 -1
  475. package/dist/src/domains/knowledge/lib/pageLayout.d.ts +0 -24
  476. package/dist/tool-card-DrqPZfPQ.cjs.map +0 -1
  477. package/dist/tool-card-sO6P2Qj4.js.map +0 -1
  478. package/dist/tool-presentation-CQlDEwgS.cjs.map +0 -1
  479. package/dist/tool-presentation-DvCsb_kz.js.map +0 -1
@@ -1,9 +1,30 @@
1
1
  import { t as cn } from "../../../utils-DQx8TpNT.js";
2
- import { buildPageTree, pageAncestorIds, visiblePageRows } from "../lib/pageTree.es.js";
2
+ import { buildPageTree, childCountLabel, pageAncestorIds, visiblePageRows } from "../lib/pageTree.es.js";
3
+ import { prefersMotion } from "../lib/useLeavingNodes.es.js";
3
4
  import { Fragment, useEffect, useMemo, useRef, useState } from "react";
4
5
  import { jsx, jsxs } from "react/jsx-runtime";
5
6
  import { ChevronRight, Pin } from "lucide-react";
6
7
  // src/domains/knowledge/components/KnowledgePageTree.tsx
8
+ /**
9
+ * The box of the nearest ancestor (or the element itself) that really scrolls vertically. The tree sets
10
+ * `overflow-y: auto` itself but, as tall as its rows, never overflows; a parent is what scrolls, so a
11
+ * node counts only when its content is taller than it is.
12
+ */
13
+ function scrollingBox(element) {
14
+ let overflowing;
15
+ for (let node = element; node; node = node.parentElement) {
16
+ const { overflowY } = getComputedStyle(node);
17
+ if (overflowY !== "auto" && overflowY !== "scroll" && overflowY !== "overlay") continue;
18
+ if (node.scrollHeight > node.clientHeight) return node.getBoundingClientRect();
19
+ overflowing ??= node;
20
+ }
21
+ return (overflowing ?? element)?.getBoundingClientRect();
22
+ }
23
+ /** Where in the scroller a row focused from elsewhere lands, as a fraction of its height from the top. */
24
+ var SCROLL_ROW_AT = 1 / 3;
25
+ /** A row between these fractions of the scroller is comfortably in view and is not moved. */
26
+ var COMFORT_TOP = .1;
27
+ var COMFORT_BOTTOM = .7;
7
28
  /** The key {@link KnowledgePageTree}'s `loadMore` uses for the root level. */
8
29
  var KNOWLEDGE_TREE_ROOT = "";
9
30
  /**
@@ -14,7 +35,8 @@ var KNOWLEDGE_TREE_ROOT = "";
14
35
  *
15
36
  * A host that loads the tree a level at a time passes `mayHaveChildren` (so unloaded pages still offer
16
37
  * a chevron), listens to `onExpandedChange` to load the opened levels, and passes `loadMore` for
17
- * levels with more children to fetch.
38
+ * levels with more children to fetch. A page's `childCount`, when the server sends one, shows beside
39
+ * its name. Selecting a page with children also opens it.
18
40
  */
19
41
  function KnowledgePageTree({ pages, pinnedIds, selectedPageId, onSelect, initiallyExpanded, mayHaveChildren, onExpandedChange, loadMore, "aria-label": ariaLabel = "Knowledge pages" }) {
20
42
  const roots = useMemo(() => buildPageTree(pages), [pages]);
@@ -22,9 +44,16 @@ function KnowledgePageTree({ pages, pinnedIds, selectedPageId, onSelect, initial
22
44
  const [expanded, setExpanded] = useState(() => new Set(initiallyExpanded ?? roots.map((root) => root.page.id)));
23
45
  const [focusedId, setFocusedId] = useState(null);
24
46
  const itemRefs = useRef(/* @__PURE__ */ new Map());
47
+ const revealed = useRef(null);
25
48
  useEffect(() => {
26
- if (!selectedPageId) return;
49
+ if (!selectedPageId) {
50
+ revealed.current = null;
51
+ return;
52
+ }
27
53
  const path = pageAncestorIds(pages, selectedPageId);
54
+ const key = [selectedPageId, ...path].join("/");
55
+ if (revealed.current === key) return;
56
+ revealed.current = key;
28
57
  setExpanded((current) => path.every((id) => current.has(id)) ? current : /* @__PURE__ */ new Set([...current, ...path]));
29
58
  }, [pages, selectedPageId]);
30
59
  useEffect(() => {
@@ -38,6 +67,35 @@ function KnowledgePageTree({ pages, pinnedIds, selectedPageId, onSelect, initial
38
67
  expanded,
39
68
  mayHaveChildren
40
69
  ]);
70
+ const scroller = useRef(null);
71
+ const scrolledTo = useRef(null);
72
+ const userScrolled = useRef(false);
73
+ useEffect(() => {
74
+ if (!selectedPageId) {
75
+ scrolledTo.current = null;
76
+ return;
77
+ }
78
+ const element = itemRefs.current.get(selectedPageId);
79
+ if (!element) return;
80
+ const first = scrolledTo.current !== selectedPageId;
81
+ if (first) {
82
+ scrolledTo.current = selectedPageId;
83
+ userScrolled.current = false;
84
+ } else if (userScrolled.current) return;
85
+ const box = scrollingBox(scroller.current);
86
+ const at = element.getBoundingClientRect();
87
+ if (!first && !box) return;
88
+ if (!first && box && box.height === 0 && at.top >= box.top && at.bottom <= box.bottom) return;
89
+ if (box && box.height > 0) {
90
+ if (at.top >= box.top + box.height * COMFORT_TOP && at.bottom <= box.top + box.height * COMFORT_BOTTOM) return;
91
+ element.style.scrollMarginTop = `${box.height * SCROLL_ROW_AT}px`;
92
+ }
93
+ element.scrollIntoView?.({
94
+ block: "start",
95
+ behavior: first && prefersMotion() ? "smooth" : "auto"
96
+ });
97
+ element.style.scrollMarginTop = "";
98
+ }, [rows, selectedPageId]);
41
99
  const activeId = focusedId && rows.some((row) => row.page.id === focusedId) ? focusedId : rows.find((row) => row.page.id === selectedPageId)?.page.id ?? rows[0]?.page.id;
42
100
  const toggle = (id, open) => setExpanded((current) => {
43
101
  if (current.has(id) === open) return current;
@@ -83,9 +141,14 @@ function KnowledgePageTree({ pages, pinnedIds, selectedPageId, onSelect, initial
83
141
  });
84
142
  const ancestorAt = [];
85
143
  return /* @__PURE__ */ jsx("div", {
144
+ ref: scroller,
86
145
  role: "tree",
87
146
  "aria-label": ariaLabel,
88
147
  className: "min-h-0 overflow-y-auto py-1",
148
+ onWheel: () => userScrolled.current = true,
149
+ onTouchMove: () => userScrolled.current = true,
150
+ onPointerDown: () => userScrolled.current = true,
151
+ onKeyDown: () => userScrolled.current = true,
89
152
  children: rows.map((row, index) => {
90
153
  const selected = row.page.id === selectedPageId;
91
154
  ancestorAt[row.depth] = row.page.id;
@@ -114,7 +177,10 @@ function KnowledgePageTree({ pages, pinnedIds, selectedPageId, onSelect, initial
114
177
  tabIndex: row.page.id === activeId ? 0 : -1,
115
178
  onFocus: () => setFocusedId(row.page.id),
116
179
  onKeyDown: (event) => onKeyDown(event, index),
117
- onClick: () => onSelect(row.page),
180
+ onClick: () => {
181
+ onSelect(row.page);
182
+ if (row.hasChildren) toggle(row.page.id, true);
183
+ },
118
184
  className: cn("flex min-h-8 cursor-pointer items-center gap-1 rounded-md pr-2 outline-none focus-visible:ring-1 focus-visible:ring-border-focus", selected ? "bg-fill text-foreground" : "text-foreground hover:bg-fill"),
119
185
  style: { paddingLeft: `${row.depth * 16 + 4}px` },
120
186
  children: [
@@ -139,6 +205,12 @@ function KnowledgePageTree({ pages, pinnedIds, selectedPageId, onSelect, initial
139
205
  className: cn("min-w-0 flex-1 truncate text-body", row.page.isScope && "font-medium"),
140
206
  children: row.page.name
141
207
  }),
208
+ row.page.childCount ? /* @__PURE__ */ jsx("span", {
209
+ "data-testid": "knowledge-tree-count",
210
+ "aria-label": `${childCountLabel(row.page)} below`,
211
+ className: "shrink-0 text-caption text-muted-foreground tabular-nums",
212
+ children: childCountLabel(row.page)
213
+ }) : null,
142
214
  pinned.has(row.page.id) ? /* @__PURE__ */ jsx(Pin, {
143
215
  size: 12,
144
216
  className: "shrink-0 text-badge-amber-indicator",
@@ -1 +1 @@
1
- {"version":3,"file":"KnowledgePageTree.es.js","names":[],"sources":["../../../../src/domains/knowledge/components/KnowledgePageTree.tsx"],"sourcesContent":["import { ChevronRight, Pin } from 'lucide-react';\nimport { Fragment, useEffect, useMemo, useRef, useState } from 'react';\nimport type { KeyboardEvent } from 'react';\n\nimport { buildPageTree, pageAncestorIds, visiblePageRows } from '../lib/pageTree';\nimport type { KnowledgePagePayload } from '../pageTypes';\n\nimport { cn } from '@/utils/cn';\n\n/** The key {@link KnowledgePageTree}'s `loadMore` uses for the root level. */\nexport const KNOWLEDGE_TREE_ROOT = '';\n\n/**\n * The Knowledge page tree: scopes and pages nested by parent, siblings in\n * stored order. Selecting a page from elsewhere (graph, search) opens the path\n * to it. Keyboard follows the WAI-ARIA tree pattern: Up/Down move, Right opens\n * or enters, Left closes or goes to the parent, Enter/Space selects.\n *\n * A host that loads the tree a level at a time passes `mayHaveChildren` (so unloaded pages still offer\n * a chevron), listens to `onExpandedChange` to load the opened levels, and passes `loadMore` for\n * levels with more children to fetch.\n */\nexport function KnowledgePageTree({\n pages,\n pinnedIds,\n selectedPageId,\n onSelect,\n initiallyExpanded,\n mayHaveChildren,\n onExpandedChange,\n loadMore,\n 'aria-label': ariaLabel = 'Knowledge pages',\n}: {\n pages: KnowledgePagePayload[];\n pinnedIds?: readonly string[];\n selectedPageId?: string | null;\n onSelect: (page: KnowledgePagePayload) => void;\n /** Ids open on first render; defaults to every root. */\n initiallyExpanded?: string[];\n /** True for a page whose children are not loaded yet, so it can still be opened. */\n mayHaveChildren?: (page: KnowledgePagePayload) => boolean;\n onExpandedChange?: (expanded: ReadonlySet<string>) => void;\n /** Parent id ({@link KNOWLEDGE_TREE_ROOT} for the roots) to a loader for its next children. */\n loadMore?: ReadonlyMap<string, () => void>;\n 'aria-label'?: string;\n}) {\n const roots = useMemo(() => buildPageTree(pages), [pages]);\n const pinned = useMemo(() => new Set(pinnedIds), [pinnedIds]);\n const [expanded, setExpanded] = useState<Set<string>>(\n () => new Set(initiallyExpanded ?? roots.map(root => root.page.id)),\n );\n const [focusedId, setFocusedId] = useState<string | null>(null);\n const itemRefs = useRef(new Map<string, HTMLDivElement>());\n\n useEffect(() => {\n if (!selectedPageId) return;\n const path = pageAncestorIds(pages, selectedPageId);\n setExpanded(current => (path.every(id => current.has(id)) ? current : new Set([...current, ...path])));\n }, [pages, selectedPageId]);\n\n useEffect(() => {\n onExpandedChange?.(expanded);\n }, [expanded, onExpandedChange]);\n\n const rows = useMemo(\n () =>\n visiblePageRows(roots, expanded).map(row =>\n !row.hasChildren && mayHaveChildren?.(row.page) ? { ...row, hasChildren: true } : row,\n ),\n [roots, expanded, mayHaveChildren],\n );\n const activeId =\n focusedId && rows.some(row => row.page.id === focusedId)\n ? focusedId\n : (rows.find(row => row.page.id === selectedPageId)?.page.id ?? rows[0]?.page.id);\n\n const toggle = (id: string, open: boolean) =>\n setExpanded(current => {\n if (current.has(id) === open) return current;\n const next = new Set(current);\n if (open) next.add(id);\n else next.delete(id);\n return next;\n });\n\n const focus = (id: string | undefined) => {\n if (!id) return;\n setFocusedId(id);\n itemRefs.current.get(id)?.focus();\n };\n\n const onKeyDown = (event: KeyboardEvent<HTMLDivElement>, index: number) => {\n const row = rows[index];\n if (!row) return;\n switch (event.key) {\n case 'ArrowDown':\n focus(rows[index + 1]?.page.id);\n break;\n case 'ArrowUp':\n focus(rows[index - 1]?.page.id);\n break;\n case 'ArrowRight':\n if (row.hasChildren && !row.expanded) toggle(row.page.id, true);\n else if (row.expanded) focus(rows[index + 1]?.page.id);\n break;\n case 'ArrowLeft':\n if (row.expanded) toggle(row.page.id, false);\n else focus(rows.slice(0, index).findLast(candidate => candidate.depth < row.depth)?.page.id);\n break;\n case 'Enter':\n case ' ':\n onSelect(row.page);\n break;\n default:\n return;\n }\n event.preventDefault();\n };\n\n if (rows.length === 0) {\n return <p className=\"px-3 py-2 text-body text-muted-foreground\">No pages yet.</p>;\n }\n\n const ancestorAt: string[] = [];\n return (\n <div role=\"tree\" aria-label={ariaLabel} className=\"min-h-0 overflow-y-auto py-1\">\n {rows.map((row, index) => {\n const selected = row.page.id === selectedPageId;\n ancestorAt[row.depth] = row.page.id;\n // Levels whose last loaded child is this row's subtree end here: offer their next children.\n const nextDepth = rows[index + 1]?.depth ?? -1;\n const closing: Array<{ parentId: string; depth: number }> = [];\n for (let depth = row.depth - 1; depth >= nextDepth; depth--) {\n const parentId = depth < 0 ? KNOWLEDGE_TREE_ROOT : ancestorAt[depth];\n if (parentId !== undefined) closing.push({ parentId, depth: depth + 1 });\n }\n if (row.expanded && rows[index + 1]?.depth !== row.depth + 1)\n closing.unshift({ parentId: row.page.id, depth: row.depth + 1 });\n return (\n <Fragment key={row.page.id}>\n <div\n ref={element => {\n if (element) itemRefs.current.set(row.page.id, element);\n else itemRefs.current.delete(row.page.id);\n }}\n role=\"treeitem\"\n aria-level={row.depth + 1}\n aria-selected={selected}\n aria-expanded={row.hasChildren ? row.expanded : undefined}\n tabIndex={row.page.id === activeId ? 0 : -1}\n onFocus={() => setFocusedId(row.page.id)}\n onKeyDown={event => onKeyDown(event, index)}\n onClick={() => onSelect(row.page)}\n className={cn(\n 'flex min-h-8 cursor-pointer items-center gap-1 rounded-md pr-2 outline-none focus-visible:ring-1 focus-visible:ring-border-focus',\n selected ? 'bg-fill text-foreground' : 'text-foreground hover:bg-fill',\n )}\n style={{ paddingLeft: `${row.depth * 16 + 4}px` }}\n >\n {row.hasChildren ? (\n <button\n type=\"button\"\n tabIndex={-1}\n aria-label={row.expanded ? `Collapse ${row.page.name}` : `Expand ${row.page.name}`}\n className=\"flex size-5 shrink-0 items-center justify-center rounded text-muted-foreground hover:text-foreground\"\n onClick={event => {\n event.stopPropagation();\n toggle(row.page.id, !row.expanded);\n }}\n >\n <ChevronRight size={14} className={cn('transition-transform', row.expanded && 'rotate-90')} />\n </button>\n ) : (\n <span className=\"size-5 shrink-0\" aria-hidden />\n )}\n <span className={cn('min-w-0 flex-1 truncate text-body', row.page.isScope && 'font-medium')}>\n {row.page.name}\n </span>\n {pinned.has(row.page.id) ? (\n <Pin size={12} className=\"shrink-0 text-badge-amber-indicator\" aria-label=\"Pinned\" />\n ) : null}\n {row.page.isScope && row.page.address && row.page.address !== row.page.name ? (\n <span\n data-testid=\"knowledge-tree-address\"\n className=\"max-w-1/2 min-w-0 truncate text-caption text-muted-foreground\"\n >\n {row.page.address}\n </span>\n ) : null}\n </div>\n {closing.map(({ parentId, depth }) => {\n const more = loadMore?.get(parentId);\n return more ? (\n <button\n key={`more-${parentId}`}\n type=\"button\"\n className=\"flex min-h-7 w-full items-center text-left text-caption text-muted-foreground hover:text-foreground\"\n style={{ paddingLeft: `${depth * 16 + 28}px` }}\n onClick={more}\n >\n Load more\n </button>\n ) : null;\n })}\n </Fragment>\n );\n })}\n </div>\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"KnowledgePageTree.es.js","names":[],"sources":["../../../../src/domains/knowledge/components/KnowledgePageTree.tsx"],"sourcesContent":["import { ChevronRight, Pin } from 'lucide-react';\nimport { Fragment, useEffect, useMemo, useRef, useState } from 'react';\nimport type { KeyboardEvent } from 'react';\n\nimport { buildPageTree, childCountLabel, pageAncestorIds, visiblePageRows } from '../lib/pageTree';\nimport { prefersMotion } from '../lib/useLeavingNodes';\nimport type { KnowledgePagePayload } from '../pageTypes';\n\nimport { cn } from '@/utils/cn';\n\n/**\n * The box of the nearest ancestor (or the element itself) that really scrolls vertically. The tree sets\n * `overflow-y: auto` itself but, as tall as its rows, never overflows; a parent is what scrolls, so a\n * node counts only when its content is taller than it is.\n */\nfunction scrollingBox(element: HTMLElement | null): DOMRect | undefined {\n let overflowing: HTMLElement | undefined;\n for (let node = element; node; node = node.parentElement) {\n const { overflowY } = getComputedStyle(node);\n if (overflowY !== 'auto' && overflowY !== 'scroll' && overflowY !== 'overlay') continue;\n if (node.scrollHeight > node.clientHeight) return node.getBoundingClientRect();\n overflowing ??= node;\n }\n return (overflowing ?? element)?.getBoundingClientRect();\n}\n\n/** Where in the scroller a row focused from elsewhere lands, as a fraction of its height from the top. */\nconst SCROLL_ROW_AT = 1 / 3;\n/** A row between these fractions of the scroller is comfortably in view and is not moved. */\nconst COMFORT_TOP = 0.1;\nconst COMFORT_BOTTOM = 0.7;\n\n/** The key {@link KnowledgePageTree}'s `loadMore` uses for the root level. */\nexport const KNOWLEDGE_TREE_ROOT = '';\n\n/**\n * The Knowledge page tree: scopes and pages nested by parent, siblings in\n * stored order. Selecting a page from elsewhere (graph, search) opens the path\n * to it. Keyboard follows the WAI-ARIA tree pattern: Up/Down move, Right opens\n * or enters, Left closes or goes to the parent, Enter/Space selects.\n *\n * A host that loads the tree a level at a time passes `mayHaveChildren` (so unloaded pages still offer\n * a chevron), listens to `onExpandedChange` to load the opened levels, and passes `loadMore` for\n * levels with more children to fetch. A page's `childCount`, when the server sends one, shows beside\n * its name. Selecting a page with children also opens it.\n */\nexport function KnowledgePageTree({\n pages,\n pinnedIds,\n selectedPageId,\n onSelect,\n initiallyExpanded,\n mayHaveChildren,\n onExpandedChange,\n loadMore,\n 'aria-label': ariaLabel = 'Knowledge pages',\n}: {\n pages: KnowledgePagePayload[];\n pinnedIds?: readonly string[];\n selectedPageId?: string | null;\n onSelect: (page: KnowledgePagePayload) => void;\n /** Ids open on first render; defaults to every root. */\n initiallyExpanded?: string[];\n /** True for a page whose children are not loaded yet, so it can still be opened. */\n mayHaveChildren?: (page: KnowledgePagePayload) => boolean;\n onExpandedChange?: (expanded: ReadonlySet<string>) => void;\n /** Parent id ({@link KNOWLEDGE_TREE_ROOT} for the roots) to a loader for its next children. */\n loadMore?: ReadonlyMap<string, () => void>;\n 'aria-label'?: string;\n}) {\n const roots = useMemo(() => buildPageTree(pages), [pages]);\n const pinned = useMemo(() => new Set(pinnedIds), [pinnedIds]);\n const [expanded, setExpanded] = useState<Set<string>>(\n () => new Set(initiallyExpanded ?? roots.map(root => root.page.id)),\n );\n const [focusedId, setFocusedId] = useState<string | null>(null);\n const itemRefs = useRef(new Map<string, HTMLDivElement>());\n\n // Open the path to a selection once. Later renders with the same selection and path (a refetch, a\n // level loading) leave it alone, so a parent the user collapses over the selection stays collapsed.\n const revealed = useRef<string | null>(null);\n useEffect(() => {\n if (!selectedPageId) {\n // Forget the last reveal, so picking the same page again after a clear opens its path.\n revealed.current = null;\n return;\n }\n const path = pageAncestorIds(pages, selectedPageId);\n const key = [selectedPageId, ...path].join('/');\n if (revealed.current === key) return;\n revealed.current = key;\n setExpanded(current => (path.every(id => current.has(id)) ? current : new Set([...current, ...path])));\n }, [pages, selectedPageId]);\n\n useEffect(() => {\n onExpandedChange?.(expanded);\n }, [expanded, onExpandedChange]);\n\n const rows = useMemo(\n () =>\n visiblePageRows(roots, expanded).map(row =>\n !row.hasChildren && mayHaveChildren?.(row.page) ? { ...row, hasChildren: true } : row,\n ),\n [roots, expanded, mayHaveChildren],\n );\n // Bring the selected row into view when it is selected, as soon as it exists, and again if rows that load\n // later push it out of view (a deep page's levels arrive one after another). Once the user scrolls, presses a key or\n // a pointer in the tree it is left alone. The row goes a third of the way down the scroller, middle-top, not\n // hard against its bottom edge; keyboard focus is not moved.\n const scroller = useRef<HTMLDivElement>(null);\n const scrolledTo = useRef<string | null>(null);\n const userScrolled = useRef(false);\n useEffect(() => {\n if (!selectedPageId) {\n scrolledTo.current = null;\n return;\n }\n const element = itemRefs.current.get(selectedPageId);\n if (!element) return;\n const first = scrolledTo.current !== selectedPageId;\n if (first) {\n scrolledTo.current = selectedPageId;\n userScrolled.current = false;\n } else if (userScrolled.current) return;\n const box = scrollingBox(scroller.current);\n const at = element.getBoundingClientRect();\n if (!first && !box) return;\n if (!first && box && box.height === 0 && at.top >= box.top && at.bottom <= box.bottom) return;\n if (box && box.height > 0) {\n // A row already well inside the scroller stays where it is.\n const inView = at.top >= box.top + box.height * COMFORT_TOP && at.bottom <= box.top + box.height * COMFORT_BOTTOM;\n if (inView) return;\n // Otherwise it lands a third of the way down; the browser clamps this at the top and bottom of the list.\n element.style.scrollMarginTop = `${box.height * SCROLL_ROW_AT}px`;\n }\n element.scrollIntoView?.({ block: 'start', behavior: first && prefersMotion() ? 'smooth' : 'auto' });\n // The margin only steers this scroll; left on, focus() scrolls and a resized pane would keep a stale gap.\n element.style.scrollMarginTop = '';\n }, [rows, selectedPageId]);\n const activeId =\n focusedId && rows.some(row => row.page.id === focusedId)\n ? focusedId\n : (rows.find(row => row.page.id === selectedPageId)?.page.id ?? rows[0]?.page.id);\n\n const toggle = (id: string, open: boolean) =>\n setExpanded(current => {\n if (current.has(id) === open) return current;\n const next = new Set(current);\n if (open) next.add(id);\n else next.delete(id);\n return next;\n });\n\n const focus = (id: string | undefined) => {\n if (!id) return;\n setFocusedId(id);\n itemRefs.current.get(id)?.focus();\n };\n\n const onKeyDown = (event: KeyboardEvent<HTMLDivElement>, index: number) => {\n const row = rows[index];\n if (!row) return;\n switch (event.key) {\n case 'ArrowDown':\n focus(rows[index + 1]?.page.id);\n break;\n case 'ArrowUp':\n focus(rows[index - 1]?.page.id);\n break;\n case 'ArrowRight':\n if (row.hasChildren && !row.expanded) toggle(row.page.id, true);\n else if (row.expanded) focus(rows[index + 1]?.page.id);\n break;\n case 'ArrowLeft':\n if (row.expanded) toggle(row.page.id, false);\n else focus(rows.slice(0, index).findLast(candidate => candidate.depth < row.depth)?.page.id);\n break;\n case 'Enter':\n case ' ':\n onSelect(row.page);\n break;\n default:\n return;\n }\n event.preventDefault();\n };\n\n if (rows.length === 0) {\n return <p className=\"px-3 py-2 text-body text-muted-foreground\">No pages yet.</p>;\n }\n\n const ancestorAt: string[] = [];\n return (\n <div\n ref={scroller}\n role=\"tree\"\n aria-label={ariaLabel}\n className=\"min-h-0 overflow-y-auto py-1\"\n onWheel={() => (userScrolled.current = true)}\n onTouchMove={() => (userScrolled.current = true)}\n onPointerDown={() => (userScrolled.current = true)}\n onKeyDown={() => (userScrolled.current = true)}\n >\n {rows.map((row, index) => {\n const selected = row.page.id === selectedPageId;\n ancestorAt[row.depth] = row.page.id;\n // Levels whose last loaded child is this row's subtree end here: offer their next children.\n const nextDepth = rows[index + 1]?.depth ?? -1;\n const closing: Array<{ parentId: string; depth: number }> = [];\n for (let depth = row.depth - 1; depth >= nextDepth; depth--) {\n const parentId = depth < 0 ? KNOWLEDGE_TREE_ROOT : ancestorAt[depth];\n if (parentId !== undefined) closing.push({ parentId, depth: depth + 1 });\n }\n if (row.expanded && rows[index + 1]?.depth !== row.depth + 1)\n closing.unshift({ parentId: row.page.id, depth: row.depth + 1 });\n return (\n <Fragment key={row.page.id}>\n <div\n ref={element => {\n if (element) itemRefs.current.set(row.page.id, element);\n else itemRefs.current.delete(row.page.id);\n }}\n role=\"treeitem\"\n aria-level={row.depth + 1}\n aria-selected={selected}\n aria-expanded={row.hasChildren ? row.expanded : undefined}\n tabIndex={row.page.id === activeId ? 0 : -1}\n onFocus={() => setFocusedId(row.page.id)}\n onKeyDown={event => onKeyDown(event, index)}\n onClick={() => {\n onSelect(row.page);\n // Selecting a page with children opens it too, which loads them in a lazily loaded tree.\n if (row.hasChildren) toggle(row.page.id, true);\n }}\n className={cn(\n 'flex min-h-8 cursor-pointer items-center gap-1 rounded-md pr-2 outline-none focus-visible:ring-1 focus-visible:ring-border-focus',\n selected ? 'bg-fill text-foreground' : 'text-foreground hover:bg-fill',\n )}\n style={{ paddingLeft: `${row.depth * 16 + 4}px` }}\n >\n {row.hasChildren ? (\n <button\n type=\"button\"\n tabIndex={-1}\n aria-label={row.expanded ? `Collapse ${row.page.name}` : `Expand ${row.page.name}`}\n className=\"flex size-5 shrink-0 items-center justify-center rounded text-muted-foreground hover:text-foreground\"\n onClick={event => {\n event.stopPropagation();\n toggle(row.page.id, !row.expanded);\n }}\n >\n <ChevronRight size={14} className={cn('transition-transform', row.expanded && 'rotate-90')} />\n </button>\n ) : (\n <span className=\"size-5 shrink-0\" aria-hidden />\n )}\n <span className={cn('min-w-0 flex-1 truncate text-body', row.page.isScope && 'font-medium')}>\n {row.page.name}\n </span>\n {row.page.childCount ? (\n <span\n data-testid=\"knowledge-tree-count\"\n aria-label={`${childCountLabel(row.page)} below`}\n className=\"shrink-0 text-caption text-muted-foreground tabular-nums\"\n >\n {childCountLabel(row.page)}\n </span>\n ) : null}\n {pinned.has(row.page.id) ? (\n <Pin size={12} className=\"shrink-0 text-badge-amber-indicator\" aria-label=\"Pinned\" />\n ) : null}\n {row.page.isScope && row.page.address && row.page.address !== row.page.name ? (\n <span\n data-testid=\"knowledge-tree-address\"\n className=\"max-w-1/2 min-w-0 truncate text-caption text-muted-foreground\"\n >\n {row.page.address}\n </span>\n ) : null}\n </div>\n {closing.map(({ parentId, depth }) => {\n const more = loadMore?.get(parentId);\n return more ? (\n <button\n key={`more-${parentId}`}\n type=\"button\"\n className=\"flex min-h-7 w-full items-center text-left text-caption text-muted-foreground hover:text-foreground\"\n style={{ paddingLeft: `${depth * 16 + 28}px` }}\n onClick={more}\n >\n Load more\n </button>\n ) : null;\n })}\n </Fragment>\n );\n })}\n </div>\n );\n}\n"],"mappings":"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"}
@@ -0,0 +1,9 @@
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
+ // src/domains/knowledge/lib/circleText.ts
3
+ /** The text with any word wider than the circle cut short with an ellipsis, so words never break mid-way. */
4
+ function fitWords(text, maxChars) {
5
+ return text.split(/(\s+|(?<=:))/).map((word) => word.length > maxChars && !/^\s+$/.test(word) ? `${word.slice(0, maxChars - 1)}\u2026` : word).join("");
6
+ }
7
+ exports.fitWords = fitWords;
8
+
9
+ //# sourceMappingURL=circleText.cjs.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"circleText.cjs.js","names":[],"sources":["../../../../src/domains/knowledge/lib/circleText.ts"],"sourcesContent":["/** The text with any word wider than the circle cut short with an ellipsis, so words never break mid-way. */\nexport function fitWords(text: string, maxChars: number): string {\n return text\n .split(/(\\s+|(?<=:))/)\n .map(word => (word.length > maxChars && !/^\\s+$/.test(word) ? `${word.slice(0, maxChars - 1)}\\u2026` : word))\n .join('');\n}\n"],"mappings":";;;AACA,SAAgB,SAAS,MAAc,UAA0B;CAC/D,OAAO,KACJ,MAAM,cAAc,CAAC,CACrB,KAAI,SAAS,KAAK,SAAS,YAAY,CAAC,QAAQ,KAAK,IAAI,IAAI,GAAG,KAAK,MAAM,GAAG,WAAW,CAAC,EAAE,UAAU,IAAK,CAAC,CAC5G,KAAK,EAAE;AACZ"}
@@ -0,0 +1 @@
1
+ export * from '../../../src/domains/knowledge/lib/circleText';
@@ -0,0 +1,8 @@
1
+ // src/domains/knowledge/lib/circleText.ts
2
+ /** The text with any word wider than the circle cut short with an ellipsis, so words never break mid-way. */
3
+ function fitWords(text, maxChars) {
4
+ return text.split(/(\s+|(?<=:))/).map((word) => word.length > maxChars && !/^\s+$/.test(word) ? `${word.slice(0, maxChars - 1)}\u2026` : word).join("");
5
+ }
6
+ export { fitWords };
7
+
8
+ //# sourceMappingURL=circleText.es.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"circleText.es.js","names":[],"sources":["../../../../src/domains/knowledge/lib/circleText.ts"],"sourcesContent":["/** The text with any word wider than the circle cut short with an ellipsis, so words never break mid-way. */\nexport function fitWords(text: string, maxChars: number): string {\n return text\n .split(/(\\s+|(?<=:))/)\n .map(word => (word.length > maxChars && !/^\\s+$/.test(word) ? `${word.slice(0, maxChars - 1)}\\u2026` : word))\n .join('');\n}\n"],"mappings":";;AACA,SAAgB,SAAS,MAAc,UAA0B;CAC/D,OAAO,KACJ,MAAM,cAAc,CAAC,CACrB,KAAI,SAAS,KAAK,SAAS,YAAY,CAAC,QAAQ,KAAK,IAAI,IAAI,GAAG,KAAK,MAAM,GAAG,WAAW,CAAC,EAAE,UAAU,IAAK,CAAC,CAC5G,KAAK,EAAE;AACZ"}
@@ -0,0 +1,82 @@
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
+ const require_domains_knowledge_lib_graphShape = require("./graphShape.cjs.js");
3
+ require("./useLeavingNodes.cjs.js");
4
+ let _xyflow_react = require("@xyflow/react");
5
+ // src/domains/knowledge/lib/fitViewport.ts
6
+ /** How far Fit view may zoom out to frame a ring of linked pages, which the readable floor would crop. */
7
+ var RING_MIN_ZOOM = .15;
8
+ /**
9
+ * The viewport that frames `bounds`. Zoom stops at the readable floor, so what is cropped is the edge, not
10
+ * the page being looked at; only Fit view, with an outer ring, goes lower so the whole ring shows.
11
+ */
12
+ function fitViewport({ bounds, width, height, ring, anchor }) {
13
+ const floor = ring ? RING_MIN_ZOOM : require_domains_knowledge_lib_graphShape.READABLE_MIN_ZOOM;
14
+ const viewport = (0, _xyflow_react.getViewportForBounds)(bounds, width, height, floor, 2, .1);
15
+ if (anchor && viewport.zoom <= floor) {
16
+ const cx = anchor.position.x + (anchor.width ?? 0) / 2;
17
+ const cy = anchor.position.y + (anchor.height ?? 0) / 2;
18
+ return {
19
+ zoom: viewport.zoom,
20
+ x: width / 2 - cx * viewport.zoom,
21
+ y: height / 2 - cy * viewport.zoom
22
+ };
23
+ }
24
+ return viewport;
25
+ }
26
+ /** Margin around the drawn nodes on the first view, as a share of the pane. */
27
+ var INITIAL_FIT_PADDING = .05;
28
+ /** The first view never zooms in past the pages' own size, however few there are. */
29
+ var INITIAL_FIT_MAX_ZOOM = 1;
30
+ /** How long after the first view the graph keeps refitting as pages arrive, unless the user acts first. */
31
+ var INITIAL_SETTLE_MS = 3e3;
32
+ /**
33
+ * The first view of a graph: every drawn node in the pane with a small margin, never zoomed in past what
34
+ * fits, and clear of `legend` (the box, in pane pixels, an overlay covers at the top left). When the plain
35
+ * fit would put a node under the legend, the pane is fitted again beside it or below it, whichever keeps
36
+ * the pages larger.
37
+ */
38
+ function fitAllViewport({ bounds, nodes, width, height, legend }) {
39
+ const fitIn = (left, top) => {
40
+ const view = (0, _xyflow_react.getViewportForBounds)(bounds, width - left, height - top, RING_MIN_ZOOM, 1, INITIAL_FIT_PADDING);
41
+ return {
42
+ zoom: view.zoom,
43
+ x: view.x + left,
44
+ y: view.y + top
45
+ };
46
+ };
47
+ const plain = fitIn(0, 0);
48
+ if (!legend) return plain;
49
+ if (!nodes.some((node) => {
50
+ const left = node.x * plain.zoom + plain.x;
51
+ const top = node.y * plain.zoom + plain.y;
52
+ return left < legend.right && top < legend.bottom;
53
+ })) return plain;
54
+ const beside = fitIn(legend.right, 0);
55
+ const below = fitIn(0, legend.bottom);
56
+ return beside.zoom >= below.zoom ? beside : below;
57
+ }
58
+ /** How long a view change animates: the same as the layout's own transition, and none under reduced motion. */
59
+ var fitDuration = (motion) => motion ? 700 : 0;
60
+ /** How close to the pane's edge a refocused page may sit before the view moves to bring it in. */
61
+ var NUDGE_PADDING = 24;
62
+ /**
63
+ * How far to move the view along one axis so a page at `start` (screen position) of `size` stays inside a
64
+ * pane of `extent`, with padding. Zero when it already is; centred when it can't fit with the padding.
65
+ */
66
+ function nudgeAxis(start, size, extent) {
67
+ if (size + 48 > extent) return extent / 2 - (start + size / 2);
68
+ if (start < 24) return 24 - start;
69
+ const overflow = start + size - (extent - 24);
70
+ return overflow > 0 ? -overflow : 0;
71
+ }
72
+ exports.INITIAL_FIT_MAX_ZOOM = INITIAL_FIT_MAX_ZOOM;
73
+ exports.INITIAL_FIT_PADDING = INITIAL_FIT_PADDING;
74
+ exports.INITIAL_SETTLE_MS = INITIAL_SETTLE_MS;
75
+ exports.NUDGE_PADDING = NUDGE_PADDING;
76
+ exports.RING_MIN_ZOOM = RING_MIN_ZOOM;
77
+ exports.fitAllViewport = fitAllViewport;
78
+ exports.fitDuration = fitDuration;
79
+ exports.fitViewport = fitViewport;
80
+ exports.nudgeAxis = nudgeAxis;
81
+
82
+ //# sourceMappingURL=fitViewport.cjs.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fitViewport.cjs.js","names":["READABLE_MIN_ZOOM","getViewportForBounds"],"sources":["../../../../src/domains/knowledge/lib/fitViewport.ts"],"sourcesContent":["import { getViewportForBounds } from '@xyflow/react';\nimport type { Viewport } from '@xyflow/react';\n\nimport { READABLE_MIN_ZOOM } from './graphShape';\nimport { KNOWLEDGE_GRAPH_TRANSITION_MS } from './useLeavingNodes';\n\n/** How far Fit view may zoom out to frame a ring of linked pages, which the readable floor would crop. */\nexport const RING_MIN_ZOOM = 0.15;\n\ninterface FitInput {\n bounds: { x: number; y: number; width: number; height: number };\n width: number;\n height: number;\n /** Fit view on a focus with an outer ring of linked pages: frame all of it, below the readable floor if need be. */\n ring?: boolean;\n /** The focus (or the layout's centre): what stays centred when a floor stops the fit. */\n anchor?: { position: { x: number; y: number }; width?: number; height?: number };\n}\n\n/**\n * The viewport that frames `bounds`. Zoom stops at the readable floor, so what is cropped is the edge, not\n * the page being looked at; only Fit view, with an outer ring, goes lower so the whole ring shows.\n */\nexport function fitViewport({ bounds, width, height, ring, anchor }: FitInput): Viewport {\n const floor = ring ? RING_MIN_ZOOM : READABLE_MIN_ZOOM;\n const viewport = getViewportForBounds(bounds, width, height, floor, 2, 0.1);\n if (anchor && viewport.zoom <= floor) {\n const cx = anchor.position.x + (anchor.width ?? 0) / 2;\n const cy = anchor.position.y + (anchor.height ?? 0) / 2;\n return { zoom: viewport.zoom, x: width / 2 - cx * viewport.zoom, y: height / 2 - cy * viewport.zoom };\n }\n return viewport;\n}\n\n/** Margin around the drawn nodes on the first view, as a share of the pane. */\nexport const INITIAL_FIT_PADDING = 0.05;\n/** The first view never zooms in past the pages' own size, however few there are. */\nexport const INITIAL_FIT_MAX_ZOOM = 1;\n/** How long after the first view the graph keeps refitting as pages arrive, unless the user acts first. */\nexport const INITIAL_SETTLE_MS = 3000;\n\ntype Rect = { x: number; y: number; width: number; height: number };\n\n/**\n * The first view of a graph: every drawn node in the pane with a small margin, never zoomed in past what\n * fits, and clear of `legend` (the box, in pane pixels, an overlay covers at the top left). When the plain\n * fit would put a node under the legend, the pane is fitted again beside it or below it, whichever keeps\n * the pages larger.\n */\nexport function fitAllViewport({\n bounds,\n nodes,\n width,\n height,\n legend,\n}: {\n bounds: Rect;\n nodes: Rect[];\n width: number;\n height: number;\n legend?: { right: number; bottom: number };\n}): Viewport {\n const fitIn = (left: number, top: number): Viewport => {\n const view = getViewportForBounds(\n bounds,\n width - left,\n height - top,\n RING_MIN_ZOOM,\n INITIAL_FIT_MAX_ZOOM,\n INITIAL_FIT_PADDING,\n );\n return { zoom: view.zoom, x: view.x + left, y: view.y + top };\n };\n const plain = fitIn(0, 0);\n if (!legend) return plain;\n const covered = nodes.some(node => {\n const left = node.x * plain.zoom + plain.x;\n const top = node.y * plain.zoom + plain.y;\n return left < legend.right && top < legend.bottom;\n });\n if (!covered) return plain;\n const beside = fitIn(legend.right, 0);\n const below = fitIn(0, legend.bottom);\n return beside.zoom >= below.zoom ? beside : below;\n}\n\n/** How long a view change animates: the same as the layout's own transition, and none under reduced motion. */\nexport const fitDuration = (motion: boolean) => (motion ? KNOWLEDGE_GRAPH_TRANSITION_MS : 0);\n\n/** How close to the pane's edge a refocused page may sit before the view moves to bring it in. */\nexport const NUDGE_PADDING = 24;\n\n/**\n * How far to move the view along one axis so a page at `start` (screen position) of `size` stays inside a\n * pane of `extent`, with padding. Zero when it already is; centred when it can't fit with the padding.\n */\nexport function nudgeAxis(start: number, size: number, extent: number): number {\n if (size + NUDGE_PADDING * 2 > extent) return extent / 2 - (start + size / 2);\n if (start < NUDGE_PADDING) return NUDGE_PADDING - start;\n const overflow = start + size - (extent - NUDGE_PADDING);\n return overflow > 0 ? -overflow : 0;\n}\n"],"mappings":";;;;;;AAOA,IAAa,gBAAgB;;;;;AAgB7B,SAAgB,YAAY,EAAE,QAAQ,OAAO,QAAQ,MAAM,UAA8B;CACvF,MAAM,QAAQ,OAAO,gBAAgBA,yCAAAA;CACrC,MAAM,YAAA,GAAWC,cAAAA,qBAAAA,CAAqB,QAAQ,OAAO,QAAQ,OAAO,GAAG,EAAG;CAC1E,IAAI,UAAU,SAAS,QAAQ,OAAO;EACpC,MAAM,KAAK,OAAO,SAAS,KAAK,OAAO,SAAS,KAAK;EACrD,MAAM,KAAK,OAAO,SAAS,KAAK,OAAO,UAAU,KAAK;EACtD,OAAO;GAAE,MAAM,SAAS;GAAM,GAAG,QAAQ,IAAI,KAAK,SAAS;GAAM,GAAG,SAAS,IAAI,KAAK,SAAS;EAAK;CACtG;CACA,OAAO;AACT;;AAGA,IAAa,sBAAsB;;AAEnC,IAAa,uBAAuB;;AAEpC,IAAa,oBAAoB;;;;;;;AAUjC,SAAgB,eAAe,EAC7B,QACA,OACA,OACA,QACA,UAOW;CACX,MAAM,SAAS,MAAc,QAA0B;EACrD,MAAM,QAAA,GAAOA,cAAAA,qBAAAA,CACX,QACA,QAAQ,MACR,SAAS,KACT,eAAA,GAEA,mBACF;EACA,OAAO;GAAE,MAAM,KAAK;GAAM,GAAG,KAAK,IAAI;GAAM,GAAG,KAAK,IAAI;EAAI;CAC9D;CACA,MAAM,QAAQ,MAAM,GAAG,CAAC;CACxB,IAAI,CAAC,QAAQ,OAAO;CAMpB,IAAI,CALY,MAAM,MAAK,SAAQ;EACjC,MAAM,OAAO,KAAK,IAAI,MAAM,OAAO,MAAM;EACzC,MAAM,MAAM,KAAK,IAAI,MAAM,OAAO,MAAM;EACxC,OAAO,OAAO,OAAO,SAAS,MAAM,OAAO;CAC7C,CACK,GAAS,OAAO;CACrB,MAAM,SAAS,MAAM,OAAO,OAAO,CAAC;CACpC,MAAM,QAAQ,MAAM,GAAG,OAAO,MAAM;CACpC,OAAO,OAAO,QAAQ,MAAM,OAAO,SAAS;AAC9C;;AAGA,IAAa,eAAe,WAAqB,SAAA,MAAyC;;AAG1F,IAAa,gBAAgB;;;;;AAM7B,SAAgB,UAAU,OAAe,MAAc,QAAwB;CAC7E,IAAI,OAAO,KAAoB,QAAQ,OAAO,SAAS,KAAK,QAAQ,OAAO;CAC3E,IAAI,QAAA,IAAuB,OAAA,KAAuB;CAClD,MAAM,WAAW,QAAQ,QAAQ,SAAA;CACjC,OAAO,WAAW,IAAI,CAAC,WAAW;AACpC"}
@@ -0,0 +1 @@
1
+ export * from '../../../src/domains/knowledge/lib/fitViewport';
@@ -0,0 +1,73 @@
1
+ import { READABLE_MIN_ZOOM } from "./graphShape.es.js";
2
+ import "./useLeavingNodes.es.js";
3
+ import { getViewportForBounds } from "@xyflow/react";
4
+ // src/domains/knowledge/lib/fitViewport.ts
5
+ /** How far Fit view may zoom out to frame a ring of linked pages, which the readable floor would crop. */
6
+ var RING_MIN_ZOOM = .15;
7
+ /**
8
+ * The viewport that frames `bounds`. Zoom stops at the readable floor, so what is cropped is the edge, not
9
+ * the page being looked at; only Fit view, with an outer ring, goes lower so the whole ring shows.
10
+ */
11
+ function fitViewport({ bounds, width, height, ring, anchor }) {
12
+ const floor = ring ? RING_MIN_ZOOM : READABLE_MIN_ZOOM;
13
+ const viewport = getViewportForBounds(bounds, width, height, floor, 2, .1);
14
+ if (anchor && viewport.zoom <= floor) {
15
+ const cx = anchor.position.x + (anchor.width ?? 0) / 2;
16
+ const cy = anchor.position.y + (anchor.height ?? 0) / 2;
17
+ return {
18
+ zoom: viewport.zoom,
19
+ x: width / 2 - cx * viewport.zoom,
20
+ y: height / 2 - cy * viewport.zoom
21
+ };
22
+ }
23
+ return viewport;
24
+ }
25
+ /** Margin around the drawn nodes on the first view, as a share of the pane. */
26
+ var INITIAL_FIT_PADDING = .05;
27
+ /** The first view never zooms in past the pages' own size, however few there are. */
28
+ var INITIAL_FIT_MAX_ZOOM = 1;
29
+ /** How long after the first view the graph keeps refitting as pages arrive, unless the user acts first. */
30
+ var INITIAL_SETTLE_MS = 3e3;
31
+ /**
32
+ * The first view of a graph: every drawn node in the pane with a small margin, never zoomed in past what
33
+ * fits, and clear of `legend` (the box, in pane pixels, an overlay covers at the top left). When the plain
34
+ * fit would put a node under the legend, the pane is fitted again beside it or below it, whichever keeps
35
+ * the pages larger.
36
+ */
37
+ function fitAllViewport({ bounds, nodes, width, height, legend }) {
38
+ const fitIn = (left, top) => {
39
+ const view = getViewportForBounds(bounds, width - left, height - top, RING_MIN_ZOOM, 1, INITIAL_FIT_PADDING);
40
+ return {
41
+ zoom: view.zoom,
42
+ x: view.x + left,
43
+ y: view.y + top
44
+ };
45
+ };
46
+ const plain = fitIn(0, 0);
47
+ if (!legend) return plain;
48
+ if (!nodes.some((node) => {
49
+ const left = node.x * plain.zoom + plain.x;
50
+ const top = node.y * plain.zoom + plain.y;
51
+ return left < legend.right && top < legend.bottom;
52
+ })) return plain;
53
+ const beside = fitIn(legend.right, 0);
54
+ const below = fitIn(0, legend.bottom);
55
+ return beside.zoom >= below.zoom ? beside : below;
56
+ }
57
+ /** How long a view change animates: the same as the layout's own transition, and none under reduced motion. */
58
+ var fitDuration = (motion) => motion ? 700 : 0;
59
+ /** How close to the pane's edge a refocused page may sit before the view moves to bring it in. */
60
+ var NUDGE_PADDING = 24;
61
+ /**
62
+ * How far to move the view along one axis so a page at `start` (screen position) of `size` stays inside a
63
+ * pane of `extent`, with padding. Zero when it already is; centred when it can't fit with the padding.
64
+ */
65
+ function nudgeAxis(start, size, extent) {
66
+ if (size + 48 > extent) return extent / 2 - (start + size / 2);
67
+ if (start < 24) return 24 - start;
68
+ const overflow = start + size - (extent - 24);
69
+ return overflow > 0 ? -overflow : 0;
70
+ }
71
+ export { INITIAL_FIT_MAX_ZOOM, INITIAL_FIT_PADDING, INITIAL_SETTLE_MS, NUDGE_PADDING, RING_MIN_ZOOM, fitAllViewport, fitDuration, fitViewport, nudgeAxis };
72
+
73
+ //# sourceMappingURL=fitViewport.es.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fitViewport.es.js","names":[],"sources":["../../../../src/domains/knowledge/lib/fitViewport.ts"],"sourcesContent":["import { getViewportForBounds } from '@xyflow/react';\nimport type { Viewport } from '@xyflow/react';\n\nimport { READABLE_MIN_ZOOM } from './graphShape';\nimport { KNOWLEDGE_GRAPH_TRANSITION_MS } from './useLeavingNodes';\n\n/** How far Fit view may zoom out to frame a ring of linked pages, which the readable floor would crop. */\nexport const RING_MIN_ZOOM = 0.15;\n\ninterface FitInput {\n bounds: { x: number; y: number; width: number; height: number };\n width: number;\n height: number;\n /** Fit view on a focus with an outer ring of linked pages: frame all of it, below the readable floor if need be. */\n ring?: boolean;\n /** The focus (or the layout's centre): what stays centred when a floor stops the fit. */\n anchor?: { position: { x: number; y: number }; width?: number; height?: number };\n}\n\n/**\n * The viewport that frames `bounds`. Zoom stops at the readable floor, so what is cropped is the edge, not\n * the page being looked at; only Fit view, with an outer ring, goes lower so the whole ring shows.\n */\nexport function fitViewport({ bounds, width, height, ring, anchor }: FitInput): Viewport {\n const floor = ring ? RING_MIN_ZOOM : READABLE_MIN_ZOOM;\n const viewport = getViewportForBounds(bounds, width, height, floor, 2, 0.1);\n if (anchor && viewport.zoom <= floor) {\n const cx = anchor.position.x + (anchor.width ?? 0) / 2;\n const cy = anchor.position.y + (anchor.height ?? 0) / 2;\n return { zoom: viewport.zoom, x: width / 2 - cx * viewport.zoom, y: height / 2 - cy * viewport.zoom };\n }\n return viewport;\n}\n\n/** Margin around the drawn nodes on the first view, as a share of the pane. */\nexport const INITIAL_FIT_PADDING = 0.05;\n/** The first view never zooms in past the pages' own size, however few there are. */\nexport const INITIAL_FIT_MAX_ZOOM = 1;\n/** How long after the first view the graph keeps refitting as pages arrive, unless the user acts first. */\nexport const INITIAL_SETTLE_MS = 3000;\n\ntype Rect = { x: number; y: number; width: number; height: number };\n\n/**\n * The first view of a graph: every drawn node in the pane with a small margin, never zoomed in past what\n * fits, and clear of `legend` (the box, in pane pixels, an overlay covers at the top left). When the plain\n * fit would put a node under the legend, the pane is fitted again beside it or below it, whichever keeps\n * the pages larger.\n */\nexport function fitAllViewport({\n bounds,\n nodes,\n width,\n height,\n legend,\n}: {\n bounds: Rect;\n nodes: Rect[];\n width: number;\n height: number;\n legend?: { right: number; bottom: number };\n}): Viewport {\n const fitIn = (left: number, top: number): Viewport => {\n const view = getViewportForBounds(\n bounds,\n width - left,\n height - top,\n RING_MIN_ZOOM,\n INITIAL_FIT_MAX_ZOOM,\n INITIAL_FIT_PADDING,\n );\n return { zoom: view.zoom, x: view.x + left, y: view.y + top };\n };\n const plain = fitIn(0, 0);\n if (!legend) return plain;\n const covered = nodes.some(node => {\n const left = node.x * plain.zoom + plain.x;\n const top = node.y * plain.zoom + plain.y;\n return left < legend.right && top < legend.bottom;\n });\n if (!covered) return plain;\n const beside = fitIn(legend.right, 0);\n const below = fitIn(0, legend.bottom);\n return beside.zoom >= below.zoom ? beside : below;\n}\n\n/** How long a view change animates: the same as the layout's own transition, and none under reduced motion. */\nexport const fitDuration = (motion: boolean) => (motion ? KNOWLEDGE_GRAPH_TRANSITION_MS : 0);\n\n/** How close to the pane's edge a refocused page may sit before the view moves to bring it in. */\nexport const NUDGE_PADDING = 24;\n\n/**\n * How far to move the view along one axis so a page at `start` (screen position) of `size` stays inside a\n * pane of `extent`, with padding. Zero when it already is; centred when it can't fit with the padding.\n */\nexport function nudgeAxis(start: number, size: number, extent: number): number {\n if (size + NUDGE_PADDING * 2 > extent) return extent / 2 - (start + size / 2);\n if (start < NUDGE_PADDING) return NUDGE_PADDING - start;\n const overflow = start + size - (extent - NUDGE_PADDING);\n return overflow > 0 ? -overflow : 0;\n}\n"],"mappings":";;;;;AAOA,IAAa,gBAAgB;;;;;AAgB7B,SAAgB,YAAY,EAAE,QAAQ,OAAO,QAAQ,MAAM,UAA8B;CACvF,MAAM,QAAQ,OAAO,gBAAgB;CACrC,MAAM,WAAW,qBAAqB,QAAQ,OAAO,QAAQ,OAAO,GAAG,EAAG;CAC1E,IAAI,UAAU,SAAS,QAAQ,OAAO;EACpC,MAAM,KAAK,OAAO,SAAS,KAAK,OAAO,SAAS,KAAK;EACrD,MAAM,KAAK,OAAO,SAAS,KAAK,OAAO,UAAU,KAAK;EACtD,OAAO;GAAE,MAAM,SAAS;GAAM,GAAG,QAAQ,IAAI,KAAK,SAAS;GAAM,GAAG,SAAS,IAAI,KAAK,SAAS;EAAK;CACtG;CACA,OAAO;AACT;;AAGA,IAAa,sBAAsB;;AAEnC,IAAa,uBAAuB;;AAEpC,IAAa,oBAAoB;;;;;;;AAUjC,SAAgB,eAAe,EAC7B,QACA,OACA,OACA,QACA,UAOW;CACX,MAAM,SAAS,MAAc,QAA0B;EACrD,MAAM,OAAO,qBACX,QACA,QAAQ,MACR,SAAS,KACT,eAAA,GAEA,mBACF;EACA,OAAO;GAAE,MAAM,KAAK;GAAM,GAAG,KAAK,IAAI;GAAM,GAAG,KAAK,IAAI;EAAI;CAC9D;CACA,MAAM,QAAQ,MAAM,GAAG,CAAC;CACxB,IAAI,CAAC,QAAQ,OAAO;CAMpB,IAAI,CALY,MAAM,MAAK,SAAQ;EACjC,MAAM,OAAO,KAAK,IAAI,MAAM,OAAO,MAAM;EACzC,MAAM,MAAM,KAAK,IAAI,MAAM,OAAO,MAAM;EACxC,OAAO,OAAO,OAAO,SAAS,MAAM,OAAO;CAC7C,CACK,GAAS,OAAO;CACrB,MAAM,SAAS,MAAM,OAAO,OAAO,CAAC;CACpC,MAAM,QAAQ,MAAM,GAAG,OAAO,MAAM;CACpC,OAAO,OAAO,QAAQ,MAAM,OAAO,SAAS;AAC9C;;AAGA,IAAa,eAAe,WAAqB,SAAA,MAAyC;;AAG1F,IAAa,gBAAgB;;;;;AAM7B,SAAgB,UAAU,OAAe,MAAc,QAAwB;CAC7E,IAAI,OAAO,KAAoB,QAAQ,OAAO,SAAS,KAAK,QAAQ,OAAO;CAC3E,IAAI,QAAA,IAAuB,OAAA,KAAuB;CAClD,MAAM,WAAW,QAAQ,QAAQ,SAAA;CACjC,OAAO,WAAW,IAAI,CAAC,WAAW;AACpC"}