@ds-mo/ui 14.28.0 → 14.29.1

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 (216) hide show
  1. package/dist/.package-ready.json +1 -1
  2. package/dist/agent-patterns.json +27 -17
  3. package/dist/agent.json +149 -25
  4. package/dist/angular/ds-button-filled.d.ts +1 -1
  5. package/dist/angular/ds-button-filled.js +3 -3
  6. package/dist/angular/ds-button-unfilled.d.ts +1 -1
  7. package/dist/angular/ds-button-unfilled.js +3 -3
  8. package/dist/angular/ds-panel-nav.d.ts +1 -1
  9. package/dist/angular/ds-panel-nav.js +3 -3
  10. package/dist/angular/ds-panel-tool-header.d.ts +1 -1
  11. package/dist/angular/ds-panel-tool-header.js +3 -3
  12. package/dist/angular/ds-panel-tool-search.d.ts +1 -1
  13. package/dist/angular/ds-panel-tool-search.js +3 -3
  14. package/dist/angular/ds-table.d.ts +1 -1
  15. package/dist/angular/ds-table.js +3 -3
  16. package/dist/angular/ds-tag.d.ts +1 -1
  17. package/dist/angular/ds-tag.js +3 -3
  18. package/dist/components/ds-agent-questionnaire.js +1 -1
  19. package/dist/components/ds-agent-response.js +1 -1
  20. package/dist/components/ds-banner.js +1 -1
  21. package/dist/components/ds-bar-nav.js +1 -1
  22. package/dist/components/ds-bar-title.js +1 -1
  23. package/dist/components/ds-bar-workflow.js +1 -1
  24. package/dist/components/ds-button-filled.js +1 -1
  25. package/dist/components/ds-button-unfilled.js +1 -1
  26. package/dist/components/ds-card-chart.js +1 -1
  27. package/dist/components/ds-card-navigation.js +1 -1
  28. package/dist/components/ds-card-navigation.js.map +1 -1
  29. package/dist/components/ds-card-overview.js +1 -1
  30. package/dist/components/ds-card-overview.js.map +1 -1
  31. package/dist/components/ds-card-setting.js +1 -1
  32. package/dist/components/ds-chart-legend.js +1 -1
  33. package/dist/components/ds-chart-legend.js.map +1 -1
  34. package/dist/components/ds-checkbox.js +1 -1
  35. package/dist/components/ds-chip.js +1 -1
  36. package/dist/components/ds-code-block.js +1 -1
  37. package/dist/components/ds-conversation-list-item.js +1 -1
  38. package/dist/components/ds-conversation-list-item.js.map +1 -1
  39. package/dist/components/ds-filter-menu.js +1 -1
  40. package/dist/components/ds-input.js +1 -1
  41. package/dist/components/ds-markdown.js +1 -1
  42. package/dist/components/ds-menu.js +1 -1
  43. package/dist/components/ds-message-actions.js +1 -1
  44. package/dist/components/ds-message-composer.js +1 -1
  45. package/dist/components/ds-message-scroller.js +1 -1
  46. package/dist/components/ds-mobile-bar-nav.js +1 -1
  47. package/dist/components/ds-mobile-header.js +1 -1
  48. package/dist/components/ds-mobile-section-switcher.js +1 -1
  49. package/dist/components/ds-mobile-sheet-nav.js +1 -1
  50. package/dist/components/ds-modal.js +1 -1
  51. package/dist/components/ds-pagination.js +1 -1
  52. package/dist/components/ds-panel-nav.js +1 -1
  53. package/dist/components/ds-panel-sub-nav.js +1 -1
  54. package/dist/components/ds-panel-sub-nav.js.map +1 -1
  55. package/dist/components/ds-panel-tool-header.js +1 -1
  56. package/dist/components/ds-panel-tool-search.js +1 -1
  57. package/dist/components/ds-panel-tool-search.js.map +1 -1
  58. package/dist/components/ds-panel-tools.js +1 -1
  59. package/dist/components/ds-radio.js +1 -1
  60. package/dist/components/ds-select.js +1 -1
  61. package/dist/components/ds-shell-app.js +1 -1
  62. package/dist/components/ds-shell-app.js.map +1 -1
  63. package/dist/components/ds-shell-page.js +1 -1
  64. package/dist/components/ds-shell-tools.js +1 -1
  65. package/dist/components/ds-tab-group.js +1 -1
  66. package/dist/components/ds-table-filter.js +1 -1
  67. package/dist/components/ds-table-group.js +1 -1
  68. package/dist/components/ds-table-group.js.map +1 -1
  69. package/dist/components/ds-table-saved-views.js +1 -1
  70. package/dist/components/ds-table-saved-views.js.map +1 -1
  71. package/dist/components/ds-table-search.js +1 -1
  72. package/dist/components/ds-table-search.js.map +1 -1
  73. package/dist/components/ds-table-sort.js +1 -1
  74. package/dist/components/ds-table-sort.js.map +1 -1
  75. package/dist/components/ds-table.js +1 -1
  76. package/dist/components/ds-table.js.map +1 -1
  77. package/dist/components/ds-tag.js +1 -1
  78. package/dist/components/ds-textarea.js +1 -1
  79. package/dist/components/ds-textarea.js.map +1 -1
  80. package/dist/components/ds-toast.js +1 -1
  81. package/dist/components/p--yvQzZoO.js +2 -0
  82. package/dist/components/p--yvQzZoO.js.map +1 -0
  83. package/dist/components/p-B5AZd41L.js +2 -0
  84. package/dist/components/p-B5AZd41L.js.map +1 -0
  85. package/dist/components/p-B5eMVBlz.js +2 -0
  86. package/dist/components/p-B5eMVBlz.js.map +1 -0
  87. package/dist/components/p-BGnRFtBa.js +2 -0
  88. package/dist/components/p-BGnRFtBa.js.map +1 -0
  89. package/dist/components/p-BIDGQ4tc.js +2 -0
  90. package/dist/components/p-BIDGQ4tc.js.map +1 -0
  91. package/dist/components/p-BZDQLjE0.js +2 -0
  92. package/dist/components/p-BZDQLjE0.js.map +1 -0
  93. package/dist/components/{p-DmYZLH_L.js → p-BdC7wxhu.js} +2 -2
  94. package/dist/components/{p-DmYZLH_L.js.map → p-BdC7wxhu.js.map} +1 -1
  95. package/dist/components/p-BfVlFinS.js +2 -0
  96. package/dist/components/{p-WM1GTEun.js.map → p-BfVlFinS.js.map} +1 -1
  97. package/dist/components/p-BmRHJ_jo.js +2 -0
  98. package/dist/components/p-BmRHJ_jo.js.map +1 -0
  99. package/dist/components/{p-CxbGZJBU.js → p-BwAWZAHk.js} +2 -2
  100. package/dist/components/{p-8atLxerP.js → p-By5TDnbF.js} +2 -2
  101. package/dist/components/{p-BdXUd-tK.js → p-CDXcINTO.js} +2 -2
  102. package/dist/components/{p-BdXUd-tK.js.map → p-CDXcINTO.js.map} +1 -1
  103. package/dist/components/{p-DGHeKNfG.js → p-CE8gsv7V.js} +2 -2
  104. package/dist/components/p-CLcwh1kq.js +2 -0
  105. package/dist/components/p-CLcwh1kq.js.map +1 -0
  106. package/dist/components/p-CcK3UiTu.js +2 -0
  107. package/dist/components/{p-NB-SoVpo.js.map → p-CcK3UiTu.js.map} +1 -1
  108. package/dist/components/p-Cr5vn5JO.js +2 -0
  109. package/dist/components/{p-CsW_2w-s.js.map → p-Cr5vn5JO.js.map} +1 -1
  110. package/dist/components/{p-CW7JhWlS.js → p-Crd3PEUx.js} +2 -2
  111. package/dist/components/{p-CW7JhWlS.js.map → p-Crd3PEUx.js.map} +1 -1
  112. package/dist/components/{p-Kp8ifB1g.js → p-Ct90k-nz.js} +2 -2
  113. package/dist/components/{p-C82vesh_.js → p-Cx2dWjaW.js} +2 -2
  114. package/dist/components/p-CyoLh8su.js +2 -0
  115. package/dist/components/p-CyoLh8su.js.map +1 -0
  116. package/dist/components/p-CysCSinT.js +2 -0
  117. package/dist/components/{p-BdU6FPu4.js.map → p-CysCSinT.js.map} +1 -1
  118. package/dist/components/p-CzbsTZt7.js.map +1 -1
  119. package/dist/components/p-D1pPq-y0.js +2 -0
  120. package/dist/components/{p-BWDbER5T.js.map → p-D1pPq-y0.js.map} +1 -1
  121. package/dist/components/{p-B3iy9Rl_.js → p-DF8W85Tz.js} +2 -2
  122. package/dist/components/p-DZBB8BVn.js +2 -0
  123. package/dist/components/p-DZBB8BVn.js.map +1 -0
  124. package/dist/components/p-GbtafFds.js +2 -0
  125. package/dist/components/p-GbtafFds.js.map +1 -0
  126. package/dist/components/{p-B_NN7k8H.js → p-K39w53Bw.js} +2 -2
  127. package/dist/components/p-K39w53Bw.js.map +1 -0
  128. package/dist/components/p-frKsmPQn.js +2 -0
  129. package/dist/components/{p-CvB76TJn.js.map → p-frKsmPQn.js.map} +1 -1
  130. package/dist/docs/components.json +188 -6
  131. package/dist/lib/components/ButtonFilled/ButtonFilled.d.ts +11 -3
  132. package/dist/lib/components/PanelTools/panel-tools-types.d.ts +2 -0
  133. package/dist/lib/components/ShellApp/shell-app-types.d.ts +2 -0
  134. package/dist/lib/shell/index.js.map +1 -1
  135. package/dist/lib/utils/choice-list.d.ts +2 -0
  136. package/dist/mcp-data/registry/bar-nav.json +7 -2
  137. package/dist/mcp-data/registry/bar-title.json +8 -3
  138. package/dist/mcp-data/registry/button-filled.json +26 -5
  139. package/dist/mcp-data/registry/button-unfilled.json +27 -6
  140. package/dist/mcp-data/registry/filter-menu.json +7 -2
  141. package/dist/mcp-data/registry/mobile-section-switcher.json +8 -3
  142. package/dist/mcp-data/registry/panel-nav.json +27 -6
  143. package/dist/mcp-data/registry/panel-tool-header.json +23 -2
  144. package/dist/mcp-data/registry/panel-tool-search.json +23 -2
  145. package/dist/mcp-data/registry/panel-tools.json +7 -2
  146. package/dist/mcp-data/registry/registry.json +148 -24
  147. package/dist/mcp-data/registry/select.json +8 -3
  148. package/dist/mcp-data/registry/shell-app.json +8 -3
  149. package/dist/mcp-data/registry/shell-page.json +2 -1
  150. package/dist/mcp-data/registry/shell-tools.json +7 -2
  151. package/dist/mcp-data/registry/table-group.json +7 -2
  152. package/dist/mcp-data/registry/table-saved-views.json +7 -2
  153. package/dist/mcp-data/registry/table-search.json +7 -2
  154. package/dist/mcp-data/registry/table-sort.json +7 -2
  155. package/dist/mcp-data/registry/table.json +24 -3
  156. package/dist/mcp-data/registry/tag.json +24 -3
  157. package/dist/styles/table.css +1 -0
  158. package/dist/types/components/BarTitle/BarTitle.d.ts +3 -0
  159. package/dist/types/components/ButtonFilled/ButtonFilled.d.ts +11 -3
  160. package/dist/types/components/ButtonUnfilled/ButtonUnfilled.d.ts +11 -5
  161. package/dist/types/components/MobileSectionSwitcher/MobileSectionSwitcher.d.ts +2 -0
  162. package/dist/types/components/PanelNav/PanelNav.d.ts +4 -1
  163. package/dist/types/components/PanelToolHeader/PanelToolHeader.d.ts +2 -0
  164. package/dist/types/components/PanelToolSearch/PanelToolSearch.d.ts +2 -0
  165. package/dist/types/components/PanelTools/panel-tools-types.d.ts +2 -0
  166. package/dist/types/components/ShellApp/ShellApp.d.ts +1 -0
  167. package/dist/types/components/ShellApp/shell-app-types.d.ts +2 -0
  168. package/dist/types/components/Table/Table.d.ts +10 -0
  169. package/dist/types/components/Table/table-row-view.d.ts +6 -1
  170. package/dist/types/components/TableSort/TableSort.d.ts +1 -0
  171. package/dist/types/components/Tag/Tag.d.ts +3 -0
  172. package/dist/types/components.d.ts +69 -6
  173. package/dist/types/utils/choice-list.d.ts +2 -0
  174. package/dist/vue/ds-button-filled.js +1 -0
  175. package/dist/vue/ds-button-unfilled.js +1 -0
  176. package/dist/vue/ds-panel-nav.js +1 -0
  177. package/dist/vue/ds-panel-tool-header.js +1 -0
  178. package/dist/vue/ds-panel-tool-search.js +1 -0
  179. package/dist/vue/ds-table.js +1 -0
  180. package/dist/vue/ds-tag.js +1 -0
  181. package/package.json +1 -1
  182. package/dist/components/p-6iF6gdoc.js +0 -2
  183. package/dist/components/p-6iF6gdoc.js.map +0 -1
  184. package/dist/components/p-BWDbER5T.js +0 -2
  185. package/dist/components/p-B_NN7k8H.js.map +0 -1
  186. package/dist/components/p-BdU6FPu4.js +0 -2
  187. package/dist/components/p-Bj018KMC.js +0 -2
  188. package/dist/components/p-Bj018KMC.js.map +0 -1
  189. package/dist/components/p-BxLF8b8a.js +0 -2
  190. package/dist/components/p-BxLF8b8a.js.map +0 -1
  191. package/dist/components/p-C1BJgnHY.js +0 -2
  192. package/dist/components/p-C1BJgnHY.js.map +0 -1
  193. package/dist/components/p-C78uTz-n.js +0 -2
  194. package/dist/components/p-C78uTz-n.js.map +0 -1
  195. package/dist/components/p-COn7l__5.js +0 -2
  196. package/dist/components/p-COn7l__5.js.map +0 -1
  197. package/dist/components/p-CsW_2w-s.js +0 -2
  198. package/dist/components/p-CvB76TJn.js +0 -2
  199. package/dist/components/p-D4-RkuER.js +0 -2
  200. package/dist/components/p-D4-RkuER.js.map +0 -1
  201. package/dist/components/p-DB_tlJ2d.js +0 -2
  202. package/dist/components/p-DB_tlJ2d.js.map +0 -1
  203. package/dist/components/p-Hzz2j1Je.js +0 -2
  204. package/dist/components/p-Hzz2j1Je.js.map +0 -1
  205. package/dist/components/p-NB-SoVpo.js +0 -2
  206. package/dist/components/p-P9My22Z1.js +0 -2
  207. package/dist/components/p-P9My22Z1.js.map +0 -1
  208. package/dist/components/p-WM1GTEun.js +0 -2
  209. package/dist/components/p-oAbq-DLk.js +0 -2
  210. package/dist/components/p-oAbq-DLk.js.map +0 -1
  211. /package/dist/components/{p-CxbGZJBU.js.map → p-BwAWZAHk.js.map} +0 -0
  212. /package/dist/components/{p-8atLxerP.js.map → p-By5TDnbF.js.map} +0 -0
  213. /package/dist/components/{p-DGHeKNfG.js.map → p-CE8gsv7V.js.map} +0 -0
  214. /package/dist/components/{p-Kp8ifB1g.js.map → p-Ct90k-nz.js.map} +0 -0
  215. /package/dist/components/{p-C82vesh_.js.map → p-Cx2dWjaW.js.map} +0 -0
  216. /package/dist/components/{p-B3iy9Rl_.js.map → p-DF8W85Tz.js.map} +0 -0
