@mastra/playground-ui 67.0.0 → 68.0.0-alpha.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 (244) hide show
  1. package/dist/KnowledgePageGraph.css +11 -0
  2. package/dist/components/ai/tool-approval.cjs.js +1 -1
  3. package/dist/components/ai/tool-approval.es.js +1 -1
  4. package/dist/components/ai/tool-call.cjs.js +2 -2
  5. package/dist/components/ai/tool-call.es.js +2 -2
  6. package/dist/domains/chat/activity/model/activity-segments.cjs.js +1 -1
  7. package/dist/domains/chat/activity/model/activity-segments.es.js +1 -1
  8. package/dist/domains/chat/activity/model/activity-words.cjs.js +2 -2
  9. package/dist/domains/chat/activity/model/activity-words.es.js +2 -2
  10. package/dist/domains/chat/knowledge/knowledge-links.cjs.js +40 -0
  11. package/dist/domains/chat/knowledge/knowledge-links.cjs.js.map +1 -0
  12. package/dist/domains/chat/knowledge/knowledge-links.d.ts +1 -0
  13. package/dist/domains/chat/knowledge/knowledge-links.es.js +38 -0
  14. package/dist/domains/chat/knowledge/knowledge-links.es.js.map +1 -0
  15. package/dist/domains/chat/knowledge/pinned-knowledge-data.cjs.js +79 -0
  16. package/dist/domains/chat/knowledge/pinned-knowledge-data.cjs.js.map +1 -0
  17. package/dist/domains/chat/knowledge/pinned-knowledge-data.d.ts +1 -0
  18. package/dist/domains/chat/knowledge/pinned-knowledge-data.es.js +77 -0
  19. package/dist/domains/chat/knowledge/pinned-knowledge-data.es.js.map +1 -0
  20. package/dist/domains/chat/knowledge/pinned-knowledge.cjs.js +124 -0
  21. package/dist/domains/chat/knowledge/pinned-knowledge.cjs.js.map +1 -0
  22. package/dist/domains/chat/knowledge/pinned-knowledge.d.ts +1 -0
  23. package/dist/domains/chat/knowledge/pinned-knowledge.es.js +123 -0
  24. package/dist/domains/chat/knowledge/pinned-knowledge.es.js.map +1 -0
  25. package/dist/domains/chat/knowledge.cjs.js +12 -0
  26. package/dist/domains/chat/knowledge.d.ts +1 -0
  27. package/dist/domains/chat/knowledge.es.js +5 -0
  28. package/dist/domains/chat/messages/message-row.cjs.js +2 -2
  29. package/dist/domains/chat/messages/message-row.es.js +2 -2
  30. package/dist/domains/chat/messages/signal-badge.cjs.js +7 -0
  31. package/dist/domains/chat/messages/signal-badge.cjs.js.map +1 -1
  32. package/dist/domains/chat/messages/signal-badge.es.js +7 -0
  33. package/dist/domains/chat/messages/signal-badge.es.js.map +1 -1
  34. package/dist/domains/chat/tools/badges/agent-badge-wrapper.cjs.js +1 -1
  35. package/dist/domains/chat/tools/badges/agent-badge-wrapper.es.js +1 -1
  36. package/dist/domains/chat/tools/badges/agent-badge.cjs.js +1 -1
  37. package/dist/domains/chat/tools/badges/agent-badge.es.js +1 -1
  38. package/dist/domains/chat/tools/badges/file-tree-badge.cjs.js +2 -2
  39. package/dist/domains/chat/tools/badges/file-tree-badge.es.js +2 -2
  40. package/dist/domains/chat/tools/badges/knowledge-tool-badge.cjs.js +273 -0
  41. package/dist/domains/chat/tools/badges/knowledge-tool-badge.cjs.js.map +1 -0
  42. package/dist/domains/chat/tools/badges/knowledge-tool-badge.d.ts +1 -0
  43. package/dist/domains/chat/tools/badges/knowledge-tool-badge.es.js +270 -0
  44. package/dist/domains/chat/tools/badges/knowledge-tool-badge.es.js.map +1 -0
  45. package/dist/domains/chat/tools/badges/observation-marker-badge.cjs.js +1 -1
  46. package/dist/domains/chat/tools/badges/observation-marker-badge.es.js +1 -1
  47. package/dist/domains/chat/tools/badges/sandbox-execution-badge.cjs.js +2 -2
  48. package/dist/domains/chat/tools/badges/sandbox-execution-badge.es.js +2 -2
  49. package/dist/domains/chat/tools/badges/tool-approval-badge.cjs.js +1 -1
  50. package/dist/domains/chat/tools/badges/tool-approval-badge.es.js +1 -1
  51. package/dist/domains/chat/tools/badges/tool-badge.cjs.js +3 -3
  52. package/dist/domains/chat/tools/badges/tool-badge.es.js +3 -3
  53. package/dist/domains/chat/tools/badges/workflow-badge.cjs.js +2 -2
  54. package/dist/domains/chat/tools/badges/workflow-badge.es.js +2 -2
  55. package/dist/domains/chat/tools/tool-card-kind.cjs.js +4 -2
  56. package/dist/domains/chat/tools/tool-card-kind.cjs.js.map +1 -1
  57. package/dist/domains/chat/tools/tool-card-kind.es.js +4 -2
  58. package/dist/domains/chat/tools/tool-card-kind.es.js.map +1 -1
  59. package/dist/domains/chat/tools/tool-card.cjs.js +1 -1
  60. package/dist/domains/chat/tools/tool-card.es.js +1 -1
  61. package/dist/domains/chat/tools/tool-groups.cjs.js +3 -2
  62. package/dist/domains/chat/tools/tool-groups.cjs.js.map +1 -1
  63. package/dist/domains/chat/tools/tool-groups.es.js +3 -2
  64. package/dist/domains/chat/tools/tool-groups.es.js.map +1 -1
  65. package/dist/domains/chat.cjs.js +11 -0
  66. package/dist/domains/chat.es.js +5 -1
  67. package/dist/domains/knowledge/components/KnowledgePageDetail.cjs.js +438 -0
  68. package/dist/domains/knowledge/components/KnowledgePageDetail.cjs.js.map +1 -0
  69. package/dist/domains/knowledge/components/KnowledgePageDetail.d.ts +1 -0
  70. package/dist/domains/knowledge/components/KnowledgePageDetail.es.js +436 -0
  71. package/dist/domains/knowledge/components/KnowledgePageDetail.es.js.map +1 -0
  72. package/dist/domains/knowledge/components/KnowledgePageExplorer.cjs.js +521 -0
  73. package/dist/domains/knowledge/components/KnowledgePageExplorer.cjs.js.map +1 -0
  74. package/dist/domains/knowledge/components/KnowledgePageExplorer.d.ts +1 -0
  75. package/dist/domains/knowledge/components/KnowledgePageExplorer.es.js +520 -0
  76. package/dist/domains/knowledge/components/KnowledgePageExplorer.es.js.map +1 -0
  77. package/dist/domains/knowledge/components/KnowledgePageGraph.cjs.js +626 -0
  78. package/dist/domains/knowledge/components/KnowledgePageGraph.cjs.js.map +1 -0
  79. package/dist/domains/knowledge/components/KnowledgePageGraph.d.ts +1 -0
  80. package/dist/domains/knowledge/components/KnowledgePageGraph.es.js +625 -0
  81. package/dist/domains/knowledge/components/KnowledgePageGraph.es.js.map +1 -0
  82. package/dist/domains/knowledge/components/KnowledgePageTree.cjs.js +170 -0
  83. package/dist/domains/knowledge/components/KnowledgePageTree.cjs.js.map +1 -0
  84. package/dist/domains/knowledge/components/KnowledgePageTree.d.ts +1 -0
  85. package/dist/domains/knowledge/components/KnowledgePageTree.es.js +168 -0
  86. package/dist/domains/knowledge/components/KnowledgePageTree.es.js.map +1 -0
  87. package/dist/domains/knowledge/hooks/useInteractionIdle.cjs.js +37 -0
  88. package/dist/domains/knowledge/hooks/useInteractionIdle.cjs.js.map +1 -0
  89. package/dist/domains/knowledge/hooks/useInteractionIdle.d.ts +1 -0
  90. package/dist/domains/knowledge/hooks/useInteractionIdle.es.js +35 -0
  91. package/dist/domains/knowledge/hooks/useInteractionIdle.es.js.map +1 -0
  92. package/dist/domains/knowledge/lib/layout.cjs.js +93 -0
  93. package/dist/domains/knowledge/lib/layout.cjs.js.map +1 -0
  94. package/dist/domains/knowledge/lib/layout.d.ts +1 -0
  95. package/dist/domains/knowledge/lib/layout.es.js +92 -0
  96. package/dist/domains/knowledge/lib/layout.es.js.map +1 -0
  97. package/dist/domains/knowledge/lib/pageGraph.cjs.js +135 -0
  98. package/dist/domains/knowledge/lib/pageGraph.cjs.js.map +1 -0
  99. package/dist/domains/knowledge/lib/pageGraph.d.ts +1 -0
  100. package/dist/domains/knowledge/lib/pageGraph.es.js +128 -0
  101. package/dist/domains/knowledge/lib/pageGraph.es.js.map +1 -0
  102. package/dist/domains/knowledge/lib/pageLayout.cjs.js +49 -0
  103. package/dist/domains/knowledge/lib/pageLayout.cjs.js.map +1 -0
  104. package/dist/domains/knowledge/lib/pageLayout.d.ts +1 -0
  105. package/dist/domains/knowledge/lib/pageLayout.es.js +48 -0
  106. package/dist/domains/knowledge/lib/pageLayout.es.js.map +1 -0
  107. package/dist/domains/knowledge/lib/pageTree.cjs.js +98 -0
  108. package/dist/domains/knowledge/lib/pageTree.cjs.js.map +1 -0
  109. package/dist/domains/knowledge/lib/pageTree.d.ts +1 -0
  110. package/dist/domains/knowledge/lib/pageTree.es.js +94 -0
  111. package/dist/domains/knowledge/lib/pageTree.es.js.map +1 -0
  112. package/dist/domains/knowledge/lib/popupPlacement.cjs.js +22 -0
  113. package/dist/domains/knowledge/lib/popupPlacement.cjs.js.map +1 -0
  114. package/dist/domains/knowledge/lib/popupPlacement.d.ts +1 -0
  115. package/dist/domains/knowledge/lib/popupPlacement.es.js +21 -0
  116. package/dist/domains/knowledge/lib/popupPlacement.es.js.map +1 -0
  117. package/dist/domains/knowledge/lib/recordText.cjs.js +26 -0
  118. package/dist/domains/knowledge/lib/recordText.cjs.js.map +1 -0
  119. package/dist/domains/knowledge/lib/recordText.d.ts +1 -0
  120. package/dist/domains/knowledge/lib/recordText.es.js +25 -0
  121. package/dist/domains/knowledge/lib/recordText.es.js.map +1 -0
  122. package/dist/domains/knowledge/pageTypes.cjs.js +0 -0
  123. package/dist/domains/knowledge/pageTypes.d.ts +1 -0
  124. package/dist/domains/knowledge/pageTypes.es.js +0 -0
  125. package/dist/domains/logs/components/logs-saved-views.cjs.js +1 -1
  126. package/dist/domains/logs/components/logs-saved-views.es.js +1 -1
  127. package/dist/domains/observability/saved-views/observability-saved-views.cjs.js +1 -1
  128. package/dist/domains/observability/saved-views/observability-saved-views.es.js +1 -1
  129. package/dist/domains/observability/saved-views/saved-views-provider.cjs.js +3 -2
  130. package/dist/domains/observability/saved-views/saved-views-provider.cjs.js.map +1 -1
  131. package/dist/domains/observability/saved-views/saved-views-provider.es.js +3 -2
  132. package/dist/domains/observability/saved-views/saved-views-provider.es.js.map +1 -1
  133. package/dist/domains/observability/saved-views/saved-views-source.cjs.js.map +1 -1
  134. package/dist/domains/observability/saved-views/saved-views-source.es.js.map +1 -1
  135. package/dist/domains/observability/saved-views/use-hosted-saved-views.cjs.js +3 -2
  136. package/dist/domains/observability/saved-views/use-hosted-saved-views.cjs.js.map +1 -1
  137. package/dist/domains/observability/saved-views/use-hosted-saved-views.es.js +3 -2
  138. package/dist/domains/observability/saved-views/use-hosted-saved-views.es.js.map +1 -1
  139. package/dist/domains/observability/saved-views.cjs.js +1 -1
  140. package/dist/domains/observability/saved-views.es.js +1 -1
  141. package/dist/domains/observability.cjs.js +1 -1
  142. package/dist/domains/observability.es.js +1 -1
  143. package/dist/domains/skills/skill-simple-form.cjs.js +2 -2
  144. package/dist/domains/skills/skill-simple-form.cjs.js.map +1 -1
  145. package/dist/domains/skills/skill-simple-form.es.js +2 -2
  146. package/dist/domains/skills/skill-simple-form.es.js.map +1 -1
  147. package/dist/domains/spans/components/spans-explorer-body.cjs.js +1 -1
  148. package/dist/domains/spans/components/spans-explorer-body.es.js +1 -1
  149. package/dist/domains/threads/components/threads-explorer-body.cjs.js +1 -1
  150. package/dist/domains/threads/components/threads-explorer-body.es.js +1 -1
  151. package/dist/domains/traces/components/span-payload/span-error-renderer.cjs.js +1 -1
  152. package/dist/domains/traces/components/span-payload/span-error-renderer.es.js +1 -1
  153. package/dist/domains/traces/components/span-payload/span-input-renderers.cjs.js +1 -1
  154. package/dist/domains/traces/components/span-payload/span-input-renderers.es.js +1 -1
  155. package/dist/domains/traces/components/span-payload/span-output-renderers.cjs.js +1 -1
  156. package/dist/domains/traces/components/span-payload/span-output-renderers.es.js +1 -1
  157. package/dist/domains/traces/components/span-payload/span-payload-messages.cjs.js +1 -1
  158. package/dist/domains/traces/components/span-payload/span-payload-messages.es.js +1 -1
  159. package/dist/domains/traces/components/span-payload/span-payload-primitives.cjs.js +1 -1
  160. package/dist/domains/traces/components/span-payload/span-payload-primitives.es.js +1 -1
  161. package/dist/domains/traces/components/span-payload/span-payload-processor.cjs.js +1 -1
  162. package/dist/domains/traces/components/span-payload/span-payload-processor.es.js +1 -1
  163. package/dist/domains/traces/components/span-payload/span-payload-tool.cjs.js +1 -1
  164. package/dist/domains/traces/components/span-payload/span-payload-tool.es.js +1 -1
  165. package/dist/domains/traces/components/span-payload/span-processor-mutations.cjs.js +1 -1
  166. package/dist/domains/traces/components/span-payload/span-processor-mutations.es.js +1 -1
  167. package/dist/domains/traces/components/span-payload/span-tools-section.cjs.js +1 -1
  168. package/dist/domains/traces/components/span-payload/span-tools-section.es.js +1 -1
  169. package/dist/domains/traces/components/traces-explorer/traces-explorer-saved-views.cjs.js +1 -1
  170. package/dist/domains/traces/components/traces-explorer/traces-explorer-saved-views.es.js +1 -1
  171. package/dist/domains/workflows/workflow/use-workflow-trigger.cjs.js +2 -1
  172. package/dist/domains/workflows/workflow/use-workflow-trigger.cjs.js.map +1 -1
  173. package/dist/domains/workflows/workflow/use-workflow-trigger.es.js +2 -1
  174. package/dist/domains/workflows/workflow/use-workflow-trigger.es.js.map +1 -1
  175. package/dist/lib/form/dynamic-form.cjs.js +2 -2
  176. package/dist/lib/form/dynamic-form.cjs.js.map +1 -1
  177. package/dist/lib/form/dynamic-form.es.js +2 -2
  178. package/dist/lib/form/dynamic-form.es.js.map +1 -1
  179. package/dist/lib/form/json-draft.cjs.js +1 -1
  180. package/dist/lib/form/json-draft.es.js +1 -1
  181. package/dist/lib/form/zod-provider/compat.cjs.js +8 -0
  182. package/dist/lib/form/zod-provider/compat.cjs.js.map +1 -1
  183. package/dist/lib/form/zod-provider/compat.es.js +8 -1
  184. package/dist/lib/form/zod-provider/compat.es.js.map +1 -1
  185. package/dist/lib/form/zod-provider.cjs.js +1 -1
  186. package/dist/lib/form/zod-provider.es.js +1 -1
  187. package/dist/{observability-saved-views-CwCii7hh.cjs → observability-saved-views-BNU3GkK6.cjs} +8 -6
  188. package/dist/observability-saved-views-BNU3GkK6.cjs.map +1 -0
  189. package/dist/{observability-saved-views-Bo5kLN20.js → observability-saved-views-Zlz74syw.js} +8 -6
  190. package/dist/observability-saved-views-Zlz74syw.js.map +1 -0
  191. package/dist/{span-payload-primitives-Dyhbqaa7.js → span-payload-primitives-ChvD2RrN.js} +2 -2
  192. package/dist/{span-payload-primitives-Dyhbqaa7.js.map → span-payload-primitives-ChvD2RrN.js.map} +1 -1
  193. package/dist/{span-payload-primitives-B10Xxmx7.cjs → span-payload-primitives-w1vtAXAw.cjs} +2 -2
  194. package/dist/{span-payload-primitives-B10Xxmx7.cjs.map → span-payload-primitives-w1vtAXAw.cjs.map} +1 -1
  195. package/dist/src/domains/chat/index.d.ts +1 -0
  196. package/dist/src/domains/chat/knowledge/index.d.ts +5 -0
  197. package/dist/src/domains/chat/knowledge/knowledge-links.d.ts +21 -0
  198. package/dist/src/domains/chat/knowledge/pinned-knowledge-data.d.ts +22 -0
  199. package/dist/src/domains/chat/knowledge/pinned-knowledge.d.ts +9 -0
  200. package/dist/src/domains/chat/tools/badges/knowledge-tool-badge.d.ts +19 -0
  201. package/dist/src/domains/chat/tools/tool-card-kind.d.ts +2 -2
  202. package/dist/src/domains/knowledge/components/KnowledgePageDetail.d.ts +42 -0
  203. package/dist/src/domains/knowledge/components/KnowledgePageExplorer.d.ts +80 -0
  204. package/dist/src/domains/knowledge/components/KnowledgePageGraph.d.ts +35 -0
  205. package/dist/src/domains/knowledge/components/KnowledgePageTree.d.ts +27 -0
  206. package/dist/src/domains/knowledge/hooks/useInteractionIdle.d.ts +12 -0
  207. package/dist/src/domains/knowledge/lib/layout.d.ts +35 -0
  208. package/dist/src/domains/knowledge/lib/pageGraph.d.ts +45 -0
  209. package/dist/src/domains/knowledge/lib/pageLayout.d.ts +24 -0
  210. package/dist/src/domains/knowledge/lib/pageTree.d.ts +28 -0
  211. package/dist/src/domains/knowledge/lib/popupPlacement.d.ts +12 -0
  212. package/dist/src/domains/knowledge/lib/recordText.d.ts +9 -0
  213. package/dist/src/domains/knowledge/pageTypes.d.ts +96 -0
  214. package/dist/src/domains/observability/saved-views/saved-views-provider.d.ts +6 -1
  215. package/dist/src/domains/observability/saved-views/saved-views-source.d.ts +1 -0
  216. package/dist/src/domains/observability/saved-views/use-hosted-saved-views.d.ts +1 -1
  217. package/dist/src/domains/skills/skill-simple-form.d.ts +3 -1
  218. package/dist/src/ds/components/SavedViews/saved-view-picker.d.ts +3 -1
  219. package/dist/src/ds/components/ai/tool-call/tool-phrases.d.ts +30 -0
  220. package/dist/src/lib/form/zod-provider/compat.d.ts +5 -0
  221. package/dist/style.css +63 -1
  222. package/dist/{tool-approval-FeuyUUcL.js → tool-approval-DHeCkWHT.js} +3 -3
  223. package/dist/{tool-approval-FeuyUUcL.js.map → tool-approval-DHeCkWHT.js.map} +1 -1
  224. package/dist/{tool-approval-BfjoSNOC.cjs → tool-approval-Dfi0uAKU.cjs} +3 -3
  225. package/dist/{tool-approval-BfjoSNOC.cjs.map → tool-approval-Dfi0uAKU.cjs.map} +1 -1
  226. package/dist/{tool-call-CvilN9ti.cjs → tool-call-BCsDhIhs.cjs} +32 -2
  227. package/dist/{tool-call-CvilN9ti.cjs.map → tool-call-BCsDhIhs.cjs.map} +1 -1
  228. package/dist/{tool-call-BxYXs9w0.js → tool-call-CILZa3tn.js} +32 -2
  229. package/dist/{tool-call-BxYXs9w0.js.map → tool-call-CILZa3tn.js.map} +1 -1
  230. package/dist/{tool-card-ELW898uw.js → tool-card-C3sDFUWc.js} +18 -4
  231. package/dist/tool-card-C3sDFUWc.js.map +1 -0
  232. package/dist/{tool-card-B7O8AsRl.cjs → tool-card-CJ7Kxi-U.cjs} +18 -4
  233. package/dist/tool-card-CJ7Kxi-U.cjs.map +1 -0
  234. package/dist/{tool-presentation-BLErsb7c.cjs → tool-presentation-CQlDEwgS.cjs} +26 -1
  235. package/dist/tool-presentation-CQlDEwgS.cjs.map +1 -0
  236. package/dist/{tool-presentation-BSZYIWx2.js → tool-presentation-DvCsb_kz.js} +26 -1
  237. package/dist/tool-presentation-DvCsb_kz.js.map +1 -0
  238. package/package.json +11 -9
  239. package/dist/observability-saved-views-Bo5kLN20.js.map +0 -1
  240. package/dist/observability-saved-views-CwCii7hh.cjs.map +0 -1
  241. package/dist/tool-card-B7O8AsRl.cjs.map +0 -1
  242. package/dist/tool-card-ELW898uw.js.map +0 -1
  243. package/dist/tool-presentation-BLErsb7c.cjs.map +0 -1
  244. package/dist/tool-presentation-BSZYIWx2.js.map +0 -1
