@ds-mo/ui 12.2.0 → 12.4.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 (301) hide show
  1. package/README.md +8 -2
  2. package/dist/.build-stamp +1 -1
  3. package/dist/agent-patterns.json +94 -16
  4. package/dist/agent.json +1092 -53
  5. package/dist/angular/ds-bar-title.d.ts +7 -1
  6. package/dist/angular/ds-bar-title.js +7 -4
  7. package/dist/angular/ds-breadcrumb.d.ts +19 -0
  8. package/dist/angular/ds-breadcrumb.js +42 -0
  9. package/dist/angular/ds-card-data-viz-bar.d.ts +18 -0
  10. package/dist/angular/ds-card-data-viz-bar.js +42 -0
  11. package/dist/angular/ds-card-data-viz-line.d.ts +18 -0
  12. package/dist/angular/ds-card-data-viz-line.js +42 -0
  13. package/dist/angular/ds-chart-bar-stacked.d.ts +12 -0
  14. package/dist/angular/ds-chart-bar-stacked.js +38 -0
  15. package/dist/angular/ds-chart-legend.d.ts +1 -1
  16. package/dist/angular/ds-chart-legend.js +3 -3
  17. package/dist/angular/ds-shell-app.d.ts +13 -2
  18. package/dist/angular/ds-shell-app.js +9 -5
  19. package/dist/angular/ds-shell-mobile-bar.d.ts +18 -0
  20. package/dist/angular/ds-shell-mobile-bar.js +46 -0
  21. package/dist/angular/ds-shell-mobile-nav.d.ts +23 -0
  22. package/dist/angular/ds-shell-mobile-nav.js +51 -0
  23. package/dist/angular/ds-shell-mobile-section-nav.d.ts +18 -0
  24. package/dist/angular/ds-shell-mobile-section-nav.js +42 -0
  25. package/dist/angular/ds-shell-page.d.ts +1 -1
  26. package/dist/angular/ds-shell-page.js +3 -3
  27. package/dist/angular/ds-shell-tools.d.ts +42 -0
  28. package/dist/angular/ds-shell-tools.js +52 -0
  29. package/dist/angular/index.d.ts +1 -1
  30. package/dist/angular/index.js +8 -0
  31. package/dist/angular/proxies.d.ts +8 -0
  32. package/dist/angular/proxies.js +8 -0
  33. package/dist/components/ds-agent-activity.js +1 -1
  34. package/dist/components/ds-agent-response.js +1 -1
  35. package/dist/components/ds-agent-source-list.js +1 -1
  36. package/dist/components/ds-agent-tool-call.js +1 -1
  37. package/dist/components/ds-attachment-list.js +1 -1
  38. package/dist/components/ds-badge.js +1 -1
  39. package/dist/components/ds-bar-nav.js +1 -1
  40. package/dist/components/ds-bar-title.js +1 -1
  41. package/dist/components/ds-bar-title.js.map +1 -1
  42. package/dist/components/ds-bar-workflow.js +1 -1
  43. package/dist/components/ds-breadcrumb.d.ts +11 -0
  44. package/dist/components/ds-breadcrumb.js +2 -0
  45. package/dist/components/ds-breadcrumb.js.map +1 -0
  46. package/dist/components/ds-button-filled.js +1 -1
  47. package/dist/components/ds-button-unfilled.js +1 -1
  48. package/dist/components/ds-card-data-viz-bar.d.ts +11 -0
  49. package/dist/components/ds-card-data-viz-bar.js +2 -0
  50. package/dist/components/ds-card-data-viz-bar.js.map +1 -0
  51. package/dist/components/ds-card-data-viz-donut.js +1 -1
  52. package/dist/components/ds-card-data-viz-donut.js.map +1 -1
  53. package/dist/components/ds-card-data-viz-line.d.ts +11 -0
  54. package/dist/components/ds-card-data-viz-line.js +2 -0
  55. package/dist/components/ds-card-data-viz-line.js.map +1 -0
  56. package/dist/components/ds-card-setting.js +1 -1
  57. package/dist/components/ds-card-setting.js.map +1 -1
  58. package/dist/components/ds-card-shell-data-viz.js +1 -1
  59. package/dist/components/ds-chart-bar-stacked.d.ts +11 -0
  60. package/dist/components/ds-chart-bar-stacked.js +2 -0
  61. package/dist/components/ds-chart-bar-stacked.js.map +1 -0
  62. package/dist/components/ds-chart-bar.js +1 -1
  63. package/dist/components/ds-chart-bar.js.map +1 -1
  64. package/dist/components/ds-chart-donut.js +1 -1
  65. package/dist/components/ds-chart-legend.js +1 -1
  66. package/dist/components/ds-chart-legend.js.map +1 -1
  67. package/dist/components/ds-chart-line.js +1 -1
  68. package/dist/components/ds-chart-line.js.map +1 -1
  69. package/dist/components/ds-checkbox.js +1 -1
  70. package/dist/components/ds-chip.js +1 -1
  71. package/dist/components/ds-code-block.js +1 -1
  72. package/dist/components/ds-conversation-list-item.js +1 -1
  73. package/dist/components/ds-conversation-list-item.js.map +1 -1
  74. package/dist/components/ds-conversation-list-section.js +1 -1
  75. package/dist/components/ds-conversation-list.js +1 -1
  76. package/dist/components/ds-divider.js +1 -1
  77. package/dist/components/ds-empty-state.js +1 -1
  78. package/dist/components/ds-field.js +1 -1
  79. package/dist/components/ds-input.js +1 -1
  80. package/dist/components/ds-markdown.js +1 -1
  81. package/dist/components/ds-menu.js +1 -1
  82. package/dist/components/ds-message-bubble.js +1 -1
  83. package/dist/components/ds-message-bubble.js.map +1 -1
  84. package/dist/components/ds-message-composer.js +1 -1
  85. package/dist/components/ds-message-scroller.js +1 -1
  86. package/dist/components/ds-message-scroller.js.map +1 -1
  87. package/dist/components/ds-message.js +1 -1
  88. package/dist/components/ds-modal.js +1 -1
  89. package/dist/components/ds-modal.js.map +1 -1
  90. package/dist/components/ds-panel-nav.js +1 -1
  91. package/dist/components/ds-panel-nav.js.map +1 -1
  92. package/dist/components/ds-panel-sub-nav.js +1 -1
  93. package/dist/components/ds-panel-tool-header.js +1 -1
  94. package/dist/components/ds-panel-tool-search.js +1 -1
  95. package/dist/components/ds-panel-tools.js +1 -1
  96. package/dist/components/ds-panel-tools.js.map +1 -1
  97. package/dist/components/ds-radio.js +1 -1
  98. package/dist/components/ds-scroll-overlay.js +1 -1
  99. package/dist/components/ds-scroll-overlay.js.map +1 -1
  100. package/dist/components/ds-select-multi.js +1 -1
  101. package/dist/components/ds-select-multi.js.map +1 -1
  102. package/dist/components/ds-select.js +1 -1
  103. package/dist/components/ds-select.js.map +1 -1
  104. package/dist/components/ds-shell-app.js +1 -1
  105. package/dist/components/ds-shell-app.js.map +1 -1
  106. package/dist/components/ds-shell-gradient-picker.js +1 -1
  107. package/dist/components/ds-shell-gradient-picker.js.map +1 -1
  108. package/dist/components/ds-shell-gradient-swatch.js +1 -1
  109. package/dist/components/ds-shell-mobile-bar.d.ts +11 -0
  110. package/dist/components/ds-shell-mobile-bar.js +2 -0
  111. package/dist/components/ds-shell-mobile-bar.js.map +1 -0
  112. package/dist/components/ds-shell-mobile-nav.d.ts +11 -0
  113. package/dist/components/ds-shell-mobile-nav.js +2 -0
  114. package/dist/components/ds-shell-mobile-nav.js.map +1 -0
  115. package/dist/components/ds-shell-mobile-section-nav.d.ts +11 -0
  116. package/dist/components/ds-shell-mobile-section-nav.js +2 -0
  117. package/dist/components/ds-shell-mobile-section-nav.js.map +1 -0
  118. package/dist/components/ds-shell-page.js +1 -1
  119. package/dist/components/ds-shell-page.js.map +1 -1
  120. package/dist/components/ds-shell-tools.d.ts +11 -0
  121. package/dist/components/ds-shell-tools.js +2 -0
  122. package/dist/components/ds-shell-tools.js.map +1 -0
  123. package/dist/components/ds-skeleton.js +1 -1
  124. package/dist/components/ds-slider.js +1 -1
  125. package/dist/components/ds-slider.js.map +1 -1
  126. package/dist/components/ds-swatch-picker.js +1 -1
  127. package/dist/components/ds-switch.js +1 -1
  128. package/dist/components/ds-tab-group.js +1 -1
  129. package/dist/components/ds-tab-group.js.map +1 -1
  130. package/dist/components/ds-tag.js +1 -1
  131. package/dist/components/ds-text.js +1 -1
  132. package/dist/components/ds-toast.js +1 -1
  133. package/dist/components/ds-toast.js.map +1 -1
  134. package/dist/components/ds-tooltip-data-viz.js +1 -1
  135. package/dist/components/ds-tooltip.js +1 -1
  136. package/dist/components/ds-typing-indicator.js +1 -1
  137. package/dist/components/ds-typing-indicator.js.map +1 -1
  138. package/dist/components/{p-DcGpdIlT.js → p-9dQQSgwT.js} +2 -2
  139. package/dist/components/p-B3rbhRAk.js +2 -0
  140. package/dist/components/p-B3rbhRAk.js.map +1 -0
  141. package/dist/components/p-B6Vuayt6.js +2 -0
  142. package/dist/components/p-B6Vuayt6.js.map +1 -0
  143. package/dist/components/{p-BWUTr_XN.js → p-BJMRBHKW.js} +2 -2
  144. package/dist/components/p-BJMRBHKW.js.map +1 -0
  145. package/dist/components/p-BPS9VExm.js +2 -0
  146. package/dist/components/{p-CCHqsF_H.js.map → p-BPS9VExm.js.map} +1 -1
  147. package/dist/components/p-BVV_rlIP.js +2 -0
  148. package/dist/components/p-BVV_rlIP.js.map +1 -0
  149. package/dist/components/{p-GMDGgtY8.js → p-BhxwpOH8.js} +2 -2
  150. package/dist/components/{p-2W-ZjZCR.js → p-Biz6xo-z.js} +2 -2
  151. package/dist/components/p-BrusnEYP.js +2 -0
  152. package/dist/components/p-BrusnEYP.js.map +1 -0
  153. package/dist/components/{p-CG5EX4NW.js → p-BtEjlcB9.js} +2 -2
  154. package/dist/components/{p-C0_8K4y7.js → p-BwGnhInj.js} +2 -2
  155. package/dist/components/p-BwGnhInj.js.map +1 -0
  156. package/dist/components/{p-D6jK2Hyi.js → p-C7bZ-jiU.js} +2 -2
  157. package/dist/components/p-CH3w-P2H.js +2 -0
  158. package/dist/components/p-CH3w-P2H.js.map +1 -0
  159. package/dist/components/{p-DOCKtrS4.js → p-CH6cNXXF.js} +2 -2
  160. package/dist/components/{p-BE_CDJeL.js → p-CY19gMiz.js} +2 -2
  161. package/dist/components/p-C_0Q8Cnp.js +2 -0
  162. package/dist/components/{p-Dg3xLna0.js.map → p-C_0Q8Cnp.js.map} +1 -1
  163. package/dist/components/p-C_ewSXTT.js +2 -0
  164. package/dist/components/p-C_ewSXTT.js.map +1 -0
  165. package/dist/components/{p-CHkI3oIS.js → p-Ce52yVXF.js} +2 -2
  166. package/dist/components/p-CgHTNfC1.js +2 -0
  167. package/dist/components/p-CgHTNfC1.js.map +1 -0
  168. package/dist/components/p-Co8hD3P-.js +2 -0
  169. package/dist/components/{p-Cxpl-rzP.js.map → p-Co8hD3P-.js.map} +1 -1
  170. package/dist/components/{p-xY3TjBF5.js → p-CoYFJD-w.js} +2 -2
  171. package/dist/components/{p-DBi1bmOL.js → p-CtD24EyI.js} +2 -2
  172. package/dist/components/{p-BRLDJmkh.js → p-D-xttdpn.js} +2 -2
  173. package/dist/components/{p-CNffejay.js → p-DSa0Hnd3.js} +2 -2
  174. package/dist/components/p-DXewjzkM.js +2 -0
  175. package/dist/components/p-DXewjzkM.js.map +1 -0
  176. package/dist/components/p-DXnFhmZF.js +2 -0
  177. package/dist/components/{p-BpA9uYKX.js.map → p-DXnFhmZF.js.map} +1 -1
  178. package/dist/components/{p-DyGB97Oy.js → p-DYqReipj.js} +2 -2
  179. package/dist/components/{p-ky1msbJ8.js → p-DjPZxzIG.js} +2 -2
  180. package/dist/components/{p-ky1msbJ8.js.map → p-DjPZxzIG.js.map} +1 -1
  181. package/dist/components/p-NUNsefU1.js +2 -0
  182. package/dist/components/{p-8OOCLGph.js.map → p-NUNsefU1.js.map} +1 -1
  183. package/dist/components/p-PZ6R_nGI.js +2 -0
  184. package/dist/components/p-PZ6R_nGI.js.map +1 -0
  185. package/dist/components/{p-B8CubPgQ.js → p-g40DTeV8.js} +2 -2
  186. package/dist/components/p-jCWtxthA.js +2 -0
  187. package/dist/components/{p-XgIQ3oI_.js.map → p-jCWtxthA.js.map} +1 -1
  188. package/dist/components/p-yhj1lIPx.js +2 -0
  189. package/dist/components/p-yhj1lIPx.js.map +1 -0
  190. package/dist/docs/components.json +8860 -6021
  191. package/dist/lib/components/BarNav/bar-nav-types.d.ts +2 -0
  192. package/dist/lib/components/PanelNav/panel-nav-types.d.ts +29 -0
  193. package/dist/lib/components/PanelTools/panel-tools-types.d.ts +40 -0
  194. package/dist/lib/components/TabGroup/tab-item-utils.d.ts +31 -0
  195. package/dist/lib/shell/index.d.ts +5 -0
  196. package/dist/lib/shell/index.js +36 -0
  197. package/dist/lib/shell/index.js.map +3 -3
  198. package/dist/lib/shell/shell-responsive.d.ts +13 -0
  199. package/dist/lib/utils/index.js +3 -1
  200. package/dist/lib/utils/index.js.map +2 -2
  201. package/dist/mcp/cli.js +142 -18
  202. package/dist/mcp-data/registry/agent-source-list.json +1 -1
  203. package/dist/mcp-data/registry/bar-title.json +68 -14
  204. package/dist/mcp-data/registry/breadcrumb.json +205 -0
  205. package/dist/mcp-data/registry/card-data-viz-bar.json +212 -0
  206. package/dist/mcp-data/registry/card-data-viz-line.json +206 -0
  207. package/dist/mcp-data/registry/card-shell-data-viz.json +7 -0
  208. package/dist/mcp-data/registry/chart-bar-stacked.json +225 -0
  209. package/dist/mcp-data/registry/chart-bar.json +9 -2
  210. package/dist/mcp-data/registry/chart-legend.json +29 -3
  211. package/dist/mcp-data/registry/chart-line.json +4 -2
  212. package/dist/mcp-data/registry/conversation-list-item.json +3 -3
  213. package/dist/mcp-data/registry/message-scroller.json +4 -2
  214. package/dist/mcp-data/registry/message.json +3 -2
  215. package/dist/mcp-data/registry/modal.json +1 -1
  216. package/dist/mcp-data/registry/registry.json +1107 -44
  217. package/dist/mcp-data/registry/shell-app.json +71 -11
  218. package/dist/mcp-data/registry/shell-mobile-bar.json +314 -0
  219. package/dist/mcp-data/registry/shell-mobile-nav.json +348 -0
  220. package/dist/mcp-data/registry/shell-mobile-section-nav.json +267 -0
  221. package/dist/mcp-data/registry/shell-page.json +31 -13
  222. package/dist/mcp-data/registry/shell-tools.json +450 -0
  223. package/dist/mcp-data/registry/text.json +1 -1
  224. package/dist/mcp-data/registry/typing-indicator.json +7 -7
  225. package/dist/react/components.d.ts +8 -0
  226. package/dist/react/components.js +8 -0
  227. package/dist/react/ds-bar-title.d.ts +2 -1
  228. package/dist/react/ds-bar-title.js +1 -0
  229. package/dist/react/ds-breadcrumb.d.ts +12 -0
  230. package/dist/react/ds-breadcrumb.js +12 -0
  231. package/dist/react/ds-card-data-viz-bar.d.ts +12 -0
  232. package/dist/react/ds-card-data-viz-bar.js +12 -0
  233. package/dist/react/ds-card-data-viz-line.d.ts +12 -0
  234. package/dist/react/ds-card-data-viz-line.js +12 -0
  235. package/dist/react/ds-chart-bar-stacked.d.ts +9 -0
  236. package/dist/react/ds-chart-bar-stacked.js +12 -0
  237. package/dist/react/ds-shell-app.d.ts +7 -2
  238. package/dist/react/ds-shell-app.js +1 -1
  239. package/dist/react/ds-shell-mobile-bar.d.ts +13 -0
  240. package/dist/react/ds-shell-mobile-bar.js +15 -0
  241. package/dist/react/ds-shell-mobile-nav.d.ts +15 -0
  242. package/dist/react/ds-shell-mobile-nav.js +17 -0
  243. package/dist/react/ds-shell-mobile-section-nav.d.ts +12 -0
  244. package/dist/react/ds-shell-mobile-section-nav.js +12 -0
  245. package/dist/react/ds-shell-tools.d.ts +25 -0
  246. package/dist/react/ds-shell-tools.js +17 -0
  247. package/dist/styles/prose.css +1 -0
  248. package/dist/types/components/BarTitle/BarTitle.d.ts +13 -1
  249. package/dist/types/components/Breadcrumb/Breadcrumb.d.ts +31 -0
  250. package/dist/types/components/Breadcrumb/breadcrumb-types.d.ts +17 -0
  251. package/dist/types/components/CardDataVizBar/CardDataVizBar.d.ts +24 -0
  252. package/dist/types/components/CardDataVizBar/index.d.ts +2 -0
  253. package/dist/types/components/CardDataVizLine/CardDataVizLine.d.ts +24 -0
  254. package/dist/types/components/CardDataVizLine/index.d.ts +2 -0
  255. package/dist/types/components/ChartBarStacked/ChartBarStacked.d.ts +15 -0
  256. package/dist/types/components/ChartBarStacked/index.d.ts +3 -0
  257. package/dist/types/components/ChartLegend/ChartLegend.d.ts +3 -0
  258. package/dist/types/components/ShellApp/ShellApp.d.ts +16 -0
  259. package/dist/types/components/ShellMobileBar/ShellMobileBar.d.ts +25 -0
  260. package/dist/types/components/ShellMobileBar/index.d.ts +4 -0
  261. package/dist/types/components/ShellMobileBar/shell-mobile-bar-types.d.ts +5 -0
  262. package/dist/types/components/ShellMobileNav/ShellMobileNav.d.ts +32 -0
  263. package/dist/types/components/ShellMobileNav/index.d.ts +2 -0
  264. package/dist/types/components/ShellMobileNav/shell-mobile-nav-types.d.ts +6 -0
  265. package/dist/types/components/ShellMobileSectionNav/ShellMobileSectionNav.d.ts +30 -0
  266. package/dist/types/components/ShellMobileSectionNav/index.d.ts +2 -0
  267. package/dist/types/components/ShellPage/ShellPage.d.ts +19 -7
  268. package/dist/types/components/ShellPage/shell-page-responsive.d.ts +0 -8
  269. package/dist/types/components/ShellTools/ShellTools.d.ts +61 -0
  270. package/dist/types/components/ShellTools/index.d.ts +3 -0
  271. package/dist/types/components/TypingIndicator/TypingIndicator.d.ts +1 -1
  272. package/dist/types/components.d.ts +953 -19
  273. package/dist/types/shell/index.d.ts +5 -0
  274. package/dist/types/shell/shell-responsive.d.ts +14 -0
  275. package/package.json +1 -1
  276. package/dist/components/p-8OOCLGph.js +0 -2
  277. package/dist/components/p-BWUTr_XN.js.map +0 -1
  278. package/dist/components/p-BpA9uYKX.js +0 -2
  279. package/dist/components/p-C0_8K4y7.js.map +0 -1
  280. package/dist/components/p-CA3kLO7K.js +0 -2
  281. package/dist/components/p-CA3kLO7K.js.map +0 -1
  282. package/dist/components/p-CCHqsF_H.js +0 -2
  283. package/dist/components/p-Cxpl-rzP.js +0 -2
  284. package/dist/components/p-CzBnvtcz.js +0 -2
  285. package/dist/components/p-CzBnvtcz.js.map +0 -1
  286. package/dist/components/p-Dg3xLna0.js +0 -2
  287. package/dist/components/p-XgIQ3oI_.js +0 -2
  288. /package/dist/components/{p-DcGpdIlT.js.map → p-9dQQSgwT.js.map} +0 -0
  289. /package/dist/components/{p-GMDGgtY8.js.map → p-BhxwpOH8.js.map} +0 -0
  290. /package/dist/components/{p-2W-ZjZCR.js.map → p-Biz6xo-z.js.map} +0 -0
  291. /package/dist/components/{p-CG5EX4NW.js.map → p-BtEjlcB9.js.map} +0 -0
  292. /package/dist/components/{p-D6jK2Hyi.js.map → p-C7bZ-jiU.js.map} +0 -0
  293. /package/dist/components/{p-DOCKtrS4.js.map → p-CH6cNXXF.js.map} +0 -0
  294. /package/dist/components/{p-BE_CDJeL.js.map → p-CY19gMiz.js.map} +0 -0
  295. /package/dist/components/{p-CHkI3oIS.js.map → p-Ce52yVXF.js.map} +0 -0
  296. /package/dist/components/{p-xY3TjBF5.js.map → p-CoYFJD-w.js.map} +0 -0
  297. /package/dist/components/{p-DBi1bmOL.js.map → p-CtD24EyI.js.map} +0 -0
  298. /package/dist/components/{p-BRLDJmkh.js.map → p-D-xttdpn.js.map} +0 -0
  299. /package/dist/components/{p-CNffejay.js.map → p-DSa0Hnd3.js.map} +0 -0
  300. /package/dist/components/{p-DyGB97Oy.js.map → p-DYqReipj.js.map} +0 -0
  301. /package/dist/components/{p-B8CubPgQ.js.map → p-g40DTeV8.js.map} +0 -0