package/dist/agent.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "schemaVersion": "1.0.0",
3
3
  "package": "@ds-mo/ui",
4
- "packageVersion": "14.28.0",
4
+ "packageVersion": "14.29.1",
5
5
  "kind": "components",
6
6
  "entries": [
7
7
  {
@@ -1121,7 +1121,8 @@
1121
1121
  "On non-tab detail routes, show the parent PanelNav destination label in BarNav while the detail-page title remains in page content.",
1122
1122
  "Dividers and groups visually organize peer route sections only and do not create hierarchy.",
1123
1123
  "The application filters unauthorized sections before passing tabs to BarNav.",
1124
- "Dashboard and Settings route state updates PanelNav groups, BarNav tabs, heading, basePath, currentUrl, and navStyle as one coordinated change."
1124
+ "Dashboard and Settings route state updates PanelNav groups, BarNav tabs, heading, basePath, currentUrl, and navStyle as one coordinated change.",
1125
+ "The overflow trigger automatically retains the shared surface-open wash through menu exit, separately from the selected route."
1125
1126
  ],
1126
1127
  "responsiveBehavior": [
1127
1128
  "Keep the BarNav region present so shell height and main-content origin remain stable across routes.",
@@ -1154,6 +1155,10 @@
1154
1155
  {
1155
1156
  "label": "Application shell composition",
1156
1157
  "path": "agent/patterns/application-shell/pattern.agent.json"
1158
+ },
1159
+ {
1160
+ "label": "Surface ownership and trigger state",
1161
+ "path": "src/docs/SurfaceOwnership.mdx"
1157
1162
  }
1158
1163
  ]
1159
1164
  },
@@ -1284,7 +1289,8 @@
1284
1289
  "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.",
1285
1290
  "The one visible ordered action collapses by default in constrained presentation. Use never for an exceptional action whose hierarchy must remain visible; explicit overflow actions never leave the shared menu.",
1286
1291
  "showDivider=false removes the bottom divider when the surrounding page composition supplies the boundary; showCompactDivider can independently restore or remove that boundary in compact and constrained variants.",