@@ -0,0 +1 @@
1
+ {"version":3,"file":"KnowledgePageGraph.es.js","names":["_Fragment"],"sources":["../../../../src/domains/knowledge/components/KnowledgePageGraph.tsx"],"sourcesContent":["import type { Edge, EdgeProps, NodeProps } from '@xyflow/react';\nimport {\n Background,\n BaseEdge,\n BackgroundVariant,\n ControlButton,\n Controls,\n getViewportForBounds,\n Handle,\n MarkerType,\n Position,\n ReactFlow,\n ReactFlowProvider,\n useReactFlow,\n} from '@xyflow/react';\nimport '@xyflow/react/dist/style.css';\nimport { Maximize, Pin } from 'lucide-react';\nimport { Fragment, memo, useCallback, useEffect, useMemo, useRef } from 'react';\nimport type { CSSProperties } from 'react';\n\nimport type { PageFlowEdge, PageFlowNode } from '../lib/pageGraph';\nimport { grantGraph, pageGraphEdges, pageNeighbourIds, toPageFlow } from '../lib/pageGraph';\nimport { layoutPageGraph } from '../lib/pageLayout';\nimport type { PageLayout } from '../lib/pageLayout';\nimport type { KnowledgePageEdge, KnowledgePagePayload, KnowledgeScopeGrantPayload } from '../pageTypes';\n\nimport { Txt } from '@/ds/components/Txt';\n\nimport './knowledge.css';\n\n// knowledge.css draws the border and the selection ring from this colour.\ntype CircleStyle = CSSProperties & { '--knowledge-color': string };\nconst SCOPE_STYLE: CircleStyle = {\n '--knowledge-color': 'var(--chart-blue)',\n background: 'color-mix(in oklab, var(--chart-blue) 16%, var(--card))',\n};\nconst PAGE_STYLE: CircleStyle = { '--knowledge-color': 'var(--border-strong)' };\n\nconst PARENT_EDGE_STYLE = {\n stroke: 'var(--foreground)',\n strokeOpacity: 0.45,\n strokeDasharray: '4 4',\n strokeWidth: 1.25,\n};\nconst MENTION_EDGE_COLOR = 'var(--chart-blue)';\n// An open chevron in the dashed line's muted tone, at the child end: distinct from a mention's filled blue head.\nconst PARENT_ARROW_COLOR = 'var(--muted-foreground)';\nconst PARENT_ARROW = { type: MarkerType.Arrow, color: PARENT_ARROW_COLOR, width: 12, height: 12, strokeWidth: 1.5 };\n// Grants: purple dash-dot from the principal scope to the scope it reaches, so neither colour nor pattern\n// alone tells it apart from a parent or mention line.\nconst GRANT_EDGE_COLOR = 'var(--chart-purple)';\nconst GRANT_EDGE_STYLE = { stroke: GRANT_EDGE_COLOR, strokeWidth: 1.75, strokeDasharray: '8 3 2 3' };\nconst GRANT_ARROW = { type: MarkerType.ArrowClosed, color: GRANT_EDGE_COLOR, width: 13, height: 13 };\n// A declared principal with no scope page yet: same size as a scope, dashed outline, nothing to open.\nconst PLACEHOLDER_STYLE = {\n background: 'var(--card)',\n borderColor: 'var(--chart-purple)',\n borderStyle: 'dashed',\n};\n\n/**\n * The pin badge sits on the circle's rim at its top-right (45°).\n */\nfunction pinBadgeStyle(size: number) {\n const badge = 20;\n const offset = (size / 2) * (1 - Math.SQRT1_2);\n return {\n badge,\n style: { width: badge, height: badge, top: offset, right: offset, transform: 'translate(50%, -50%)' },\n };\n}\n\ntype PageNodeData = PageFlowNode['data'] & { pinned: boolean; dimmed: boolean };\n\n/** A scope or page: its kind on top, its name below, both inside the circle. */\nfunction PageNodeComponent({ data }: NodeProps<PageFlowNode & { data: PageNodeData }>) {\n const { page, size, selected, pinned, dimmed } = data;\n const kind = page.isScope ? (page.displayLabel ?? 'Scope') : 'Page';\n const placeholder = isPlaceholder(page);\n return (\n <div\n data-testid=\"knowledge-page-node\"\n data-page-id={page.id}\n data-page-type={placeholder ? 'placeholder' : page.isScope ? 'scope' : 'page'}\n className={`relative transition-opacity ${placeholder ? 'cursor-default' : 'cursor-pointer'}`}\n style={{ width: size, height: size, opacity: dimmed ? 0.35 : 1 }}\n title={\n placeholder\n ? `${kind} · ${page.address} · nothing written to it yet`\n : page.isScope && page.address\n ? `${kind} · ${page.address}`\n : page.name\n }\n >\n <div\n className=\"knowledge-circle flex size-full flex-col items-center justify-center gap-0.5 overflow-hidden rounded-full border-2 px-3 text-center shadow-raised\"\n data-selected={selected || undefined}\n style={placeholder ? PLACEHOLDER_STYLE : page.isScope ? SCOPE_STYLE : PAGE_STYLE}\n >\n <Txt\n as=\"span\"\n variant=\"meta\"\n tone={page.isScope ? undefined : 'muted'}\n className=\"pointer-events-none line-clamp-2 max-w-full tracking-wide uppercase\"\n style={page.isScope ? { color: 'var(--chart-blue)' } : undefined}\n data-testid={page.isScope ? 'knowledge-scope-caption' : 'knowledge-page-caption'}\n >\n {kind}\n </Txt>\n <Txt as=\"span\" variant=\"label\" tone=\"ink\" className=\"pointer-events-none line-clamp-3 max-w-full break-words\">\n {page.isScope && page.address ? <BreakAtColons text={page.address} /> : page.name}\n </Txt>\n </div>\n {pinned ? <PinBadge size={size} /> : null}\n <Handle type=\"target\" position={Position.Top} className=\"!invisible\" />\n <Handle type=\"source\" position={Position.Bottom} className=\"!invisible\" />\n </div>\n );\n}\n\nfunction isPlaceholder(page: KnowledgePagePayload): boolean {\n return page.id.startsWith('unplaced:');\n}\n\n/** Lets a scope address like `role:acme:admin` wrap after a colon instead of mid-word. */\nfunction BreakAtColons({ text }: { text: string }) {\n const parts = text.split(':');\n return (\n <>\n {parts.map((part, index) => (\n <Fragment key={index}>\n {part}\n {index < parts.length - 1 ? (\n <>\n :<wbr />\n </>\n ) : null}\n </Fragment>\n ))}\n </>\n );\n}\n\nfunction PinBadge({ size }: { size: number }) {\n const { badge, style } = pinBadgeStyle(size);\n return (\n <span\n data-testid=\"knowledge-pin-badge\"\n className=\"absolute flex items-center justify-center rounded-full bg-badge-amber-strong text-badge-amber-foreground shadow-raised\"\n style={style}\n aria-label=\"Pinned\"\n >\n <Pin size={Math.round(badge * 0.6)} aria-hidden />\n </span>\n );\n}\n\ntype RimEdgeData = PageFlowEdge['data'] & { from: Circle; to: Circle; dimmed: boolean };\ninterface Circle {\n x: number;\n y: number;\n r: number;\n}\n\n/** A straight line from one circle's rim to the other's, so lines never loop or hide behind circles. */\nfunction rimToRim(from: Circle, to: Circle, gap = 3) {\n const dx = to.x - from.x;\n const dy = to.y - from.y;\n const length = Math.hypot(dx, dy) || 1;\n const ux = dx / length;\n const uy = dy / length;\n return {\n x1: from.x + ux * (from.r + gap),\n y1: from.y + uy * (from.r + gap),\n x2: to.x - ux * (to.r + gap),\n y2: to.y - uy * (to.r + gap),\n };\n}\n\nfunction RimEdgeComponent({ id, data, style, markerEnd }: EdgeProps<Edge<RimEdgeData>>) {\n if (!data) return null;\n const { x1, y1, x2, y2 } = rimToRim(data.from, data.to);\n const mention = data.kind === 'mention';\n const path = `M ${x1} ${y1} L ${x2} ${y2}`;\n return (\n <>\n <BaseEdge\n id={id}\n path={path}\n style={{ ...style, opacity: data.dimmed ? 0.2 : 1 }}\n markerEnd={markerEnd}\n interactionWidth={mention ? 20 : 0}\n />\n {data.kind === 'grant' && data.role ? (\n // A wide invisible path over the line, so hovering it names the access level.\n <path\n d={path}\n fill=\"none\"\n stroke=\"transparent\"\n strokeWidth={14}\n data-testid=\"knowledge-grant-edge\"\n data-role={data.role}\n aria-label={`Grants ${data.role}`}\n >\n <title>{`Grants ${data.role}`}</title>\n </path>\n ) : null}\n </>\n );\n}\n\nconst edgeTypes = { rim: RimEdgeComponent };\n\nconst nodeTypes = { page: memo(PageNodeComponent) };\n\n/** The box around laid-out circles, in graph coordinates; `null` when there are none. */\nfunction graphBounds(nodes: Array<{ position: { x: number; y: number }; width?: number; height?: number }>) {\n if (nodes.length === 0) return null;\n let minX = Infinity;\n let minY = Infinity;\n let maxX = -Infinity;\n let maxY = -Infinity;\n for (const node of nodes) {\n minX = Math.min(minX, node.position.x);\n minY = Math.min(minY, node.position.y);\n maxX = Math.max(maxX, node.position.x + (node.width ?? 0));\n maxY = Math.max(maxY, node.position.y + (node.height ?? 0));\n }\n return { x: minX, y: minY, width: maxX - minX, height: maxY - minY };\n}\n\nconst LEGEND_SWATCH = 'knowledge-circle inline-block size-3 shrink-0 rounded-full border-2';\n\n/** What the circles, lines and badge mean. */\nfunction GraphLegend({ grants }: { grants: boolean }) {\n return (\n <ul\n aria-label=\"Legend\"\n className=\"pointer-events-none absolute top-2 left-2 z-10 flex flex-col gap-1 rounded-md border border-border bg-card/90 px-2 py-1.5 shadow-raised\"\n >\n <li className=\"flex items-center gap-2\">\n <span className={LEGEND_SWATCH} style={{ ...SCOPE_STYLE }} aria-hidden />\n <Txt as=\"span\" variant=\"meta\" tone=\"muted\">\n Scope\n </Txt>\n </li>\n <li className=\"flex items-center gap-2\">\n <span className={LEGEND_SWATCH} style={{ ...PAGE_STYLE }} aria-hidden />\n <Txt as=\"span\" variant=\"meta\" tone=\"muted\">\n Page\n </Txt>\n </li>\n <li className=\"flex items-center gap-2\">\n <svg width=\"12\" height=\"4\" aria-hidden className=\"shrink-0\">\n <line x1=\"0\" y1=\"2\" x2=\"12\" y2=\"2\" stroke={MENTION_EDGE_COLOR} strokeWidth=\"2\" />\n </svg>\n <Txt as=\"span\" variant=\"meta\" tone=\"muted\">\n Mentioned in notes\n </Txt>\n </li>\n <li className=\"flex items-center gap-2\">\n <svg width=\"16\" height=\"8\" aria-hidden className=\"shrink-0\" data-testid=\"knowledge-legend-parent-arrow\">\n <line x1=\"0\" y1=\"4\" x2=\"14\" y2=\"4\" {...PARENT_EDGE_STYLE} strokeDasharray=\"3 2\" />\n <polyline\n points=\"10,1 14,4 10,7\"\n fill=\"none\"\n stroke={PARENT_ARROW_COLOR}\n strokeWidth=\"1.25\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n />\n </svg>\n <Txt as=\"span\" variant=\"meta\" tone=\"muted\">\n Parent → child\n </Txt>\n </li>\n {grants ? (\n <li className=\"flex items-center gap-2\">\n <svg width=\"16\" height=\"8\" aria-hidden className=\"shrink-0\" data-testid=\"knowledge-legend-grant\">\n <line x1=\"0\" y1=\"4\" x2=\"12\" y2=\"4\" {...GRANT_EDGE_STYLE} strokeDasharray=\"4 2 1 2\" strokeWidth=\"1.5\" />\n <polygon points=\"11,1 16,4 11,7\" fill={GRANT_EDGE_COLOR} />\n </svg>\n <Txt as=\"span\" variant=\"meta\" tone=\"muted\">\n Grants access (hover for role)\n </Txt>\n </li>\n ) : null}\n <li className=\"flex items-center gap-2\">\n <span\n className=\"flex size-3 shrink-0 items-center justify-center rounded-full bg-badge-amber-strong text-badge-amber-foreground\"\n aria-hidden\n >\n <Pin size={8} />\n </span>\n <Txt as=\"span\" variant=\"meta\" tone=\"muted\">\n Pinned\n </Txt>\n </li>\n </ul>\n );\n}\n\n/** How far the pointer may move between press and release and still count as a click, not a pan. */\nconst CLICK_SLOP_PX = 4;\n\nexport interface KnowledgePageGraphProps {\n pages: KnowledgePagePayload[];\n /** Mention edges between pages; parent edges are derived from `pages`. */\n edges: KnowledgePageEdge[];\n pinnedIds?: readonly string[];\n /** Access grants between scopes, drawn from each principal scope to the scope it reaches. */\n grants?: readonly KnowledgeScopeGrantPayload[];\n selectedPageId?: string | null;\n /** A page that wasn't selected was clicked, tapped, or activated with Enter or Space: select it. */\n onSelect: (page: KnowledgePagePayload) => void;\n /** The already-selected page was clicked, tapped, or activated again: open it. Without it, that only reselects. */\n onOpen?: (page: KnowledgePagePayload) => void;\n /** Empty canvas was clicked without moving the pointer (a pan doesn't count): clear the selection. */\n onClearSelection?: () => void;\n /** A mention line was clicked: notes on `source` mention `target`. `point` is where, in the graph's own box. */\n onMentionSelect?: (mention: {\n source: KnowledgePagePayload;\n target: KnowledgePagePayload;\n point: { x: number; y: number };\n /** The graph's own size, so a popup can open on whichever side of `point` has room. */\n pane: { width: number; height: number };\n }) => void;\n}\n\n/**\n * The schema-4 Knowledge page graph: scopes and pages as circles sized by how often they are mentioned,\n * parent links as faint edges and mentions as solid ones. The first layout is deterministic for the same pages; later updates start from where pages already sit.\n */\nexport function KnowledgePageGraph(props: KnowledgePageGraphProps) {\n return (\n <ReactFlowProvider>\n <KnowledgePageGraphInner {...props} />\n </ReactFlowProvider>\n );\n}\n\nfunction KnowledgePageGraphInner({\n pages,\n edges,\n pinnedIds = [],\n grants,\n selectedPageId,\n onSelect,\n onOpen,\n onClearSelection,\n onMentionSelect,\n}: KnowledgePageGraphProps) {\n // Grants add placeholder circles for declared principals with no scope page yet, and their own lines.\n const { graphPages, allEdges } = useMemo(() => {\n const granted = grantGraph(pages, grants);\n const withPlaceholders = granted.placeholders.length ? [...pages, ...granted.placeholders] : pages;\n return { graphPages: withPlaceholders, allEdges: [...pageGraphEdges(pages, edges), ...granted.edges] };\n }, [pages, edges, grants]);\n // The last layout: a refetch or live update starts from it, so placed pages stay put.\n const lastLayout = useRef<PageLayout | undefined>(undefined);\n const laidOut = useMemo(() => {\n const flow = toPageFlow(graphPages, allEdges);\n const layout = layoutPageGraph(\n lastLayout.current,\n flow.nodes.map(node => ({ id: node.id, size: node.data.size })),\n flow.edges.map(edge => ({ source: edge.source, target: edge.target })),\n );\n lastLayout.current = layout;\n return { nodes: flow.nodes, edges: flow.edges, positions: layout.positions };\n }, [graphPages, allEdges]);\n\n const pinned = useMemo(() => new Set(pinnedIds), [pinnedIds]);\n // With a page selected, everything more than one line away fades so its neighbourhood reads at a glance.\n const neighbours = useMemo(\n () => (selectedPageId && laidOut.positions.has(selectedPageId) ? pageNeighbourIds(selectedPageId, allEdges) : null),\n [selectedPageId, laidOut, allEdges],\n );\n // Each circle's size is known from the layout, so hand it to React Flow as the node's fixed size. Left to\n // React Flow's own DOM measurement, a production Studio sometimes never got one and every node stayed\n // `visibility: hidden`.\n const nodes = useMemo(\n () =>\n laidOut.nodes.map(node => {\n const center = laidOut.positions.get(node.id) ?? { x: 0, y: 0 };\n return {\n ...node,\n width: node.data.size,\n height: node.data.size,\n // Declared handles (where the hidden ones sit in PageNodeComponent) let lines draw without React\n // Flow measuring the node in the DOM, for the same reason as the fixed size above.\n handles: [\n { type: 'target' as const, position: Position.Top, x: node.data.size / 2, y: 0, width: 1, height: 1 },\n {\n type: 'source' as const,\n position: Position.Bottom,\n x: node.data.size / 2,\n y: node.data.size,\n width: 1,\n height: 1,\n },\n ],\n position: { x: center.x - node.data.size / 2, y: center.y - node.data.size / 2 },\n data: {\n ...node.data,\n selected: node.id === selectedPageId,\n pinned: pinned.has(node.id),\n dimmed: !!neighbours && !neighbours.has(node.id),\n },\n };\n }),\n [laidOut, selectedPageId, pinned, neighbours],\n );\n const flowEdges = useMemo(() => {\n const sizes = new Map(laidOut.nodes.map(node => [node.id, node.data.size]));\n const circle = (id: string): Circle => {\n const center = laidOut.positions.get(id) ?? { x: 0, y: 0 };\n return { ...center, r: (sizes.get(id) ?? 0) / 2 };\n };\n return laidOut.edges.map((edge): Edge<RimEdgeData> => {\n const mention = edge.data?.kind === 'mention';\n const grant = edge.data?.kind === 'grant';\n const dimmed = !!neighbours && !(neighbours.has(edge.source) && neighbours.has(edge.target));\n return {\n ...edge,\n type: 'rim',\n data: {\n kind: edge.data?.kind ?? 'parent',\n count: edge.data?.count ?? 1,\n ...(edge.data?.role ? { role: edge.data.role } : {}),\n from: circle(edge.source),\n to: circle(edge.target),\n dimmed,\n },\n ...(mention && onMentionSelect ? { className: 'cursor-pointer' } : {}),\n style: mention\n ? { stroke: MENTION_EDGE_COLOR, strokeWidth: Math.min(1.5 + (edge.data?.count ?? 1) * 0.5, 4) }\n : grant\n ? GRANT_EDGE_STYLE\n : PARENT_EDGE_STYLE,\n markerEnd: mention\n ? { type: MarkerType.ArrowClosed, color: MENTION_EDGE_COLOR, width: 14, height: 14 }\n : grant\n ? GRANT_ARROW\n : PARENT_ARROW,\n };\n });\n }, [laidOut, onMentionSelect, neighbours]);\n const pagesById = useMemo(() => new Map(pages.map(page => [page.id, page])), [pages]);\n const reactFlow = useReactFlow();\n const containerRef = useRef<HTMLDivElement>(null);\n const hasNodes = nodes.length > 0;\n\n // The view frames the selected page and its neighbours, or every page when nothing is selected. It is\n // computed from the layout's own positions and sizes rather than React Flow's `fitView`, which only\n // counts nodes it has measured in the DOM: in a production Studio it measured none, so the view never\n // moved. State is read through a ref so a refetch with the same selection never moves the view.\n const fitState = useRef({ nodes, allEdges, selectedPageId, reactFlow });\n fitState.current = { nodes, allEdges, selectedPageId, reactFlow };\n // Set when a fit found the pane 0×0, so the next non-zero size fits even if it matches the last one seen.\n const fitPending = useRef(false);\n const fit = useCallback((focusSelection: boolean, duration?: number) => {\n const container = containerRef.current;\n const width = container?.clientWidth ?? 0;\n const height = container?.clientHeight ?? 0;\n if (width === 0 || height === 0) {\n fitPending.current = true;\n return;\n }\n fitPending.current = false;\n const { nodes: current, allEdges: edgesNow, selectedPageId: selected, reactFlow: flow } = fitState.current;\n const focus = focusSelection && selected ? pageNeighbourIds(selected, edgesNow) : null;\n const targets = focus ? current.filter(node => focus.has(node.id)) : current;\n const bounds = graphBounds(targets);\n if (!bounds) return;\n const viewport = getViewportForBounds(bounds, width, height, 0.1, focus ? 1.5 : 2, focus ? 0.3 : 0.1);\n void flow.setViewport(viewport, duration ? { duration } : undefined);\n }, []);\n\n // A host that hides the graph behind a Tree/Graph toggle gives it zero size at first, so fit again\n // whenever the container gets a new non-zero size (shown, or the window resized), at most once a frame.\n useEffect(() => {\n const container = containerRef.current;\n if (!container || typeof ResizeObserver === 'undefined') return;\n let last = { width: container.clientWidth, height: container.clientHeight };\n let frame: number | undefined;\n const observer = new ResizeObserver(([entry]) => {\n if (!entry) return;\n const { width, height } = entry.contentRect;\n const changed = width !== last.width || height !== last.height;\n last = { width, height };\n if ((!changed && !fitPending.current) || width === 0 || height === 0) return;\n if (frame !== undefined) cancelAnimationFrame(frame);\n frame = requestAnimationFrame(() => {\n frame = undefined;\n fit(true);\n });\n });\n observer.observe(container);\n return () => {\n observer.disconnect();\n if (frame !== undefined) cancelAnimationFrame(frame);\n };\n }, [hasNodes, fit]);\n\n // A selection made outside the graph (tree, search, a link) brings that page and its neighbours into\n // view. A click on the graph itself leaves the view where the user put it.\n const selectedHere = useRef<string | null>(null);\n const selectedIsLoaded = !!selectedPageId && pagesById.has(selectedPageId);\n const initialized = useRef(false);\n useEffect(() => {\n if (!initialized.current || !selectedIsLoaded || !selectedPageId) return;\n const fromGraph = selectedHere.current === selectedPageId;\n selectedHere.current = null;\n if (fromGraph) return;\n fit(true, 300);\n }, [selectedPageId, selectedIsLoaded, fit]);\n\n // First click selects; a click on the page that is already selected opens it. A double-click is the two.\n const activate = (page: KnowledgePagePayload) => {\n if (page.id === selectedPageId && onOpen) return onOpen(page);\n selectedHere.current = page.id;\n onSelect(page);\n };\n // Where the pointer went down, so a click that ends a pan isn't taken for a click on empty canvas.\n const pressedAt = useRef<{ x: number; y: number } | null>(null);\n const onPaneClick = (event: React.MouseEvent) => {\n const start = pressedAt.current;\n pressedAt.current = null;\n if (start && Math.hypot(event.clientX - start.x, event.clientY - start.y) > CLICK_SLOP_PX) return;\n onClearSelection?.();\n };\n // React Flow focuses nodes but only toggles its own selection on Enter or Space; route them like a click.\n const onKeyDown = (event: React.KeyboardEvent) => {\n if (event.key !== 'Enter' && event.key !== ' ') return;\n const id = (event.target as HTMLElement).closest<HTMLElement>('.react-flow__node')?.dataset.id;\n const page = id ? pagesById.get(id) : undefined;\n if (!page) return;\n event.preventDefault();\n activate(page);\n };\n\n if (!hasNodes) {\n return (\n <div className=\"flex h-full items-center justify-center p-6\">\n <Txt variant=\"body\" tone=\"muted\">\n No pages yet.\n </Txt>\n </div>\n );\n }\n\n return (\n <div\n ref={containerRef}\n className=\"relative size-full\"\n data-testid=\"knowledge-page-graph\"\n onKeyDown={onKeyDown}\n onPointerDownCapture={event => {\n pressedAt.current = { x: event.clientX, y: event.clientY };\n }}\n >\n <GraphLegend grants={allEdges.some(edge => edge.kind === 'grant')} />\n <ReactFlow\n nodes={nodes}\n edges={flowEdges}\n nodeTypes={nodeTypes}\n edgeTypes={edgeTypes}\n onInit={() => {\n initialized.current = true;\n fit(true);\n }}\n minZoom={0.1}\n proOptions={{ hideAttribution: true }}\n nodesConnectable={false}\n nodesDraggable={false}\n onPaneClick={onPaneClick}\n onNodeClick={(_: unknown, node: PageFlowNode) => {\n if (!isPlaceholder(node.data.page)) activate(node.data.page);\n }}\n onEdgeClick={(event: React.MouseEvent, edge: Edge<RimEdgeData>) => {\n if (edge.data?.kind !== 'mention' || !onMentionSelect) return;\n const source = pagesById.get(edge.source);\n const target = pagesById.get(edge.target);\n if (!source || !target) return;\n const box = containerRef.current?.getBoundingClientRect();\n onMentionSelect({\n source,\n target,\n point: { x: event.clientX - (box?.left ?? 0), y: event.clientY - (box?.top ?? 0) },\n pane: { width: box?.width ?? 0, height: box?.height ?? 0 },\n });\n }}\n >\n <Background variant={BackgroundVariant.Dots} gap={26} size={1.4} color=\"var(--border-strong)\" />\n <Controls showInteractive={false} showFitView={false}>\n <ControlButton onClick={() => fit(false, 300)} title=\"Fit view\" aria-label=\"Fit view\">\n <Maximize aria-hidden />\n </ControlButton>\n </Controls>\n </ReactFlow>\n </div>\n );\n}\n"],"mappings":"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"}
@@ -0,0 +1,170 @@
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
+ const require_utils = require("../../../utils-uDc1ofX1.cjs");
3
+ const require_domains_knowledge_lib_pageTree = require("../lib/pageTree.cjs.js");
4
+ let react = require("react");
5
+ let react_jsx_runtime = require("react/jsx-runtime");
6
+ let lucide_react = require("lucide-react");
7
+ // src/domains/knowledge/components/KnowledgePageTree.tsx
8
+ /** The key {@link KnowledgePageTree}'s `loadMore` uses for the root level. */
9
+ var KNOWLEDGE_TREE_ROOT = "";
10
+ /**
11
+ * The Knowledge page tree: scopes and pages nested by parent, siblings in
12
+ * stored order. Selecting a page from elsewhere (graph, search) opens the path
13
+ * to it. Keyboard follows the WAI-ARIA tree pattern: Up/Down move, Right opens
14
+ * or enters, Left closes or goes to the parent, Enter/Space selects.
15
+ *
16
+ * A host that loads the tree a level at a time passes `mayHaveChildren` (so unloaded pages still offer
17
+ * a chevron), listens to `onExpandedChange` to load the opened levels, and passes `loadMore` for
18
+ * levels with more children to fetch.
19
+ */
20
+ function KnowledgePageTree({ pages, pinnedIds, selectedPageId, onSelect, initiallyExpanded, mayHaveChildren, onExpandedChange, loadMore, "aria-label": ariaLabel = "Knowledge pages" }) {
21
+ const roots = (0, react.useMemo)(() => require_domains_knowledge_lib_pageTree.buildPageTree(pages), [pages]);
22
+ const pinned = (0, react.useMemo)(() => new Set(pinnedIds), [pinnedIds]);
23
+ const [expanded, setExpanded] = (0, react.useState)(() => new Set(initiallyExpanded ?? roots.map((root) => root.page.id)));
24
+ const [focusedId, setFocusedId] = (0, react.useState)(null);
25
+ const itemRefs = (0, react.useRef)(/* @__PURE__ */ new Map());
26
+ (0, react.useEffect)(() => {
27
+ if (!selectedPageId) return;
28
+ const path = require_domains_knowledge_lib_pageTree.pageAncestorIds(pages, selectedPageId);
29
+ setExpanded((current) => path.every((id) => current.has(id)) ? current : /* @__PURE__ */ new Set([...current, ...path]));
30
+ }, [pages, selectedPageId]);
31
+ (0, react.useEffect)(() => {
32
+ onExpandedChange?.(expanded);
33
+ }, [expanded, onExpandedChange]);
34
+ const rows = (0, react.useMemo)(() => require_domains_knowledge_lib_pageTree.visiblePageRows(roots, expanded).map((row) => !row.hasChildren && mayHaveChildren?.(row.page) ? {
35
+ ...row,
36
+ hasChildren: true
37
+ } : row), [
38
+ roots,
39
+ expanded,
40
+ mayHaveChildren
41
+ ]);
42
+ const activeId = focusedId && rows.some((row) => row.page.id === focusedId) ? focusedId : rows.find((row) => row.page.id === selectedPageId)?.page.id ?? rows[0]?.page.id;
43
+ const toggle = (id, open) => setExpanded((current) => {
44
+ if (current.has(id) === open) return current;
45
+ const next = new Set(current);
46
+ if (open) next.add(id);
47
+ else next.delete(id);
48
+ return next;
49
+ });
50
+ const focus = (id) => {
51
+ if (!id) return;
52
+ setFocusedId(id);
53
+ itemRefs.current.get(id)?.focus();
54
+ };
55
+ const onKeyDown = (event, index) => {
56
+ const row = rows[index];
57
+ if (!row) return;
58
+ switch (event.key) {
59
+ case "ArrowDown":
60
+ focus(rows[index + 1]?.page.id);
61
+ break;
62
+ case "ArrowUp":
63
+ focus(rows[index - 1]?.page.id);
64
+ break;
65
+ case "ArrowRight":
66
+ if (row.hasChildren && !row.expanded) toggle(row.page.id, true);
67
+ else if (row.expanded) focus(rows[index + 1]?.page.id);
68
+ break;
69
+ case "ArrowLeft":
70
+ if (row.expanded) toggle(row.page.id, false);
71
+ else focus(rows.slice(0, index).findLast((candidate) => candidate.depth < row.depth)?.page.id);
72
+ break;
73
+ case "Enter":
74
+ case " ":
75
+ onSelect(row.page);
76
+ break;
77
+ default: return;
78
+ }
79
+ event.preventDefault();
80
+ };
81
+ if (rows.length === 0) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
82
+ className: "px-3 py-2 text-body text-muted-foreground",
83
+ children: "No pages yet."
84
+ });
85
+ const ancestorAt = [];
86
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
87
+ role: "tree",
88
+ "aria-label": ariaLabel,
89
+ className: "min-h-0 overflow-y-auto py-1",
90
+ children: rows.map((row, index) => {
91
+ const selected = row.page.id === selectedPageId;
92
+ ancestorAt[row.depth] = row.page.id;
93
+ const nextDepth = rows[index + 1]?.depth ?? -1;
94
+ const closing = [];
95
+ for (let depth = row.depth - 1; depth >= nextDepth; depth--) {
96
+ const parentId = depth < 0 ? "" : ancestorAt[depth];
97
+ if (parentId !== void 0) closing.push({
98
+ parentId,
99
+ depth: depth + 1
100
+ });
101
+ }
102
+ if (row.expanded && rows[index + 1]?.depth !== row.depth + 1) closing.unshift({
103
+ parentId: row.page.id,
104
+ depth: row.depth + 1
105
+ });
106
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
107
+ ref: (element) => {
108
+ if (element) itemRefs.current.set(row.page.id, element);
109
+ else itemRefs.current.delete(row.page.id);
110
+ },
111
+ role: "treeitem",
112
+ "aria-level": row.depth + 1,
113
+ "aria-selected": selected,
114
+ "aria-expanded": row.hasChildren ? row.expanded : void 0,
115
+ tabIndex: row.page.id === activeId ? 0 : -1,
116
+ onFocus: () => setFocusedId(row.page.id),
117
+ onKeyDown: (event) => onKeyDown(event, index),
118
+ onClick: () => onSelect(row.page),
119
+ className: require_utils.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"),
120
+ style: { paddingLeft: `${row.depth * 16 + 4}px` },
121
+ children: [
122
+ row.hasChildren ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
123
+ type: "button",
124
+ tabIndex: -1,
125
+ "aria-label": row.expanded ? `Collapse ${row.page.name}` : `Expand ${row.page.name}`,
126
+ className: "flex size-5 shrink-0 items-center justify-center rounded text-muted-foreground hover:text-foreground",
127
+ onClick: (event) => {
128
+ event.stopPropagation();
129
+ toggle(row.page.id, !row.expanded);
130
+ },
131
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(lucide_react.ChevronRight, {
132
+ size: 14,
133
+ className: require_utils.cn("transition-transform", row.expanded && "rotate-90")
134
+ })
135
+ }) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
136
+ className: "size-5 shrink-0",
137
+ "aria-hidden": true
138
+ }),
139
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
140
+ className: require_utils.cn("min-w-0 flex-1 truncate text-body", row.page.isScope && "font-medium"),
141
+ children: row.page.name
142
+ }),
143
+ pinned.has(row.page.id) ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(lucide_react.Pin, {
144
+ size: 12,
145
+ className: "shrink-0 text-badge-amber-indicator",
146
+ "aria-label": "Pinned"
147
+ }) : null,
148
+ row.page.isScope && row.page.address && row.page.address !== row.page.name ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
149
+ "data-testid": "knowledge-tree-address",
150
+ className: "max-w-1/2 min-w-0 truncate text-caption text-muted-foreground",
151
+ children: row.page.address
152
+ }) : null
153
+ ]
154
+ }), closing.map(({ parentId, depth }) => {
155
+ const more = loadMore?.get(parentId);
156
+ return more ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
157
+ type: "button",
158
+ className: "flex min-h-7 w-full items-center text-left text-caption text-muted-foreground hover:text-foreground",
159
+ style: { paddingLeft: `${depth * 16 + 28}px` },
160
+ onClick: more,
161
+ children: "Load more"
162
+ }, `more-${parentId}`) : null;
163
+ })] }, row.page.id);
164
+ })
165
+ });
166
+ }
167
+ exports.KNOWLEDGE_TREE_ROOT = KNOWLEDGE_TREE_ROOT;
168
+ exports.KnowledgePageTree = KnowledgePageTree;
169
+
170
+ //# sourceMappingURL=KnowledgePageTree.cjs.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"KnowledgePageTree.cjs.js","names":["useMemo","buildPageTree","useState","useRef","pageAncestorIds","visiblePageRows","Fragment","cn","ChevronRight","Pin"],"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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"}
@@ -0,0 +1 @@
1
+ export * from '../../../src/domains/knowledge/components/KnowledgePageTree';
@@ -0,0 +1,168 @@
1
+ import { t as cn } from "../../../utils-DQx8TpNT.js";
2
+ import { buildPageTree, pageAncestorIds, visiblePageRows } from "../lib/pageTree.es.js";
3
+ import { Fragment, useEffect, useMemo, useRef, useState } from "react";
4
+ import { jsx, jsxs } from "react/jsx-runtime";
5
+ import { ChevronRight, Pin } from "lucide-react";
6
+ // src/domains/knowledge/components/KnowledgePageTree.tsx
7
+ /** The key {@link KnowledgePageTree}'s `loadMore` uses for the root level. */
8
+ var KNOWLEDGE_TREE_ROOT = "";
9
+ /**
10
+ * The Knowledge page tree: scopes and pages nested by parent, siblings in
11
+ * stored order. Selecting a page from elsewhere (graph, search) opens the path
12
+ * to it. Keyboard follows the WAI-ARIA tree pattern: Up/Down move, Right opens
13
+ * or enters, Left closes or goes to the parent, Enter/Space selects.
14
+ *
15
+ * A host that loads the tree a level at a time passes `mayHaveChildren` (so unloaded pages still offer
16
+ * a chevron), listens to `onExpandedChange` to load the opened levels, and passes `loadMore` for
17
+ * levels with more children to fetch.
18
+ */
19
+ function KnowledgePageTree({ pages, pinnedIds, selectedPageId, onSelect, initiallyExpanded, mayHaveChildren, onExpandedChange, loadMore, "aria-label": ariaLabel = "Knowledge pages" }) {
20
+ const roots = useMemo(() => buildPageTree(pages), [pages]);
21
+ const pinned = useMemo(() => new Set(pinnedIds), [pinnedIds]);
22
+ const [expanded, setExpanded] = useState(() => new Set(initiallyExpanded ?? roots.map((root) => root.page.id)));
23
+ const [focusedId, setFocusedId] = useState(null);
24
+ const itemRefs = useRef(/* @__PURE__ */ new Map());
25
+ useEffect(() => {
26
+ if (!selectedPageId) return;
27
+ const path = pageAncestorIds(pages, selectedPageId);
28
+ setExpanded((current) => path.every((id) => current.has(id)) ? current : /* @__PURE__ */ new Set([...current, ...path]));
29
+ }, [pages, selectedPageId]);
30
+ useEffect(() => {
31
+ onExpandedChange?.(expanded);
32
+ }, [expanded, onExpandedChange]);
33
+ const rows = useMemo(() => visiblePageRows(roots, expanded).map((row) => !row.hasChildren && mayHaveChildren?.(row.page) ? {
34
+ ...row,
35
+ hasChildren: true
36
+ } : row), [
37
+ roots,
38
+ expanded,
39
+ mayHaveChildren
40
+ ]);
41
+ 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
+ const toggle = (id, open) => setExpanded((current) => {
43
+ if (current.has(id) === open) return current;
44
+ const next = new Set(current);
45
+ if (open) next.add(id);
46
+ else next.delete(id);
47
+ return next;
48
+ });
49
+ const focus = (id) => {
50
+ if (!id) return;
51
+ setFocusedId(id);
52
+ itemRefs.current.get(id)?.focus();
53
+ };
54
+ const onKeyDown = (event, index) => {
55
+ const row = rows[index];
56
+ if (!row) return;
57
+ switch (event.key) {
58
+ case "ArrowDown":
59
+ focus(rows[index + 1]?.page.id);
60
+ break;
61
+ case "ArrowUp":
62
+ focus(rows[index - 1]?.page.id);
63
+ break;
64
+ case "ArrowRight":
65
+ if (row.hasChildren && !row.expanded) toggle(row.page.id, true);
66
+ else if (row.expanded) focus(rows[index + 1]?.page.id);
67
+ break;
68
+ case "ArrowLeft":
69
+ if (row.expanded) toggle(row.page.id, false);
70
+ else focus(rows.slice(0, index).findLast((candidate) => candidate.depth < row.depth)?.page.id);
71
+ break;
72
+ case "Enter":
73
+ case " ":
74
+ onSelect(row.page);
75
+ break;
76
+ default: return;
77
+ }
78
+ event.preventDefault();
79
+ };
80
+ if (rows.length === 0) return /* @__PURE__ */ jsx("p", {
81
+ className: "px-3 py-2 text-body text-muted-foreground",
82
+ children: "No pages yet."
83
+ });
84
+ const ancestorAt = [];
85
+ return /* @__PURE__ */ jsx("div", {
86
+ role: "tree",
87
+ "aria-label": ariaLabel,
88
+ className: "min-h-0 overflow-y-auto py-1",
89
+ children: rows.map((row, index) => {
90
+ const selected = row.page.id === selectedPageId;
91
+ ancestorAt[row.depth] = row.page.id;
92
+ const nextDepth = rows[index + 1]?.depth ?? -1;
93
+ const closing = [];
94
+ for (let depth = row.depth - 1; depth >= nextDepth; depth--) {
95
+ const parentId = depth < 0 ? "" : ancestorAt[depth];
96
+ if (parentId !== void 0) closing.push({
97
+ parentId,
98
+ depth: depth + 1
99
+ });
100
+ }
101
+ if (row.expanded && rows[index + 1]?.depth !== row.depth + 1) closing.unshift({
102
+ parentId: row.page.id,
103
+ depth: row.depth + 1
104
+ });
105
+ return /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsxs("div", {
106
+ ref: (element) => {
107
+ if (element) itemRefs.current.set(row.page.id, element);
108
+ else itemRefs.current.delete(row.page.id);
109
+ },
110
+ role: "treeitem",
111
+ "aria-level": row.depth + 1,
112
+ "aria-selected": selected,
113
+ "aria-expanded": row.hasChildren ? row.expanded : void 0,
114
+ tabIndex: row.page.id === activeId ? 0 : -1,
115
+ onFocus: () => setFocusedId(row.page.id),
116
+ onKeyDown: (event) => onKeyDown(event, index),
117
+ onClick: () => onSelect(row.page),
118
+ 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
+ style: { paddingLeft: `${row.depth * 16 + 4}px` },
120
+ children: [
121
+ row.hasChildren ? /* @__PURE__ */ jsx("button", {
122
+ type: "button",
123
+ tabIndex: -1,
124
+ "aria-label": row.expanded ? `Collapse ${row.page.name}` : `Expand ${row.page.name}`,
125
+ className: "flex size-5 shrink-0 items-center justify-center rounded text-muted-foreground hover:text-foreground",
126
+ onClick: (event) => {
127
+ event.stopPropagation();
128
+ toggle(row.page.id, !row.expanded);
129
+ },
130
+ children: /* @__PURE__ */ jsx(ChevronRight, {
131
+ size: 14,
132
+ className: cn("transition-transform", row.expanded && "rotate-90")
133
+ })
134
+ }) : /* @__PURE__ */ jsx("span", {
135
+ className: "size-5 shrink-0",
136
+ "aria-hidden": true
137
+ }),
138
+ /* @__PURE__ */ jsx("span", {
139
+ className: cn("min-w-0 flex-1 truncate text-body", row.page.isScope && "font-medium"),
140
+ children: row.page.name
141
+ }),
142
+ pinned.has(row.page.id) ? /* @__PURE__ */ jsx(Pin, {
143
+ size: 12,
144
+ className: "shrink-0 text-badge-amber-indicator",
145
+ "aria-label": "Pinned"
146
+ }) : null,
147
+ row.page.isScope && row.page.address && row.page.address !== row.page.name ? /* @__PURE__ */ jsx("span", {
148
+ "data-testid": "knowledge-tree-address",
149
+ className: "max-w-1/2 min-w-0 truncate text-caption text-muted-foreground",
150
+ children: row.page.address
151
+ }) : null
152
+ ]
153
+ }), closing.map(({ parentId, depth }) => {
154
+ const more = loadMore?.get(parentId);
155
+ return more ? /* @__PURE__ */ jsx("button", {
156
+ type: "button",
157
+ className: "flex min-h-7 w-full items-center text-left text-caption text-muted-foreground hover:text-foreground",
158
+ style: { paddingLeft: `${depth * 16 + 28}px` },
159
+ onClick: more,
160
+ children: "Load more"
161
+ }, `more-${parentId}`) : null;
162
+ })] }, row.page.id);
163
+ })
164
+ });
165
+ }
166
+ export { KNOWLEDGE_TREE_ROOT, KnowledgePageTree };
167
+
168
+ //# sourceMappingURL=KnowledgePageTree.es.js.map
@@ -0,0 +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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"}
@@ -0,0 +1,37 @@
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
+ let react = require("react");
3
+ // src/domains/knowledge/hooks/useInteractionIdle.ts
4
+ /** Pure gate: idle once the last interaction is at least idleMs ago. */
5
+ function isIdle(lastActivityAt, now, idleMs) {
6
+ return now - lastActivityAt >= idleMs;
7
+ }
8
+ /**
9
+ * Tracks whether the user has left a surface alone for at least idleMs.
10
+ * Wire `onActivity` to capture-phase pointer/wheel handlers on the surface;
11
+ * `idle` flips false immediately on activity and back true after idleMs of
12
+ * silence (checked on a 1s tick). Starts idle — a fresh page updates freely.
13
+ */
14
+ function useInteractionIdle(idleMs) {
15
+ const lastActivity = (0, react.useRef)(0);
16
+ const [idle, setIdle] = (0, react.useState)(true);
17
+ (0, react.useEffect)(() => {
18
+ const timer = setInterval(() => {
19
+ setIdle((current) => {
20
+ const next = lastActivity.current === 0 || isIdle(lastActivity.current, Date.now(), idleMs);
21
+ return next === current ? current : next;
22
+ });
23
+ }, 1e3);
24
+ return () => clearInterval(timer);
25
+ }, [idleMs]);
26
+ return {
27
+ idle,
28
+ onActivity: (0, react.useCallback)(() => {
29
+ lastActivity.current = Date.now();
30
+ setIdle(false);
31
+ }, [])
32
+ };
33
+ }
34
+ exports.isIdle = isIdle;
35
+ exports.useInteractionIdle = useInteractionIdle;
36
+
37
+ //# sourceMappingURL=useInteractionIdle.cjs.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useInteractionIdle.cjs.js","names":["useRef","useState","useCallback"],"sources":["../../../../src/domains/knowledge/hooks/useInteractionIdle.ts"],"sourcesContent":["import { useCallback, useEffect, useRef, useState } from 'react';\n\n/** Pure gate: idle once the last interaction is at least idleMs ago. */\nexport function isIdle(lastActivityAt: number, now: number, idleMs: number): boolean {\n return now - lastActivityAt >= idleMs;\n}\n\n/**\n * Tracks whether the user has left a surface alone for at least idleMs.\n * Wire `onActivity` to capture-phase pointer/wheel handlers on the surface;\n * `idle` flips false immediately on activity and back true after idleMs of\n * silence (checked on a 1s tick). Starts idle — a fresh page updates freely.\n */\nexport function useInteractionIdle(idleMs: number): { idle: boolean; onActivity: () => void } {\n const lastActivity = useRef(0);\n const [idle, setIdle] = useState(true);\n useEffect(() => {\n const timer = setInterval(() => {\n setIdle(current => {\n const next = lastActivity.current === 0 || isIdle(lastActivity.current, Date.now(), idleMs);\n return next === current ? current : next;\n });\n }, 1000);\n return () => clearInterval(timer);\n }, [idleMs]);\n const onActivity = useCallback(() => {\n lastActivity.current = Date.now();\n setIdle(false);\n }, []);\n return { idle, onActivity };\n}\n"],"mappings":";;;;AAGA,SAAgB,OAAO,gBAAwB,KAAa,QAAyB;CACnF,OAAO,MAAM,kBAAkB;AACjC;;;;;;;AAQA,SAAgB,mBAAmB,QAA2D;CAC5F,MAAM,gBAAA,GAAeA,MAAAA,OAAAA,CAAO,CAAC;CAC7B,MAAM,CAAC,MAAM,YAAA,GAAWC,MAAAA,SAAAA,CAAS,IAAI;CACrC,CAAA,GAAA,MAAA,UAAA,OAAgB;EACd,MAAM,QAAQ,kBAAkB;GAC9B,SAAQ,YAAW;IACjB,MAAM,OAAO,aAAa,YAAY,KAAK,OAAO,aAAa,SAAS,KAAK,IAAI,GAAG,MAAM;IAC1F,OAAO,SAAS,UAAU,UAAU;GACtC,CAAC;EACH,GAAG,GAAI;EACP,aAAa,cAAc,KAAK;CAClC,GAAG,CAAC,MAAM,CAAC;CAKX,OAAO;EAAE;EAAM,aAAA,GAJIC,MAAAA,YAAAA,OAAkB;GACnC,aAAa,UAAU,KAAK,IAAI;GAChC,QAAQ,KAAK;EACf,GAAG,CAAC,CACW;CAAW;AAC5B"}
@@ -0,0 +1 @@
1
+ export * from '../../../src/domains/knowledge/hooks/useInteractionIdle';
@@ -0,0 +1,35 @@
1
+ import { useCallback, useEffect, useRef, useState } from "react";
2
+ // src/domains/knowledge/hooks/useInteractionIdle.ts
3
+ /** Pure gate: idle once the last interaction is at least idleMs ago. */
4
+ function isIdle(lastActivityAt, now, idleMs) {
5
+ return now - lastActivityAt >= idleMs;
6
+ }
7
+ /**
8
+ * Tracks whether the user has left a surface alone for at least idleMs.
9
+ * Wire `onActivity` to capture-phase pointer/wheel handlers on the surface;
10
+ * `idle` flips false immediately on activity and back true after idleMs of
11
+ * silence (checked on a 1s tick). Starts idle — a fresh page updates freely.
12
+ */
13
+ function useInteractionIdle(idleMs) {
14
+ const lastActivity = useRef(0);
15
+ const [idle, setIdle] = useState(true);
16
+ useEffect(() => {
17
+ const timer = setInterval(() => {
18
+ setIdle((current) => {
19
+ const next = lastActivity.current === 0 || isIdle(lastActivity.current, Date.now(), idleMs);
20
+ return next === current ? current : next;
21
+ });
22
+ }, 1e3);
23
+ return () => clearInterval(timer);
24
+ }, [idleMs]);
25
+ return {
26
+ idle,
27
+ onActivity: useCallback(() => {
28
+ lastActivity.current = Date.now();
29
+ setIdle(false);
30
+ }, [])
31
+ };
32
+ }
33
+ export { isIdle, useInteractionIdle };
34
+
35
+ //# sourceMappingURL=useInteractionIdle.es.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useInteractionIdle.es.js","names":[],"sources":["../../../../src/domains/knowledge/hooks/useInteractionIdle.ts"],"sourcesContent":["import { useCallback, useEffect, useRef, useState } from 'react';\n\n/** Pure gate: idle once the last interaction is at least idleMs ago. */\nexport function isIdle(lastActivityAt: number, now: number, idleMs: number): boolean {\n return now - lastActivityAt >= idleMs;\n}\n\n/**\n * Tracks whether the user has left a surface alone for at least idleMs.\n * Wire `onActivity` to capture-phase pointer/wheel handlers on the surface;\n * `idle` flips false immediately on activity and back true after idleMs of\n * silence (checked on a 1s tick). Starts idle — a fresh page updates freely.\n */\nexport function useInteractionIdle(idleMs: number): { idle: boolean; onActivity: () => void } {\n const lastActivity = useRef(0);\n const [idle, setIdle] = useState(true);\n useEffect(() => {\n const timer = setInterval(() => {\n setIdle(current => {\n const next = lastActivity.current === 0 || isIdle(lastActivity.current, Date.now(), idleMs);\n return next === current ? current : next;\n });\n }, 1000);\n return () => clearInterval(timer);\n }, [idleMs]);\n const onActivity = useCallback(() => {\n lastActivity.current = Date.now();\n setIdle(false);\n }, []);\n return { idle, onActivity };\n}\n"],"mappings":";;;AAGA,SAAgB,OAAO,gBAAwB,KAAa,QAAyB;CACnF,OAAO,MAAM,kBAAkB;AACjC;;;;;;;AAQA,SAAgB,mBAAmB,QAA2D;CAC5F,MAAM,eAAe,OAAO,CAAC;CAC7B,MAAM,CAAC,MAAM,WAAW,SAAS,IAAI;CACrC,gBAAgB;EACd,MAAM,QAAQ,kBAAkB;GAC9B,SAAQ,YAAW;IACjB,MAAM,OAAO,aAAa,YAAY,KAAK,OAAO,aAAa,SAAS,KAAK,IAAI,GAAG,MAAM;IAC1F,OAAO,SAAS,UAAU,UAAU;GACtC,CAAC;EACH,GAAG,GAAI;EACP,aAAa,cAAc,KAAK;CAClC,GAAG,CAAC,MAAM,CAAC;CAKX,OAAO;EAAE;EAAM,YAJI,kBAAkB;GACnC,aAAa,UAAU,KAAK,IAAI;GAChC,QAAQ,KAAK;EACf,GAAG,CAAC,CACW;CAAW;AAC5B"}