@ds-mo/ui 9.0.0 → 9.2.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 (385) hide show
  1. package/README.md +28 -0
  2. package/dist/.build-stamp +1 -1
  3. package/dist/agent-patterns.json +397 -0
  4. package/dist/agent.json +2347 -735
  5. package/dist/angular/ds-agent-activity.d.ts +12 -0
  6. package/dist/angular/ds-agent-activity.js +38 -0
  7. package/dist/angular/ds-agent-response.d.ts +12 -0
  8. package/dist/angular/ds-agent-response.js +38 -0
  9. package/dist/angular/ds-agent-source-list.d.ts +12 -0
  10. package/dist/angular/ds-agent-source-list.js +38 -0
  11. package/dist/angular/ds-agent-tool-call.d.ts +12 -0
  12. package/dist/angular/ds-agent-tool-call.js +38 -0
  13. package/dist/angular/ds-attachment-list.d.ts +12 -0
  14. package/dist/angular/ds-attachment-list.js +38 -0
  15. package/dist/angular/ds-avatar.d.ts +12 -0
  16. package/dist/angular/ds-avatar.js +38 -0
  17. package/dist/angular/ds-code-block.d.ts +12 -0
  18. package/dist/angular/ds-code-block.js +38 -0
  19. package/dist/angular/ds-conversation-list-item.d.ts +19 -0
  20. package/dist/angular/ds-conversation-list-item.js +42 -0
  21. package/dist/angular/ds-conversation-list-section.d.ts +12 -0
  22. package/dist/angular/ds-conversation-list-section.js +38 -0
  23. package/dist/angular/ds-conversation-list.d.ts +12 -0
  24. package/dist/angular/ds-conversation-list.js +37 -0
  25. package/dist/angular/ds-markdown.d.ts +12 -0
  26. package/dist/angular/ds-markdown.js +38 -0
  27. package/dist/angular/ds-menu.d.ts +6 -1
  28. package/dist/angular/ds-menu.js +7 -4
  29. package/dist/angular/ds-message-bubble.d.ts +12 -0
  30. package/dist/angular/ds-message-bubble.js +38 -0
  31. package/dist/angular/ds-message-composer.d.ts +23 -0
  32. package/dist/angular/ds-message-composer.js +49 -0
  33. package/dist/angular/ds-message-scroller.d.ts +15 -0
  34. package/dist/angular/ds-message-scroller.js +43 -0
  35. package/dist/angular/ds-message.d.ts +12 -0
  36. package/dist/angular/ds-message.js +38 -0
  37. package/dist/angular/ds-panel-tool-header.d.ts +25 -0
  38. package/dist/angular/ds-panel-tool-header.js +49 -0
  39. package/dist/angular/ds-panel-tool-search.d.ts +19 -0
  40. package/dist/angular/ds-panel-tool-search.js +49 -0
  41. package/dist/angular/ds-panel-tools.d.ts +30 -1
  42. package/dist/angular/ds-panel-tools.js +14 -5
  43. package/dist/angular/ds-swatch-picker.d.ts +15 -0
  44. package/dist/angular/ds-swatch-picker.js +42 -0
  45. package/dist/angular/index.d.ts +1 -1
  46. package/dist/angular/index.js +18 -0
  47. package/dist/angular/proxies.d.ts +18 -0
  48. package/dist/angular/proxies.js +18 -0
  49. package/dist/components/ds-agent-activity.d.ts +11 -0
  50. package/dist/components/ds-agent-activity.js +2 -0
  51. package/dist/components/ds-agent-activity.js.map +1 -0
  52. package/dist/components/ds-agent-response.d.ts +11 -0
  53. package/dist/components/ds-agent-response.js +2 -0
  54. package/dist/components/ds-agent-response.js.map +1 -0
  55. package/dist/components/ds-agent-source-list.d.ts +11 -0
  56. package/dist/components/ds-agent-source-list.js +2 -0
  57. package/dist/components/ds-agent-source-list.js.map +1 -0
  58. package/dist/components/ds-agent-tool-call.d.ts +11 -0
  59. package/dist/components/ds-agent-tool-call.js +2 -0
  60. package/dist/components/ds-agent-tool-call.js.map +1 -0
  61. package/dist/components/ds-app-shell.js +1 -1
  62. package/dist/components/ds-app-shell.js.map +1 -1
  63. package/dist/components/ds-attachment-list.d.ts +11 -0
  64. package/dist/components/ds-attachment-list.js +2 -0
  65. package/dist/components/ds-attachment-list.js.map +1 -0
  66. package/dist/components/ds-avatar.d.ts +11 -0
  67. package/dist/components/ds-avatar.js +2 -0
  68. package/dist/components/ds-avatar.js.map +1 -0
  69. package/dist/components/ds-badge.js +1 -1
  70. package/dist/components/ds-banner.js +1 -1
  71. package/dist/components/ds-bar-nav.js +1 -1
  72. package/dist/components/ds-bar-nav.js.map +1 -1
  73. package/dist/components/ds-button-filled.js +1 -1
  74. package/dist/components/ds-button-unfilled.js +1 -1
  75. package/dist/components/ds-card-data-viz-donut.js +1 -1
  76. package/dist/components/ds-card-setting.js +1 -1
  77. package/dist/components/ds-card-shell-data-viz.js +1 -1
  78. package/dist/components/ds-card.js +1 -1
  79. package/dist/components/ds-chart-bar.js +1 -1
  80. package/dist/components/ds-chart-bar.js.map +1 -1
  81. package/dist/components/ds-chart-donut.js +1 -1
  82. package/dist/components/ds-chart-legend.js +1 -1
  83. package/dist/components/ds-chart-line.js +1 -1
  84. package/dist/components/ds-checkbox.js +1 -1
  85. package/dist/components/ds-chip.js +1 -1
  86. package/dist/components/ds-code-block.d.ts +11 -0
  87. package/dist/components/ds-code-block.js +2 -0
  88. package/dist/components/ds-code-block.js.map +1 -0
  89. package/dist/components/ds-conversation-list-item.d.ts +11 -0
  90. package/dist/components/ds-conversation-list-item.js +2 -0
  91. package/dist/components/ds-conversation-list-item.js.map +1 -0
  92. package/dist/components/ds-conversation-list-section.d.ts +11 -0
  93. package/dist/components/ds-conversation-list-section.js +2 -0
  94. package/dist/components/ds-conversation-list-section.js.map +1 -0
  95. package/dist/components/ds-conversation-list.d.ts +11 -0
  96. package/dist/components/ds-conversation-list.js +2 -0
  97. package/dist/components/ds-conversation-list.js.map +1 -0
  98. package/dist/components/ds-divider.js +1 -1
  99. package/dist/components/ds-divider.js.map +1 -1
  100. package/dist/components/ds-empty-state.js +1 -1
  101. package/dist/components/ds-field.js +1 -1
  102. package/dist/components/ds-icon.js +1 -1
  103. package/dist/components/ds-input.js +1 -1
  104. package/dist/components/ds-markdown.d.ts +11 -0
  105. package/dist/components/ds-markdown.js +2 -0
  106. package/dist/components/ds-markdown.js.map +1 -0
  107. package/dist/components/ds-menu.js +1 -1
  108. package/dist/components/ds-message-bubble.d.ts +11 -0
  109. package/dist/components/ds-message-bubble.js +2 -0
  110. package/dist/components/ds-message-bubble.js.map +1 -0
  111. package/dist/components/ds-message-composer.d.ts +11 -0
  112. package/dist/components/ds-message-composer.js +2 -0
  113. package/dist/components/ds-message-composer.js.map +1 -0
  114. package/dist/components/ds-message-scroller.d.ts +11 -0
  115. package/dist/components/ds-message-scroller.js +2 -0
  116. package/dist/components/ds-message-scroller.js.map +1 -0
  117. package/dist/components/ds-message.d.ts +11 -0
  118. package/dist/components/ds-message.js +2 -0
  119. package/dist/components/ds-message.js.map +1 -0
  120. package/dist/components/ds-modal.js +1 -1
  121. package/dist/components/ds-panel-nav.js +1 -1
  122. package/dist/components/ds-panel-nav.js.map +1 -1
  123. package/dist/components/ds-panel-sub-nav.js +1 -1
  124. package/dist/components/ds-panel-tool-header.d.ts +11 -0
  125. package/dist/components/ds-panel-tool-header.js +2 -0
  126. package/dist/components/ds-panel-tool-header.js.map +1 -0
  127. package/dist/components/ds-panel-tool-search.d.ts +11 -0
  128. package/dist/components/ds-panel-tool-search.js +2 -0
  129. package/dist/components/ds-panel-tool-search.js.map +1 -0
  130. package/dist/components/ds-panel-tools.js +1 -1
  131. package/dist/components/ds-panel-tools.js.map +1 -1
  132. package/dist/components/ds-radio.js +1 -1
  133. package/dist/components/ds-select-multi.js +1 -1
  134. package/dist/components/ds-select-multi.js.map +1 -1
  135. package/dist/components/ds-select.js +1 -1
  136. package/dist/components/ds-select.js.map +1 -1
  137. package/dist/components/ds-shell-gradient-picker.js +1 -1
  138. package/dist/components/ds-shell-gradient-picker.js.map +1 -1
  139. package/dist/components/ds-shell-gradient-swatch.js +1 -1
  140. package/dist/components/ds-shell-gradient-swatch.js.map +1 -1
  141. package/dist/components/ds-skeleton.js +1 -1
  142. package/dist/components/ds-slider.js +1 -1
  143. package/dist/components/ds-slider.js.map +1 -1
  144. package/dist/components/ds-swatch-picker.d.ts +11 -0
  145. package/dist/components/ds-swatch-picker.js +2 -0
  146. package/dist/components/ds-swatch-picker.js.map +1 -0
  147. package/dist/components/ds-switch.js +1 -1
  148. package/dist/components/ds-tab-group.js +1 -1
  149. package/dist/components/ds-tab-group.js.map +1 -1
  150. package/dist/components/ds-tag.js +1 -1
  151. package/dist/components/ds-text.js +1 -1
  152. package/dist/components/ds-tooltip-data-viz.js +1 -1
  153. package/dist/components/ds-tooltip.js +1 -1
  154. package/dist/components/index.d.ts +14 -0
  155. package/dist/components/p--KbMQblZ.js +2 -0
  156. package/dist/components/p--KbMQblZ.js.map +1 -0
  157. package/dist/components/p-2br9YDbG.js +2 -0
  158. package/dist/components/p-2br9YDbG.js.map +1 -0
  159. package/dist/components/p-41UAx2eq.js +2 -0
  160. package/dist/components/p-41UAx2eq.js.map +1 -0
  161. package/dist/components/p-B1pWGQn1.js +2 -0
  162. package/dist/components/p-B1pWGQn1.js.map +1 -0
  163. package/dist/components/p-B7NbIYjS.js +2 -0
  164. package/dist/components/p-B7NbIYjS.js.map +1 -0
  165. package/dist/components/p-BBu_Svz7.js +2 -0
  166. package/dist/components/p-BBu_Svz7.js.map +1 -0
  167. package/dist/components/p-BEQB8EnB.js +2 -0
  168. package/dist/components/p-BEQB8EnB.js.map +1 -0
  169. package/dist/components/{p-CZ9wemOA.js → p-BFWC17em.js} +2 -2
  170. package/dist/components/{p-KRGBGTu5.js → p-BO6C8abO.js} +2 -2
  171. package/dist/components/{p-CbS_WWs2.js → p-BSOZXagj.js} +2 -2
  172. package/dist/components/p-BSOZXagj.js.map +1 -0
  173. package/dist/components/{p-DT2MK8Kt.js → p-BZAEZENv.js} +2 -2
  174. package/dist/components/p-BhC1YyId.js +2 -0
  175. package/dist/components/p-BhC1YyId.js.map +1 -0
  176. package/dist/components/p-BjtXYFhw.js +2 -0
  177. package/dist/components/p-BjtXYFhw.js.map +1 -0
  178. package/dist/components/{p-B-zhgAvL.js → p-Bo5wikia.js} +2 -2
  179. package/dist/components/p-Bx1G7P6W.js +2 -0
  180. package/dist/components/p-Bx1G7P6W.js.map +1 -0
  181. package/dist/components/p-C0sq948W.js +2 -0
  182. package/dist/components/p-C0sq948W.js.map +1 -0
  183. package/dist/components/p-CC1C8s6m.js +2 -0
  184. package/dist/components/p-CC1C8s6m.js.map +1 -0
  185. package/dist/components/p-CKaJx0IX.js +2 -0
  186. package/dist/components/p-CKaJx0IX.js.map +1 -0
  187. package/dist/components/{p-DyZj3k9S.js → p-CZMEhdlA.js} +2 -2
  188. package/dist/components/{p-BbV68F23.js → p-CiwdnKKp.js} +2 -2
  189. package/dist/components/{p-BLzivrE3.js → p-CnM9SW_8.js} +2 -2
  190. package/dist/components/{p-C7UFYvsO.js → p-CuKn9I5f.js} +2 -2
  191. package/dist/components/p-D1HFMTdC.js +2 -0
  192. package/dist/components/p-D1HFMTdC.js.map +1 -0
  193. package/dist/components/p-DFMM60My.js +2 -0
  194. package/dist/components/p-DFMM60My.js.map +1 -0
  195. package/dist/components/p-DIsDiGcp.js +2 -0
  196. package/dist/components/p-DIsDiGcp.js.map +1 -0
  197. package/dist/components/p-DVsje4AY.js +2 -0
  198. package/dist/components/p-DVsje4AY.js.map +1 -0
  199. package/dist/components/p-Di-ThR90.js +2 -0
  200. package/dist/components/p-Di-ThR90.js.map +1 -0
  201. package/dist/components/{p-C7RObioO.js → p-Di4HBckb.js} +2 -2
  202. package/dist/components/p-a9nGf1s6.js +2 -0
  203. package/dist/components/p-a9nGf1s6.js.map +1 -0
  204. package/dist/components/p-gidVv1FX.js +2 -0
  205. package/dist/components/p-gidVv1FX.js.map +1 -0
  206. package/dist/components/p-l6PmnW_P.js +2 -0
  207. package/dist/components/p-l6PmnW_P.js.map +1 -0
  208. package/dist/components/p-rEe-3KR_.js +2 -0
  209. package/dist/components/p-rEe-3KR_.js.map +1 -0
  210. package/dist/components/p-t9Ei1kHP.js +2 -0
  211. package/dist/components/p-t9Ei1kHP.js.map +1 -0
  212. package/dist/docs/components.json +8097 -3924
  213. package/dist/lib/components/Menu/menu-placement.d.ts +19 -3
  214. package/dist/lib/shell/index.d.ts +3 -3
  215. package/dist/lib/shell/index.js +48 -39
  216. package/dist/lib/shell/index.js.map +3 -3
  217. package/dist/lib/shell/shell-gradient-presets.d.ts +15 -0
  218. package/dist/lib/utils/choice-popup-alignment.d.ts +20 -0
  219. package/dist/lib/utils/index.d.ts +2 -0
  220. package/dist/lib/utils/index.js +16 -0
  221. package/dist/lib/utils/index.js.map +3 -3
  222. package/dist/mcp/cli.js +31409 -0
  223. package/dist/mcp-data/registry/agent-activity.json +158 -0
  224. package/dist/mcp-data/registry/agent-response.json +211 -0
  225. package/dist/mcp-data/registry/agent-source-list.json +153 -0
  226. package/dist/mcp-data/registry/agent-tool-call.json +213 -0
  227. package/dist/mcp-data/registry/app-shell.json +210 -0
  228. package/dist/mcp-data/registry/attachment-list.json +137 -0
  229. package/dist/mcp-data/registry/avatar.json +136 -0
  230. package/dist/mcp-data/registry/badge.json +289 -0
  231. package/dist/mcp-data/registry/banner.json +206 -0
  232. package/dist/mcp-data/registry/bar-nav.json +341 -0
  233. package/dist/mcp-data/registry/button-filled.json +386 -0
  234. package/dist/mcp-data/registry/button-unfilled.json +537 -0
  235. package/dist/mcp-data/registry/card-data-viz-donut.json +143 -0
  236. package/dist/mcp-data/registry/card-setting.json +194 -0
  237. package/dist/mcp-data/registry/card-shell-data-viz.json +173 -0
  238. package/dist/mcp-data/registry/card.json +126 -0
  239. package/dist/mcp-data/registry/chart-bar.json +121 -0
  240. package/dist/mcp-data/registry/chart-donut.json +257 -0
  241. package/dist/mcp-data/registry/chart-legend.json +209 -0
  242. package/dist/mcp-data/registry/chart-line.json +153 -0
  243. package/dist/mcp-data/registry/checkbox.json +361 -0
  244. package/dist/mcp-data/registry/chip.json +276 -0
  245. package/dist/mcp-data/registry/code-block.json +150 -0
  246. package/dist/mcp-data/registry/conversation-list-item.json +265 -0
  247. package/dist/mcp-data/registry/conversation-list-section.json +139 -0
  248. package/dist/mcp-data/registry/conversation-list.json +101 -0
  249. package/dist/mcp-data/registry/divider.json +225 -0
  250. package/dist/mcp-data/registry/empty-state.json +197 -0
  251. package/dist/mcp-data/registry/field.json +222 -0
  252. package/dist/mcp-data/registry/icon.json +242 -0
  253. package/dist/mcp-data/registry/input.json +597 -0
  254. package/dist/mcp-data/registry/loader.json +192 -0
  255. package/dist/mcp-data/registry/markdown.json +141 -0
  256. package/dist/mcp-data/registry/menu.json +479 -0
  257. package/dist/mcp-data/registry/message-bubble.json +119 -0
  258. package/dist/mcp-data/registry/message-composer.json +265 -0
  259. package/dist/mcp-data/registry/message-scroller.json +217 -0
  260. package/dist/mcp-data/registry/message.json +255 -0
  261. package/dist/mcp-data/registry/modal.json +150 -0
  262. package/dist/mcp-data/registry/panel-nav.json +622 -0
  263. package/dist/mcp-data/registry/panel-sub-nav.json +249 -0
  264. package/dist/mcp-data/registry/panel-tool-header.json +342 -0
  265. package/dist/mcp-data/registry/panel-tool-search.json +387 -0
  266. package/dist/mcp-data/registry/panel-tools.json +514 -0
  267. package/dist/mcp-data/registry/radio.json +374 -0
  268. package/dist/mcp-data/registry/registry.json +6916 -0
  269. package/dist/mcp-data/registry/select-multi.json +755 -0
  270. package/dist/mcp-data/registry/select.json +740 -0
  271. package/dist/mcp-data/registry/shell-gradient-picker.json +195 -0
  272. package/dist/mcp-data/registry/shell-gradient-swatch.json +215 -0
  273. package/dist/mcp-data/registry/skeleton.json +282 -0
  274. package/dist/mcp-data/registry/slider.json +657 -0
  275. package/dist/mcp-data/registry/swatch-picker.json +231 -0
  276. package/dist/mcp-data/registry/switch.json +361 -0
  277. package/dist/mcp-data/registry/tab-group.json +255 -0
  278. package/dist/mcp-data/registry/tag.json +352 -0
  279. package/dist/mcp-data/registry/text.json +371 -0
  280. package/dist/mcp-data/registry/tooltip-data-viz.json +158 -0
  281. package/dist/mcp-data/registry/tooltip.json +311 -0
  282. package/dist/react/components.d.ts +18 -0
  283. package/dist/react/components.js +18 -0
  284. package/dist/react/ds-agent-activity.d.ts +9 -0
  285. package/dist/react/ds-agent-activity.js +12 -0
  286. package/dist/react/ds-agent-response.d.ts +9 -0
  287. package/dist/react/ds-agent-response.js +12 -0
  288. package/dist/react/ds-agent-source-list.d.ts +9 -0
  289. package/dist/react/ds-agent-source-list.js +12 -0
  290. package/dist/react/ds-agent-tool-call.d.ts +9 -0
  291. package/dist/react/ds-agent-tool-call.js +12 -0
  292. package/dist/react/ds-attachment-list.d.ts +9 -0
  293. package/dist/react/ds-attachment-list.js +12 -0
  294. package/dist/react/ds-avatar.d.ts +9 -0
  295. package/dist/react/ds-avatar.js +12 -0
  296. package/dist/react/ds-code-block.d.ts +9 -0
  297. package/dist/react/ds-code-block.js +12 -0
  298. package/dist/react/ds-conversation-list-item.d.ts +14 -0
  299. package/dist/react/ds-conversation-list-item.js +12 -0
  300. package/dist/react/ds-conversation-list-section.d.ts +9 -0
  301. package/dist/react/ds-conversation-list-section.js +12 -0
  302. package/dist/react/ds-conversation-list.d.ts +9 -0
  303. package/dist/react/ds-conversation-list.js +12 -0
  304. package/dist/react/ds-markdown.d.ts +9 -0
  305. package/dist/react/ds-markdown.js +12 -0
  306. package/dist/react/ds-menu.d.ts +1 -0
  307. package/dist/react/ds-menu.js +2 -1
  308. package/dist/react/ds-message-bubble.d.ts +9 -0
  309. package/dist/react/ds-message-bubble.js +12 -0
  310. package/dist/react/ds-message-composer.d.ts +16 -0
  311. package/dist/react/ds-message-composer.js +16 -0
  312. package/dist/react/ds-message-scroller.d.ts +12 -0
  313. package/dist/react/ds-message-scroller.js +12 -0
  314. package/dist/react/ds-message.d.ts +9 -0
  315. package/dist/react/ds-message.js +12 -0
  316. package/dist/react/ds-panel-tool-header.d.ts +17 -0
  317. package/dist/react/ds-panel-tool-header.js +16 -0
  318. package/dist/react/ds-panel-tool-search.d.ts +14 -0
  319. package/dist/react/ds-panel-tool-search.js +16 -0
  320. package/dist/react/ds-panel-tools.d.ts +10 -0
  321. package/dist/react/ds-panel-tools.js +3 -0
  322. package/dist/react/ds-swatch-picker.d.ts +12 -0
  323. package/dist/react/ds-swatch-picker.js +12 -0
  324. package/dist/types/components/AgentActivity/AgentActivity.d.ts +14 -0
  325. package/dist/types/components/AgentResponse/AgentResponse.d.ts +12 -0
  326. package/dist/types/components/AgentSourceList/AgentSourceList.d.ts +9 -0
  327. package/dist/types/components/AgentToolCall/AgentToolCall.d.ts +13 -0
  328. package/dist/types/components/AppShell/AppShell.d.ts +4 -0
  329. package/dist/types/components/AttachmentList/AttachmentList.d.ts +8 -0
  330. package/dist/types/components/Avatar/Avatar.d.ts +8 -0
  331. package/dist/types/components/CodeBlock/CodeBlock.d.ts +11 -0
  332. package/dist/types/components/ConversationList/ConversationList.d.ts +4 -0
  333. package/dist/types/components/ConversationListItem/ConversationListItem.d.ts +22 -0
  334. package/dist/types/components/ConversationListSection/ConversationListSection.d.ts +9 -0
  335. package/dist/types/components/Markdown/Markdown.d.ts +15 -0
  336. package/dist/types/components/Menu/Menu.d.ts +10 -1
  337. package/dist/types/components/Menu/menu-placement.d.ts +19 -3
  338. package/dist/types/components/Menu/menu-types.d.ts +15 -2
  339. package/dist/types/components/Message/Message.d.ts +17 -0
  340. package/dist/types/components/MessageBubble/MessageBubble.d.ts +6 -0
  341. package/dist/types/components/MessageComposer/MessageComposer.d.ts +29 -0
  342. package/dist/types/components/MessageScroller/MessageScroller.d.ts +37 -0
  343. package/dist/types/components/PanelNav/PanelNav.d.ts +3 -0
  344. package/dist/types/components/PanelToolHeader/PanelToolHeader.d.ts +34 -0
  345. package/dist/types/components/PanelToolSearch/PanelToolSearch.d.ts +35 -0
  346. package/dist/types/components/PanelTools/PanelTools.d.ts +40 -1
  347. package/dist/types/components/PanelTools/panel-tools-types.d.ts +20 -0
  348. package/dist/types/components/PanelTools/panel-tools-utils.d.ts +2 -0
  349. package/dist/types/components/ShellGradientPicker/ShellGradientPicker.d.ts +2 -5
  350. package/dist/types/components/ShellGradientSwatch/ShellGradientSwatch.d.ts +1 -0
  351. package/dist/types/components/Slider/Slider.d.ts +1 -1
  352. package/dist/types/components/SwatchPicker/SwatchPicker.d.ts +21 -0
  353. package/dist/types/components/SwatchPicker/swatch-picker-types.d.ts +26 -0
  354. package/dist/types/components/conversation-types.d.ts +55 -0
  355. package/dist/types/components.d.ts +1298 -4
  356. package/dist/types/shell/index.d.ts +3 -3
  357. package/dist/types/shell/shell-gradient-presets.d.ts +15 -0
  358. package/dist/types/utils/choice-list-parts.d.ts +4 -1
  359. package/dist/types/utils/choice-popup-alignment.d.ts +21 -0
  360. package/dist/types/utils/index.d.ts +2 -0
  361. package/package.json +9 -2
  362. package/dist/components/p-Bafp65bw.js +0 -2
  363. package/dist/components/p-Bafp65bw.js.map +0 -1
  364. package/dist/components/p-BdnR3jxi.js +0 -2
  365. package/dist/components/p-BdnR3jxi.js.map +0 -1
  366. package/dist/components/p-CXF8yd-g.js +0 -2
  367. package/dist/components/p-CXF8yd-g.js.map +0 -1
  368. package/dist/components/p-C_cu-HIT.js +0 -2
  369. package/dist/components/p-C_cu-HIT.js.map +0 -1
  370. package/dist/components/p-CbS_WWs2.js.map +0 -1
  371. package/dist/components/p-D0B9uDTP.js +0 -2
  372. package/dist/components/p-D0B9uDTP.js.map +0 -1
  373. package/dist/components/p-DF0yLZG_.js +0 -2
  374. package/dist/components/p-DF0yLZG_.js.map +0 -1
  375. package/dist/components/p-VKIsOVza.js +0 -2
  376. package/dist/components/p-VKIsOVza.js.map +0 -1
  377. /package/dist/components/{p-CZ9wemOA.js.map → p-BFWC17em.js.map} +0 -0
  378. /package/dist/components/{p-KRGBGTu5.js.map → p-BO6C8abO.js.map} +0 -0
  379. /package/dist/components/{p-DT2MK8Kt.js.map → p-BZAEZENv.js.map} +0 -0
  380. /package/dist/components/{p-B-zhgAvL.js.map → p-Bo5wikia.js.map} +0 -0
  381. /package/dist/components/{p-DyZj3k9S.js.map → p-CZMEhdlA.js.map} +0 -0
  382. /package/dist/components/{p-BbV68F23.js.map → p-CiwdnKKp.js.map} +0 -0
  383. /package/dist/components/{p-BLzivrE3.js.map → p-CnM9SW_8.js.map} +0 -0
  384. /package/dist/components/{p-C7UFYvsO.js.map → p-CuKn9I5f.js.map} +0 -0
  385. /package/dist/components/{p-C7RObioO.js.map → p-Di4HBckb.js.map} +0 -0