1287
- "placement=shell-bar is reserved for ShellApp panel section navigation. It remains compact, omits description and breadcrumb presentation, and preserves applicable Back, section, primary, and overflow controls."
1292
+ "placement=shell-bar is reserved for ShellApp panel section navigation. It remains compact, omits description and breadcrumb presentation, and preserves applicable Back, section, primary, and overflow controls.",
1293
+ "Section, action, split-menu, and overflow triggers automatically retain the shared surface-open wash through exit. The expanded header presentation is layout, not surface ownership, and does not itself acquire a pressed wash."
1288
1294
  ],
1289
1295
  "responsiveBehavior": [
1290
1296
  "BarTitle does not observe viewport, shell, scroll, or container state. Its owner selects an explicit variant.",
@@ -1321,6 +1327,10 @@
1321
1327
  {
1322
1328
  "label": "Cross-browser shell-page and header coverage",
1323
1329
  "path": "tests/e2e/bar-title.spec.ts"
1330
+ },
1331
+ {
1332
+ "label": "Surface ownership and trigger state",
1333
+ "path": "src/docs/SurfaceOwnership.mdx"
1324
1334
  }
1325
1335
  ]
1326
1336
  },
@@ -1795,10 +1805,11 @@
1795
1805
  "Physical press scaling is on by default. Disable it only when an owning composite must keep child or background geometry fixed; hover and pressed interaction washes remain available.",
1796
1806
  "Visible labels are emphasized by default. Set labelEmphasis to false when a composed surface deliberately needs the button label to match adjacent regular-weight control labels; this does not change the action hierarchy, foreground, icon, or interaction states.",
1797
1807
  "ButtonFilled has no active, pressed, or selected state; a filled action is a command, not a toggle or a persistent selection.",
1798
- "An open popup is a transient pressed state instead. While expanded is true the pressed wash is held for the popup's complete rendered lifecycle and survives hover, so the trigger reads as held open without introducing a selected treatment.",
1808
+ "An open popup is a transient pressed state instead. While surfaceOpen is true the pressed wash is held for the popup's complete rendered lifecycle and survives hover, so the trigger reads as held open without introducing a selected treatment.",
1799
1809
  "hasMenu supports only the label and icon-label variants. The chevron is what communicates that a menu will open, so an icon-only filled menu button would leave the affordance unstated.",
1800
1810
  "Split mode supports label, icon, and icon-label primary segments. The primary segment emits dsClick and the appended menu segment emits dsMenuClick.",
1801
- "Split mode keeps both segments flush and uses a tertiary on-background separator. Rounded changes the shared outer radius without separating the segments."
1811
+ "Split mode keeps both segments flush and uses a tertiary on-background separator. Rounded changes the shared outer radius without separating the segments.",
1812
+ "Use surfaceOpen to identify this command as the owner of a visible menu, picker, or panel, even when that surface is distant. Keep the pressed wash through exit motion without adding selected styling or sustained physical scaling. Inline expansion and completed commands do not acquire this treatment."
1802
1813
  ],
1803
1814
  "responsiveBehavior": [
1804
1815
  "Use fill width only when the parent layout calls for a full-width action, commonly on narrow form layouts."
@@ -1818,6 +1829,10 @@
1818
1829
  {
1819
1830
  "label": "Storybook examples",
1820
1831
  "path": "src/wc/components/ButtonFilled/ButtonFilled.stories.ts"
1832
+ },
1833
+ {
1834
+ "label": "Surface ownership and trigger state",
1835
+ "path": "src/docs/SurfaceOwnership.mdx"
1821
1836
  }
1822
1837
  ]
1823
1838
  },
@@ -1907,6 +1922,10 @@
1907
1922
  "type": "boolean",
1908
1923
  "required": false
1909
1924
  },
1925
+ "surfaceOpen": {
1926
+ "type": "boolean | undefined",
1927
+ "required": false
1928
+ },
1910
1929
  "type": {
1911
1930
  "type": "'button' | 'submit' | 'reset'",
1912
1931
  "required": false
@@ -2002,7 +2021,7 @@
2002
2021
  "accessibility": [
2003
2022
  "Provide an explicit accessible name for every icon-only action.",
2004
2023
  "In split mode, provide menuAriaLabel for the appended ChevronDown segment, pass controls with the Menu id, and synchronize expanded with the Menu open state.",
2005
- "Set hasMenu when the button triggers a Menu; it implies aria-haspopup of menu. Pass controls with the Menu id and expanded from the same open state given to Menu. Expanded popup triggers hold only the pressed wash while open, without changing their resting foreground; expanded disclosure controls without popup semantics retain the normal resting appearance.",
2024
+ "Set hasMenu when the button triggers a Menu; it implies aria-haspopup of menu. Pass controls with the Menu id and expanded from the same open state given to Menu. Surface-open popup triggers hold only the pressed wash while rendered, without changing their resting foreground; expanded disclosure controls without popup semantics retain the normal resting appearance.",
2006
2025
  "Give an icon-only menu button an accessible name that states the role, such as More options or Customize table, because no visible label or chevron carries it.",
2007
2026
  "Use haspopup directly for a non-menu popup such as a listbox or dialog; those cases get no chevron.",
2008
2027
  "Use pressed only for a genuine toggle button; it supplies aria-pressed and dsChange intent. Use isActive only for owner-controlled visual emphasis inside a composite whose selection semantics live on the owner.",
@@ -2027,9 +2046,10 @@
2027
2046
  "Icon and icon-label loading replace the icon in place. Label-only loading centers the loader while preserving the button's measured width.",
2028
2047
  "hasMenu covers two distinct menu-button shapes and the variant selects between them. With label or icon-label the action has a menu, and a trailing chevron carries the affordance. With icon the button is a menu and no chevron is added.",
2029
2048
  "Because the icon-only shape has no chevron, its glyph must convey the menu on its own. Use Ellipses for a generic more-options or overflow control. Use a specific icon when the menu has a named purpose, such as Table for Customize table.",
2030
- "An open popup is a transient pressed state rather than a selected one. While expanded is true and haspopup or hasMenu identifies a popup, the pressed wash is held for the popup's complete rendered lifecycle and survives hover without promoting foreground or selected fill, including when chrome opts out of selected fills with activeFill set to false. Expanded disclosure buttons without popup semantics remain visually neutral.",
2049
+ "An open popup is a transient pressed state rather than a selected one. While surfaceOpen is true, the pressed wash is held for the popup's complete rendered lifecycle and survives hover without promoting foreground or selected fill, including when chrome opts out of selected fills with activeFill set to false. Expanded disclosure buttons without popup semantics remain visually neutral.",
2031
2050
  "Split mode supports label, icon, and icon-label primary segments. The primary segment emits dsClick and the appended menu segment emits dsMenuClick.",
2032
- "Split mode keeps both segments flush and uses a tertiary surface-aware separator. Bordered mode also preserves the shared outer border; borderless mode limits the separator to the content line height."
2051
+ "Split mode keeps both segments flush and uses a tertiary surface-aware separator. Bordered mode also preserves the shared outer border; borderless mode limits the separator to the content line height.",
2052
+ "Use surfaceOpen to identify the owner of a visible menu, picker, or panel, even when it is distant. Preserve it through exit motion independently of expanded semantics, pressed toggles, and isActive selection. It preserves resting foreground and does not hold physical scaling. Inline expansion and last-click history do not acquire this treatment."
2033
2053
  ],
2034
2054
  "responsiveBehavior": [
2035
2055
  "The consuming layout decides when an icon-label action becomes icon-only and must provide an explicit accessible name after changing variants. Table caption Customize is one such layout: below 900px it uses the icon shape while keeping the same neutral resting foreground regardless of the controlled column configuration.",
@@ -2052,6 +2072,10 @@
2052
2072
  {
2053
2073
  "label": "Storybook examples",
2054
2074
  "path": "src/wc/components/ButtonUnfilled/ButtonUnfilled.stories.ts"
2075
+ },
2076
+ {
2077
+ "label": "Surface ownership and trigger state",
2078
+ "path": "src/docs/SurfaceOwnership.mdx"
2055
2079
  }
2056
2080
  ]
2057
2081
  },
@@ -2157,6 +2181,10 @@
2157
2181
  "type": "boolean",
2158
2182
  "required": false
2159
2183
  },