package/dist/mcp/cli.js CHANGED
@@ -31121,6 +31121,54 @@ var IS_SOURCE_CHECKOUT = fs.existsSync(path.join(SOURCE_ROOT, "scripts", "build-
31121
31121
  var REGISTRY_DIR = IS_SOURCE_CHECKOUT ? path.resolve(SOURCE_ROOT, "public", "r") : path.resolve(__dirname, "..", "mcp-data", "registry");
31122
31122
  var PATTERN_DIR = path.resolve(SOURCE_ROOT, "agent", "patterns");
31123
31123
  var PATTERN_MANIFEST = path.resolve(__dirname, "..", "agent-patterns.json");
31124
+ var PACKAGE_ROOT = IS_SOURCE_CHECKOUT ? SOURCE_ROOT : path.resolve(__dirname, "..", "..");
31125
+ var PACKAGE_VERSION = JSON.parse(
31126
+ fs.readFileSync(path.join(PACKAGE_ROOT, "package.json"), "utf8")
31127
+ ).version;
31128
+ var READ_ONLY_TOOL_ANNOTATIONS = {
31129
+ readOnlyHint: true,
31130
+ destructiveHint: false,
31131
+ idempotentHint: true,
31132
+ openWorldHint: false
31133
+ };
31134
+ var JSON_OBJECT_SCHEMA = external_exports.record(external_exports.string(), external_exports.unknown());
31135
+ var COMPONENT_SUMMARY_SCHEMA = external_exports.object({
31136
+ name: external_exports.string(),
31137
+ title: external_exports.string(),
31138
+ description: external_exports.string(),
31139
+ type: external_exports.string(),
31140
+ status: external_exports.string(),
31141
+ audience: external_exports.string(),
31142
+ dependencies: external_exports.array(external_exports.string()),
31143
+ registryDependencies: external_exports.array(external_exports.string()),
31144
+ patterns: external_exports.array(external_exports.string())
31145
+ });
31146
+ var COMPONENT_LIST_OUTPUT_SCHEMA = external_exports.object({
31147
+ count: external_exports.number().int().nonnegative(),
31148
+ query: external_exports.string().nullable(),
31149
+ components: external_exports.array(COMPONENT_SUMMARY_SCHEMA)
31150
+ });
31151
+ var COMPONENT_OUTPUT_SCHEMA = external_exports.object({
31152
+ component: JSON_OBJECT_SCHEMA
31153
+ });
31154
+ var PATTERN_SUMMARY_SCHEMA = external_exports.object({
31155
+ id: external_exports.string(),
31156
+ status: external_exports.string(),
31157
+ summary: external_exports.string(),
31158
+ useWhen: external_exports.array(external_exports.string()),
31159
+ avoidWhen: external_exports.array(external_exports.string()),
31160
+ components: external_exports.array(external_exports.string()),
31161
+ frameworks: external_exports.array(external_exports.string())
31162
+ });
31163
+ var PATTERN_LIST_OUTPUT_SCHEMA = external_exports.object({
31164
+ count: external_exports.number().int().nonnegative(),
31165
+ query: external_exports.string().nullable(),
31166
+ patterns: external_exports.array(PATTERN_SUMMARY_SCHEMA)
31167
+ });
31168
+ var PATTERN_OUTPUT_SCHEMA = external_exports.object({
31169
+ framework: external_exports.enum(["customElements", "react", "angular"]).nullable(),
31170
+ pattern: JSON_OBJECT_SCHEMA
31171
+ });
31124
31172
  function ensureRegistry() {
31125
31173
  const registryPath = path.join(REGISTRY_DIR, "registry.json");
31126
31174
  if (!fs.existsSync(registryPath)) {
@@ -31168,6 +31216,41 @@ function loadPattern(name) {
31168
31216
  const normalized = name.replace(/^pattern:/, "").toLowerCase();
31169
31217
  return loadPatterns().find((pattern) => pattern.id === `pattern:${normalized}`) ?? null;
31170
31218
  }
31219
+ function componentSummary(component) {
31220
+ return {
31221
+ name: component.name,
31222
+ title: component.title,
31223
+ description: component.description,
31224
+ type: component.type,
31225
+ status: component.meta?.intent?.status ?? "unknown",
31226
+ audience: component.meta?.intent?.audience ?? "unknown",
31227
+ dependencies: component.dependencies ?? [],
31228
+ registryDependencies: component.registryDependencies ?? [],
31229
+ patterns: component.meta?.intent?.patterns ?? []
31230
+ };
31231
+ }
31232
+ function componentDetail(component) {
31233
+ const { files: _files, ...detail } = component;
31234
+ return detail;
31235
+ }
31236
+ function patternSummary(pattern) {
31237
+ return {
31238
+ id: pattern.id,
31239
+ status: pattern.status,
31240
+ summary: pattern.summary,
31241
+ useWhen: pattern.useWhen ?? [],
31242
+ avoidWhen: pattern.avoidWhen ?? [],
31243
+ components: (pattern.components ?? []).map((entry) => entry.component),
31244
+ frameworks: Object.entries(pattern.implementations ?? {}).filter(([, implementation]) => implementation.recipes?.length).map(([framework]) => framework)
31245
+ };
31246
+ }
31247
+ function patternDetail(pattern, framework) {
31248
+ if (!framework) return pattern;
31249
+ return {
31250
+ ...pattern,
31251
+ implementations: pattern.implementations?.[framework] ? { [framework]: pattern.implementations[framework] } : {}
31252
+ };
31253
+ }
31171
31254
  function formatSetupGuide() {
31172
31255
  const m = loadRegistry().meta;
31173
31256
  return `# @ds-mo/ui \u2014 Project Setup Guide
@@ -31247,16 +31330,18 @@ Never hardcode these values. The tokens support light/dark theming automatically
31247
31330
  }
31248
31331
  var server = new McpServer({
31249
31332
  name: "compomo",
31250
- version: "1.0.0"
31333
+ version: PACKAGE_VERSION
31251
31334
  });
31252
31335
  server.registerTool(
31253
31336
  "list_components",
31254
31337
  {
31255
31338
  title: "List Components",
31256
31339
  description: "List all available components in the @ds-mo/ui design system library. Returns component names, descriptions, and required packages.",
31257
- inputSchema: {
31340
+ inputSchema: external_exports.object({
31258
31341
  search: external_exports.string().optional().describe("Optional text to filter components by name or description.")
31259
- }
31342
+ }),
31343
+ outputSchema: COMPONENT_LIST_OUTPUT_SCHEMA,
31344
+ annotations: READ_ONLY_TOOL_ANNOTATIONS
31260
31345
  },
31261
31346
  async ({ search }) => {
31262
31347
  let items = loadRegistry().items;
@@ -31268,13 +31353,25 @@ server.registerTool(
31268
31353
  }
31269
31354
  if (items.length === 0) {
31270
31355
  return {
31271
- content: [{ type: "text", text: `No components found${search ? ` matching "${search}"` : ""}.` }]
31356
+ content: [{ type: "text", text: `No components found${search ? ` matching "${search}"` : ""}.` }],
31357
+ structuredContent: {
31358
+ count: 0,
31359
+ query: search ?? null,
31360
+ components: []
31361
+ }
31272
31362
  };
31273
31363
  }
31274
31364
  const text = `# @ds-mo/ui \u2014 ${items.length} component${items.length === 1 ? "" : "s"}${search ? ` matching "${search}"` : ""}
31275
31365
 
31276
31366
  ${formatComponentList(items)}`;
31277
- return { content: [{ type: "text", text }] };
31367
+ return {
31368
+ content: [{ type: "text", text }],
31369
+ structuredContent: {
31370
+ count: items.length,
31371
+ query: search ?? null,
31372
+ components: items.map(componentSummary)
31373
+ }
31374
+ };
31278
31375
  }
31279
31376
  );
31280
31377
  server.registerTool(
@@ -31282,9 +31379,11 @@ server.registerTool(
31282
31379
  {
31283
31380
  title: "Get Component",
31284
31381
  description: "Get detailed information about a specific @ds-mo/ui component including props API, import statements, setup instructions, peer dependencies, and full source code for reference.",
31285
- inputSchema: {
31382
+ inputSchema: external_exports.object({
31286
31383
  name: external_exports.string().describe('Component name in kebab-case (e.g., "button", "tab-group", "toggle-button") or PascalCase (e.g., "Button", "TabGroup").')
31287
- }
31384
+ }),
31385
+ outputSchema: COMPONENT_OUTPUT_SCHEMA,
31386
+ annotations: READ_ONLY_TOOL_ANNOTATIONS
31288
31387
  },
31289
31388
  async ({ name }) => {
31290
31389
  const kebab = name.replace(/([a-z])([A-Z])/g, "$1-$2").replace(/([A-Z])([A-Z][a-z])/g, "$1-$2").toLowerCase();
@@ -31302,14 +31401,18 @@ Available: ${allNames.join(", ")}`;
31302
31401
  isError: true
31303
31402
  };
31304
31403
  }
31305
- return { content: [{ type: "text", text: formatComponentDetail(comp) }] };
31404
+ return {
31405
+ content: [{ type: "text", text: formatComponentDetail(comp) }],
31406
+ structuredContent: { component: componentDetail(comp) }
31407
+ };
31306
31408
  }
31307
31409
  );
31308
31410
  server.registerTool(
31309
31411
  "get_setup_guide",
31310
31412
  {
31311
31413
  title: "Get Setup Guide",
31312
- description: "Get the full project setup guide for @ds-mo/ui \u2014 install commands, CSS imports, theme configuration, and design token architecture."
31414
+ description: "Get the full project setup guide for @ds-mo/ui \u2014 install commands, CSS imports, theme configuration, and design token architecture.",
31415
+ annotations: READ_ONLY_TOOL_ANNOTATIONS
31313
31416
  },
31314
31417
  async () => {
31315
31418
  return { content: [{ type: "text", text: formatSetupGuide() }] };
@@ -31320,9 +31423,10 @@ server.registerTool(
31320
31423
  {
31321
31424
  title: "Get Component Source",
31322
31425
  description: "Get the full source code of a @ds-mo/ui component for reference. Use this to understand implementation patterns, not to copy the code into a project.",
31323
- inputSchema: {
31426
+ inputSchema: external_exports.object({
31324
31427
  name: external_exports.string().describe('Component name in kebab-case (e.g., "button", "modal").')
31325
- }
31428
+ }),
31429
+ annotations: READ_ONLY_TOOL_ANNOTATIONS
31326
31430
  },
31327
31431
  async ({ name }) => {
31328
31432
  const kebab = name.replace(/([a-z])([A-Z])/g, "$1-$2").replace(/([A-Z])([A-Z][a-z])/g, "$1-$2").toLowerCase();
@@ -31352,9 +31456,11 @@ server.registerTool(
31352
31456
  {
31353
31457
  title: "List Patterns",
31354
31458
  description: "List supported @ds-mo/ui multi-component composition patterns with executable framework recipes.",
31355
- inputSchema: {
31459
+ inputSchema: external_exports.object({
31356
31460
  search: external_exports.string().optional().describe("Optional text to filter patterns by id, summary, or use case.")
31357
- }
31461
+ }),
31462
+ outputSchema: PATTERN_LIST_OUTPUT_SCHEMA,
31463
+ annotations: READ_ONLY_TOOL_ANNOTATIONS
31358
31464
  },
31359
31465
  async ({ search }) => {
31360
31466
  let patterns = loadPatterns();
@@ -31369,13 +31475,23 @@ server.registerTool(
31369
31475
  }
31370
31476
  if (!patterns.length) {
31371
31477
  return {
31372
- content: [{ type: "text", text: `No composition patterns found${search ? ` matching "${search}"` : ""}.` }]
31478
+ content: [{ type: "text", text: `No composition patterns found${search ? ` matching "${search}"` : ""}.` }],
31479
+ structuredContent: {
31480
+ count: 0,
31481
+ query: search ?? null,
31482
+ patterns: []
31483
+ }
31373
31484
  };
31374
31485
  }
31375
31486
  return {
31376
31487
  content: [{ type: "text", text: `# @ds-mo/ui \u2014 ${patterns.length} composition pattern${patterns.length === 1 ? "" : "s"}
31377
31488
 
31378
- ${formatPatternList(patterns)}` }]
31489
+ ${formatPatternList(patterns)}` }],
31490
+ structuredContent: {
31491
+ count: patterns.length,
31492
+ query: search ?? null,
31493
+ patterns: patterns.map(patternSummary)
31494
+ }
31379
31495
  };
31380
31496
  }
31381
31497
  );
@@ -31384,10 +31500,12 @@ server.registerTool(
31384
31500
  {
31385
31501
  title: "Get Pattern",
31386
31502
  description: "Get design intent, state ownership, accessibility requirements, and executable Custom Elements, React, or Angular recipes for an @ds-mo/ui composition.",
31387
- inputSchema: {
31503
+ inputSchema: external_exports.object({
31388
31504
  name: external_exports.string().describe('Pattern id or name, for example "menu-trigger" or "pattern:menu-trigger".'),
31389
31505
  framework: external_exports.enum(["customElements", "react", "angular"]).optional().describe("Return recipes only for this framework. Omit to return every implementation.")
31390
- }
31506
+ }),
31507
+ outputSchema: PATTERN_OUTPUT_SCHEMA,
31508
+ annotations: READ_ONLY_TOOL_ANNOTATIONS
31391
31509
  },
31392
31510
  async ({ name, framework }) => {
31393
31511
  const pattern = loadPattern(name);
@@ -31398,7 +31516,13 @@ server.registerTool(
31398
31516
  isError: true
31399
31517
  };
31400
31518
  }
31401
- return { content: [{ type: "text", text: formatPatternDetail(pattern, framework) }] };
31519
+ return {
31520
+ content: [{ type: "text", text: formatPatternDetail(pattern, framework) }],
31521
+ structuredContent: {
31522
+ framework: framework ?? null,
31523
+ pattern: patternDetail(pattern, framework)
31524
+ }
31525
+ };
31402
31526
  }
31403
31527
  );
31404
31528
  var transport = new StdioServerTransport();
@@ -141,7 +141,7 @@
141
141
  "files": [
142
142
  {
143
143
  "path": "src/wc/components/AgentSourceList/AgentSourceList.css",
144
- "content": ":host { display: block; }\n.agent-sources { border-block-start: var(--dimension-stroke-width-012) solid var(--color-border-tertiary); }\nsummary { align-items: center; cursor: pointer; display: flex; gap: var(--dimension-space-050); list-style: none; padding-block: var(--dimension-space-075); }\nsummary::-webkit-details-marker { display: none; }\ndetails[open] summary ds-icon { transform: rotate(90deg); }\nol { display: grid; gap: var(--dimension-space-075); margin: 0; padding: 0 0 var(--dimension-space-075) var(--dimension-space-150); }\nli { display: grid; gap: var(--dimension-space-025); }\na { align-items: center; color: inherit; display: inline-flex; gap: var(--dimension-space-025); width: fit-content; }\n\n@media (prefers-reduced-motion: no-preference) { summary ds-icon { transition: transform var(--effect-motion-short-2); } }\n",
144
+ "content": ":host { display: block; }\n.agent-sources { border-block-start: var(--dimension-stroke-width-012) solid var(--color-border-tertiary); }\nsummary { align-items: center; cursor: pointer; display: flex; gap: var(--dimension-space-050); list-style: none; padding-block: var(--dimension-space-075); }\nsummary::-webkit-details-marker { display: none; }\ndetails[open] summary ds-icon { transform: rotate(90deg); }\nol { display: grid; gap: var(--dimension-space-075); margin: 0; padding: 0 0 var(--dimension-space-075) var(--dimension-space-150); }\nli { display: grid; gap: var(--dimension-space-025); }\na { align-items: center; color: inherit; display: inline-flex; gap: var(--dimension-space-025); text-decoration-color: var(--color-foreground-tertiary); width: fit-content; }\n\n@media (prefers-reduced-motion: no-preference) { summary ds-icon { transition: transform var(--effect-motion-short-2); } }\n",
145
145
  "type": "registry:ui"
146
146
  },
147
147
  {
@@ -2,7 +2,7 @@
2
2
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
3
3
  "name": "bar-title",
4
4
  "title": "BarTitle",
5
- "description": "Page-level title chrome with optional route navigation, supporting description, inline active-section menu, one primary action, grouped overflow actions, and explicit expanded, compact, or constrained variants.",
5
+ "description": "Page-level title chrome with an optional expanded route breadcrumb, compact Back action, supporting description, inline active-section menu, one primary action, grouped overflow actions, and explicit expanded, compact, or constrained variants.",
6
6
  "type": "registry:ui",
7
7
  "meta": {
8
8
  "library": "@ds-mo/ui",
@@ -13,11 +13,11 @@
13
13
  "intent": {
14
14
  "audience": "general",
15
15
  "status": "stable",
16
- "summary": "Page-level title chrome with optional route navigation, supporting description, inline active-section menu, one primary action, grouped overflow actions, and explicit expanded, compact, or constrained variants.",
16
+ "summary": "Page-level title chrome with an optional expanded route breadcrumb, compact Back action, supporting description, inline active-section menu, one primary action, grouped overflow actions, and explicit expanded, compact, or constrained variants.",
17
17
  "useWhen": [
18
18
  "A top-level page needs one h1 above its content.",
19
19
  "A list or detail page has multiple route-level sections that belong in the inline active-section menu.",
20
- "A detail page needs a page-level Back action.",
20
+ "A detail page needs route ancestors in expanded presentation and a page-level Back action in compact chrome.",
21
21
  "A page needs one primary action plus optional secondary or destructive overflow commands."
22
22
  ],
23
23
  "avoidWhen": [
@@ -48,6 +48,7 @@
48
48
  "component:ds-shell-page",
49
49
  "component:ds-button-filled",
50
50
  "component:ds-button-unfilled",
51
+ "component:ds-breadcrumb",
51
52
  "component:ds-menu",
52
53
  "component:ds-text"
53
54
  ],
@@ -56,7 +57,8 @@
56
57
  ],
57
58
  "accessibility": [
58
59
  "Provide one concise heading; BarTitle renders exactly one h1 and changes only its visual recipe between variants.",
59
- "Give Back a destination-specific accessible name such as Back to Drivers, provide the concise parent label such as Drivers for the expanded breadcrumb, and handle dsBack in the route owner.",
60
+ "Give compact Back a destination-specific accessible name such as Back to Drivers and handle dsBack in the route owner.",
61
+ "Provide ordered breadcrumb items for deeper expanded paths and handle dsBreadcrumbSelect when native href navigation is not used; backLabel remains the single-parent expanded fallback.",
60
62
  "Keep value synchronized with the current child route; dsSectionChange returns the selected section id.",
61
63
  "Section and overflow triggers expose menu relationships and restore focus after selection or dismissal.",
62
64
  "Use one filled primary action in the page decision area and mark destructive overflow actions explicitly."
@@ -65,7 +67,8 @@
65
67
  "Omitting Back, sections, primaryAction, and actions produces the top-level title-only header.",
66
68
  "Two or more selectable sections add the inline section trigger; one section does not render a redundant menu.",
67
69
  "Dividers in sections or actions create separate Menu groups without becoming selectable rows.",
68
- "expanded renders the larger heading, optional description, inset divider, and an xs icon-label Back breadcrumb in the top inset. The title and right-side actions share one top alignment whether Back is present, while the description remains in the left title column; compact renders 48px chrome with inline Back; constrained uses compact chrome and moves an auto-collapse primary action into overflow.",
70
+ "The overflow trigger uses its bordered treatment whenever the primary action is visible beside it; overflow-only and auto-collapsed-primary presentations keep the trigger borderless.",
71
+ "expanded renders the larger heading, optional description, inset divider, and a full-width caption breadcrumb row above the title. The breadcrumb begins after 32px top padding; the following title and right-side actions share one top alignment. Compact renders 48px chrome with the existing icon Back action; constrained uses compact chrome and moves an auto-collapse primary action into overflow.",
69
72
  "primaryAction collapse defaults to auto. Use never for exceptional actions whose hierarchy must remain visible in constrained layouts."
70
73
  ],
71
74
  "responsiveBehavior": [
@@ -76,15 +79,15 @@
76
79
  ],
77
80
  "frameworkCaveats": {
78
81
  "customElements": [
79
- "Assign sections, primaryAction, and actions as JavaScript properties and replace array or object identities when controlled state changes.",
80
- "Handle dsBack in the router owner, update value after dsSectionChange, and execute product commands from dsAction."
82
+ "Assign breadcrumbs, sections, primaryAction, and actions as JavaScript properties and replace array or object identities when controlled state changes.",
83
+ "Handle dsBack for compact navigation and dsBreadcrumbSelect for application-owned expanded breadcrumb navigation, update value after dsSectionChange, and execute product commands from dsAction."
81
84
  ],
82
85
  "react": [
83
- "Pass arrays and objects directly to DsBarTitle and keep value controlled from route state.",
86
+ "Pass breadcrumb, section, and action arrays directly to DsBarTitle and keep value controlled from route state.",
84
87
  "Place DsBarTitle in DsShellPage with slot=header when automatic page behavior is required."
85
88
  ],
86
89
  "angular": [
87
- "Bind complex values on the standalone DsBarTitle adapter and handle the three intent events in the route shell.",
90
+ "Bind complex values on the standalone DsBarTitle adapter and handle Back, breadcrumb, section, and action intent events in the route shell.",
88
91
  "Place ds-bar-title in ds-shell-page with slot=header; do not render router-outlet inside BarTitle."
89
92
  ]
90
93
  },
@@ -138,7 +141,24 @@
138
141
  "default": "'Back'",
139
142
  "required": false,
140
143
  "mutable": false,
141
- "description": "Visible parent-page label used by the expanded Back breadcrumb."
144
+ "description": "Visible parent-page label used by the expanded breadcrumb when breadcrumbs is empty."
145
+ },
146
+ "breadcrumbAriaLabel": {
147
+ "type": "string",
148
+ "resolvedType": "string",
149
+ "attribute": "breadcrumb-aria-label",
150
+ "default": "'Breadcrumb'",
151
+ "required": false,
152
+ "mutable": false,
153
+ "description": "Accessible name for the expanded breadcrumb navigation landmark."
154
+ },
155
+ "breadcrumbs": {
156
+ "type": "BreadcrumbItem[]",
157
+ "resolvedType": "BreadcrumbItem[]",
158
+ "default": "[]",
159
+ "required": false,
160
+ "mutable": false,
161
+ "description": "Optional expanded ancestor path. Compact variants continue to use the Back action."
142
162
  },
143
163
  "description": {
144
164
  "type": "string",
@@ -227,6 +247,14 @@
227
247
  "composed": true,
228
248
  "description": "Emitted when the leading Back action is activated."
229
249
  },
250
+ {
251
+ "name": "dsBreadcrumbSelect",
252
+ "detail": "BreadcrumbSelectDetail",
253
+ "bubbles": true,
254
+ "cancelable": true,
255
+ "composed": true,
256
+ "description": "Emitted when an authored expanded breadcrumb item is activated."
257
+ },
230
258
  {
231
259
  "name": "dsSectionChange",
232
260
  "detail": "string",
@@ -273,7 +301,24 @@
273
301
  "default": "'Back'",
274
302
  "required": false,
275
303
  "mutable": false,
276
- "description": "Visible parent-page label used by the expanded Back breadcrumb."
304
+ "description": "Visible parent-page label used by the expanded breadcrumb when breadcrumbs is empty."
305
+ },
306
+ "breadcrumbAriaLabel": {
307
+ "type": "string",
308
+ "resolvedType": "string",
309
+ "attribute": "breadcrumb-aria-label",
310
+ "default": "'Breadcrumb'",
311
+ "required": false,
312
+ "mutable": false,
313
+ "description": "Accessible name for the expanded breadcrumb navigation landmark."
314
+ },
315
+ "breadcrumbs": {
316
+ "type": "BreadcrumbItem[]",
317
+ "resolvedType": "BreadcrumbItem[]",
318
+ "default": "[]",
319
+ "required": false,
320
+ "mutable": false,
321
+ "description": "Optional expanded ancestor path. Compact variants continue to use the Back action."
277
322
  },
278
323
  "description": {
279
324
  "type": "string",
@@ -362,6 +407,14 @@
362
407
  "composed": true,
363
408
  "description": "Emitted when the leading Back action is activated."
364
409
  },
410
+ {
411
+ "name": "dsBreadcrumbSelect",
412
+ "detail": "BreadcrumbSelectDetail",
413
+ "bubbles": true,
414
+ "cancelable": true,
415
+ "composed": true,
416
+ "description": "Emitted when an authored expanded breadcrumb item is activated."
417
+ },
365
418
  {
366
419
  "name": "dsSectionChange",
367
420
  "detail": "string",
@@ -393,7 +446,7 @@
393
446
  "import": "import { DsBarTitle } from '@ds-mo/ui/angular/ds-bar-title';",
394
447
  "example": "<ds-bar-title></ds-bar-title>"
395
448
  },
396
- "complexPropertyNote": "Assign these non-primitive values as JavaScript properties: actions, primaryAction, sections.",
449
+ "complexPropertyNote": "Assign these non-primitive values as JavaScript properties: actions, breadcrumbs, primaryAction, sections.",
397
450
  "peerDependencies": {
398
451
  "required": [
399
452
  "@ds-mo/tokens ^3.1.1",
@@ -409,6 +462,7 @@
409
462
  "@ds-mo/icons"
410
463
  ],
411
464
  "registryDependencies": [
465
+ "breadcrumb",
412
466
  "button-filled",
413
467
  "button-unfilled",
414
468
  "icon",
@@ -419,12 +473,12 @@
419
473
  "files": [
420
474
  {
421
475
  "path": "src/wc/components/BarTitle/BarTitle.css",
422
- "content": "@import '../../utils/control-density.css';\n@import '../../utils/focus-ring.css';\n@import '../../utils/interaction-fill.css';\n\n:host {\n display: block;\n min-width: 0;\n box-sizing: border-box;\n background: var(--color-background-primary);\n}\n\n:host([data-shell-page-syncing]) {\n visibility: hidden;\n}\n\n.bar-title {\n position: relative;\n min-width: 0;\n padding: 0;\n box-sizing: border-box;\n background: var(--color-background-primary);\n}\n\n.bar-title::after {\n content: '';\n position: absolute;\n inset: auto var(--dimension-space-400) 0;\n height: var(--dimension-stroke-width-012);\n background: var(--color-border-tertiary);\n pointer-events: none;\n}\n\n.bar-title__inner {\n position: relative;\n display: flex;\n flex-direction: column;\n align-items: stretch;\n gap: var(--dimension-space-100);\n padding: var(--dimension-space-400);\n box-sizing: border-box;\n}\n\n.bar-title__row {\n display: flex;\n align-items: flex-start;\n justify-content: space-between;\n gap: var(--dimension-space-100);\n min-height: var(--dimension-size-400);\n min-width: 0;\n}\n\n:host(.bar-title-host--expanded) .bar-title__row {\n gap: var(--dimension-space-400);\n}\n\n.bar-title__leading {\n display: flex;\n flex: 1 1 auto;\n flex-direction: column;\n gap: var(--dimension-space-050);\n min-width: 0;\n}\n\n/*\n * Pull the whole leading block up by exactly the breadcrumb row's own box\n * (its xs control-height + its top margin + the row-gap below it), so the\n * title row lands flush with the actions' top without moving actions.\n * Tied to the same tokens that size the breadcrumb, not a guessed pixel value.\n */\n:host(.bar-title-host--expanded.bar-title-host--has-back) .bar-title__leading {\n margin-block-start: calc(-1 * (var(--dimension-size-200) + var(--dimension-space-050) * 2));\n}\n\n.bar-title__title-row {\n display: flex;\n align-items: center;\n gap: var(--dimension-space-100);\n min-width: 0;\n min-height: var(--dimension-size-400);\n}\n\n.bar-title__identity {\n display: flex;\n flex: 0 1 auto;\n align-items: center;\n gap: var(--dimension-space-050);\n min-width: 0;\n}\n\n.bar-title__back,\n.bar-title__breadcrumb-back,\n.bar-title__section-chevron {\n flex: 0 0 auto;\n}\n\n.bar-title__breadcrumb {\n display: flex;\n align-items: center;\n min-width: 0;\n margin-block-start: var(--dimension-space-050);\n}\n\n.bar-title__heading {\n display: block;\n width: auto;\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n user-select: none;\n}\n\n.bar-title__divider {\n width: var(--dimension-stroke-width-012);\n height: var(--dimension-size-250);\n margin-inline-start: var(--dimension-space-100);\n flex: 0 0 var(--dimension-stroke-width-012);\n background: var(--color-border-tertiary);\n}\n\n.bar-title__section-selector {\n display: flex;\n flex: 0 1 auto;\n min-width: 0;\n max-width: var(--dimension-panel-width-sm);\n}\n\n.bar-title__section-trigger {\n --ds-control-radius: var(--dimension-radius-half);\n\n display: inline-flex;\n align-items: center;\n justify-content: center;\n gap: var(--ds-control-gap);\n height: var(--ds-control-height);\n min-width: 0;\n max-width: 100%;\n padding-inline: var(--ds-control-padding-inline);\n border: none;\n border-radius: var(--ds-control-radius);\n box-sizing: border-box;\n background: transparent;\n color: var(--color-foreground-secondary);\n cursor: pointer;\n font-family: inherit;\n user-select: none;\n transition: color var(--effect-motion-short-2);\n}\n\n.bar-title__section-trigger--expanded {\n color: var(--color-foreground-primary);\n}\n\n.bar-title__section-trigger--expanded::after,\n.bar-title__section-trigger--expanded:hover::after {\n background: var(--ds-interaction-pressed);\n}\n\n.bar-title__section-label {\n min-width: 0;\n padding-inline: var(--ds-control-label-inset);\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.bar-title__actions {\n display: flex;\n align-items: center;\n gap: var(--dimension-space-100);\n flex: 0 0 auto;\n}\n\n.bar-title__description {\n display: block;\n min-width: 0;\n max-width: 100%;\n}\n\n:host(.bar-title-host--compact) .bar-title {\n height: var(--dimension-size-600);\n padding: var(--dimension-space-100);\n}\n\n:host(.bar-title-host--compact) .bar-title::after {\n inset-inline: 0;\n}\n\n:host(.bar-title-host--compact) .bar-title__inner {\n height: 100%;\n padding: 0;\n gap: 0;\n}\n\n:host(.bar-title-host--compact) .bar-title__row {\n height: 100%;\n align-items: center;\n}\n\n:host(.bar-title-host--compact) .bar-title__identity {\n height: var(--dimension-size-400);\n}\n\n:host(.bar-title-host--compact) .bar-title__divider {\n margin-inline-start: 0;\n}\n\n:host(.bar-title-host--compact) .bar-title__heading {\n display: inline-flex;\n flex: 1 1 auto;\n align-items: center;\n height: var(--dimension-size-400);\n padding-inline: calc(var(--ds-control-padding-inline) + var(--ds-control-label-inset));\n box-sizing: border-box;\n}\n\n@media (prefers-reduced-motion: reduce) {\n .bar-title__section-trigger {\n transition: none;\n }\n}\n",
476
+ "content": "@import '../../utils/control-density.css';\n@import '../../utils/focus-ring.css';\n@import '../../utils/interaction-fill.css';\n\n:host {\n display: block;\n min-width: 0;\n box-sizing: border-box;\n background: var(--color-background-primary);\n}\n\n:host([data-shell-page-syncing]) {\n visibility: hidden;\n}\n\n.bar-title {\n position: relative;\n min-width: 0;\n padding: 0;\n box-sizing: border-box;\n background: var(--color-background-primary);\n}\n\n.bar-title::after {\n content: '';\n position: absolute;\n inset: auto var(--dimension-space-400) 0;\n height: var(--dimension-stroke-width-012);\n background: var(--color-border-tertiary);\n pointer-events: none;\n}\n\n.bar-title__inner {\n position: relative;\n display: flex;\n flex-direction: column;\n align-items: stretch;\n gap: var(--dimension-space-100);\n padding: var(--dimension-space-400);\n box-sizing: border-box;\n}\n\n.bar-title__row {\n display: flex;\n align-items: flex-start;\n justify-content: space-between;\n gap: var(--dimension-space-100);\n min-height: var(--dimension-size-400);\n min-width: 0;\n}\n\n:host(.bar-title-host--expanded) .bar-title__row {\n gap: var(--dimension-space-400);\n}\n\n.bar-title__leading {\n display: flex;\n flex: 1 1 auto;\n flex-direction: column;\n gap: var(--dimension-space-100);\n min-width: 0;\n}\n\n.bar-title__title-row {\n display: flex;\n align-items: center;\n gap: var(--dimension-space-100);\n min-width: 0;\n min-height: var(--dimension-size-400);\n}\n\n.bar-title__identity {\n display: flex;\n flex: 0 1 auto;\n align-items: center;\n gap: var(--dimension-space-050);\n min-width: 0;\n}\n\n.bar-title__back,\n.bar-title__section-chevron {\n flex: 0 0 auto;\n}\n\n.bar-title__breadcrumb {\n display: block;\n width: 100%;\n min-width: 0;\n}\n\n.bar-title__heading {\n display: block;\n width: auto;\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n user-select: none;\n}\n\n.bar-title__divider {\n width: var(--dimension-stroke-width-012);\n height: var(--dimension-size-250);\n margin-inline-start: var(--dimension-space-100);\n flex: 0 0 var(--dimension-stroke-width-012);\n background: var(--color-border-tertiary);\n}\n\n.bar-title__section-selector {\n display: flex;\n flex: 0 1 auto;\n min-width: 0;\n max-width: var(--dimension-panel-width-sm);\n}\n\n.bar-title__section-trigger {\n --ds-control-radius: var(--dimension-radius-half);\n\n display: inline-flex;\n align-items: center;\n justify-content: center;\n gap: var(--ds-control-gap);\n height: var(--ds-control-height);\n min-width: 0;\n max-width: 100%;\n padding-inline: var(--ds-control-padding-inline);\n border: none;\n border-radius: var(--ds-control-radius);\n box-sizing: border-box;\n background: transparent;\n color: var(--color-foreground-secondary);\n cursor: pointer;\n font-family: inherit;\n user-select: none;\n transition: color var(--effect-motion-short-2);\n}\n\n.bar-title__section-trigger--expanded {\n color: var(--color-foreground-primary);\n}\n\n.bar-title__section-trigger--expanded::after,\n.bar-title__section-trigger--expanded:hover::after {\n background: var(--ds-interaction-pressed);\n}\n\n.bar-title__section-label {\n min-width: 0;\n padding-inline: var(--ds-control-label-inset);\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.bar-title__actions {\n display: flex;\n align-items: center;\n gap: var(--dimension-space-100);\n flex: 0 0 auto;\n}\n\n.bar-title__description {\n display: block;\n min-width: 0;\n max-width: 100%;\n}\n\n:host(.bar-title-host--compact) .bar-title {\n height: var(--dimension-size-600);\n padding: var(--dimension-space-100);\n}\n\n:host(.bar-title-host--compact) .bar-title::after {\n inset-inline: 0;\n}\n\n:host(.bar-title-host--compact) .bar-title__inner {\n height: 100%;\n padding: 0;\n gap: 0;\n}\n\n:host(.bar-title-host--compact) .bar-title__row {\n height: 100%;\n align-items: center;\n}\n\n:host(.bar-title-host--compact) .bar-title__identity {\n height: var(--dimension-size-400);\n}\n\n:host(.bar-title-host--compact) .bar-title__divider {\n margin-inline-start: 0;\n}\n\n:host(.bar-title-host--compact) .bar-title__heading {\n display: inline-flex;\n flex: 1 1 auto;\n align-items: center;\n height: var(--dimension-size-400);\n padding-inline: calc(var(--ds-control-padding-inline) + var(--ds-control-label-inset));\n box-sizing: border-box;\n}\n\n@media (prefers-reduced-motion: reduce) {\n .bar-title__section-trigger {\n transition: none;\n }\n}\n",
423
477
  "type": "registry:ui"
424
478
  },
425
479
  {
426
480
  "path": "src/wc/components/BarTitle/BarTitle.tsx",
427
- "content": "import { Component, Event, EventEmitter, h, Host, Prop, State, Watch } from '@stencil/core';\nimport type { MenuItemData, MenuSection } from '../Menu/menu-types';\nimport {\n isBarTitleDivider,\n type BarTitleAction,\n type BarTitleActionItem,\n type BarTitlePrimaryAction,\n type BarTitleSection,\n type BarTitleSectionItem,\n type BarTitleVariant,\n} from './bar-title-types';\n\nlet nextBarTitleId = 0;\n\ntype FocusableButton = HTMLElement & { setFocus?: () => Promise<void> };\n\n@Component({\n tag: 'ds-bar-title',\n styleUrl: 'BarTitle.css',\n scoped: true,\n})\nexport class BarTitle {\n /** The page's single visible h1. */\n @Prop() heading!: string;\n\n /** Optional supporting copy shown in the expanded presentation. */\n @Prop() description: string = '';\n\n /** Show the leading page-level Back action. */\n @Prop({ attribute: 'show-back' }) showBack: boolean = false;\n\n /** Accessible name for the leading Back action. */\n @Prop() backAriaLabel: string = 'Back';\n\n /** Visible parent-page label used by the expanded Back breadcrumb. */\n @Prop() backLabel: string = 'Back';\n\n /** Optional page sections exposed through the active-section menu. */\n @Prop() sections: BarTitleSectionItem[] = [];\n\n /** Id of the active page section. */\n @Prop() value: string = '';\n\n /** Accessible name for the page-section menu. */\n @Prop() sectionsAriaLabel: string = 'Change page section';\n\n /** The one highest-emphasis page action. */\n @Prop() primaryAction: BarTitlePrimaryAction | null = null;\n\n /** Secondary page actions shown in the overflow menu. Dividers create groups. */\n @Prop() actions: BarTitleActionItem[] = [];\n\n /** Accessible name for the page-actions menu. */\n @Prop() actionsAriaLabel: string = 'More page actions';\n\n /** Explicit visual/capacity variant. ShellPage owns automatic selection. */\n @Prop() variant: BarTitleVariant = 'expanded';\n\n /** Emitted when the leading Back action is activated. */\n @Event() dsBack!: EventEmitter<MouseEvent>;\n\n /** Emitted with the newly selected page-section id. */\n @Event() dsSectionChange!: EventEmitter<string>;\n\n /** Emitted with the activated primary or overflow action id. */\n @Event() dsAction!: EventEmitter<string>;\n\n @State() private sectionMenuOpen = false;\n @State() private actionMenuOpen = false;\n @State() private sectionMenuInitialFocusVisible = false;\n @State() private actionMenuInitialFocusVisible = false;\n\n private readonly instanceId = nextBarTitleId++;\n private readonly sectionMenuTriggerId = `bar-title-section-trigger-${this.instanceId}`;\n private readonly sectionMenuId = `bar-title-section-menu-${this.instanceId}`;\n private readonly actionMenuTriggerId = `bar-title-action-trigger-${this.instanceId}`;\n private readonly actionMenuId = `bar-title-action-menu-${this.instanceId}`;\n private sectionTriggerEl: HTMLButtonElement | null = null;\n private actionTriggerEl: FocusableButton | null = null;\n\n @Watch('sections')\n handleSectionsChange() {\n if (!this.hasSectionSelector) this.closeSectionMenu();\n }\n\n @Watch('actions')\n @Watch('primaryAction')\n handleActionsChange() {\n if (!this.showActionMenuTrigger) this.closeActionMenu();\n }\n\n private get compact(): boolean {\n return this.variant !== 'expanded';\n }\n\n /** Tooltip copy is fixed and generic; backAriaLabel/actionsAriaLabel stay page-specific. */\n private get backTooltipLabel(): string {\n return 'Go back';\n }\n\n private get primaryCollapsed(): boolean {\n return (\n this.variant === 'constrained' &&\n this.primaryAction !== null &&\n (this.primaryAction.collapse ?? 'auto') === 'auto'\n );\n }\n\n private get selectableSections(): BarTitleSection[] {\n return this.sections.filter((item): item is BarTitleSection => !isBarTitleDivider(item));\n }\n\n private get hasSectionSelector(): boolean {\n return this.selectableSections.length > 1;\n }\n\n private get effectiveValue(): string {\n return this.selectableSections.some(section => section.id === this.value)\n ? this.value\n : (this.selectableSections[0]?.id ?? '');\n }\n\n private get selectedSectionLabel(): string {\n return this.selectableSections.find(section => section.id === this.effectiveValue)?.label ?? '';\n }\n\n private get sectionTriggerAriaLabel(): string {\n return `${this.sectionsAriaLabel}. Current section: ${this.selectedSectionLabel}`;\n }\n\n private groupsFromItems<T extends BarTitleSection | BarTitleAction>(\n source: Array<T | { type: 'divider' }>,\n map: (item: T) => MenuItemData\n ): MenuSection[] {\n const groups: MenuSection[] = [];\n let items: MenuItemData[] = [];\n const commit = () => {\n if (items.length > 0) groups.push({ items });\n items = [];\n };\n\n for (const item of source) {\n if (isBarTitleDivider(item)) {\n commit();\n } else {\n items.push(map(item));\n }\n }\n commit();\n return groups;\n }\n\n private get sectionMenuSections(): MenuSection[] {\n return this.groupsFromItems(this.sections, section => ({\n label: section.label,\n value: section.id,\n isSelected: section.id === this.effectiveValue,\n isInactive: section.isInactive,\n }));\n }\n\n private get selectableActions(): BarTitleAction[] {\n return this.actions.filter((item): item is BarTitleAction => !isBarTitleDivider(item));\n }\n\n private get showActionMenuTrigger(): boolean {\n return (\n this.selectableActions.length > 0 || (this.primaryCollapsed && this.primaryAction !== null)\n );\n }\n\n private actionMenuItem(action: BarTitleAction | BarTitlePrimaryAction): MenuItemData {\n const primary = action as BarTitlePrimaryAction;\n return {\n label: action.label,\n value: action.id,\n isInactive: action.isInactive || primary.isLoading,\n isDestructive: action.isDestructive || primary.intent === 'negative',\n };\n }\n\n private get actionMenuSections(): MenuSection[] {\n const groups = this.groupsFromItems(this.actions, action => this.actionMenuItem(action));\n if (!this.primaryCollapsed || !this.primaryAction) return groups;\n return [{ items: [this.actionMenuItem(this.primaryAction)] }, ...groups];\n }\n\n private toggleSectionMenu = (event: MouseEvent) => {\n this.sectionMenuInitialFocusVisible = event.detail === 0;\n this.actionMenuOpen = false;\n this.sectionMenuOpen = !this.sectionMenuOpen;\n };\n\n private closeSectionMenu = () => {\n this.sectionMenuOpen = false;\n };\n\n private handleSectionSelect = (event: CustomEvent<MenuItemData>) => {\n const id = String(event.detail?.value ?? '');\n const selected = this.selectableSections.find(section => section.id === id);\n if (!selected || selected.isInactive) return;\n this.closeSectionMenu();\n this.dsSectionChange.emit(id);\n requestAnimationFrame(() => this.sectionTriggerEl?.focus());\n };\n\n private toggleActionMenu = (event: MouseEvent) => {\n this.actionMenuInitialFocusVisible = event.detail === 0;\n this.sectionMenuOpen = false;\n this.actionMenuOpen = !this.actionMenuOpen;\n };\n\n private closeActionMenu = () => {\n this.actionMenuOpen = false;\n };\n\n private handleActionSelect = (event: CustomEvent<MenuItemData>) => {\n const id = String(event.detail?.value ?? '');\n const primaryMatches = this.primaryCollapsed && this.primaryAction?.id === id;\n const action = this.selectableActions.find(candidate => candidate.id === id);\n if (!primaryMatches && !action) return;\n if (\n (primaryMatches && (this.primaryAction?.isInactive || this.primaryAction?.isLoading)) ||\n action?.isInactive\n ) {\n return;\n }\n this.closeActionMenu();\n this.dsAction.emit(id);\n requestAnimationFrame(() => void this.actionTriggerEl?.setFocus?.());\n };\n\n private renderSectionSelector() {\n if (!this.hasSectionSelector) return null;\n return [\n <div class=\"bar-title__divider\" aria-hidden=\"true\" />,\n <div class=\"bar-title__section-selector\">\n <button\n ref={el => {\n this.sectionTriggerEl = el ?? null;\n }}\n id={this.sectionMenuTriggerId}\n class={{\n 'bar-title__section-trigger': true,\n 'bar-title__section-trigger--expanded': this.sectionMenuOpen,\n 'ds-control--md': true,\n 'ds-focus-ring-inset': true,\n 'ds-interaction-fill': true,\n }}\n type=\"button\"\n aria-haspopup=\"menu\"\n aria-controls={this.sectionMenuId}\n aria-expanded={String(this.sectionMenuOpen)}\n aria-label={this.sectionTriggerAriaLabel}\n onClick={this.toggleSectionMenu}\n >\n <ds-text\n class=\"bar-title__section-label ds-interaction-fill__content\"\n as=\"span\"\n variant=\"text-body-medium\"\n emphasis\n color=\"primary\"\n >\n {this.selectedSectionLabel}\n </ds-text>\n <ds-icon\n class=\"bar-title__section-chevron ds-interaction-fill__content\"\n name=\"ChevronUpDown\"\n size=\"md\"\n color=\"inherit\"\n aria-hidden=\"true\"\n />\n </button>\n </div>,\n ];\n }\n\n private renderActions() {\n const primary = this.primaryAction;\n if (!primary && !this.showActionMenuTrigger) return null;\n\n return (\n <div class=\"bar-title__actions\">\n {primary && !this.primaryCollapsed ? (\n <ds-button-filled\n class=\"bar-title__primary-action\"\n variant={primary.icon ? 'icon-label' : 'label'}\n icon={primary.icon ?? ''}\n label={primary.label}\n intent={primary.intent ?? 'brand'}\n contrast={primary.contrast ?? 'bold'}\n size=\"md\"\n type={primary.type ?? 'button'}\n isInactive={primary.isInactive}\n isLoading={primary.isLoading}\n onDsClick={() => this.dsAction.emit(primary.id)}\n />\n ) : null}\n {this.showActionMenuTrigger ? (\n <ds-tooltip label=\"Page options\" side=\"bottom\" size=\"sm\">\n <ds-button-unfilled\n ref={el => {\n this.actionTriggerEl = el ?? null;\n }}\n id={this.actionMenuTriggerId}\n class=\"bar-title__more-actions\"\n variant=\"icon\"\n icon=\"Ellipses\"\n aria-label={this.actionsAriaLabel}\n size=\"md\"\n activeFill={!this.compact}\n hasBorder={!this.compact && !this.primaryCollapsed}\n haspopup=\"menu\"\n controls={this.actionMenuId}\n expanded={this.actionMenuOpen}\n onDsClick={(event: CustomEvent<MouseEvent>) => this.toggleActionMenu(event.detail)}\n />\n </ds-tooltip>\n ) : null}\n </div>\n );\n }\n\n private renderBack(compact: boolean) {\n if (!this.showBack) return null;\n\n if (!compact) {\n return (\n <div class=\"bar-title__breadcrumb\">\n <ds-button-unfilled\n class=\"bar-title__breadcrumb-back\"\n variant=\"icon-label\"\n icon=\"ChevronLeft\"\n label={this.backLabel}\n aria-label={this.backAriaLabel}\n size=\"xs\"\n hasBorder={false}\n onDsClick={(event: CustomEvent<MouseEvent>) => this.dsBack.emit(event.detail)}\n />\n </div>\n );\n }\n\n return (\n <ds-tooltip label={this.backTooltipLabel} side=\"bottom\" size=\"sm\">\n <ds-button-unfilled\n class=\"bar-title__back\"\n variant=\"icon\"\n icon=\"ChevronLeft\"\n aria-label={this.backAriaLabel}\n size=\"md\"\n activeFill={false}\n hasBorder={false}\n onDsClick={(event: CustomEvent<MouseEvent>) => this.dsBack.emit(event.detail)}\n />\n </ds-tooltip>\n );\n }\n\n render() {\n const compact = this.compact;\n return (\n <Host\n class={{\n 'bar-title-host--compact': compact,\n 'bar-title-host--expanded': this.variant === 'expanded',\n 'bar-title-host--constrained': this.variant === 'constrained',\n 'bar-title-host--has-description': !!this.description,\n 'bar-title-host--has-back': this.showBack,\n }}\n >\n <div class=\"bar-title\">\n <div class=\"bar-title__inner\">\n <div class=\"bar-title__row\">\n <div class=\"bar-title__leading\">\n {!compact ? this.renderBack(false) : null}\n <div class=\"bar-title__title-row\">\n <div class=\"bar-title__identity\">\n {compact ? this.renderBack(true) : null}\n <ds-text\n class=\"bar-title__heading ds-control--md\"\n variant={compact ? 'text-title-small' : 'text-title-medium'}\n emphasis\n color=\"primary\"\n as=\"h1\"\n lineTruncation={1}\n >\n {this.heading}\n </ds-text>\n </div>\n {this.renderSectionSelector()}\n </div>\n {this.description && !compact ? (\n <ds-text\n class=\"bar-title__description\"\n variant=\"text-body-small\"\n color=\"secondary\"\n lineTruncation={2}\n wrap=\"wrap\"\n as=\"p\"\n >\n {this.description}\n </ds-text>\n ) : null}\n </div>\n {this.renderActions()}\n </div>\n </div>\n </div>\n\n {this.hasSectionSelector ? (\n <ds-menu\n id={this.sectionMenuId}\n class=\"bar-title__section-menu\"\n anchorId={this.sectionMenuTriggerId}\n menuLabel={this.sectionsAriaLabel}\n open={this.sectionMenuOpen}\n initialFocusVisible={this.sectionMenuInitialFocusVisible}\n sections={this.sectionMenuSections}\n onDsClose={this.closeSectionMenu}\n onDsSelect={this.handleSectionSelect}\n />\n ) : null}\n\n {this.showActionMenuTrigger ? (\n <ds-menu\n id={this.actionMenuId}\n class=\"bar-title__action-menu\"\n anchorId={this.actionMenuTriggerId}\n align=\"end\"\n menuLabel={this.actionsAriaLabel}\n open={this.actionMenuOpen}\n initialFocusVisible={this.actionMenuInitialFocusVisible}\n sections={this.actionMenuSections}\n onDsClose={this.closeActionMenu}\n onDsSelect={this.handleActionSelect}\n />\n ) : null}\n </Host>\n );\n }\n}\n",
481
+ "content": "import {\n Component,\n Element,\n Event,\n EventEmitter,\n h,\n Host,\n Prop,\n State,\n Watch,\n} from '@stencil/core';\nimport type { BreadcrumbItem, BreadcrumbSelectDetail } from '../Breadcrumb/breadcrumb-types';\nimport type { MenuItemData, MenuSection } from '../Menu/menu-types';\nimport {\n isBarTitleDivider,\n type BarTitleAction,\n type BarTitleActionItem,\n type BarTitlePrimaryAction,\n type BarTitleSection,\n type BarTitleSectionItem,\n type BarTitleVariant,\n} from './bar-title-types';\n\nlet nextBarTitleId = 0;\n\ntype FocusableButton = HTMLElement & { setFocus?: () => Promise<void> };\n\n@Component({\n tag: 'ds-bar-title',\n styleUrl: 'BarTitle.css',\n scoped: true,\n})\nexport class BarTitle {\n @Element() el!: HTMLElement;\n\n /** The page's single visible h1. */\n @Prop() heading!: string;\n\n /** Optional supporting copy shown in the expanded presentation. */\n @Prop() description: string = '';\n\n /** Show the leading page-level Back action. */\n @Prop({ attribute: 'show-back' }) showBack: boolean = false;\n\n /** Accessible name for the leading Back action. */\n @Prop() backAriaLabel: string = 'Back';\n\n /** Visible parent-page label used by the expanded breadcrumb when breadcrumbs is empty. */\n @Prop() backLabel: string = 'Back';\n\n /** Optional expanded ancestor path. Compact variants continue to use the Back action. */\n @Prop() breadcrumbs: BreadcrumbItem[] = [];\n\n /** Accessible name for the expanded breadcrumb navigation landmark. */\n @Prop() breadcrumbAriaLabel: string = 'Breadcrumb';\n\n /** Optional page sections exposed through the active-section menu. */\n @Prop() sections: BarTitleSectionItem[] = [];\n\n /** Id of the active page section. */\n @Prop() value: string = '';\n\n /** Accessible name for the page-section menu. */\n @Prop() sectionsAriaLabel: string = 'Change page section';\n\n /** The one highest-emphasis page action. */\n @Prop() primaryAction: BarTitlePrimaryAction | null = null;\n\n /** Secondary page actions shown in the overflow menu. Dividers create groups. */\n @Prop() actions: BarTitleActionItem[] = [];\n\n /** Accessible name for the page-actions menu. */\n @Prop() actionsAriaLabel: string = 'More page actions';\n\n /** Explicit visual/capacity variant. ShellPage owns automatic selection. */\n @Prop() variant: BarTitleVariant = 'expanded';\n\n /** Emitted when the leading Back action is activated. */\n @Event() dsBack!: EventEmitter<MouseEvent>;\n\n /** Emitted when an authored expanded breadcrumb item is activated. */\n @Event({ cancelable: true }) dsBreadcrumbSelect!: EventEmitter<BreadcrumbSelectDetail>;\n\n /** Emitted with the newly selected page-section id. */\n @Event() dsSectionChange!: EventEmitter<string>;\n\n /** Emitted with the activated primary or overflow action id. */\n @Event() dsAction!: EventEmitter<string>;\n\n @State() private sectionMenuOpen = false;\n @State() private actionMenuOpen = false;\n @State() private sectionMenuInitialFocusVisible = false;\n @State() private actionMenuInitialFocusVisible = false;\n\n private readonly instanceId = nextBarTitleId++;\n private readonly sectionMenuTriggerId = `bar-title-section-trigger-${this.instanceId}`;\n private readonly sectionMenuId = `bar-title-section-menu-${this.instanceId}`;\n private readonly actionMenuTriggerId = `bar-title-action-trigger-${this.instanceId}`;\n private readonly actionMenuId = `bar-title-action-menu-${this.instanceId}`;\n private sectionTriggerEl: HTMLButtonElement | null = null;\n private actionTriggerEl: FocusableButton | null = null;\n\n componentWillLoad() {\n if (this.el.closest('ds-shell-page')) {\n this.el.setAttribute('data-shell-page-syncing', '');\n }\n }\n\n @Watch('sections')\n handleSectionsChange() {\n if (!this.hasSectionSelector) this.closeSectionMenu();\n }\n\n @Watch('actions')\n @Watch('primaryAction')\n handleActionsChange() {\n if (!this.showActionMenuTrigger) this.closeActionMenu();\n }\n\n private get compact(): boolean {\n return this.variant !== 'expanded';\n }\n\n private get expandedBreadcrumbItems(): BreadcrumbItem[] {\n if (this.breadcrumbs.length > 0) return this.breadcrumbs;\n if (!this.showBack) return [];\n return [\n {\n id: 'back',\n label: this.backLabel,\n ariaLabel: this.backAriaLabel,\n },\n ];\n }\n\n /** Tooltip copy is fixed and generic; backAriaLabel/actionsAriaLabel stay page-specific. */\n private get backTooltipLabel(): string {\n return 'Go back';\n }\n\n private get primaryCollapsed(): boolean {\n return (\n this.variant === 'constrained' &&\n this.primaryAction !== null &&\n (this.primaryAction.collapse ?? 'auto') === 'auto'\n );\n }\n\n private get selectableSections(): BarTitleSection[] {\n return this.sections.filter((item): item is BarTitleSection => !isBarTitleDivider(item));\n }\n\n private get hasSectionSelector(): boolean {\n return this.selectableSections.length > 1;\n }\n\n private get effectiveValue(): string {\n return this.selectableSections.some(section => section.id === this.value)\n ? this.value\n : (this.selectableSections[0]?.id ?? '');\n }\n\n private get selectedSectionLabel(): string {\n return this.selectableSections.find(section => section.id === this.effectiveValue)?.label ?? '';\n }\n\n private get sectionTriggerAriaLabel(): string {\n return `${this.sectionsAriaLabel}. Current section: ${this.selectedSectionLabel}`;\n }\n\n private groupsFromItems<T extends BarTitleSection | BarTitleAction>(\n source: Array<T | { type: 'divider' }>,\n map: (item: T) => MenuItemData\n ): MenuSection[] {\n const groups: MenuSection[] = [];\n let items: MenuItemData[] = [];\n const commit = () => {\n if (items.length > 0) groups.push({ items });\n items = [];\n };\n\n for (const item of source) {\n if (isBarTitleDivider(item)) {\n commit();\n } else {\n items.push(map(item));\n }\n }\n commit();\n return groups;\n }\n\n private get sectionMenuSections(): MenuSection[] {\n return this.groupsFromItems(this.sections, section => ({\n label: section.label,\n value: section.id,\n isSelected: section.id === this.effectiveValue,\n isInactive: section.isInactive,\n }));\n }\n\n private get selectableActions(): BarTitleAction[] {\n return this.actions.filter((item): item is BarTitleAction => !isBarTitleDivider(item));\n }\n\n private get showActionMenuTrigger(): boolean {\n return (\n this.selectableActions.length > 0 || (this.primaryCollapsed && this.primaryAction !== null)\n );\n }\n\n private actionMenuItem(action: BarTitleAction | BarTitlePrimaryAction): MenuItemData {\n const primary = action as BarTitlePrimaryAction;\n return {\n label: action.label,\n value: action.id,\n isInactive: action.isInactive || primary.isLoading,\n isDestructive: action.isDestructive || primary.intent === 'negative',\n };\n }\n\n private get actionMenuSections(): MenuSection[] {\n const groups = this.groupsFromItems(this.actions, action => this.actionMenuItem(action));\n if (!this.primaryCollapsed || !this.primaryAction) return groups;\n return [{ items: [this.actionMenuItem(this.primaryAction)] }, ...groups];\n }\n\n private toggleSectionMenu = (event: MouseEvent) => {\n this.sectionMenuInitialFocusVisible = event.detail === 0;\n this.actionMenuOpen = false;\n this.sectionMenuOpen = !this.sectionMenuOpen;\n };\n\n private closeSectionMenu = () => {\n this.sectionMenuOpen = false;\n };\n\n private handleSectionSelect = (event: CustomEvent<MenuItemData>) => {\n const id = String(event.detail?.value ?? '');\n const selected = this.selectableSections.find(section => section.id === id);\n if (!selected || selected.isInactive) return;\n this.closeSectionMenu();\n this.dsSectionChange.emit(id);\n requestAnimationFrame(() => this.sectionTriggerEl?.focus());\n };\n\n private toggleActionMenu = (event: MouseEvent) => {\n this.actionMenuInitialFocusVisible = event.detail === 0;\n this.sectionMenuOpen = false;\n this.actionMenuOpen = !this.actionMenuOpen;\n };\n\n private closeActionMenu = () => {\n this.actionMenuOpen = false;\n };\n\n private handleActionSelect = (event: CustomEvent<MenuItemData>) => {\n const id = String(event.detail?.value ?? '');\n const primaryMatches = this.primaryCollapsed && this.primaryAction?.id === id;\n const action = this.selectableActions.find(candidate => candidate.id === id);\n if (!primaryMatches && !action) return;\n if (\n (primaryMatches && (this.primaryAction?.isInactive || this.primaryAction?.isLoading)) ||\n action?.isInactive\n ) {\n return;\n }\n this.closeActionMenu();\n this.dsAction.emit(id);\n requestAnimationFrame(() => void this.actionTriggerEl?.setFocus?.());\n };\n\n private renderSectionSelector() {\n if (!this.hasSectionSelector) return null;\n return [\n <div class=\"bar-title__divider\" aria-hidden=\"true\" />,\n <div class=\"bar-title__section-selector\">\n <button\n ref={el => {\n this.sectionTriggerEl = el ?? null;\n }}\n id={this.sectionMenuTriggerId}\n class={{\n 'bar-title__section-trigger': true,\n 'bar-title__section-trigger--expanded': this.sectionMenuOpen,\n 'ds-control--md': true,\n 'ds-focus-ring-inset': true,\n 'ds-interaction-fill': true,\n }}\n type=\"button\"\n aria-haspopup=\"menu\"\n aria-controls={this.sectionMenuId}\n aria-expanded={String(this.sectionMenuOpen)}\n aria-label={this.sectionTriggerAriaLabel}\n onClick={this.toggleSectionMenu}\n >\n <ds-text\n class=\"bar-title__section-label ds-interaction-fill__content\"\n as=\"span\"\n variant=\"text-body-medium\"\n emphasis\n color=\"primary\"\n >\n {this.selectedSectionLabel}\n </ds-text>\n <ds-icon\n class=\"bar-title__section-chevron ds-interaction-fill__content\"\n name=\"ChevronUpDown\"\n size=\"md\"\n color=\"inherit\"\n aria-hidden=\"true\"\n />\n </button>\n </div>,\n ];\n }\n\n private renderActions() {\n const primary = this.primaryAction;\n if (!primary && !this.showActionMenuTrigger) return null;\n\n return (\n <div class=\"bar-title__actions\">\n {primary && !this.primaryCollapsed ? (\n <ds-button-filled\n class=\"bar-title__primary-action\"\n variant={primary.icon ? 'icon-label' : 'label'}\n icon={primary.icon ?? ''}\n label={primary.label}\n intent={primary.intent ?? 'brand'}\n contrast={primary.contrast ?? 'bold'}\n size=\"md\"\n type={primary.type ?? 'button'}\n isInactive={primary.isInactive}\n isLoading={primary.isLoading}\n onDsClick={() => this.dsAction.emit(primary.id)}\n />\n ) : null}\n {this.showActionMenuTrigger ? (\n <ds-tooltip label=\"Page options\" side=\"bottom\" size=\"sm\">\n <ds-button-unfilled\n ref={el => {\n this.actionTriggerEl = el ?? null;\n }}\n id={this.actionMenuTriggerId}\n class=\"bar-title__more-actions\"\n variant=\"icon\"\n icon=\"Ellipses\"\n aria-label={this.actionsAriaLabel}\n size=\"md\"\n activeFill={!this.compact}\n hasBorder={primary !== null && !this.primaryCollapsed}\n haspopup=\"menu\"\n controls={this.actionMenuId}\n expanded={this.actionMenuOpen}\n onDsClick={(event: CustomEvent<MouseEvent>) => this.toggleActionMenu(event.detail)}\n />\n </ds-tooltip>\n ) : null}\n </div>\n );\n }\n\n private handleBreadcrumbSelect = (event: CustomEvent<BreadcrumbSelectDetail>) => {\n if (this.breadcrumbs.length === 0) {\n this.dsBack.emit(event.detail.originalEvent);\n return;\n }\n const forwarded = this.dsBreadcrumbSelect.emit(event.detail);\n if (forwarded.defaultPrevented) event.preventDefault();\n };\n\n private renderBreadcrumb() {\n const items = this.expandedBreadcrumbItems;\n if (items.length === 0) return null;\n return (\n <ds-breadcrumb\n class=\"bar-title__breadcrumb\"\n items={items}\n ariaLabel={this.breadcrumbAriaLabel}\n onDsSelect={this.handleBreadcrumbSelect}\n />\n );\n }\n\n private renderBack() {\n if (!this.showBack) return null;\n return (\n <ds-tooltip label={this.backTooltipLabel} side=\"bottom\" size=\"sm\">\n <ds-button-unfilled\n class=\"bar-title__back\"\n variant=\"icon\"\n icon=\"ChevronLeft\"\n aria-label={this.backAriaLabel}\n size=\"md\"\n activeFill={false}\n hasBorder={false}\n onDsClick={(event: CustomEvent<MouseEvent>) => this.dsBack.emit(event.detail)}\n />\n </ds-tooltip>\n );\n }\n\n render() {\n const compact = this.compact;\n return (\n <Host\n class={{\n 'bar-title-host--compact': compact,\n 'bar-title-host--expanded': this.variant === 'expanded',\n 'bar-title-host--constrained': this.variant === 'constrained',\n 'bar-title-host--has-description': !!this.description,\n 'bar-title-host--has-back': this.showBack,\n 'bar-title-host--has-breadcrumb': !compact && this.expandedBreadcrumbItems.length > 0,\n }}\n >\n <div class=\"bar-title\">\n <div class=\"bar-title__inner\">\n {!compact ? this.renderBreadcrumb() : null}\n <div class=\"bar-title__row\">\n <div class=\"bar-title__leading\">\n <div class=\"bar-title__title-row\" data-shell-page-header-anchor>\n <div class=\"bar-title__identity\">\n {compact ? this.renderBack() : null}\n <ds-text\n class=\"bar-title__heading ds-control--md\"\n variant={compact ? 'text-title-small' : 'text-title-medium'}\n emphasis\n color=\"primary\"\n as=\"h1\"\n lineTruncation={1}\n >\n {this.heading}\n </ds-text>\n </div>\n {this.renderSectionSelector()}\n </div>\n {this.description && !compact ? (\n <ds-text\n class=\"bar-title__description\"\n variant=\"text-body-small\"\n color=\"secondary\"\n lineTruncation={2}\n wrap=\"wrap\"\n as=\"p\"\n >\n {this.description}\n </ds-text>\n ) : null}\n </div>\n {this.renderActions()}\n </div>\n </div>\n </div>\n\n {this.hasSectionSelector ? (\n <ds-menu\n id={this.sectionMenuId}\n class=\"bar-title__section-menu\"\n anchorId={this.sectionMenuTriggerId}\n menuLabel={this.sectionsAriaLabel}\n open={this.sectionMenuOpen}\n initialFocusVisible={this.sectionMenuInitialFocusVisible}\n sections={this.sectionMenuSections}\n onDsClose={this.closeSectionMenu}\n onDsSelect={this.handleSectionSelect}\n />\n ) : null}\n\n {this.showActionMenuTrigger ? (\n <ds-menu\n id={this.actionMenuId}\n class=\"bar-title__action-menu\"\n anchorId={this.actionMenuTriggerId}\n align=\"end\"\n menuLabel={this.actionsAriaLabel}\n open={this.actionMenuOpen}\n initialFocusVisible={this.actionMenuInitialFocusVisible}\n sections={this.actionMenuSections}\n onDsClose={this.closeActionMenu}\n onDsSelect={this.handleActionSelect}\n />\n ) : null}\n </Host>\n );\n }\n}\n",
428
482
  "type": "registry:ui"
429
483
  },
430
484
  {