@@ -0,0 +1,514 @@
1
+ {
2
+ "$schema": "https://ui.shadcn.com/schema/registry-item.json",
3
+ "name": "panel-tools",
4
+ "title": "PanelTools",
5
+ "description": "Required AppShell utility rail and persistent drawer host for the fixed set of global Search, Agents, Messages, Stacks, Activity, and Help products.",
6
+ "type": "registry:ui",
7
+ "meta": {
8
+ "library": "@ds-mo/ui",
9
+ "distribution": "npm",
10
+ "storybook": "https://zainadeel.github.io/compomo/?path=/story/panel-tools",
11
+ "source": "src/wc/components/PanelTools/PanelTools.tsx",
12
+ "intentStatus": "complete",
13
+ "intent": {
14
+ "audience": "specialized",
15
+ "status": "stable",
16
+ "summary": "Required AppShell utility rail and persistent drawer host for the fixed set of global Search, Agents, Messages, Stacks, Activity, and Help products.",
17
+ "useWhen": [
18
+ "Composing the required global tools region inside the application's single AppShell.",
19
+ "Users need to move between application-wide utilities without losing each tool's in-progress state.",
20
+ "Search, AI conversations, user messages, review stacks, notifications, or help content must remain available alongside route content."
21
+ ],
22
+ "avoidWhen": [
23
+ "The action is specific to the current page or selected content rather than globally available across the application.",
24
+ "The item navigates to a primary or secondary route; use PanelNav or BarNav instead.",
25
+ "A consumer wants to add arbitrary tools, reorder fixed tools, or repurpose a semantic tool id.",
26
+ "Building the mobile tools experience; future mobile AppShell composition uses a different bottom-bar and panel pattern.",
27
+ "PanelTools would be mounted outside the application's single AppShell."
28
+ ],
29
+ "alternatives": [
30
+ {
31
+ "when": "The action navigates to a top-level application destination.",
32
+ "component": "component:ds-panel-nav",
33
+ "reason": "PanelNav exclusively owns primary application navigation."
34
+ },
35
+ {
36
+ "when": "The action navigates between route sections of the active destination.",
37
+ "component": "component:ds-bar-nav",
38
+ "reason": "BarNav exclusively owns secondary route navigation."
39
+ },
40
+ {
41
+ "when": "Temporary contextual actions or options are needed.",
42
+ "component": "component:ds-menu",
43
+ "reason": "Menu owns transient contextual choices rather than persistent global products."
44
+ }
45
+ ],
46
+ "commonlyComposedWith": [
47
+ "component:ds-app-shell",
48
+ "component:ds-panel-nav",
49
+ "component:ds-bar-nav"
50
+ ],
51
+ "patterns": [
52
+ "pattern:application-shell"
53
+ ],
54
+ "accessibility": [
55
+ "Provide localized accessible labels for the rail, shortcut group, and every rendered tool.",
56
+ "Keep Search first in the rail header and Help last in the rail footer so keyboard and visual order remain predictable.",
57
+ "Keep focus on the selected rail action when opening a drawer and allow normal Tab navigation into its content.",
58
+ "Do not trigger global shortcuts while focus is in an editable control.",
59
+ "Use notification dots only as supplemental unread or new-content status and never as the sole status indication.",
60
+ "Explain temporarily inactive tools through an accessible label or adjacent product guidance; omit unauthorized tools entirely."
61
+ ],
62
+ "states": [
63
+ "Search and Help are required; optional Agents, Messages, Stacks, and Activity tools are filtered by the application for authorization and entitlement.",
64
+ "Use only the fixed semantic tool ids and canonical order: Search, Agents, Messages, Stacks, Activity, Help; do not reorder, duplicate, or repurpose them.",
65
+ "Search is application-wide; Agents is user-to-AI chat; Messages is user-to-user chat; Stacks is a specialized inbox of grouped application events for review; Activity is the notification center; Help is drawer content that may link to external resources.",
66
+ "Only one drawer is open at a time; selecting another tool switches directly and selecting the active tool closes to rail-only mode.",
67
+ "The drawer starts closed, remains open across ordinary route changes, and retains every mounted tool's independent conversation, query, scroll, and work state.",
68
+ "When storageKey is set, persist only the last active tool in this browser and still restore the drawer closed after reload.",
69
+ "The application owns unread state; opening Messages, Agents, Stacks, or Activity does not automatically clear its notification dot.",
70
+ "PanelTools owns the one visible header above every drawer tool view and above fullscreen views using the default shared header mode. Slotted tool content must not render a second header unless the conversation product explicitly opts into split fullscreen headers.",
71
+ "PanelTools composes ds-panel-tool-header as its canonical left-aligned header implementation so standalone header stories and shell rendering cannot diverge.",
72
+ "Each tool supplies its current header title, base-versus-detail Back state, and right-side actions through the headers property. Base views omit Back; deeper views expose Back and update the same header in place.",
73
+ "Header Back and action events express intent only; the owning tool changes product navigation, menus, and data state. PanelTools keeps the final header action exactly 8px from the drawer edge.",
74
+ "Menus opened from a right-side header action use PANEL_TOOLS_HEADER_MENU_PLACEMENT: bottom/end choice-cell alignment and a 12px side offset, placing the popup 4px below the 48px header while aligning the final menu item edge with the trigger.",
75
+ "Tool view roots stay transparent so AppShell's chrome wash remains visible; only explicitly designed child surfaces introduce a fill.",
76
+ "Tools with search compose ds-panel-tool-search immediately below the shared header. Its 48px row always contains the md search control and must not be reduced to sm or xs.",
77
+ "If an active optional tool becomes unavailable, PanelTools closes the drawer, clears activeTool, and emits its deselection.",
78
+ "Use isInactive only for a temporarily unavailable visible tool; omit tools the user is not authorized to access.",
79
+ "The application owns slotted tool products and data while PanelTools owns rail ordering, drawer selection, open state, motion, and shell events.",
80
+ "Opening and closing clip an already-rendered fixed-width surface. Header and tool content remain fully opaque and retained during width motion; transition completion is accepted only at the measured terminal clip width, after which the closed surface becomes inert and paint-skipped.",
81
+ "Entering and exiting fullscreen snaps without borrowing the drawer open or close animation.",
82
+ "When fullscreenHeaderMode is split, PanelTools suppresses only its fullscreen shared header. The application renders exactly two canonical ds-panel-tool-header instances: a tool-title/list-actions header over the 300px history pane and a chat-title/Exit-fullscreen/chat-actions header over the detail pane. The detail header omits Back because the list remains visible."
83
+ ],
84
+ "responsiveBehavior": [
85
+ "The open drawer reduces main-content width and uses --dimension-panel-width-xs (300px) on every supported desktop and tablet viewport.",
86
+ "AppShell owns the fixed drawer-width variable; consumers must not hardcode alternate drawer widths.",
87
+ "Below 768px, do not reuse desktop PanelTools: future AppShell mobile composition uses a bottom bar for Search, Agents, Notifications, and Stacks, while Help moves into mobile primary navigation.",
88
+ "Keep named-slot content mounted while tools switch or the drawer closes so users can return to in-progress global work.",
89
+ "Conversation products may use fullscreenHeaderMode split for a 300px history rail beside a flexible detail pane, each with its own canonical header; the application owns that internal split layout.",
90
+ "Use fixed drawer widths for now; do not add user resizing or width persistence."
91
+ ],
92
+ "frameworkCaveats": {
93
+ "customElements": [
94
+ "Assign items as a JavaScript property for structured data; items-json is the string fallback.",
95
+ "Assign headers as a JavaScript property and replace its object identity whenever an active tool changes title, depth, or actions.",
96
+ "Keep PanelTools mounted at AppShell scope across route changes and provide each product through its matching named slot."
97
+ ],
98
+ "react": [
99
+ "Pass the fixed item collection through the generated React wrapper and keep named-slot product content mounted at AppShell scope.",
100
+ "Use storageKey only for same-browser last-tool continuity; do not persist the open drawer."
101
+ ],
102
+ "angular": [
103
+ "Import DsPanelTools from @ds-mo/ui/angular/ds-panel-tools and bind items as a property.",
104
+ "Bind headers as a replaced object and route dsHeaderBack and dsHeaderAction to the active tool owner.",
105
+ "Keep the component in the persistent shell layout rather than recreating it in routed page components."
106
+ ]
107
+ },
108
+ "references": [
109
+ {
110
+ "label": "Executable Storybook examples",
111
+ "path": "src/wc/components/PanelTools/PanelTools.stories.ts"
112
+ },
113
+ {
114
+ "label": "Framework and shell integration",
115
+ "path": "docs/framework-integration.md"
116
+ },
117
+ {
118
+ "label": "Application shell composition",
119
+ "path": "agent/patterns/application-shell/pattern.agent.json"
120
+ }
121
+ ]
122
+ },
123
+ "api": {
124
+ "props": {
125
+ "activeTool": {
126
+ "type": "PanelToolsToolId | ''",
127
+ "resolvedType": "\"\" | \"activity\" | \"agents\" | \"help\" | \"messages\" | \"search\" | \"stacks\"",
128
+ "attribute": "active-tool",
129
+ "default": "''",
130
+ "required": false,
131
+ "mutable": true,
132
+ "description": "Active tool view — `search`, `agents`, `messages`, `stacks`, `activity`, or `help`."
133
+ },
134
+ "fullscreenHeaderMode": {
135
+ "type": "'shared' | 'split'",
136
+ "resolvedType": "\"shared\" | \"split\"",
137
+ "attribute": "fullscreen-header-mode",
138
+ "default": "'shared'",
139
+ "required": false,
140
+ "mutable": false,
141
+ "description": "Let a fullscreen product supply independent master/detail headers inside its view."
142
+ },
143
+ "headers": {
144
+ "type": "PanelToolsHeaders",
145
+ "resolvedType": "\"activity\" | \"agents\" | \"help\" | \"messages\" | \"search\" | \"stacks\" | PanelToolsHeaderConfig",
146
+ "default": "{}",
147
+ "required": false,
148
+ "mutable": false,
149
+ "description": "Active header state per tool. Replace the object when title, depth, or actions change."
150
+ },
151
+ "headersJson": {
152
+ "type": "string",
153
+ "resolvedType": "string",
154
+ "attribute": "headers-json",
155
+ "default": "''",
156
+ "required": false,
157
+ "mutable": false,
158
+ "description": "JSON fallback for `headers`. The `headers` property takes precedence when non-empty."
159
+ },
160
+ "items": {
161
+ "type": "PanelToolsItem[]",
162
+ "resolvedType": "PanelToolsItem[]",
163
+ "default": "[]",
164
+ "required": false,
165
+ "mutable": false,
166
+ "description": "Rail items rendered in the right column.\nSet via JS property: `el.items = [...]`. Replace the array reference to update."
167
+ },
168
+ "itemsJson": {
169
+ "type": "string",
170
+ "resolvedType": "string",
171
+ "attribute": "items-json",
172
+ "default": "''",
173
+ "required": false,
174
+ "mutable": false,
175
+ "description": "JSON fallback for `items` — useful when framework bindings don't propagate arrays."
176
+ },
177
+ "open": {
178
+ "type": "boolean",
179
+ "resolvedType": "boolean",
180
+ "attribute": "open",
181
+ "default": "false",
182
+ "required": false,
183
+ "mutable": true,
184
+ "description": "When false, only the icon rail is shown."
185
+ },
186
+ "presentation": {
187
+ "type": "'drawer' | 'fullscreen'",
188
+ "resolvedType": "\"drawer\" | \"fullscreen\"",
189
+ "attribute": "presentation",
190
+ "default": "'drawer'",
191
+ "required": false,
192
+ "mutable": true,
193
+ "description": "Drawer presentation or viewport-covering presentation for the active tool."
194
+ },
195
+ "storageKey": {
196
+ "type": "string",
197
+ "resolvedType": "string",
198
+ "attribute": "storage-key",
199
+ "default": "''",
200
+ "required": false,
201
+ "mutable": false,
202
+ "description": "Optional localStorage key for the last active tool. The drawer always starts\nclosed; only the tool identity is restored for continuity within this browser."
203
+ },
204
+ "toolShortcutsLabel": {
205
+ "type": "string",
206
+ "resolvedType": "string",
207
+ "attribute": "tool-shortcuts-label",
208
+ "default": "'Tool shortcuts'",
209
+ "required": false,
210
+ "mutable": false
211
+ },
212
+ "toolsLabel": {
213
+ "type": "string",
214
+ "resolvedType": "string",
215
+ "attribute": "tools-label",
216
+ "default": "'Tools'",
217
+ "required": false,
218
+ "mutable": false
219
+ }
220
+ },
221
+ "events": [
222
+ {
223
+ "name": "dsChromeTransitionEnd",
224
+ "detail": "ChromeTransitionDetail",
225
+ "bubbles": true,
226
+ "cancelable": true,
227
+ "composed": true
228
+ },
229
+ {
230
+ "name": "dsChromeTransitionStart",
231
+ "detail": "ChromeTransitionDetail",
232
+ "bubbles": true,
233
+ "cancelable": true,
234
+ "composed": true,
235
+ "description": "Bubbling lifecycle — `ds-bar-nav` defers overflow checks during drawer motion."
236
+ },
237
+ {
238
+ "name": "dsHeaderAction",
239
+ "detail": "{\n tool: PanelToolsToolId;\n id: string;\n }",
240
+ "bubbles": true,
241
+ "cancelable": true,
242
+ "composed": true,
243
+ "description": "Requests one application-owned action from the active tool header."
244
+ },
245
+ {
246
+ "name": "dsHeaderBack",
247
+ "detail": "{\n tool: PanelToolsToolId;\n }",
248
+ "bubbles": true,
249
+ "cancelable": true,
250
+ "composed": true,
251
+ "description": "Requests navigation to the active tool's parent view."
252
+ },
253
+ {
254
+ "name": "dsPresentationChange",
255
+ "detail": "{\n presentation: 'drawer' | 'fullscreen';\n }",
256
+ "bubbles": true,
257
+ "cancelable": true,
258
+ "composed": true,
259
+ "description": "Emitted when fullscreen changes, including Escape-initiated exits."
260
+ },
261
+ {
262
+ "name": "dsToolChange",
263
+ "detail": "{\n id: PanelToolsToolId;\n selected: boolean;\n }",
264
+ "bubbles": true,
265
+ "cancelable": true,
266
+ "composed": true,
267
+ "description": "Emitted when a rail button is toggled. Detail = { id, selected }."
268
+ }
269
+ ],
270
+ "methods": [
271
+ {
272
+ "name": "activateTool",
273
+ "signature": "activateTool(id: PanelToolsToolId) => Promise<void>",
274
+ "description": "Toggle any rail tool open/closed — shell shortcuts K/A/S/M/N call this."
275
+ },
276
+ {
277
+ "name": "closeDrawer",
278
+ "signature": "closeDrawer() => Promise<void>",
279
+ "description": "Close the tools drawer when open — used by shell keyboard shortcuts."
280
+ },
281
+ {
282
+ "name": "focusHeaderAction",
283
+ "signature": "focusHeaderAction(id: string) => Promise<void>",
284
+ "description": "Focus an active tool-header action by its application-owned id."
285
+ }
286
+ ],
287
+ "slots": []
288
+ },
289
+ "props": {
290
+ "activeTool": {
291
+ "type": "PanelToolsToolId | ''",
292
+ "resolvedType": "\"\" | \"activity\" | \"agents\" | \"help\" | \"messages\" | \"search\" | \"stacks\"",
293
+ "attribute": "active-tool",
294
+ "default": "''",
295
+ "required": false,
296
+ "mutable": true,
297
+ "description": "Active tool view — `search`, `agents`, `messages`, `stacks`, `activity`, or `help`."
298
+ },
299
+ "fullscreenHeaderMode": {
300
+ "type": "'shared' | 'split'",
301
+ "resolvedType": "\"shared\" | \"split\"",
302
+ "attribute": "fullscreen-header-mode",
303
+ "default": "'shared'",
304
+ "required": false,
305
+ "mutable": false,
306
+ "description": "Let a fullscreen product supply independent master/detail headers inside its view."
307
+ },
308
+ "headers": {
309
+ "type": "PanelToolsHeaders",
310
+ "resolvedType": "\"activity\" | \"agents\" | \"help\" | \"messages\" | \"search\" | \"stacks\" | PanelToolsHeaderConfig",
311
+ "default": "{}",
312
+ "required": false,
313
+ "mutable": false,
314
+ "description": "Active header state per tool. Replace the object when title, depth, or actions change."
315
+ },
316
+ "headersJson": {
317
+ "type": "string",
318
+ "resolvedType": "string",
319
+ "attribute": "headers-json",
320
+ "default": "''",
321
+ "required": false,
322
+ "mutable": false,
323
+ "description": "JSON fallback for `headers`. The `headers` property takes precedence when non-empty."
324
+ },
325
+ "items": {
326
+ "type": "PanelToolsItem[]",
327
+ "resolvedType": "PanelToolsItem[]",
328
+ "default": "[]",
329
+ "required": false,
330
+ "mutable": false,
331
+ "description": "Rail items rendered in the right column.\nSet via JS property: `el.items = [...]`. Replace the array reference to update."
332
+ },
333
+ "itemsJson": {
334
+ "type": "string",
335
+ "resolvedType": "string",
336
+ "attribute": "items-json",
337
+ "default": "''",
338
+ "required": false,
339
+ "mutable": false,
340
+ "description": "JSON fallback for `items` — useful when framework bindings don't propagate arrays."
341
+ },
342
+ "open": {
343
+ "type": "boolean",
344
+ "resolvedType": "boolean",
345
+ "attribute": "open",
346
+ "default": "false",
347
+ "required": false,
348
+ "mutable": true,
349
+ "description": "When false, only the icon rail is shown."
350
+ },
351
+ "presentation": {
352
+ "type": "'drawer' | 'fullscreen'",
353
+ "resolvedType": "\"drawer\" | \"fullscreen\"",
354
+ "attribute": "presentation",
355
+ "default": "'drawer'",
356
+ "required": false,
357
+ "mutable": true,
358
+ "description": "Drawer presentation or viewport-covering presentation for the active tool."
359
+ },
360
+ "storageKey": {
361
+ "type": "string",
362
+ "resolvedType": "string",
363
+ "attribute": "storage-key",
364
+ "default": "''",
365
+ "required": false,
366
+ "mutable": false,
367
+ "description": "Optional localStorage key for the last active tool. The drawer always starts\nclosed; only the tool identity is restored for continuity within this browser."
368
+ },
369
+ "toolShortcutsLabel": {
370
+ "type": "string",
371
+ "resolvedType": "string",
372
+ "attribute": "tool-shortcuts-label",
373
+ "default": "'Tool shortcuts'",
374
+ "required": false,
375
+ "mutable": false
376
+ },
377
+ "toolsLabel": {
378
+ "type": "string",
379
+ "resolvedType": "string",
380
+ "attribute": "tools-label",
381
+ "default": "'Tools'",
382
+ "required": false,
383
+ "mutable": false
384
+ }
385
+ },
386
+ "events": [
387
+ {
388
+ "name": "dsChromeTransitionEnd",
389
+ "detail": "ChromeTransitionDetail",
390
+ "bubbles": true,
391
+ "cancelable": true,
392
+ "composed": true
393
+ },
394
+ {
395
+ "name": "dsChromeTransitionStart",
396
+ "detail": "ChromeTransitionDetail",
397
+ "bubbles": true,
398
+ "cancelable": true,
399
+ "composed": true,
400
+ "description": "Bubbling lifecycle — `ds-bar-nav` defers overflow checks during drawer motion."
401
+ },
402
+ {
403
+ "name": "dsHeaderAction",
404
+ "detail": "{\n tool: PanelToolsToolId;\n id: string;\n }",
405
+ "bubbles": true,
406
+ "cancelable": true,
407
+ "composed": true,
408
+ "description": "Requests one application-owned action from the active tool header."
409
+ },
410
+ {
411
+ "name": "dsHeaderBack",
412
+ "detail": "{\n tool: PanelToolsToolId;\n }",
413
+ "bubbles": true,
414
+ "cancelable": true,
415
+ "composed": true,
416
+ "description": "Requests navigation to the active tool's parent view."
417
+ },
418
+ {
419
+ "name": "dsPresentationChange",
420
+ "detail": "{\n presentation: 'drawer' | 'fullscreen';\n }",
421
+ "bubbles": true,
422
+ "cancelable": true,
423
+ "composed": true,
424
+ "description": "Emitted when fullscreen changes, including Escape-initiated exits."
425
+ },
426
+ {
427
+ "name": "dsToolChange",
428
+ "detail": "{\n id: PanelToolsToolId;\n selected: boolean;\n }",
429
+ "bubbles": true,
430
+ "cancelable": true,
431
+ "composed": true,
432
+ "description": "Emitted when a rail button is toggled. Detail = { id, selected }."
433
+ }
434
+ ],
435
+ "methods": [
436
+ {
437
+ "name": "activateTool",
438
+ "signature": "activateTool(id: PanelToolsToolId) => Promise<void>",
439
+ "description": "Toggle any rail tool open/closed — shell shortcuts K/A/S/M/N call this."
440
+ },
441
+ {
442
+ "name": "closeDrawer",
443
+ "signature": "closeDrawer() => Promise<void>",
444
+ "description": "Close the tools drawer when open — used by shell keyboard shortcuts."
445
+ },
446
+ {
447
+ "name": "focusHeaderAction",
448
+ "signature": "focusHeaderAction(id: string) => Promise<void>",
449
+ "description": "Focus an active tool-header action by its application-owned id."
450
+ }
451
+ ],
452
+ "slots": [],
453
+ "exports": {
454
+ "customElement": "ds-panel-tools",
455
+ "react": "DsPanelTools",
456
+ "angular": "DsPanelTools"
457
+ },
458
+ "consumption": {
459
+ "install": "npm install @ds-mo/ui @ds-mo/tokens @ds-mo/icons",
460
+ "cssSetup": "import '@ds-mo/tokens';\nimport '@ds-mo/tokens/reset';\nimport '@ds-mo/tokens/globals';",
461
+ "customElements": {
462
+ "import": "import '@ds-mo/ui/dist/components/ds-panel-tools.js';",
463
+ "example": "<ds-panel-tools></ds-panel-tools>"
464
+ },
465
+ "react": {
466
+ "import": "import { DsPanelTools } from '@ds-mo/ui/react';",
467
+ "example": "<DsPanelTools />"
468
+ },
469
+ "angular": {
470
+ "import": "import { DsPanelTools } from '@ds-mo/ui/angular/ds-panel-tools';",
471
+ "example": "<ds-panel-tools></ds-panel-tools>"
472
+ },
473
+ "complexPropertyNote": "Assign these non-primitive values as JavaScript properties: headers, items.",
474
+ "peerDependencies": {
475
+ "required": [
476
+ "@ds-mo/tokens ^3.1.1",
477
+ "@ds-mo/icons ^6.2.0"
478
+ ],
479
+ "frameworks": "Custom Elements; React 18/19 wrappers; Angular 19-22 standalone adapters."
480
+ }
481
+ }
482
+ },
483
+ "dependencies": [
484
+ "@ds-mo/ui",
485
+ "@ds-mo/tokens"
486
+ ],
487
+ "registryDependencies": [
488
+ "button-unfilled",
489
+ "panel-tool-header",
490
+ "tooltip"
491
+ ],
492
+ "files": [
493
+ {
494
+ "path": "src/wc/components/PanelTools/PanelTools.css",
495
+ "content": "@import '../../utils/control-density.css';\n\n:host {\n display: block;\n flex: 0 0 auto;\n box-sizing: border-box;\n height: 100%;\n min-height: 0;\n overflow: hidden;\n --_panel-tools-rail-width: var(--dimension-size-600);\n --_panel-tools-drawer-width: var(--ds-shell-panel-tools-width, var(--dimension-panel-width-xs));\n --_panel-tools-border: var(--dimension-stroke-width-012, 1px) solid var(--color-border-tertiary);\n /* Match panel-nav expand timing (medium-1); easing differs by direction. */\n --_panel-tools-expand-dur: var(--effect-animation-duration-medium-1, 300ms);\n}\n\n.panel-tools__layout {\n display: flex;\n flex-direction: row-reverse;\n align-items: stretch;\n height: 100%;\n min-height: 0;\n box-sizing: border-box;\n}\n\n/* Clip frame — only max-width animates (slide reveal, same as pre-rail :host). */\n.panel-tools__drawer {\n flex: 0 0 auto;\n max-width: 0;\n min-width: 0;\n height: 100%;\n min-height: 0;\n overflow: hidden;\n box-sizing: border-box;\n transition: none;\n}\n\n:host(.panel-tools--ready) .panel-tools__drawer {\n transition: max-width var(--_panel-tools-expand-dur)\n var(--effect-animation-easing-ease-in-out, ease);\n}\n\n:host(.panel-tools--ready.panel-tools--motion-opening) .panel-tools__drawer {\n transition: max-width var(--_panel-tools-expand-dur)\n var(--effect-animation-easing-ease-out, ease-out);\n}\n\n:host(.panel-tools--ready.panel-tools--motion-closing) .panel-tools__drawer {\n transition: max-width var(--_panel-tools-expand-dur)\n var(--effect-animation-easing-ease-in, ease-in);\n}\n\n:host(.panel-tools--open) .panel-tools__drawer {\n max-width: var(--_panel-tools-drawer-width);\n}\n\n.panel-tools__drawer--visible {\n border-left: var(--_panel-tools-border);\n}\n\n/* Fixed-width surface — AppShell supplies the standard 300px tools width. */\n.panel-tools__drawer-surface {\n display: flex;\n flex-direction: column;\n width: var(--_panel-tools-drawer-width);\n height: 100%;\n min-height: 0;\n box-sizing: border-box;\n background-color: transparent;\n}\n\n.panel-tools__full-views,\n.panel-tools__full-view {\n flex: 1 1 auto;\n min-height: 0;\n overflow: hidden;\n}\n\n.panel-tools__full-view {\n height: 100%;\n}\n\n.panel-tools__full-view {\n display: none;\n}\n.panel-tools__full-view--active {\n display: block;\n}\n\n:host([presentation='fullscreen']) {\n height: 100vh;\n inset: 0;\n position: fixed;\n width: 100vw;\n z-index: var(--dimension-z-index-modal);\n}\n\n:host([presentation='fullscreen']) .panel-tools__rail {\n display: none;\n}\n:host([presentation='fullscreen']) .panel-tools__drawer {\n max-width: 100vw;\n transition: none;\n width: 100vw;\n}\n:host([presentation='fullscreen']) .panel-tools__drawer-surface {\n background-color: transparent;\n width: 100vw;\n}\n\n:host(.panel-tools--presentation-snap) .panel-tools__drawer {\n transition: none;\n}\n\n.panel-tools__body {\n flex: 1 1 auto;\n min-height: 0;\n overflow: auto;\n position: relative;\n}\n\n/* Skip paint while fully closed; cleared during open/close motion for WYSIWYG slide. */\n:host(.panel-tools--drawer-resting) .panel-tools__body {\n content-visibility: auto;\n contain-intrinsic-size: auto 200px;\n}\n\n.panel-tools__view {\n display: none;\n height: 100%;\n min-height: 0;\n box-sizing: border-box;\n padding: var(--dimension-space-200);\n color: var(--color-foreground-secondary);\n font-family: var(--typography-font-family);\n font-size: var(--typography-fontsize-md);\n line-height: var(--typography-lineheight-md);\n font-weight: var(--typography-weight-regular);\n letter-spacing: var(--typography-letterspacing-negative-half);\n}\n\n.panel-tools__view ::slotted(*) {\n margin: 0;\n color: var(--color-foreground-secondary);\n font-family: var(--typography-font-family);\n font-size: var(--typography-fontsize-md);\n line-height: var(--typography-lineheight-md);\n font-weight: var(--typography-weight-regular);\n letter-spacing: var(--typography-letterspacing-negative-half);\n}\n\n.panel-tools__view--active {\n display: block;\n}\n\n/* Rail — mirrors collapsed panel-nav width, padding, and item rhythm. */\n.panel-tools__rail {\n flex: 0 0 var(--_panel-tools-rail-width);\n width: var(--_panel-tools-rail-width);\n min-width: var(--_panel-tools-rail-width);\n display: flex;\n flex-direction: column;\n box-sizing: border-box;\n height: 100%;\n min-height: 0;\n border-left: var(--_panel-tools-border);\n background-color: transparent;\n}\n\n.panel-tools__rail-header {\n display: flex;\n align-items: center;\n justify-content: center;\n height: var(--dimension-size-600);\n padding: var(--dimension-space-100);\n flex-shrink: 0;\n box-sizing: border-box;\n border-bottom: var(--_panel-tools-border);\n}\n\n.panel-tools__rail-body {\n flex: 1 1 auto;\n min-height: 0;\n overflow-y: auto;\n overflow-x: hidden;\n display: flex;\n flex-direction: column;\n gap: var(--dimension-space-050);\n padding: var(--dimension-space-100);\n box-sizing: border-box;\n scrollbar-width: none;\n}\n\n.panel-tools__rail-body::-webkit-scrollbar {\n display: none;\n}\n\n/* Flush to the bottom of the rail — mirrors Search header pin. */\n.panel-tools__rail-footer {\n display: flex;\n align-items: center;\n justify-content: center;\n flex-shrink: 0;\n margin-top: auto;\n padding: var(--dimension-space-100);\n box-sizing: border-box;\n}\n\n.panel-tools__rail-action {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 100%;\n height: var(--ds-control-height);\n flex-shrink: 0;\n}\n\n@media (prefers-reduced-motion: reduce) {\n :host(.panel-tools--ready.panel-tools--motion-opening) .panel-tools__drawer,\n :host(.panel-tools--ready.panel-tools--motion-closing) .panel-tools__drawer {\n transition: none;\n }\n}\n",
496
+ "type": "registry:ui"
497
+ },
498
+ {
499
+ "path": "src/wc/components/PanelTools/PanelTools.tsx",
500
+ "content": "import {\n Component,\n Prop,\n Event,\n EventEmitter,\n Element,\n State,\n Watch,\n Method,\n Listen,\n h,\n Host,\n} from '@stencil/core';\nimport type { ChromeTransitionDetail } from '../../shell/chrome-transition';\nimport {\n PANEL_TOOLS_FOOTER_TOOL_ID,\n PANEL_TOOLS_LABELS,\n PANEL_TOOLS_PRIMARY_TOOL_ID,\n PANEL_TOOLS_SHORTCUTS,\n type PanelToolsHeaderAction,\n type PanelToolsHeaderConfig,\n type PanelToolsHeaders,\n type PanelToolsItem,\n type PanelToolsToolId,\n} from './panel-tools-types';\nimport {\n isPanelToolsToolId,\n orderPanelToolsItems,\n panelToolsDrawerAtTerminal,\n parsePanelToolsItems,\n panelToolsDrawerResting,\n panelToolsDrawerTransitionMs,\n reconcilePanelToolsAvailability,\n resolvePanelToolActivation,\n} from './panel-tools-utils';\n\n@Component({\n tag: 'ds-panel-tools',\n styleUrl: 'PanelTools.css',\n scoped: true,\n})\nexport class PanelTools {\n @Element() el!: HTMLElement;\n\n /** When false, only the icon rail is shown. */\n @Prop({ mutable: true, reflect: true }) open: boolean = false;\n\n /** Drawer presentation or viewport-covering presentation for the active tool. */\n @Prop({ mutable: true, reflect: true }) presentation: 'drawer' | 'fullscreen' = 'drawer';\n\n /** Let a fullscreen product supply independent master/detail headers inside its view. */\n @Prop({ attribute: 'fullscreen-header-mode', reflect: true })\n fullscreenHeaderMode: 'shared' | 'split' = 'shared';\n\n /** Active tool view — `search`, `agents`, `messages`, `stacks`, `activity`, or `help`. */\n @Prop({ mutable: true, attribute: 'active-tool', reflect: true })\n activeTool: PanelToolsToolId | '' = '';\n\n /**\n * Rail items rendered in the right column.\n * Set via JS property: `el.items = [...]`. Replace the array reference to update.\n */\n @Prop() items: PanelToolsItem[] = [];\n\n /** JSON fallback for `items` — useful when framework bindings don't propagate arrays. */\n @Prop({ attribute: 'items-json' }) itemsJson: string = '';\n @Prop() toolsLabel: string = 'Tools';\n @Prop() toolShortcutsLabel: string = 'Tool shortcuts';\n\n /** Active header state per tool. Replace the object when title, depth, or actions change. */\n @Prop() headers: PanelToolsHeaders = {};\n\n /** JSON fallback for `headers`. The `headers` property takes precedence when non-empty. */\n @Prop({ attribute: 'headers-json' }) headersJson: string = '';\n\n /**\n * Optional localStorage key for the last active tool. The drawer always starts\n * closed; only the tool identity is restored for continuity within this browser.\n */\n @Prop({ attribute: 'storage-key' }) storageKey: string = '';\n\n /** Emitted when a rail button is toggled. Detail = { id, selected }. */\n @Event({ bubbles: true, composed: true }) dsToolChange!: EventEmitter<{\n id: PanelToolsToolId;\n selected: boolean;\n }>;\n\n /** Emitted when fullscreen changes, including Escape-initiated exits. */\n @Event({ bubbles: true, composed: true }) dsPresentationChange!: EventEmitter<{\n presentation: 'drawer' | 'fullscreen';\n }>;\n\n /** Requests navigation to the active tool's parent view. */\n @Event({ bubbles: true, composed: true }) dsHeaderBack!: EventEmitter<{\n tool: PanelToolsToolId;\n }>;\n\n /** Requests one application-owned action from the active tool header. */\n @Event({ bubbles: true, composed: true }) dsHeaderAction!: EventEmitter<{\n tool: PanelToolsToolId;\n id: string;\n }>;\n\n /** Bubbling lifecycle — `ds-bar-nav` defers overflow checks during drawer motion. */\n @Event({ bubbles: true, composed: true })\n dsChromeTransitionStart!: EventEmitter<ChromeTransitionDetail>;\n\n @Event({ bubbles: true, composed: true })\n dsChromeTransitionEnd!: EventEmitter<ChromeTransitionDetail>;\n\n /** Arms open vs close easing for the in-flight width transition. */\n @State() private motion: 'opening' | 'closing' | 'idle' = 'idle';\n\n /** Keeps header and slotted content painted until the closing clip transition completes. */\n @State() private drawerSurfaceRetained = false;\n\n /** Suppresses width transition until the host has painted its initial open state. */\n @State() private readyForMotion = false;\n\n /** Fullscreen presentation changes snap without borrowing drawer width motion. */\n @State() private presentationMotionSuppressed = false;\n\n @State() private rovingIndex = 0;\n @State() private fullViewToolIds: PanelToolsToolId[] = [];\n\n private motionEnableGeneration = 0;\n private presentationMotionGeneration = 0;\n private transitionGeneration = 0;\n private transitionFallbackTimer: number | null = null;\n /** Ignores the old transition's terminal event when reversing direction. */\n private ignoreReplacementTerminal = false;\n private focusBeforeFullscreen: HTMLElement | null = null;\n private fullViewObserver: MutationObserver | null = null;\n\n private get railItems(): PanelToolsItem[] {\n return parsePanelToolsItems(this.items, this.itemsJson);\n }\n\n private get orderedRailItems(): PanelToolsItem[] {\n const railItems = orderPanelToolsItems(this.railItems);\n const headerItem = railItems.find(item => item.id === PANEL_TOOLS_PRIMARY_TOOL_ID);\n const footerItem = railItems.find(item => item.id === PANEL_TOOLS_FOOTER_TOOL_ID);\n const bodyItems = railItems.filter(\n item => item.id !== PANEL_TOOLS_PRIMARY_TOOL_ID && item.id !== PANEL_TOOLS_FOOTER_TOOL_ID\n );\n const ordered: PanelToolsItem[] = [];\n if (headerItem) ordered.push(headerItem);\n ordered.push(...bodyItems);\n if (footerItem) ordered.push(footerItem);\n return ordered;\n }\n\n disconnectedCallback() {\n this.el.removeEventListener('transitionend', this.handleTransitionEnd);\n this.el.removeEventListener('transitioncancel', this.handleTransitionEnd);\n this.el.removeEventListener('dsAction', this.handleComposedHeaderAction);\n this.clearTransitionCompletion();\n this.motionEnableGeneration += 1;\n this.fullViewObserver?.disconnect();\n this.fullViewObserver = null;\n }\n\n @Watch('presentation')\n presentationChanged(next: 'drawer' | 'fullscreen', previous?: 'drawer' | 'fullscreen') {\n if (next === previous) return;\n const presentationGeneration = ++this.presentationMotionGeneration;\n this.presentationMotionSuppressed = true;\n requestAnimationFrame(() => {\n requestAnimationFrame(() => {\n if (presentationGeneration !== this.presentationMotionGeneration) return;\n this.presentationMotionSuppressed = false;\n });\n });\n if (next === 'fullscreen') {\n this.focusBeforeFullscreen =\n document.activeElement instanceof HTMLElement ? document.activeElement : null;\n this.open = true;\n } else if (previous === 'fullscreen') {\n const focusBeforeFullscreen = this.focusBeforeFullscreen;\n const fallbackActionId = this.activeHeader().actions?.[0]?.id;\n requestAnimationFrame(async () => {\n if (focusBeforeFullscreen?.isConnected) {\n focusBeforeFullscreen.focus({ preventScroll: true });\n }\n const focusRestored = focusBeforeFullscreen\n ? document.activeElement === focusBeforeFullscreen ||\n focusBeforeFullscreen.contains(document.activeElement)\n : false;\n if (!focusRestored && fallbackActionId) await this.focusHeaderAction(fallbackActionId);\n this.focusBeforeFullscreen = null;\n });\n }\n this.dsPresentationChange.emit({ presentation: next });\n }\n\n @Listen('keydown', { target: 'window', capture: true })\n handleFullscreenEscape(event: KeyboardEvent) {\n if (this.presentation !== 'fullscreen' || event.key !== 'Escape') return;\n event.preventDefault();\n event.stopPropagation();\n this.presentation = 'drawer';\n }\n\n private deferMotionEnable() {\n if (this.readyForMotion) return;\n const generation = ++this.motionEnableGeneration;\n requestAnimationFrame(() => {\n if (generation !== this.motionEnableGeneration) return;\n requestAnimationFrame(() => {\n if (generation !== this.motionEnableGeneration) return;\n this.readyForMotion = true;\n });\n });\n }\n\n connectedCallback() {\n this.el.addEventListener('transitionend', this.handleTransitionEnd);\n this.el.addEventListener('transitioncancel', this.handleTransitionEnd);\n this.el.addEventListener('dsAction', this.handleComposedHeaderAction);\n }\n\n private handleComposedHeaderAction = (event: Event) => {\n const detail = (event as CustomEvent<{ id?: string }>).detail;\n if (!this.activeTool || !detail?.id) return;\n event.stopPropagation();\n this.dsHeaderAction.emit({ tool: this.activeTool, id: detail.id });\n };\n\n componentWillLoad() {\n this.restoreLastActiveTool();\n this.drawerSurfaceRetained = this.open;\n }\n\n @Watch('open')\n openChanged(isOpen: boolean, wasOpen?: boolean) {\n if (isOpen) this.drawerSurfaceRetained = true;\n if (this.readyForMotion && wasOpen !== undefined && wasOpen !== isOpen) {\n this.startDrawerTransition(isOpen ? 'opening' : 'closing');\n } else if (!isOpen) {\n this.drawerSurfaceRetained = false;\n }\n this.deferMotionEnable();\n }\n\n @Watch('activeTool')\n activeToolChanged() {\n this.persistLastActiveTool();\n this.deferMotionEnable();\n }\n\n @Watch('storageKey')\n storageKeyChanged() {\n this.restoreLastActiveTool();\n }\n\n componentDidLoad() {\n this.deferMotionEnable();\n this.syncFullViewTools();\n this.fullViewObserver = new MutationObserver(() => this.syncFullViewTools());\n this.fullViewObserver.observe(this.el, {\n childList: true,\n attributes: true,\n attributeFilter: ['slot'],\n });\n }\n\n @Watch('items')\n @Watch('itemsJson')\n itemsChanged() {\n this.rovingIndex = 0;\n this.reconcileActiveTool();\n this.deferMotionEnable();\n }\n\n private restoreLastActiveTool() {\n if (!this.storageKey || this.activeTool) return;\n try {\n const stored = localStorage.getItem(this.storageKey);\n if (isPanelToolsToolId(stored)) this.activeTool = stored;\n } catch {\n /* localStorage unavailable */\n }\n }\n\n private persistLastActiveTool() {\n if (!this.storageKey || !this.activeTool) return;\n try {\n localStorage.setItem(this.storageKey, this.activeTool);\n } catch {\n /* unavailable */\n }\n }\n\n private clearPersistedTool() {\n if (!this.storageKey) return;\n try {\n localStorage.removeItem(this.storageKey);\n } catch {\n /* unavailable */\n }\n }\n\n private reconcileActiveTool() {\n const next = reconcilePanelToolsAvailability(this.railItems, this.open, this.activeTool);\n if (!next.removedTool) return;\n this.clearPersistedTool();\n this.open = next.open;\n this.activeTool = next.activeTool;\n this.dsToolChange.emit({ id: next.removedTool, selected: false });\n }\n\n private startDrawerTransition(phase: 'opening' | 'closing') {\n const drawer = this.el.querySelector('.panel-tools__drawer') as HTMLElement | null;\n if (this.motion !== 'idle') {\n this.finishDrawerTransition();\n this.ignoreReplacementTerminal = true;\n }\n this.motion = phase;\n this.dsChromeTransitionStart.emit({ source: 'panel-tools', phase });\n const generation = ++this.transitionGeneration;\n\n requestAnimationFrame(() => {\n requestAnimationFrame(() => {\n if (generation !== this.transitionGeneration || this.motion !== phase) return;\n if (!drawer) {\n this.finishDrawerTransition();\n return;\n }\n\n if (this.drawerTransitionAtTerminal(drawer, phase)) {\n this.finishDrawerTransition();\n return;\n }\n\n const fallbackMs = panelToolsDrawerTransitionMs(getComputedStyle(drawer));\n if (fallbackMs <= 0) {\n this.finishDrawerTransition();\n return;\n }\n this.transitionFallbackTimer = window.setTimeout(() => {\n this.finishDrawerTransition();\n }, fallbackMs);\n });\n });\n }\n\n private handleTransitionEnd = (event: TransitionEvent) => {\n const drawer = this.el.querySelector('.panel-tools__drawer') as HTMLElement | null;\n if (event.target !== drawer) return;\n if (event.propertyName !== 'max-width') return;\n if (this.ignoreReplacementTerminal) {\n this.ignoreReplacementTerminal = false;\n return;\n }\n // Changing from the neutral transition recipe to the direction-specific\n // easing can cancel the transition that the reflected `open` class began.\n // The replacement transition and its watchdog still own completion; ending\n // motion here would hide the fixed-width tool surface while it is visible.\n if (event.type === 'transitioncancel') return;\n if (drawer && !this.drawerTransitionAtTerminal(drawer, this.motion)) return;\n this.finishDrawerTransition();\n };\n\n private drawerTransitionAtTerminal(\n drawer: HTMLElement,\n phase: 'opening' | 'closing' | 'idle'\n ): boolean {\n const width = drawer.getBoundingClientRect().width;\n const surface = drawer.querySelector('.panel-tools__drawer-surface') as HTMLElement | null;\n const targetWidth = surface?.getBoundingClientRect().width ?? 0;\n return panelToolsDrawerAtTerminal(width, targetWidth, phase);\n }\n\n private finishDrawerTransition() {\n const completedPhase = this.motion;\n const wasTransitioning = completedPhase !== 'idle';\n this.clearTransitionCompletion();\n if (!wasTransitioning) return;\n this.ignoreReplacementTerminal = false;\n this.motion = 'idle';\n if (completedPhase === 'closing' && !this.open) {\n this.drawerSurfaceRetained = false;\n }\n this.dsChromeTransitionEnd.emit({ source: 'panel-tools' });\n }\n\n private clearTransitionCompletion() {\n this.transitionGeneration += 1;\n if (this.transitionFallbackTimer !== null) {\n window.clearTimeout(this.transitionFallbackTimer);\n this.transitionFallbackTimer = null;\n }\n }\n\n /** Rail selection follows `open` immediately — independent of the slide animation. */\n private isRailSelected(id: PanelToolsToolId): boolean {\n return this.open && this.activeTool === id;\n }\n\n /** Drawer body stays mounted while the clip frame animates closed. */\n private isDrawerPresent(): boolean {\n return this.open || this.drawerSurfaceRetained;\n }\n\n private isViewActive(id: PanelToolsToolId): boolean {\n return this.isDrawerPresent() && this.activeTool === id;\n }\n\n private hasFullView(id: PanelToolsToolId): boolean {\n return this.fullViewToolIds.includes(id);\n }\n\n private syncFullViewTools() {\n const ids: PanelToolsToolId[] = ['search', 'messages', 'stacks', 'activity', 'agents', 'help'];\n const next = ids.filter(id => Boolean(this.el.querySelector(`[slot=\"${id}-view\"]`)));\n if (next.join('|') !== this.fullViewToolIds.join('|')) this.fullViewToolIds = next;\n }\n\n private headerLabel(): string {\n if (!this.isDrawerPresent() || !this.activeTool) return '';\n return PANEL_TOOLS_LABELS[this.activeTool as PanelToolsToolId] ?? '';\n }\n\n private resolvedHeaders(): PanelToolsHeaders {\n if (Object.keys(this.headers).length) return this.headers;\n if (!this.headersJson.trim()) return {};\n try {\n const parsed = JSON.parse(this.headersJson);\n return parsed && typeof parsed === 'object' && !Array.isArray(parsed)\n ? (parsed as PanelToolsHeaders)\n : {};\n } catch {\n return {};\n }\n }\n\n private activeHeader(): PanelToolsHeaderConfig {\n if (!this.activeTool) return {};\n return this.resolvedHeaders()[this.activeTool] ?? {};\n }\n\n private handleToolChange = (id: PanelToolsToolId) => {\n const next = resolvePanelToolActivation(this.open, this.activeTool, id);\n this.open = next.open;\n this.activeTool = next.activeTool;\n this.dsToolChange.emit({ id, selected: next.selected });\n };\n\n /** Toggle any rail tool open/closed — shell shortcuts K/A/S/M/N call this. */\n @Method()\n async activateTool(id: PanelToolsToolId) {\n const item = this.railItems.find(entry => entry.id === id);\n if (!item || item.isInactive) return;\n this.handleToolChange(id);\n }\n\n /** Close the tools drawer when open — used by shell keyboard shortcuts. */\n @Method()\n async closeDrawer() {\n if (!this.open) return;\n const id = this.activeTool;\n this.open = false;\n if (id) {\n this.dsToolChange.emit({ id, selected: false });\n }\n }\n\n /** Focus an active tool-header action by its application-owned id. */\n @Method()\n async focusHeaderAction(id: string) {\n const action = this.el.querySelector(`[data-header-action-id=\"${CSS.escape(id)}\"]`) as\n | (HTMLElement & { setFocus?: () => Promise<void> })\n | null;\n await action?.setFocus?.();\n }\n\n private focusRailAt(index: number) {\n const items = this.orderedRailItems;\n if (!items.length) return;\n const bounded = Math.max(0, Math.min(index, items.length - 1));\n if (bounded === this.rovingIndex) return;\n this.rovingIndex = bounded;\n const actions = Array.from(\n this.el.querySelectorAll<HTMLElement>('.panel-tools__rail-action .button-icon')\n );\n actions[bounded]?.focus({ preventScroll: true });\n }\n\n private handleRailKeyDown = (e: KeyboardEvent, index: number) => {\n const items = this.orderedRailItems;\n if (!items.length) return;\n\n if (e.key === 'Enter' || e.key === ' ') {\n e.preventDefault();\n this.handleToolChange(items[index].id);\n return;\n }\n\n if (e.key === 'ArrowDown') {\n if (index >= items.length - 1) return;\n e.preventDefault();\n this.focusRailAt(index + 1);\n return;\n }\n\n if (e.key === 'ArrowUp') {\n if (index <= 0) return;\n e.preventDefault();\n this.focusRailAt(index - 1);\n }\n };\n\n private renderRailAction(item: PanelToolsItem, index: number) {\n const label = item.ariaLabel ?? PANEL_TOOLS_LABELS[item.id];\n return (\n <ds-tooltip\n key={item.id}\n label={label}\n shortcutKey={PANEL_TOOLS_SHORTCUTS[item.id]}\n side=\"left\"\n size=\"sm\"\n >\n <ds-button-unfilled\n variant=\"icon\"\n class=\"panel-tools__rail-action\"\n icon={item.icon}\n isActive={this.isRailSelected(item.id)}\n activeFill={false}\n hasBorder={false}\n dot={item.dot ?? false}\n isInactive={item.isInactive}\n focusTabIndex={index === this.rovingIndex ? 0 : -1}\n aria-label={label}\n pressed={this.isRailSelected(item.id)}\n onFocusin={() => {\n this.rovingIndex = index;\n }}\n onKeyDown={(e: KeyboardEvent) => this.handleRailKeyDown(e, index)}\n onDsClick={() => this.handleToolChange(item.id)}\n />\n </ds-tooltip>\n );\n }\n\n render() {\n const headerLabel = this.headerLabel();\n const header = this.activeHeader();\n const headerTitle = header.title?.trim() || headerLabel;\n const headerActions = header.actions ?? [];\n const orderedRailItems = this.orderedRailItems;\n const headerItem = orderedRailItems.find(item => item.id === PANEL_TOOLS_PRIMARY_TOOL_ID);\n const footerItem = orderedRailItems.find(item => item.id === PANEL_TOOLS_FOOTER_TOOL_ID);\n const bodyItems = orderedRailItems.filter(\n item => item.id !== PANEL_TOOLS_PRIMARY_TOOL_ID && item.id !== PANEL_TOOLS_FOOTER_TOOL_ID\n );\n const footerIndex = footerItem ? (headerItem ? 1 : 0) + bodyItems.length : -1;\n const showDrawerChrome = this.isDrawerPresent();\n const drawerResting = panelToolsDrawerResting(this.open, this.motion);\n const activeFullView = Boolean(\n showDrawerChrome && this.activeTool && this.hasFullView(this.activeTool)\n );\n const toolIds: PanelToolsToolId[] = [\n 'search',\n 'messages',\n 'stacks',\n 'activity',\n 'agents',\n 'help',\n ];\n\n return (\n <Host\n class={{\n 'panel-tools': true,\n 'panel-tools--open': this.open,\n 'panel-tools--ready': this.readyForMotion,\n 'panel-tools--motion-opening': this.motion === 'opening',\n 'panel-tools--motion-closing': this.motion === 'closing',\n 'panel-tools--drawer-resting': drawerResting,\n 'panel-tools--fullscreen': this.presentation === 'fullscreen',\n 'panel-tools--presentation-snap': this.presentationMotionSuppressed,\n }}\n role={this.presentation === 'fullscreen' ? 'dialog' : 'complementary'}\n aria-modal={this.presentation === 'fullscreen' ? 'true' : undefined}\n aria-label={this.toolsLabel}\n >\n <div class=\"panel-tools__layout\">\n <nav class=\"panel-tools__rail\" aria-label={this.toolShortcutsLabel}>\n {headerItem ? (\n <div class=\"panel-tools__rail-header\">{this.renderRailAction(headerItem, 0)}</div>\n ) : null}\n <div class=\"panel-tools__rail-body\">\n {bodyItems.map((item, bodyIdx) =>\n this.renderRailAction(item, headerItem ? bodyIdx + 1 : bodyIdx)\n )}\n </div>\n {footerItem ? (\n <div class=\"panel-tools__rail-footer\">\n {this.renderRailAction(footerItem, footerIndex)}\n </div>\n ) : null}\n </nav>\n\n <div\n class={{\n 'panel-tools__drawer': true,\n 'panel-tools__drawer--visible': showDrawerChrome,\n }}\n aria-hidden={showDrawerChrome ? null : 'true'}\n inert={showDrawerChrome ? undefined : true}\n >\n <div class=\"panel-tools__drawer-surface\">\n {this.presentation !== 'fullscreen' || this.fullscreenHeaderMode === 'shared' ? (\n <ds-panel-tool-header\n class=\"panel-tools__header\"\n heading={headerTitle}\n showBack={header.showBack ?? false}\n backIcon={header.backIcon || 'ChevronLeft'}\n backAriaLabel={header.backAriaLabel || 'Back'}\n showMenu={false}\n ref={element => {\n const toolHeader = element as\n | (HTMLDsPanelToolHeaderElement & {\n actions: PanelToolsHeaderAction[];\n })\n | undefined;\n if (toolHeader) toolHeader.actions = headerActions;\n }}\n onDsBack={() => {\n if (this.activeTool) this.dsHeaderBack.emit({ tool: this.activeTool });\n }}\n />\n ) : null}\n <div class=\"panel-tools__body\" hidden={activeFullView}>\n {toolIds.map(id => {\n const active = this.isViewActive(id);\n return (\n <div\n class={{\n 'panel-tools__view': true,\n 'panel-tools__view--active': active,\n }}\n hidden={!active}\n >\n <slot name={id} />\n </div>\n );\n })}\n </div>\n <div class=\"panel-tools__full-views\" hidden={!activeFullView}>\n {toolIds.map(id => (\n <div\n class={{\n 'panel-tools__full-view': true,\n 'panel-tools__full-view--active':\n this.isViewActive(id) && this.hasFullView(id),\n }}\n hidden={!(this.isViewActive(id) && this.hasFullView(id))}\n >\n <slot name={`${id}-view`} />\n </div>\n ))}\n </div>\n </div>\n </div>\n </div>\n </Host>\n );\n }\n}\n",
501
+ "type": "registry:ui"
502
+ },
503
+ {
504
+ "path": "src/wc/components/PanelTools/panel-tools-types.ts",
505
+ "content": "/** Tool ids for the `ds-panel-tools` rail and drawer views. */\nexport type PanelToolsToolId = 'search' | 'agents' | 'messages' | 'stacks' | 'activity' | 'help';\n\nexport const PANEL_TOOLS_TOOL_IDS: PanelToolsToolId[] = [\n 'search',\n 'agents',\n 'messages',\n 'stacks',\n 'activity',\n 'help',\n];\n\n/** Rail header slot — mirrors panel-nav M logo row. */\nexport const PANEL_TOOLS_PRIMARY_TOOL_ID: PanelToolsToolId = 'search';\n\n/** Rail footer slot — flush to the bottom of the tools column. */\nexport const PANEL_TOOLS_FOOTER_TOOL_ID: PanelToolsToolId = 'help';\n\nexport const PANEL_TOOLS_LABELS: Record<PanelToolsToolId, string> = {\n search: 'Search',\n messages: 'Messages',\n stacks: 'Stacks',\n activity: 'Activity',\n agents: 'Agents',\n help: 'Help & Support',\n};\n\nexport const PANEL_TOOLS_SHORTCUTS: Partial<Record<PanelToolsToolId, string>> = {\n search: 'K',\n agents: 'A',\n messages: 'M',\n stacks: 'S',\n activity: 'N',\n help: '?',\n};\n\nexport interface PanelToolsItem {\n id: PanelToolsToolId;\n /** Icon name for <ds-icon>. */\n icon: string;\n /** Whether this rail button is currently pressed/active. */\n selected?: boolean;\n /** Show a notification dot. */\n dot?: boolean;\n isInactive?: boolean;\n ariaLabel?: string;\n}\n\nexport interface PanelToolsHeaderAction {\n id: string;\n icon: string;\n ariaLabel: string;\n triggerId?: string;\n controls?: string;\n expanded?: boolean;\n haspopup?: 'menu' | 'dialog' | 'listbox' | 'tree' | 'grid';\n pressed?: boolean;\n isInactive?: boolean;\n}\n\nexport interface PanelToolsHeaderConfig {\n title?: string;\n showBack?: boolean;\n backIcon?: string;\n backAriaLabel?: string;\n actions?: PanelToolsHeaderAction[];\n}\n\n/** Per-tool header state. The application replaces the object when a tool changes depth or actions. */\nexport type PanelToolsHeaders = Partial<Record<PanelToolsToolId, PanelToolsHeaderConfig>>;\n",
506
+ "type": "registry:ui"
507
+ },
508
+ {
509
+ "path": "src/wc/components/PanelTools/panel-tools-utils.ts",
510
+ "content": "import { parseJsonArrayProp } from '../BarNav/bar-nav-utils';\nimport { parseCssTimeMs } from '../../utils/resolve-css-time-ms';\nimport {\n PANEL_TOOLS_TOOL_IDS,\n type PanelToolsItem,\n type PanelToolsToolId,\n} from './panel-tools-types';\n\nexport function parsePanelToolsItems(items: PanelToolsItem[], itemsJson: string): PanelToolsItem[] {\n if (itemsJson) {\n return parseJsonArrayProp<PanelToolsItem>(itemsJson, []);\n }\n return items ?? [];\n}\n\nexport function orderPanelToolsItems(items: PanelToolsItem[]): PanelToolsItem[] {\n const firstById = new Map<PanelToolsToolId, PanelToolsItem>();\n for (const item of items) {\n if (!firstById.has(item.id)) firstById.set(item.id, item);\n }\n return PANEL_TOOLS_TOOL_IDS.flatMap(id => {\n const item = firstById.get(id);\n return item ? [item] : [];\n });\n}\n\nexport function isPanelToolsToolId(value: string | null): value is PanelToolsToolId {\n return value !== null && PANEL_TOOLS_TOOL_IDS.includes(value as PanelToolsToolId);\n}\n\nexport function reconcilePanelToolsAvailability(\n items: PanelToolsItem[],\n open: boolean,\n activeTool: PanelToolsToolId | ''\n): { open: boolean; activeTool: PanelToolsToolId | ''; removedTool: PanelToolsToolId | '' } {\n if (!activeTool || items.some(item => item.id === activeTool)) {\n return { open, activeTool, removedTool: '' };\n }\n return { open: false, activeTool: '', removedTool: activeTool };\n}\n\nexport function shouldResyncPanelToolsItems(\n prev: PanelToolsItem[],\n next: PanelToolsItem[]\n): boolean {\n if (prev.length !== next.length) return true;\n return next.some((item, index) => {\n const prior = prev[index];\n if (!prior) return true;\n return (\n prior.id !== item.id ||\n prior.icon !== item.icon ||\n prior.selected !== item.selected ||\n prior.dot !== item.dot ||\n prior.isInactive !== item.isInactive ||\n prior.ariaLabel !== item.ariaLabel\n );\n });\n}\n\nexport type PanelToolsMotion = 'opening' | 'closing' | 'idle';\n\nexport interface PanelToolsTransitionStyle {\n transitionProperty: string;\n transitionDuration: string;\n transitionDelay: string;\n}\n\n/** Maximum computed time for the drawer's max-width transition, including delay. */\nexport function panelToolsDrawerTransitionMs(style: PanelToolsTransitionStyle): number {\n const properties = style.transitionProperty.split(',').map(item => item.trim());\n const durations = style.transitionDuration.split(',').map(item => parseCssTimeMs(item.trim(), 0));\n const delays = style.transitionDelay.split(',').map(item => parseCssTimeMs(item.trim(), 0));\n\n return properties.reduce((max, property, index) => {\n if (property !== 'all' && property !== 'max-width') return max;\n const duration = durations[index % durations.length] ?? 0;\n const delay = delays[index % delays.length] ?? 0;\n return Math.max(max, duration + delay, 0);\n }, 0);\n}\n\n/** True when the drawer clip is fully closed — safe to skip painting slot content. */\nexport function panelToolsDrawerResting(open: boolean, motion: PanelToolsMotion): boolean {\n return !open && motion === 'idle';\n}\n\n/** True only when the animated clip has reached the terminal width for its motion phase. */\nexport function panelToolsDrawerAtTerminal(\n width: number,\n targetWidth: number,\n motion: PanelToolsMotion\n): boolean {\n if (motion === 'closing') return width <= 0.5;\n if (motion === 'opening') return targetWidth > 0 && width >= targetWidth - 0.5;\n return true;\n}\n\n/** Toggle or switch rail tool selection — repeat activation closes the active tool. */\nexport function resolvePanelToolActivation(\n open: boolean,\n activeTool: PanelToolsToolId | '',\n id: PanelToolsToolId\n): { open: boolean; activeTool: PanelToolsToolId; selected: boolean } {\n if (open && activeTool === id) {\n return { open: false, activeTool: id, selected: false };\n }\n return { open: true, activeTool: id, selected: true };\n}\n",
511
+ "type": "registry:ui"
512
+ }
513
+ ]
514
+ }