2184
+ "surfaceOpen": {
2185
+ "type": "boolean | undefined",
2186
+ "required": false
2187
+ },
2160
2188
  "type": {
2161
2189
  "type": "'button' | 'submit' | 'reset'",
2162
2190
  "required": false
@@ -4152,7 +4180,8 @@
4152
4180
  "Range selection applies the first date immediately as a one-day range; while an end is pending, that selected start retains its bold treatment and hovering or focusing another day paints the rest of the provisional inclusive span faint without emitting a value. A second activation completes an ordered inclusive range and gives both edges the bold treatment. A new activation after completion starts a replacement range.",
4153
4181
  "Selection applies immediately and does not close the popup.",
4154
4182
  "Changing category replaces the option-pane subtree so checkbox and other option visuals mount in their new state instead of transitioning from the previous category's row state.",
4155
- "The trigger reports how many filter categories have selections. footerLayout=summary adds a full-width selected-count footer only while values are selected; footerLayout=categories-clear always reserves the category-pane footer height while keeping its inactive divider hidden, then reveals the divider and only its left-aligned Clear action while values are selected."
4183
+ "The trigger reports how many filter categories have selections. footerLayout=summary adds a full-width selected-count footer only while values are selected; footerLayout=categories-clear always reserves the category-pane footer height while keeping its inactive divider hidden, then reveals the divider and only its left-aligned Clear action while values are selected.",
4184
+ "The built-in trigger derives the shared surface-open wash from the rendered popup lifecycle, including closing. For an external trigger, the application owns that relationship and retains the wash until dsAfterClose; selected filter values remain independent."
4156
4185
  ],
4157
4186
  "responsiveBehavior": [
4158
4187
  "The popup defaults to the large menu-width token and clamps to the nearest data-ds-overlay-boundary rectangle or the viewport fallback.",
@@ -4175,6 +4204,10 @@
4175
4204
  {
4176
4205
  "label": "Storybook example",
4177
4206
  "path": "src/wc/components/FilterMenu/FilterMenu.stories.ts"
4207
+ },
4208
+ {
4209
+ "label": "Surface ownership and trigger state",
4210
+ "path": "src/docs/SurfaceOwnership.mdx"
4178
4211
  }
4179
4212
  ]
4180
4213
  },
@@ -5936,7 +5969,8 @@
5936
5969
  "Dividers group menu items but never participate in previous or next resolution.",
5937
5970
  "The anchored local-view menu retains its neighboring-direction hints; the primary-page sheet uses an unfilled perimeter trigger without hints.",
5938
5971
  "A sheet trigger can combine stable page identity and the current local view, separated by a decorative middle dot. The whole control opens only the supplied local destinations; long page names truncate before crowding out the active view.",
5939
- "Sheet selection emits navigation intent immediately while exit motion runs independently, so the controlled title can update without waiting for dismissal. Removing the owner or hiding its header closes the top layer without leaving the application blocked."
5972
+ "Sheet selection emits navigation intent immediately while exit motion runs independently, so the controlled title can update without waiting for dismissal. Removing the owner or hiding its header closes the top layer without leaving the application blocked.",
5973
+ "The trigger automatically retains the shared surface-open pressed wash through menu or sheet exit. Selecting a destination remains separate from owning the open surface."
5940
5974
  ],
5941
5975
  "responsiveBehavior": [
5942
5976
  "Use only in the dedicated mobile header presentation."
@@ -5945,6 +5979,10 @@
5945
5979
  {
5946
5980
  "label": "Storybook",
5947
5981
  "path": "src/wc/components/MobileSectionSwitcher/MobileSectionSwitcher.stories.ts"
5982
+ },
5983
+ {
5984
+ "label": "Surface ownership and trigger state",
5985
+ "path": "src/docs/SurfaceOwnership.mdx"
5948
5986
  }
5949
5987
  ]
5950
5988
  },
@@ -6526,9 +6564,10 @@
6526
6564
  "Dashboard presents day-to-day operational destinations; Settings presents administrative and configuration destinations.",
6527
6565
  "The standard footer switches the entire destination collection and navStyle between Dashboard and Settings and exposes the user/account entry.",
6528
6566
  "The host owns the external user menu opened from dsNavUserAction.",
6529
- "While the external user menu is open or closing, accountMenuExpanded keeps its trigger visibly pressed without applying selected-destination foreground treatment in either expanded or collapsed presentation.",
6567
+ "While the external user menu is open or closing, accountMenuSurfaceOpen keeps its trigger visibly pressed without applying selected-destination foreground treatment in either expanded or collapsed presentation.",
6530
6568
  "Item and header controls inherit the shared md control radius while local shell geometry continues to own collapsed layout and footer animation positioning.",
6531
- "On desktop, allow user-controlled expand and collapse and persist the preference with storageKey when cross-session persistence is appropriate."
6569
+ "On desktop, allow user-controlled expand and collapse and persist the preference with storageKey when cross-session persistence is appropriate.",
6570
+ "Flyout triggers automatically hold the shared surface-open wash through exit; expanded inline branches do not. For the external account surface, the application supplies accountMenuSurfaceOpen for its rendered lifetime and keeps accountMenuExpanded tied to disclosure semantics."
6532
6571
  ],
6533
6572
  "responsiveBehavior": [
6534
6573
  "At 1200px and wider, default to expanded, allow the user to expand or collapse, and restore the locally persisted desktop preference when available.",
@@ -6566,6 +6605,10 @@
6566
6605
  {
6567
6606
  "label": "Application shell composition",
6568
6607
  "path": "agent/patterns/application-shell/pattern.agent.json"
6608
+ },
6609
+ {
6610
+ "label": "Surface ownership and trigger state",
6611
+ "path": "src/docs/SurfaceOwnership.mdx"
6569
6612
  }
6570
6613
  ]
6571
6614
  },
@@ -6579,6 +6622,10 @@
6579
6622
  "type": "boolean",
6580
6623
  "required": false
6581
6624
  },
6625
+ "accountMenuSurfaceOpen": {
6626
+ "type": "boolean | undefined",
6627
+ "required": false
6628
+ },
6582
6629
  "activeChildId": {
6583
6630
  "type": "string",
6584
6631
  "required": false
@@ -6870,7 +6917,8 @@
6870
6917
  "Header chrome text is not selectable; actions remain keyboard focusable and interactive.",
6871
6918
  "Adjacent trailing actions keep the shared 4px control gap in drawer and fullscreen presentations.",
6872
6919
  "When fullscreen and overflow actions appear together, author fullscreen before overflow so Ellipses remains the rightmost action.",
6873
- "PanelTools supplies application-owned actions and relays their ids through its shared dsHeaderAction event."
6920
+ "PanelTools supplies application-owned actions and relays their ids through its shared dsHeaderAction event.",
6921
+ "Application-owned action surfaces carry surfaceOpen independently from expanded disclosure and pressed toggle state. Retain surfaceOpen until the associated surface completes closing; the header forwards this relationship without owning the menu or panel."
6874
6922
  ],
6875
6923
  "responsiveBehavior": [
6876
6924
  "The title truncates between optional leading navigation and trailing action zones."
@@ -6879,6 +6927,10 @@
6879
6927
  {
6880
6928
  "label": "Standalone examples",
6881
6929
  "path": "src/wc/components/PanelToolHeader/PanelToolHeader.stories.ts"
6930
+ },
6931
+ {
6932
+ "label": "Surface ownership and trigger state",
6933
+ "path": "src/docs/SurfaceOwnership.mdx"
6882
6934
  }
6883
6935
  ]
6884
6936
  },
@@ -6912,6 +6964,10 @@
6912
6964
  "type": "boolean",
6913
6965
  "required": false
6914
6966
  },
6967
+ "menuSurfaceOpen": {
6968
+ "type": "boolean | undefined",
6969
+ "required": false
6970
+ },
6915
6971
  "menuTriggerId": {
6916
6972
  "type": "string",
6917
6973
  "required": false
@@ -6992,7 +7048,8 @@
6992
7048
  "The search icon stays foreground-secondary at rest, hover, focus, active, and while the query is filled.",
6993
7049
  "The row and control surface remain transparent so the ShellApp chrome wash is visible behind them.",
6994
7050
  "The row divider remains the same tertiary 1px boundary while the input is focused because it belongs to the 48px container rather than the input control.",
6995
- "With filtering enabled, the md search control, decorative vertical divider, and borderless md Filter action are separated by 8px; filterActive promotes only the trigger foreground without adding a selected fill."
7051
+ "With filtering enabled, the md search control, decorative vertical divider, and borderless md Filter action are separated by 8px; filterActive promotes only the trigger foreground without adding a selected fill.",
7052
+ "Applied filters and an open filter surface are independent states. Use filterSurfaceOpen through the external surface exit while filterExpanded describes disclosure and filterActive describes applied values."
6996
7053
  ],
6997
7054
  "responsiveBehavior": [
6998
7055
  "The row fills the available drawer or fullscreen width, allows its search region to shrink inside a 300px drawer without pushing the filter trigger under the tool rail, and does not reduce its control below md density."
@@ -7015,6 +7072,10 @@
7015
7072
  {
7016
7073
  "label": "Storybook examples",
7017
7074
  "path": "src/wc/components/PanelToolSearch/PanelToolSearch.stories.ts"
7075
+ },
7076
+ {
7077
+ "label": "Surface ownership and trigger state",
7078
+ "path": "src/docs/SurfaceOwnership.mdx"
7018
7079
  }
7019
7080
  ]
7020
7081
  },
@@ -7044,6 +7105,10 @@
7044
7105
  "type": "boolean",
7045
7106
  "required": false
7046
7107
  },
7108
+ "filterSurfaceOpen": {
7109
+ "type": "boolean | undefined",
7110
+ "required": false
7111
+ },
7047
7112
  "filterTriggerId": {
7048
7113
  "type": "string",
7049
7114
  "required": false
@@ -7187,7 +7252,8 @@
7187
7252
  "The application owns slotted tool products and data while PanelTools owns rail ordering, drawer selection, open state, motion, and shell events.",
7188
7253
  "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.",
7189
7254
  "Entering and exiting fullscreen snaps without borrowing the drawer open or close animation.",
7190
- "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."
7255
+ "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.",
7256
+ "Header action surfaceOpen identifies the owner of an external menu or panel without turning that action into a selected tool or toggle. The application owns this surface lifecycle."
7191
7257
  ],
7192
7258
  "responsiveBehavior": [
7193
7259
  "The open drawer reduces main-content width and uses --dimension-panel-width-xs (300px) on every supported desktop and tablet viewport.",
@@ -7226,6 +7292,10 @@
7226
7292
  {
7227
7293
  "label": "Application shell composition",
7228
7294
  "path": "agent/patterns/application-shell/pattern.agent.json"
7295
+ },
7296
+ {
7297
+ "label": "Surface ownership and trigger state",
7298
+ "path": "src/docs/SurfaceOwnership.mdx"
7229
7299
  }
7230
7300
  ]
7231
7301
  },
@@ -7818,7 +7888,7 @@
7818
7888
  "Create sections only for categories that are meaningful to customers, not merely to break a long list into arbitrary chunks.",
7819
7889
  "When any option supplies subtext, every row uses the same subtext structure and missing values render an em dash. Subtext should disambiguate or add decision-helpful information.",
7820
7890
  "Option labels and the selected trigger label stay on one line and truncate when constrained. Option subtext may wrap to at most two lines.",
7821
- "Use an option action only for a contextual menu about that user-managed option. The fixed ellipsis action appears on hover, keyboard activity, focus, and touch; expanded keeps it visible while its controlled menu is open. Activating it emits dsOptionAction without selecting the option or closing the Select popup.",
7891
+ "Use an option action only for a contextual menu about that user-managed option. The fixed ellipsis action appears on hover, keyboard activity, focus, and touch; surfaceOpen keeps it visible while its controlled menu is rendered. Activating it emits dsOptionAction without selecting the option or closing the Select popup.",
7822
7892
  "Use option subtextActions for a compact set of immediate actions that belong to one option. They render beneath only that option's label using the standard supporting-text inset and rhythm, use action or negative semantic color, and emit dsOptionSubtextAction without selecting the option or closing the popup. Unlike descriptive subtext, they do not reserve a blank supporting line on neighboring options.",
7823
7893
  "The optional prefix icon and trailing indicator always use the parent surface's secondary foreground color, including when a selected value promotes the label to primary. When collapseLabel compact icon-only chrome is active, a selected value promotes the prefix icon to primary instead. The default down indicator communicates disclosure; up-down is reserved for compact value steppers such as pagination page size.",
7824
7894
  "While the popup is open, the trigger holds the pressed interaction wash without changing its resting foreground or selected-value treatment.",
@@ -7832,7 +7902,8 @@
7832
7902
  "The error trigger uses a 1.5px bold-negative inset stroke so invalid state remains distinguishable from the normal 1px border without changing control geometry. Set hasBorder to false for chrome where the trigger must remain borderless at rest, when selected or focused, and when invalid; error semantics and supporting copy remain available.",
7833
7903
  "An initially empty option set is not an expected Select use case. The no-results state describes a search with no matches, not a source with no choices.",
7834
7904
  "Use options for a flat list or sections for grouped choices; when sections are present they take precedence.",
7835
- "The background prop describes the actual parent surface and uses the same surface set as ButtonUnfilled."
7905
+ "The background prop describes the actual parent surface and uses the same surface set as ButtonUnfilled.",
7906
+ "Select owns its associated popup and automatically retains the shared surface-open pressed wash. Consumers do not synchronize a second flag for the built-in picker. Contextual option actions are externally owned: their surfaceOpen state keeps the action visible through the associated menu exit, independently of the selected option."
7836
7907
  ],
7837
7908
  "responsiveBehavior": [
7838
7909
  "Use width fill for form fields and width hug for compact filter bars. Override those defaults only when the owning layout has a clear constraint.",
@@ -7863,6 +7934,10 @@
7863
7934
  {
7864
7935
  "label": "Selection patterns",
7865
7936
  "path": "src/docs/SelectionPatterns.mdx"
7937
+ },
7938
+ {
7939
+ "label": "Surface ownership and trigger state",
7940
+ "path": "src/docs/SurfaceOwnership.mdx"
7866
7941
  }
7867
7942
  ]
7868
7943
  },
@@ -8150,7 +8225,8 @@
8150
8225
  "Managed mobile Back and page-action controls use the same large touch density as the mobile navigation header without increasing the shared header height.",
8151
8226
  "Managed ShellApp keeps the selected desktop section-navigation presentation and ShellPage present and owns page header stickiness and the content scroller.",
8152
8227
  "Route-owned pageChrome independently selects ShellPage contentInset, page-header seams, scroll compaction, expanded and compact header-divider visibility, and contentSurface. ShellApp forwards them while resolving whether desktop title geometry is page-local or shell-bar-owned.",
8153
- "The application filters unauthorized destinations, sections, and tools before passing them into shell components."
8228
+ "The application filters unauthorized destinations, sections, and tools before passing them into shell components.",
8229
+ "Application-owned header actions and the account trigger retain surface ownership across shell presentations. Supply surfaceOpen on header actions and accountMenuSurfaceOpen on navigation for rendered surface lifetimes; keep disclosure and selected-route state separate."
8154
8230
  ],
8155
8231
  "responsiveBehavior": [
8156
8232
  "ShellApp owns the fixed system breakpoints and resolves desktop at 1200px and wider, tablet from 768px through 1199px, and mobile below 768px.",
@@ -8209,6 +8285,10 @@
8209
8285
  {
8210
8286
  "label": "Application shell contract",
8211
8287
  "path": "agent/patterns/application-shell/pattern.agent.json"
8288
+ },
8289
+ {
8290
+ "label": "Surface ownership and trigger state",
8291
+ "path": "src/docs/SurfaceOwnership.mdx"
8212
8292
  }
8213
8293
  ]
8214
8294
  },
@@ -8431,6 +8511,7 @@
8431
8511
  "The flow-preservation spacer follows contentSurface so compacting a secondary page cannot expose a primary strip before its content.",
8432
8512
  "On roomy pages, the expanded header scrolls upward until its title and action row reaches the compact row position, while its bottom divider progressively extends from the expanded inset to edge-to-edge; it then snaps variants without moving that shared visual anchor.",
8433
8513
  "Scroll compaction preserves the expanded page flow offset so content never jumps beneath the sticky header.",
8514
+ "The sticky header paints above the isolated routed-content layer, so product surfaces and callouts scroll beneath its opaque boundary instead of covering page chrome.",
8434
8515
  "ShellPage relies on ShellApp's content scroller and never introduces nested scrolling.",
8435
8516
  "BarWorkflow remains compact and is not assigned BarTitle's capacity or scroll variants."
8436
8517
  ],
@@ -8567,7 +8648,8 @@
8567
8648
  "Items with mobileDestination inbox map to one mobile Inbox destination while retaining the actual active tool id; the canonical recipe exposes Activity directly and keeps Inbox grouping opt-in.",
8568
8649
  "Stable tool ids own named slots; label, order, rail placement, shortcut, and mobile destination are explicit item data.",
8569
8650
  "Application-owned rail accessories are forwarded unchanged to PanelTools on desktop and tablet and remain independent from activeTool and open.",
8570
- "Switching responsive mode must not recreate application-owned slotted product elements."
8651
+ "Switching responsive mode must not recreate application-owned slotted product elements.",
8652
+ "Header actions forward application-owned surfaceOpen through each presentation, independently of expanded semantics and pressed toggles."
8571
8653
  ],
8572
8654
  "responsiveBehavior": [
8573
8655
  "Desktop and tablet compose PanelTools-compatible rail and drawer chrome.",
@@ -8593,6 +8675,10 @@
8593
8675
  {
8594
8676
  "label": "PanelTools contract",
8595
8677
  "path": "src/wc/components/PanelTools/PanelTools.agent.json"
8678
+ },
8679
+ {
8680
+ "label": "Surface ownership and trigger state",
8681
+ "path": "src/docs/SurfaceOwnership.mdx"
8596
8682
  }
8597
8683
  ]
8598
8684
  },
@@ -9548,7 +9634,8 @@
9548
9634
  "Row selection owns the single sticky start lane. One explicitly sized application column can own the sticky end lane, or the start lane when selection is absent. Each sticky boundary owns one fixed divider and a row-clipped directional shadow that paints into the adjacent scrolling columns only while more inline content remains beyond that edge.",
9549
9635
  "Cells accept scalar content, standard primary-and-secondary or dual-primary text primitives, declarative Tag, wrapping multiple-Tag content, icon-only, icon-and-text, 16:9 Image, or ButtonUnfilled Action content, or explicit Empty and Blank absence values. Text objects may declare an optional href (and target) on the primary track only; the table renders a native anchor with the shared brand text-action treatment when the URL is safe, and leaves scalars unlinked. Standard secondary copy defaults to the secondary foreground and may declare a semantic Text color when the application data carries intent; an optional tertiary track uses the same subdued body-small recipe as secondary. Secondary and tertiary may also be a short list of colorable runs, rendered on one line with the table's middle-dot separator. A run may supply help to add the shared dotted underline and a bottom-start Tooltip when compact visible copy summarizes supplementary details; explicit line breaks create a compact unbulleted list without obscuring the current cell's earlier tracks. Dual-primary copy keeps both tracks primary unless explicitly colored and does not gain a tertiary track. Body data cells share 8px outer padding; header and group rows keep their own geometry. Text tracks, including Empty, keep 4px inline padding so copy lines up with column-header labels; Tag and icon-only tracks stay on the 8px cell chrome alone. Icon-and-text cells (`kind: 'icon-text'`) place one md prefix icon beside the same copy stack as a text cell. The icon slot takes 2px padding on every side, then a 2px flex gap before the copy; text-track padding stays on the copy. Omit iconLabel when the glyph is decorative. 20px content (body-medium text, md icon, and the row checkbox) sits in a 24px track so it stays optically aligned with 24px Tag and Action content. Single-track text, selection, tag-only, icon-only, icon-and-text, Action, Empty, Blank, and 1-track Image cells resolve a 40px base contract while two-track cells grow to 64px and three-track cells grow to 88px. Every later track adds 24px, so four tracks resolve to 112px, five to 136px, and the sequence may continue. Tracks stack with no gap. Wrapping primary on a 1-track cell uses that same rhythm: two wrapped lines share the 64px row and three wrapped lines share the 88px row. Wrapping secondary keeps primary on the first track and consumes later tracks: two secondary lines share the 88px row and three secondary lines share a 112px fourth track. Keep the same track count in every row of a table or group when those rows should share one height. Tag cells use the inset Tag recipe: md double-inset is a 24px control for tag-only and tag-with-text, while text-with-tag uses sm single-inset at 20px so the second-track pill sits in the same 24px lane. Multiple-Tag cells use `kind: 'tags'`, a positive `tracks` count, and small single-inset Tags that wrap naturally at the column edge. Each wrap line is a 24px track with no stack gap, matching text. The tallest cell establishes the native row height, so all sibling cells match even at four, five, or more tracks; virtual tables use the declared count as the initial estimate and measure responsive wrapping after paint. Action cells primarily use an icon-only Ellipses treatment, render a 24px small ButtonUnfilled, default to unbordered, and emit row, column, and action identities through dsCellAction. When an action cell declares items, that Ellipses trigger opens the shared ds-menu for commands, dividers, inactive rows, and destructive rows instead of emitting on click; choosing a command emits dsCellAction with that item's actionId. Omit items to keep a single-shot control. Image cells declare tracks 1, 2, or 3 so the 16:9 bordered preview fills that body-row content box (cell height minus 8px padding) and the column hugs the resulting width; omit tracks for the 1-track recipe, and keep image tracks aligned with the other cells in the table or group. Image cells fall back to an accessible placeholder when no source is supplied. Empty means the data applies but has no value and renders an em dash with localized assistive text; Blank means the data is not applicable and renders no content. Nullish values remain backward-compatible Empty values. Stable type, variant, and track-count hooks keep every cell family independently styleable.",
9550
9636
  "Score-and-text cells (`kind: score-text`) place the small 24px safety score at the top-right of the cell while the same one-, two-, or three-track copy stack as a standard text cell fills from the start edge. The score is top-aligned with the first text track, adds no inner padding, and defaults its accessible name prefix to Safety score. Score-and-text loading geometry uses the matching small score skeleton and declared copy tracks.",
9551
- "The public @ds-mo/ui/table.css export is the authoritative zero-specificity visual recipe. Override its --ds-table-* properties or target its stable element classes for product-specific styling."
9637
+ "The public @ds-mo/ui/table.css export is the authoritative zero-specificity visual recipe. Override its --ds-table-* properties or target its stable element classes for product-specific styling.",
9638
+ "Use surfaceOpenRowId to identify the interactive row associated with a visible detail panel or other contextual surface. The application owns opening, same-row toggling, switching records, and closing; retain the identity through exit motion, then clear it. Move it when panel navigation changes the displayed record. This pressed wash spans sticky and scrolling cells, follows stable row identity through virtualization, and never checks a checkbox or changes selectedRowIds. Group expansion remains an inline disclosure."
9552
9639
  ],
9553
9640
  "responsiveBehavior": [
9554
9641
  "The table keeps native semantics at narrow widths and scrolls horizontally instead of transforming into cards.",
@@ -9591,6 +9678,10 @@
9591
9678
  {
9592
9679
  "label": "Menu trigger composition",
9593
9680
  "path": "agent/patterns/menu-trigger/pattern.agent.json"
9681
+ },
9682
+ {
9683
+ "label": "Surface ownership and trigger state",
9684
+ "path": "src/docs/SurfaceOwnership.mdx"
9594
9685
  }
9595
9686
  ]
9596
9687
  },
@@ -9820,6 +9911,10 @@
9820
9911
  "type": "boolean",
9821
9912
  "required": false
9822
9913
  },
9914
+ "surfaceOpenRowId": {
9915
+ "type": "string | undefined",
9916
+ "required": false
9917
+ },
9823
9918
  "totalCount": {
9824
9919
  "type": "number | undefined",
9825
9920
  "required": false
@@ -10125,7 +10220,8 @@
10125
10220
  "states": [
10126
10221
  "options and grouping are controlled. A data option may supply product-owned orderOptions; otherwise Order defaults to Ascending and Descending. dsGroupChange reports a complete TableGroupingState and dsClear requests null grouping without mutating either input.",
10127
10222
  "Selecting a new data point starts at its first custom order option, or ascending when it has no custom order options. Re-selecting the active data point preserves its complete order state.",
10128
- "Selecting a data point or direction applies immediately and leaves the dialog open so the other pane can be changed."
10223
+ "Selecting a data point or direction applies immediately and leaves the dialog open so the other pane can be changed.",
10224
+ "The grouping picker automatically holds the shared surface-open wash through exit. Opening this picker is separate from expanding an inline table group."
10129
10225
  ],
10130
10226
  "responsiveBehavior": [
10131
10227
  "Use in the trailing region of ds-table-toolbar.",
@@ -10151,6 +10247,10 @@
10151
10247
  {
10152
10248
  "label": "Toolbar composition owner",
10153
10249
  "path": "src/wc/components/TableToolbar/TableToolbar.agent.json"
10250
+ },
10251
+ {
10252
+ "label": "Surface ownership and trigger state",
10253
+ "path": "src/docs/SurfaceOwnership.mdx"
10154
10254
  }
10155
10255
  ]
10156
10256
  },
@@ -10251,7 +10351,8 @@
10251
10351
  "states": [
10252
10352
  "views, value, and dirty are controlled. Dirty state is presented only for a selected custom view; the default template never shows the trigger dot or save/discard actions even if dirty is supplied. Selection, create, save, discard, rename, and remove events communicate intent and never mutate application records.",
10253
10353
  "The component owns only transient interaction state: the contextual menu, naming dialog, draft name, duplicate-name validation, and focus restoration.",
10254
- "The default view is a non-editable template. Application-owned custom views appear in a separate section with Rename and Remove actions. New view opens the naming dialog. When an editable selected view is dirty, that view row shows Save and negative Discard supporting actions while the footer remains dedicated to New view. The application decides which table state to capture, restore, and persist."
10354
+ "The default view is a non-editable template. Application-owned custom views appear in a separate section with Rename and Remove actions. New view opens the naming dialog. When an editable selected view is dirty, that view row shows Save and negative Discard supporting actions while the footer remains dedicated to New view. The application decides which table state to capture, restore, and persist.",
10355
+ "The built-in picker and contextual option menu each retain their own surface-open treatment. Opening a view menu does not select that view."
10255
10356
  ],
10256
10357
  "responsiveBehavior": [
10257
10358
  "The control remains a single toolbar item and relies on Select, Menu, and Modal collision and viewport behavior. Its trigger hugs short view names and is capped at the compact menu-width token so long names truncate while the dirty dot stays visible. Its choice popup keeps that same token as the minimum width.",
@@ -10276,6 +10377,10 @@
10276
10377
  {
10277
10378
  "label": "Toolbar composition owner",
10278
10379
  "path": "src/wc/components/TableToolbar/TableToolbar.agent.json"
10380
+ },
10381
+ {
10382
+ "label": "Surface ownership and trigger state",
10383
+ "path": "src/docs/SurfaceOwnership.mdx"
10279
10384
  }
10280
10385
  ]
10281
10386
  },
@@ -10403,7 +10508,8 @@
10403
10508
  "Selected scopes render as neutral md Chips using the double-inset recipe so they remain 24px high inside the 32px md search control and each can be removed directly.",
10404
10509
  "Backspace edits a non-empty field-picker query, then closes the open slash listbox when that query is empty. When the table query is empty and the listbox is already closed, the next Backspace removes the last selected field. Ordinary Backspace edits table query text when the listbox is closed.",
10405
10510
  "Duplicate, blank, and unknown field identities are ignored for presentation. Selected fields preserve the consumer's order.",
10406
- "Inactive search leaves the tab order, closes the field listbox, and does not emit query or field changes."
10511
+ "Inactive search leaves the tab order, closes the field listbox, and does not emit query or field changes.",
10512
+ "The field-picker action holds the shared surface-open wash while its listbox is visible; chosen search fields remain independent."
10407
10513
  ],
10408
10514
  "responsiveBehavior": [
10409
10515
  "The control fills the available inline size supplied by the table toolbar search slot. Selected Chips and the editable query share one horizontal editor lane so the md control does not grow vertically.",
@@ -10430,6 +10536,10 @@
10430
10536
  {
10431
10537
  "label": "Toolbar composition owner",
10432
10538
  "path": "src/wc/components/TableToolbar/TableToolbar.agent.json"
10539
+ },
10540
+ {
10541
+ "label": "Surface ownership and trigger state",
10542
+ "path": "src/docs/SurfaceOwnership.mdx"
10433
10543
  }
10434
10544
  ]
10435
10545
  },
@@ -10551,7 +10661,8 @@
10551
10661
  "columns and sort are controlled. dsSortChange reports the next TableSortState and never mutates those inputs. The same sort object is what column headers emit through the table.",
10552
10662
  "Selecting a different data field keeps the current direction, or starts ascending when no sort exists. Selecting a direction applies it to the current field, or to the first sortable field when no sort exists. Selecting the already-active field or direction is a no-op and does not toggle the way a header click does.",
10553
10663
  "The trigger stays Sort in regular-weight resting secondary chrome. Field and direction selection live in the menu and on column headers, so the trigger never uses active primary emphasis. It keeps pressed interaction paint without physically scaling inside the stable table caption row.",
10554
- "Compound sortable headers contribute one Data row per segment. Action columns never appear."
10664
+ "Compound sortable headers contribute one Data row per segment. Action columns never appear.",
10665
+ "The trigger automatically holds the shared surface-open wash through menu exit while the selected sort remains independently controlled."
10555
10666
  ],
10556
10667
  "responsiveBehavior": [
10557
10668
  "Place the control in the trailing region of ds-table-toolbar with Filter and Group.",
@@ -10577,6 +10688,10 @@
10577
10688
  {
10578
10689
  "label": "Toolbar composition owner",
10579
10690
  "path": "src/wc/components/TableToolbar/TableToolbar.agent.json"
10691
+ },
10692
+ {
10693
+ "label": "Surface ownership and trigger state",
10694
+ "path": "src/docs/SurfaceOwnership.mdx"
10580
10695
  }
10581
10696
  ]
10582
10697
  },
@@ -10776,7 +10891,8 @@
10776
10891
  "isInset opts into reduced outer geometry only when Tag is nested inside a control of the same density. The default single inset removes 4px overall; insetDepth double removes 8px overall and falls back to single at xs to protect minimum icon geometry. Semantic styling, typography, icons, gaps, radius, and interaction remain unchanged.",
10777
10892
  "Labels stay on one line and truncate only when the owner supplies a maximum width.",
10778
10893
  "Omitted interactive renders static metadata with no focus, event, or suffix. Interactive adds the fixed ChevronUpDown suffix and emits dsClick without toggling expanded internally.",
10779
- "isInactive disables only the interactive button and applies the shared inactive treatment."
10894
+ "isInactive disables only the interactive button and applies the shared inactive treatment.",
10895
+ "Interactive tags use surfaceOpen for the associated menu lifecycle, including exit motion. This holds the shared pressed wash without changing the intent that describes the metadata value. Static tags never acquire surface ownership."
10780
10896
  ],
10781
10897
  "responsiveBehavior": [
10782
10898
  "The owner selects md, sm, or xs density to match its local layout and owns collection wrapping, overflow, and condensation. Use isInset only for same-density control nesting.",
@@ -10797,6 +10913,10 @@
10797
10913
  {
10798
10914
  "label": "Storybook examples",
10799
10915
  "path": "src/wc/components/Tag/Tag.stories.ts"
10916
+ },
10917
+ {
10918
+ "label": "Surface ownership and trigger state",
10919
+ "path": "src/docs/SurfaceOwnership.mdx"
10800
10920
  }
10801
10921
  ]
10802
10922
  },
@@ -10853,6 +10973,10 @@
10853
10973
  "size": {
10854
10974
  "type": "TagSize",
10855
10975
  "required": false
10976
+ },
10977
+ "surfaceOpen": {
10978
+ "type": "boolean | undefined",
10979
+ "required": false
10856
10980
  }
10857
10981
  },
10858
10982
  "events": [
@@ -9,7 +9,7 @@ export declare class DsButtonFilled {
9
9
  dsMenuClick: EventEmitter<DsButtonFilledCustomEvent<MouseEvent>>;
10
10
  constructor(c: ChangeDetectorRef, r: ElementRef, z: NgZone);
11
11
  static ɵfac: i0.ɵɵFactoryDeclaration<DsButtonFilled, never>;
12
- static ɵcmp: i0.ɵɵComponentDeclaration<DsButtonFilled, "ds-button-filled", never, { "ariaLabel": { "alias": "ariaLabel"; "required": false; }; "background": { "alias": "background"; "required": false; }; "contrast": { "alias": "contrast"; "required": false; }; "controls": { "alias": "controls"; "required": false; }; "expanded": { "alias": "expanded"; "required": false; }; "hasBorder": { "alias": "hasBorder"; "required": false; }; "hasMenu": { "alias": "hasMenu"; "required": false; }; "haspopup": { "alias": "haspopup"; "required": false; }; "icon": { "alias": "icon"; "required": false; }; "insetDepth": { "alias": "insetDepth"; "required": false; }; "intent": { "alias": "intent"; "required": false; }; "isInactive": { "alias": "isInactive"; "required": false; }; "isInset": { "alias": "isInset"; "required": false; }; "isLoading": { "alias": "isLoading"; "required": false; }; "label": { "alias": "label"; "required": false; }; "labelEmphasis": { "alias": "labelEmphasis"; "required": false; }; "menuAriaLabel": { "alias": "menuAriaLabel"; "required": false; }; "pressScale": { "alias": "pressScale"; "required": false; }; "rounded": { "alias": "rounded"; "required": false; }; "size": { "alias": "size"; "required": false; }; "split": { "alias": "split"; "required": false; }; "type": { "alias": "type"; "required": false; }; "variant": { "alias": "variant"; "required": false; }; "width": { "alias": "width"; "required": false; }; }, { "dsClick": "dsClick"; "dsMenuClick": "dsMenuClick"; }, never, ["*"], true, never>;
12
+ static ɵcmp: i0.ɵɵComponentDeclaration<DsButtonFilled, "ds-button-filled", never, { "ariaLabel": { "alias": "ariaLabel"; "required": false; }; "background": { "alias": "background"; "required": false; }; "contrast": { "alias": "contrast"; "required": false; }; "controls": { "alias": "controls"; "required": false; }; "expanded": { "alias": "expanded"; "required": false; }; "hasBorder": { "alias": "hasBorder"; "required": false; }; "hasMenu": { "alias": "hasMenu"; "required": false; }; "haspopup": { "alias": "haspopup"; "required": false; }; "icon": { "alias": "icon"; "required": false; }; "insetDepth": { "alias": "insetDepth"; "required": false; }; "intent": { "alias": "intent"; "required": false; }; "isInactive": { "alias": "isInactive"; "required": false; }; "isInset": { "alias": "isInset"; "required": false; }; "isLoading": { "alias": "isLoading"; "required": false; }; "label": { "alias": "label"; "required": false; }; "labelEmphasis": { "alias": "labelEmphasis"; "required": false; }; "menuAriaLabel": { "alias": "menuAriaLabel"; "required": false; }; "pressScale": { "alias": "pressScale"; "required": false; }; "rounded": { "alias": "rounded"; "required": false; }; "size": { "alias": "size"; "required": false; }; "split": { "alias": "split"; "required": false; }; "surfaceOpen": { "alias": "surfaceOpen"; "required": false; }; "type": { "alias": "type"; "required": false; }; "variant": { "alias": "variant"; "required": false; }; "width": { "alias": "width"; "required": false; }; }, { "dsClick": "dsClick"; "dsMenuClick": "dsMenuClick"; }, never, ["*"], true, never>;
13
13
  }
14
14
  export declare interface DsButtonFilled extends Components.DsButtonFilled {
15
15
  dsClick: EventEmitter<DsButtonFilledCustomEvent<MouseEvent>>;
@@ -19,12 +19,12 @@ let DsButtonFilled = class DsButtonFilled {
19
19
  this.el = r.nativeElement;
20
20
  }
21
21
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.0", ngImport: i0, type: DsButtonFilled, deps: [{ token: i0.ChangeDetectorRef }, { token: i0.ElementRef }, { token: i0.NgZone }], target: i0.ɵɵFactoryTarget.Component }); }
22
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "22.1.0", type: DsButtonFilled, isStandalone: true, selector: "ds-button-filled", inputs: { ariaLabel: "ariaLabel", background: "background", contrast: "contrast", controls: "controls", expanded: "expanded", hasBorder: "hasBorder", hasMenu: "hasMenu", haspopup: "haspopup", icon: "icon", insetDepth: "insetDepth", intent: "intent", isInactive: "isInactive", isInset: "isInset", isLoading: "isLoading", label: "label", labelEmphasis: "labelEmphasis", menuAriaLabel: "menuAriaLabel", pressScale: "pressScale", rounded: "rounded", size: "size", split: "split", type: "type", variant: "variant", width: "width" }, outputs: { dsClick: "dsClick", dsMenuClick: "dsMenuClick" }, ngImport: i0, template: '<ng-content></ng-content>', isInline: true, changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
22
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "22.1.0", type: DsButtonFilled, isStandalone: true, selector: "ds-button-filled", inputs: { ariaLabel: "ariaLabel", background: "background", contrast: "contrast", controls: "controls", expanded: "expanded", hasBorder: "hasBorder", hasMenu: "hasMenu", haspopup: "haspopup", icon: "icon", insetDepth: "insetDepth", intent: "intent", isInactive: "isInactive", isInset: "isInset", isLoading: "isLoading", label: "label", labelEmphasis: "labelEmphasis", menuAriaLabel: "menuAriaLabel", pressScale: "pressScale", rounded: "rounded", size: "size", split: "split", surfaceOpen: "surfaceOpen", type: "type", variant: "variant", width: "width" }, outputs: { dsClick: "dsClick", dsMenuClick: "dsMenuClick" }, ngImport: i0, template: '<ng-content></ng-content>', isInline: true, changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
23
23
  };
24
24
  DsButtonFilled = __decorate([
25
25
  ProxyCmp({
26
26
  defineCustomElementFn: defineDsButtonFilled,
27
- inputs: ['ariaLabel', 'background', 'contrast', 'controls', 'expanded', 'hasBorder', 'hasMenu', 'haspopup', 'icon', 'insetDepth', 'intent', 'isInactive', 'isInset', 'isLoading', 'label', 'labelEmphasis', 'menuAriaLabel', 'pressScale', 'rounded', 'size', 'split', 'type', 'variant', 'width'],
27
+ inputs: ['ariaLabel', 'background', 'contrast', 'controls', 'expanded', 'hasBorder', 'hasMenu', 'haspopup', 'icon', 'insetDepth', 'intent', 'isInactive', 'isInset', 'isLoading', 'label', 'labelEmphasis', 'menuAriaLabel', 'pressScale', 'rounded', 'size', 'split', 'surfaceOpen', 'type', 'variant', 'width'],
28
28
  methods: ['setFocus']
29
29
  })
30
30
  ], DsButtonFilled);
@@ -36,7 +36,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.0", ngImpor
36
36
  changeDetection: ChangeDetectionStrategy.OnPush,
37
37
  template: '<ng-content></ng-content>',
38
38
  // eslint-disable-next-line @angular-eslint/no-inputs-metadata-property
39
- inputs: ['ariaLabel', 'background', 'contrast', 'controls', 'expanded', 'hasBorder', 'hasMenu', 'haspopup', 'icon', 'insetDepth', 'intent', 'isInactive', 'isInset', 'isLoading', 'label', 'labelEmphasis', 'menuAriaLabel', 'pressScale', 'rounded', 'size', 'split', 'type', 'variant', 'width'],
39
+ inputs: ['ariaLabel', 'background', 'contrast', 'controls', 'expanded', 'hasBorder', 'hasMenu', 'haspopup', 'icon', 'insetDepth', 'intent', 'isInactive', 'isInset', 'isLoading', 'label', 'labelEmphasis', 'menuAriaLabel', 'pressScale', 'rounded', 'size', 'split', 'surfaceOpen', 'type', 'variant', 'width'],
40
40
  outputs: ['dsClick', 'dsMenuClick'],
41
41
  }]
42
42
  }], ctorParameters: () => [{ type: i0.ChangeDetectorRef }, { type: i0.ElementRef }, { type: i0.NgZone }], propDecorators: { dsClick: [{
@@ -10,7 +10,7 @@ export declare class DsButtonUnfilled {
10
10
  dsChange: EventEmitter<DsButtonUnfilledCustomEvent<boolean>>;
11
11
  constructor(c: ChangeDetectorRef, r: ElementRef, z: NgZone);
12
12
  static ɵfac: i0.ɵɵFactoryDeclaration<DsButtonUnfilled, never>;
13
- static ɵcmp: i0.ɵɵComponentDeclaration<DsButtonUnfilled, "ds-button-unfilled", never, { "activeFill": { "alias": "activeFill"; "required": false; }; "ariaLabel": { "alias": "ariaLabel"; "required": false; }; "background": { "alias": "background"; "required": false; }; "collapseLabel": { "alias": "collapseLabel"; "required": false; }; "controls": { "alias": "controls"; "required": false; }; "dot": { "alias": "dot"; "required": false; }; "expanded": { "alias": "expanded"; "required": false; }; "focusTabIndex": { "alias": "focusTabIndex"; "required": false; }; "hasBorder": { "alias": "hasBorder"; "required": false; }; "hasMenu": { "alias": "hasMenu"; "required": false; }; "haspopup": { "alias": "haspopup"; "required": false; }; "icon": { "alias": "icon"; "required": false; }; "insetDepth": { "alias": "insetDepth"; "required": false; }; "isActive": { "alias": "isActive"; "required": false; }; "isInactive": { "alias": "isInactive"; "required": false; }; "isInset": { "alias": "isInset"; "required": false; }; "isLoading": { "alias": "isLoading"; "required": false; }; "label": { "alias": "label"; "required": false; }; "labelEmphasis": { "alias": "labelEmphasis"; "required": false; }; "menuAriaLabel": { "alias": "menuAriaLabel"; "required": false; }; "pressScale": { "alias": "pressScale"; "required": false; }; "pressed": { "alias": "pressed"; "required": false; }; "rounded": { "alias": "rounded"; "required": false; }; "size": { "alias": "size"; "required": false; }; "split": { "alias": "split"; "required": false; }; "type": { "alias": "type"; "required": false; }; "variant": { "alias": "variant"; "required": false; }; "width": { "alias": "width"; "required": false; }; }, { "dsClick": "dsClick"; "dsMenuClick": "dsMenuClick"; "dsChange": "dsChange"; }, never, ["*"], true, never>;
13
+ static ɵcmp: i0.ɵɵComponentDeclaration<DsButtonUnfilled, "ds-button-unfilled", never, { "activeFill": { "alias": "activeFill"; "required": false; }; "ariaLabel": { "alias": "ariaLabel"; "required": false; }; "background": { "alias": "background"; "required": false; }; "collapseLabel": { "alias": "collapseLabel"; "required": false; }; "controls": { "alias": "controls"; "required": false; }; "dot": { "alias": "dot"; "required": false; }; "expanded": { "alias": "expanded"; "required": false; }; "focusTabIndex": { "alias": "focusTabIndex"; "required": false; }; "hasBorder": { "alias": "hasBorder"; "required": false; }; "hasMenu": { "alias": "hasMenu"; "required": false; }; "haspopup": { "alias": "haspopup"; "required": false; }; "icon": { "alias": "icon"; "required": false; }; "insetDepth": { "alias": "insetDepth"; "required": false; }; "isActive": { "alias": "isActive"; "required": false; }; "isInactive": { "alias": "isInactive"; "required": false; }; "isInset": { "alias": "isInset"; "required": false; }; "isLoading": { "alias": "isLoading"; "required": false; }; "label": { "alias": "label"; "required": false; }; "labelEmphasis": { "alias": "labelEmphasis"; "required": false; }; "menuAriaLabel": { "alias": "menuAriaLabel"; "required": false; }; "pressScale": { "alias": "pressScale"; "required": false; }; "pressed": { "alias": "pressed"; "required": false; }; "rounded": { "alias": "rounded"; "required": false; }; "size": { "alias": "size"; "required": false; }; "split": { "alias": "split"; "required": false; }; "surfaceOpen": { "alias": "surfaceOpen"; "required": false; }; "type": { "alias": "type"; "required": false; }; "variant": { "alias": "variant"; "required": false; }; "width": { "alias": "width"; "required": false; }; }, { "dsClick": "dsClick"; "dsMenuClick": "dsMenuClick"; "dsChange": "dsChange"; }, never, ["*"], true, never>;
14
14
  }
15
15
  export declare interface DsButtonUnfilled extends Components.DsButtonUnfilled {
16
16
  dsClick: EventEmitter<DsButtonUnfilledCustomEvent<MouseEvent>>;