@ds-mo/ui 14.20.0 → 14.21.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 (257) hide show
  1. package/dist/.package-ready.json +1 -1
  2. package/dist/agent-patterns.json +1 -1
  3. package/dist/agent.json +386 -33
  4. package/dist/angular/ds-chip.d.ts +1 -1
  5. package/dist/angular/ds-chip.js +3 -3
  6. package/dist/angular/ds-filter-menu.d.ts +7 -1
  7. package/dist/angular/ds-filter-menu.js +7 -4
  8. package/dist/angular/ds-input.d.ts +1 -1
  9. package/dist/angular/ds-input.js +3 -3
  10. package/dist/angular/ds-tab-group.d.ts +1 -1
  11. package/dist/angular/ds-tab-group.js +3 -3
  12. package/dist/angular/ds-table-filter.d.ts +7 -1
  13. package/dist/angular/ds-table-filter.js +7 -4
  14. package/dist/angular/ds-table-group.d.ts +29 -0
  15. package/dist/angular/ds-table-group.js +48 -0
  16. package/dist/angular/ds-table-search.d.ts +20 -0
  17. package/dist/angular/ds-table-search.js +49 -0
  18. package/dist/angular/ds-table.d.ts +1 -1
  19. package/dist/angular/ds-table.js +3 -3
  20. package/dist/angular/index.d.ts +1 -1
  21. package/dist/angular/index.js +2 -0
  22. package/dist/angular/proxies.d.ts +2 -0
  23. package/dist/angular/proxies.js +2 -0
  24. package/dist/components/ds-agent-activity.js +1 -1
  25. package/dist/components/ds-agent-questionnaire.js +1 -1
  26. package/dist/components/ds-agent-response.js +1 -1
  27. package/dist/components/ds-agent-source-list.js +1 -1
  28. package/dist/components/ds-agent-tool-call.js +1 -1
  29. package/dist/components/ds-attachment-list.js +1 -1
  30. package/dist/components/ds-badge.js +1 -1
  31. package/dist/components/ds-banner.js +1 -1
  32. package/dist/components/ds-bar-action.js +1 -1
  33. package/dist/components/ds-bar-nav.js +1 -1
  34. package/dist/components/ds-bar-title.js +1 -1
  35. package/dist/components/ds-bar-workflow.js +1 -1
  36. package/dist/components/ds-breadcrumb.js +1 -1
  37. package/dist/components/ds-button-filled.js +1 -1
  38. package/dist/components/ds-button-unfilled.js +1 -1
  39. package/dist/components/ds-card-chart.js +1 -1
  40. package/dist/components/ds-card-overview.js +1 -1
  41. package/dist/components/ds-card-setting.js +1 -1
  42. package/dist/components/ds-chart-legend.js +1 -1
  43. package/dist/components/ds-chart.js +1 -1
  44. package/dist/components/ds-checkbox.js +1 -1
  45. package/dist/components/ds-chip.js +1 -1
  46. package/dist/components/ds-chip.js.map +1 -1
  47. package/dist/components/ds-code-block.js +1 -1
  48. package/dist/components/ds-conversation-list-item.js +1 -1
  49. package/dist/components/ds-conversation-list-section.js +1 -1
  50. package/dist/components/ds-empty-state.js +1 -1
  51. package/dist/components/ds-field.js +1 -1
  52. package/dist/components/ds-filter-menu.js +1 -1
  53. package/dist/components/ds-input.js +1 -1
  54. package/dist/components/ds-markdown.js +1 -1
  55. package/dist/components/ds-menu.js +1 -1
  56. package/dist/components/ds-message-actions.js +1 -1
  57. package/dist/components/ds-message-composer.js +1 -1
  58. package/dist/components/ds-message-scroller.js +1 -1
  59. package/dist/components/ds-message-scroller.js.map +1 -1
  60. package/dist/components/ds-message.js +1 -1
  61. package/dist/components/ds-mobile-bar-nav.js +1 -1
  62. package/dist/components/ds-mobile-header.js +1 -1
  63. package/dist/components/ds-mobile-section-switcher.js +1 -1
  64. package/dist/components/ds-mobile-sheet-nav.js +1 -1
  65. package/dist/components/ds-modal.js +1 -1
  66. package/dist/components/ds-pagination.js +1 -1
  67. package/dist/components/ds-panel-nav.js +1 -1
  68. package/dist/components/ds-panel-sub-nav.js +1 -1
  69. package/dist/components/ds-panel-tool-header.js +1 -1
  70. package/dist/components/ds-panel-tool-search.js +1 -1
  71. package/dist/components/ds-panel-tool-search.js.map +1 -1
  72. package/dist/components/ds-panel-tools.js +1 -1
  73. package/dist/components/ds-paper-texture.js +1 -1
  74. package/dist/components/ds-radio.js +1 -1
  75. package/dist/components/ds-select.js +1 -1
  76. package/dist/components/ds-shell-app.js +1 -1
  77. package/dist/components/ds-shell-page.js +1 -1
  78. package/dist/components/ds-shell-tools.js +1 -1
  79. package/dist/components/ds-slider.js +1 -1
  80. package/dist/components/ds-swatch-picker.js +1 -1
  81. package/dist/components/ds-tab-group.js +1 -1
  82. package/dist/components/ds-table-filter.js +1 -1
  83. package/dist/components/ds-table-filter.js.map +1 -1
  84. package/dist/components/ds-table-group.d.ts +11 -0
  85. package/dist/components/ds-table-group.js +2 -0
  86. package/dist/components/ds-table-group.js.map +1 -0
  87. package/dist/components/ds-table-saved-views.js +1 -1
  88. package/dist/components/ds-table-search.d.ts +11 -0
  89. package/dist/components/ds-table-search.js +2 -0
  90. package/dist/components/ds-table-search.js.map +1 -0
  91. package/dist/components/ds-table-sort.js +1 -1
  92. package/dist/components/ds-table-sort.js.map +1 -1
  93. package/dist/components/ds-table-toolbar.js +1 -1
  94. package/dist/components/ds-table-toolbar.js.map +1 -1
  95. package/dist/components/ds-table.js +1 -1
  96. package/dist/components/ds-table.js.map +1 -1
  97. package/dist/components/ds-tag.js +1 -1
  98. package/dist/components/ds-text.js +1 -1
  99. package/dist/components/ds-toast.js +1 -1
  100. package/dist/components/ds-tooltip-chart.js +1 -1
  101. package/dist/components/ds-tooltip.js +1 -1
  102. package/dist/components/ds-typing-indicator.js +1 -1
  103. package/dist/components/{p-Bf7PZJPT.js → p-5Z4oYuiK.js} +2 -2
  104. package/dist/components/{p-DIlScMvI.js → p-6rB0eAda.js} +2 -2
  105. package/dist/components/{p-CptSB-tA.js → p-9ykZwPlI.js} +2 -2
  106. package/dist/components/{p-BHhmB9-4.js → p-B0kSlcaw.js} +2 -2
  107. package/dist/components/{p-DWjTOoXs.js → p-B1wMpt1z.js} +2 -2
  108. package/dist/components/p-BEttT0UB.js +2 -0
  109. package/dist/components/p-BEttT0UB.js.map +1 -0
  110. package/dist/components/p-BFit8o0r.js +2 -0
  111. package/dist/components/p-BFit8o0r.js.map +1 -0
  112. package/dist/components/{p-fRDzpfi9.js → p-BXv6RpoF.js} +2 -2
  113. package/dist/components/{p-D7QlTWbN.js → p-BbG7nOcz.js} +2 -2
  114. package/dist/components/{p-B2FT4Da6.js → p-Bc_z1UwJ.js} +2 -2
  115. package/dist/components/{p-Bx5BSd6F.js → p-BcxidW9k.js} +2 -2
  116. package/dist/components/{p-1UAVanY9.js → p-Bd8I2oXN.js} +2 -2
  117. package/dist/components/{p-DGe5oXR0.js → p-Bjq1KP_Y.js} +2 -2
  118. package/dist/components/p-Bjq1KP_Y.js.map +1 -0
  119. package/dist/components/{p-DW5Ita-P.js → p-BnTPuV3x.js} +2 -2
  120. package/dist/components/{p-DW5Ita-P.js.map → p-BnTPuV3x.js.map} +1 -1
  121. package/dist/components/p-BqVXMEJm.js +2 -0
  122. package/dist/components/p-BqVXMEJm.js.map +1 -0
  123. package/dist/components/{p-DdH7b4JF.js → p-CBymzuOO.js} +2 -2
  124. package/dist/components/{p-BjRD57w3.js → p-CE2b5GPu.js} +2 -2
  125. package/dist/components/{p-DfDoqOlx.js → p-CEnoPUn5.js} +2 -2
  126. package/dist/components/{p-DBYv7fRq.js → p-CFkZSDwI.js} +2 -2
  127. package/dist/components/{p-Bb4KnRy0.js → p-CTH3dSYg.js} +2 -2
  128. package/dist/components/{p-BmssRAEZ.js → p-CZ144LS5.js} +2 -2
  129. package/dist/components/{p-B-HsfQOK.js → p-Cd1JnnVK.js} +2 -2
  130. package/dist/components/p-CeKa4VbU.js +2 -0
  131. package/dist/components/{p-AtUP95E_.js.map → p-CeKa4VbU.js.map} +1 -1
  132. package/dist/components/{p-CDw_WEVt.js → p-Cnsvgx1M.js} +2 -2
  133. package/dist/components/{p-BYFS2qWb.js → p-CpeJMKJ5.js} +2 -2
  134. package/dist/components/{p-DM1Z_hh0.js → p-D36EmETH.js} +2 -2
  135. package/dist/components/{p-DFC0sRM-.js → p-DI8DUozc.js} +2 -2
  136. package/dist/components/{p-v4oqkJms.js → p-DSy1oOnd.js} +2 -2
  137. package/dist/components/{p-v4oqkJms.js.map → p-DSy1oOnd.js.map} +1 -1
  138. package/dist/components/{p-DQBT1Jkf.js → p-DbLLH3hr.js} +2 -2
  139. package/dist/components/{p-B6rSDhJY.js → p-Dit6JmAK.js} +2 -2
  140. package/dist/components/{p-caLOcQUK.js → p-DzPtYdXy.js} +2 -2
  141. package/dist/components/{p-Do8wbFff.js → p-XaCYqck3.js} +2 -2
  142. package/dist/components/{p-DKt_8s-U.js → p-Y5_MkCFn.js} +2 -2
  143. package/dist/components/{p-BUexfjjg.js → p-YDxDyedE.js} +2 -2
  144. package/dist/components/{p-L8IIeDXM.js → p-_C-XRpCB.js} +2 -2
  145. package/dist/components/{p-CyZqk196.js → p-bHnk8t5I.js} +2 -2
  146. package/dist/components/p-hYjmOPCI.js +2 -0
  147. package/dist/components/p-hYjmOPCI.js.map +1 -0
  148. package/dist/components/{p-ChfVRPHw.js → p-pUOA3iDG.js} +2 -2
  149. package/dist/components/{p-DLbHgbVj.js → p-pnO8tAYB.js} +2 -2
  150. package/dist/components/{p-CCmgtju-.js → p-pxN8JGEh.js} +2 -2
  151. package/dist/components/p-pxN8JGEh.js.map +1 -0
  152. package/dist/components/{p-B4wTnsUL.js → p-w9fkkwL2.js} +2 -2
  153. package/dist/components/p-x5u5Ueli.js +2 -0
  154. package/dist/components/{p-BeA6Jv-3.js.map → p-x5u5Ueli.js.map} +1 -1
  155. package/dist/docs/components.json +1291 -33
  156. package/dist/mcp-data/registry/button-filled.json +1 -0
  157. package/dist/mcp-data/registry/button-unfilled.json +1 -0
  158. package/dist/mcp-data/registry/chip.json +39 -2
  159. package/dist/mcp-data/registry/filter-menu.json +84 -11
  160. package/dist/mcp-data/registry/input.json +54 -2
  161. package/dist/mcp-data/registry/panel-tool-search.json +4 -5
  162. package/dist/mcp-data/registry/registry.json +391 -32
  163. package/dist/mcp-data/registry/select.json +1 -0
  164. package/dist/mcp-data/registry/tab-group.json +21 -2
  165. package/dist/mcp-data/registry/table-filter.json +79 -9
  166. package/dist/mcp-data/registry/table-group.json +301 -0
  167. package/dist/mcp-data/registry/table-search.json +343 -0
  168. package/dist/mcp-data/registry/table-sort.json +1 -1
  169. package/dist/mcp-data/registry/table-toolbar.json +7 -6
  170. package/dist/mcp-data/registry/table.json +55 -17
  171. package/dist/react/components.d.ts +2 -0
  172. package/dist/react/components.js +2 -0
  173. package/dist/react/ds-filter-menu.d.ts +2 -1
  174. package/dist/react/ds-filter-menu.js +1 -0
  175. package/dist/react/ds-table-filter.d.ts +2 -1
  176. package/dist/react/ds-table-filter.js +1 -0
  177. package/dist/react/ds-table-group.d.ts +14 -0
  178. package/dist/react/ds-table-group.js +16 -0
  179. package/dist/react/ds-table-search.d.ts +14 -0
  180. package/dist/react/ds-table-search.js +16 -0
  181. package/dist/styles/table.css +46 -0
  182. package/dist/types/components/Chip/Chip.d.ts +5 -0
  183. package/dist/types/components/FilterMenu/FilterMenu.d.ts +26 -0
  184. package/dist/types/components/Input/Input.d.ts +6 -0
  185. package/dist/types/components/TabGroup/TabGroup.d.ts +2 -0
  186. package/dist/types/components/Table/Table.d.ts +6 -0
  187. package/dist/types/components/Table/index.d.ts +1 -1
  188. package/dist/types/components/Table/table-cell-model.d.ts +11 -1
  189. package/dist/types/components/Table/table-highlight.d.ts +12 -0
  190. package/dist/types/components/Table/table-model.d.ts +6 -5
  191. package/dist/types/components/Table/table-render-model.d.ts +1 -1
  192. package/dist/types/components/Table/table-row-view.d.ts +4 -1
  193. package/dist/types/components/Table/table-types.d.ts +22 -4
  194. package/dist/types/components/Table/table-virtual-model.d.ts +2 -0
  195. package/dist/types/components/TableFilter/TableFilter.d.ts +9 -1
  196. package/dist/types/components/TableGroup/TableGroup.d.ts +60 -0
  197. package/dist/types/components/TableSearch/TableSearch.d.ts +56 -0
  198. package/dist/types/components/TableSearch/table-search-model.d.ts +10 -0
  199. package/dist/types/components/TableSearch/table-search-types.d.ts +10 -0
  200. package/dist/types/components.d.ts +386 -6
  201. package/dist/types/utils/choice-list-parts.d.ts +11 -1
  202. package/dist/types/utils/select-controller.d.ts +1 -1
  203. package/dist/vue/components.d.ts +2 -0
  204. package/dist/vue/components.js +2 -0
  205. package/dist/vue/ds-chip.js +2 -0
  206. package/dist/vue/ds-filter-menu.js +5 -0
  207. package/dist/vue/ds-input.js +3 -0
  208. package/dist/vue/ds-tab-group.js +1 -0
  209. package/dist/vue/ds-table-filter.js +5 -0
  210. package/dist/vue/ds-table-group.d.ts +3 -0
  211. package/dist/vue/ds-table-group.js +20 -0
  212. package/dist/vue/ds-table-search.d.ts +3 -0
  213. package/dist/vue/ds-table-search.js +22 -0
  214. package/dist/vue/ds-table.js +2 -0
  215. package/package.json +1 -1
  216. package/dist/components/p-AtUP95E_.js +0 -2
  217. package/dist/components/p-B5-R5mb8.js +0 -2
  218. package/dist/components/p-B5-R5mb8.js.map +0 -1
  219. package/dist/components/p-BeA6Jv-3.js +0 -2
  220. package/dist/components/p-BkelrY4-.js +0 -2
  221. package/dist/components/p-BkelrY4-.js.map +0 -1
  222. package/dist/components/p-CCmgtju-.js.map +0 -1
  223. package/dist/components/p-DA5H_Iq_.js +0 -2
  224. package/dist/components/p-DA5H_Iq_.js.map +0 -1
  225. package/dist/components/p-DGe5oXR0.js.map +0 -1
  226. /package/dist/components/{p-Bf7PZJPT.js.map → p-5Z4oYuiK.js.map} +0 -0
  227. /package/dist/components/{p-DIlScMvI.js.map → p-6rB0eAda.js.map} +0 -0
  228. /package/dist/components/{p-CptSB-tA.js.map → p-9ykZwPlI.js.map} +0 -0
  229. /package/dist/components/{p-BHhmB9-4.js.map → p-B0kSlcaw.js.map} +0 -0
  230. /package/dist/components/{p-DWjTOoXs.js.map → p-B1wMpt1z.js.map} +0 -0
  231. /package/dist/components/{p-fRDzpfi9.js.map → p-BXv6RpoF.js.map} +0 -0
  232. /package/dist/components/{p-D7QlTWbN.js.map → p-BbG7nOcz.js.map} +0 -0
  233. /package/dist/components/{p-B2FT4Da6.js.map → p-Bc_z1UwJ.js.map} +0 -0
  234. /package/dist/components/{p-Bx5BSd6F.js.map → p-BcxidW9k.js.map} +0 -0
  235. /package/dist/components/{p-1UAVanY9.js.map → p-Bd8I2oXN.js.map} +0 -0
  236. /package/dist/components/{p-DdH7b4JF.js.map → p-CBymzuOO.js.map} +0 -0
  237. /package/dist/components/{p-BjRD57w3.js.map → p-CE2b5GPu.js.map} +0 -0
  238. /package/dist/components/{p-DfDoqOlx.js.map → p-CEnoPUn5.js.map} +0 -0
  239. /package/dist/components/{p-DBYv7fRq.js.map → p-CFkZSDwI.js.map} +0 -0
  240. /package/dist/components/{p-Bb4KnRy0.js.map → p-CTH3dSYg.js.map} +0 -0
  241. /package/dist/components/{p-BmssRAEZ.js.map → p-CZ144LS5.js.map} +0 -0
  242. /package/dist/components/{p-B-HsfQOK.js.map → p-Cd1JnnVK.js.map} +0 -0
  243. /package/dist/components/{p-CDw_WEVt.js.map → p-Cnsvgx1M.js.map} +0 -0
  244. /package/dist/components/{p-BYFS2qWb.js.map → p-CpeJMKJ5.js.map} +0 -0
  245. /package/dist/components/{p-DM1Z_hh0.js.map → p-D36EmETH.js.map} +0 -0
  246. /package/dist/components/{p-DFC0sRM-.js.map → p-DI8DUozc.js.map} +0 -0
  247. /package/dist/components/{p-DQBT1Jkf.js.map → p-DbLLH3hr.js.map} +0 -0
  248. /package/dist/components/{p-B6rSDhJY.js.map → p-Dit6JmAK.js.map} +0 -0
  249. /package/dist/components/{p-caLOcQUK.js.map → p-DzPtYdXy.js.map} +0 -0
  250. /package/dist/components/{p-Do8wbFff.js.map → p-XaCYqck3.js.map} +0 -0
  251. /package/dist/components/{p-DKt_8s-U.js.map → p-Y5_MkCFn.js.map} +0 -0
  252. /package/dist/components/{p-BUexfjjg.js.map → p-YDxDyedE.js.map} +0 -0
  253. /package/dist/components/{p-L8IIeDXM.js.map → p-_C-XRpCB.js.map} +0 -0
  254. /package/dist/components/{p-CyZqk196.js.map → p-bHnk8t5I.js.map} +0 -0
  255. /package/dist/components/{p-ChfVRPHw.js.map → p-pUOA3iDG.js.map} +0 -0
  256. /package/dist/components/{p-DLbHgbVj.js.map → p-pnO8tAYB.js.map} +0 -0
  257. /package/dist/components/{p-B4wTnsUL.js.map → p-w9fkkwL2.js.map} +0 -0
@@ -56,10 +56,12 @@
56
56
  ],
57
57
  "states": [
58
58
  "Every size applies one complete control-density recipe across frame height, inline padding, icon zones, text-container inset, gap, and radius; supporting error content follows the shared 4px field flow.",
59
- "The normal field boundary uses the shared secondary inset border. Focus promotes it to the thicker bold-brand inset stroke, while error uses the thicker bold-negative inset stroke without changing geometry. Set hasBorder to false only in chrome that supplies enough surrounding structure; the control then remains borderless at rest, while focused, and while invalid, with semantics and supporting error copy unchanged.",
59
+ "The normal field boundary uses the shared secondary inset border. Focus promotes it to the thicker bold-brand inset stroke, while error uses the thicker bold-negative inset stroke without changing geometry. Set hasBorder to false only in chrome that supplies enough surrounding structure; set hasInteractionFill to false when that containing chrome also owns hover and pressed feedback.",
60
60
  "Placeholder text is secondary at rest and quaternary while the editable field is focused because it becomes decorative once typing begins. Single-line placeholder and entered value text truncate with an ellipsis when the field is narrower than its content.",
61
61
  "Entered values use the parent surface's primary foreground; prefix icons, suffix content, and resting placeholder text use its secondary foreground.",
62
62
  "Search fields show a standard borderless CrossCircle icon action only while they contain a value. Clearing emits the empty value and restores focus to the native field.",
63
+ "Search fields disable browser autocomplete history, automatic capitalization, autocorrection, and spellchecking by default so browser-owned suggestions do not compete with product-owned results. Consumers can explicitly provide autoComplete when a different native history behavior is required.",
64
+ "Search fields used with owned result sets forward aria-controls and aria-activedescendant to the native field so keyboard focus can remain in the query while assistive technology tracks the active result.",
63
65
  "The suffix slot is for compact units or decorations. The optional leading icon is decorative and does not replace the field label.",
64
66
  "Use autoComplete, inputMode, and enterKeyHint to provide browser and virtual-keyboard hints without changing the value's semantic type.",
65
67
  "Number fields preserve native spinbutton semantics, keyboard stepping, and min/max constraint behavior while dsChange continues to report the native string value. Two borderless inset chevron actions split the available inner height, disable independently at their numeric bound, and restore focus to the spinbutton after pointer activation.",
@@ -100,6 +102,22 @@
100
102
  },
101
103
  "api": {
102
104
  "props": {
105
+ "ariaActiveDescendant": {
106
+ "type": "string | undefined",
107
+ "resolvedType": "string | undefined",
108
+ "attribute": "aria-activedescendant",
109
+ "required": false,
110
+ "mutable": false,
111
+ "description": "Identifies the active descendant while focus remains in the editable field."
112
+ },
113
+ "ariaControls": {
114
+ "type": "string | undefined",
115
+ "resolvedType": "string | undefined",
116
+ "attribute": "aria-controls",
117
+ "required": false,
118
+ "mutable": false,
119
+ "description": "Identifies the results or popup controlled by the editable field."
120
+ },
103
121
  "ariaDescribedby": {
104
122
  "type": "string | undefined",
105
123
  "resolvedType": "string | undefined",
@@ -194,6 +212,15 @@
194
212
  "mutable": false,
195
213
  "description": "Show the standard inset border, including focused and invalid strokes."
196
214
  },
215
+ "hasInteractionFill": {
216
+ "type": "boolean",
217
+ "resolvedType": "boolean",
218
+ "attribute": "has-interaction-fill",
219
+ "default": "true",
220
+ "required": false,
221
+ "mutable": false,
222
+ "description": "Show the standard hover and pressed fill when the field is not embedded in interactive chrome."
223
+ },
197
224
  "icon": {
198
225
  "type": "string | undefined",
199
226
  "resolvedType": "string | undefined",
@@ -359,6 +386,22 @@
359
386
  "slots": []
360
387
  },
361
388
  "props": {
389
+ "ariaActiveDescendant": {
390
+ "type": "string | undefined",
391
+ "resolvedType": "string | undefined",
392
+ "attribute": "aria-activedescendant",
393
+ "required": false,
394
+ "mutable": false,
395
+ "description": "Identifies the active descendant while focus remains in the editable field."
396
+ },
397
+ "ariaControls": {
398
+ "type": "string | undefined",
399
+ "resolvedType": "string | undefined",
400
+ "attribute": "aria-controls",
401
+ "required": false,
402
+ "mutable": false,
403
+ "description": "Identifies the results or popup controlled by the editable field."
404
+ },
362
405
  "ariaDescribedby": {
363
406
  "type": "string | undefined",
364
407
  "resolvedType": "string | undefined",
@@ -453,6 +496,15 @@
453
496
  "mutable": false,
454
497
  "description": "Show the standard inset border, including focused and invalid strokes."
455
498
  },
499
+ "hasInteractionFill": {
500
+ "type": "boolean",
501
+ "resolvedType": "boolean",
502
+ "attribute": "has-interaction-fill",
503
+ "default": "true",
504
+ "required": false,
505
+ "mutable": false,
506
+ "description": "Show the standard hover and pressed fill when the field is not embedded in interactive chrome."
507
+ },
456
508
  "icon": {
457
509
  "type": "string | undefined",
458
510
  "resolvedType": "string | undefined",
@@ -668,7 +720,7 @@
668
720
  },
669
721
  {
670
722
  "path": "src/wc/components/Input/Input.tsx",
671
- "content": "import {\n AttachInternals,\n Component,\n Prop,\n State,\n Event,\n EventEmitter,\n Element,\n Method,\n Watch,\n h,\n Host,\n} from '@stencil/core';\nimport {\n controlWidthClass,\n CONTROL_TEXT_VARIANT,\n DEFAULT_REQUIRED_MESSAGE,\n restoreStringFormState,\n setFormControlValue,\n setRequiredValidity,\n type ControlWidth,\n} from '../../utils';\n\nexport type InputType = 'text' | 'email' | 'tel' | 'url' | 'search' | 'password' | 'number';\nexport type InputSize = 'lg' | 'md' | 'sm' | 'xs';\nexport type InputWidth = ControlWidth;\nexport type InputTextAlign = 'start' | 'end';\n\nconst ICON_SIZE: Record<InputSize, 'lg' | 'md' | 'sm' | 'xs'> = {\n lg: 'lg',\n md: 'md',\n sm: 'sm',\n xs: 'xs',\n};\n\nconst CLEAR_BUTTON_SIZE: Record<InputSize, 'md' | 'sm' | 'xs'> = {\n lg: 'md',\n md: 'sm',\n sm: 'xs',\n xs: 'xs',\n};\n\nlet idCounter = 0;\n\n@Component({\n tag: 'ds-input',\n styleUrl: 'Input.css',\n scoped: true,\n formAssociated: true,\n})\nexport class Input {\n @Element() el!: HTMLElement;\n @AttachInternals() internals!: ElementInternals;\n\n private generatedId = `ds-input-${++idCounter}`;\n private errorId = `${this.generatedId}-error`;\n\n @Prop({ mutable: true }) value: string = '';\n @Prop({ reflect: true }) name: string | undefined;\n @Prop({ reflect: true }) form: string | undefined;\n @Prop({ reflect: true }) disabled: boolean = false;\n /** Keeps the value focusable and submittable while preventing edits. */\n @Prop({ reflect: true }) readOnly: boolean = false;\n @Prop({ reflect: true }) required: boolean = false;\n @Prop() requiredMessage: string = DEFAULT_REQUIRED_MESSAGE;\n @Prop() clearLabel: string = 'Clear';\n @Prop() placeholder: string | undefined;\n @Prop() type: InputType = 'text';\n /** Minimum accepted value when type is number. */\n @Prop() min: number | undefined;\n /** Maximum accepted value when type is number. */\n @Prop() max: number | undefined;\n /** Numeric increment used by native stepping and constraint validation. */\n @Prop() step: number | undefined;\n /** Align the editable value; number steppers follow the same inline edge. */\n @Prop() textAlign: InputTextAlign = 'start';\n /** Native browser autofill hint. */\n @Prop({ attribute: 'autocomplete' }) autoComplete: string | undefined;\n /** Preferred virtual keyboard without changing the value semantics. */\n @Prop({ attribute: 'inputmode' }) inputMode: string = '';\n /** Preferred virtual-keyboard action label. */\n @Prop({ attribute: 'enterkeyhint' }) enterKeyHint: string = '';\n /** Control density. */\n @Prop() size: InputSize = 'md';\n /** Width fit — fill the parent (default) or hug the available content. */\n @Prop() width: InputWidth = 'fill';\n /** Show the standard inset border, including focused and invalid strokes. */\n @Prop() hasBorder: boolean = true;\n /** Optional leading icon name. */\n @Prop() icon: string | undefined;\n @Prop() isInactive: boolean = false;\n @Prop() autoFocus: boolean = false;\n @Prop() error: boolean = false;\n @Prop() errorMessage: string | undefined;\n /** Associates the internal input with an external <label>. */\n @Prop() inputId: string | undefined;\n @Prop({ attribute: 'aria-label' }) ariaLabel: string | null = null;\n @Prop({ attribute: 'aria-labelledby' }) ariaLabelledby: string | undefined;\n @Prop({ attribute: 'aria-describedby' }) ariaDescribedby: string | undefined;\n\n @Event() dsChange!: EventEmitter<string>;\n @Event() dsClear!: EventEmitter<void>;\n\n private initialValue = '';\n private inputEl?: HTMLInputElement;\n @State() private formDisabled = false;\n @State() private hasSuffix = false;\n @State() private focused = false;\n @State() private touched = false;\n\n componentWillLoad() {\n this.initialValue = this.value;\n this.hasSuffix = Boolean(this.el.querySelector('[slot=\"suffix\"]'));\n this.syncFormValue();\n }\n\n componentDidRender() {\n const hasSuffix = Boolean(this.el.querySelector('[slot=\"suffix\"]'));\n if (hasSuffix !== this.hasSuffix) this.hasSuffix = hasSuffix;\n }\n\n @Watch('value')\n @Watch('disabled')\n @Watch('isInactive')\n @Watch('required')\n syncFormValue() {\n const inactive = this.isInactive || this.disabled || this.formDisabled;\n setFormControlValue(this.internals, this.value, { inactive });\n const missing = this.required && !inactive && this.value.length === 0;\n setRequiredValidity(this.internals, missing, this.requiredMessage);\n }\n\n formDisabledCallback(disabled: boolean) {\n this.formDisabled = disabled;\n this.syncFormValue();\n }\n\n formResetCallback() {\n this.value = this.initialValue;\n }\n\n formStateRestoreCallback(state: string | File | FormData | null) {\n this.value = restoreStringFormState(state);\n }\n\n @Method()\n async setFocus() {\n this.inputEl?.focus();\n }\n\n private handleInput = (e: Event) => {\n this.value = (e.target as HTMLInputElement).value;\n this.dsChange.emit(this.value);\n };\n\n private handleFocus = () => {\n this.focused = true;\n };\n\n private handleBlur = () => {\n this.focused = false;\n this.touched = true;\n };\n\n private handleClear = () => {\n this.value = '';\n this.dsChange.emit('');\n this.dsClear.emit();\n this.inputEl?.focus();\n };\n\n private numericStepDisabled(direction: 1 | -1): boolean {\n if (this.value.trim() === '') return false;\n const value = Number(this.value);\n if (!Number.isFinite(value)) return false;\n if (direction > 0 && this.max !== undefined) return value >= this.max;\n if (direction < 0 && this.min !== undefined) return value <= this.min;\n return false;\n }\n\n private handleNumericStep = (direction: 1 | -1) => {\n const input = this.inputEl;\n if (!input || input.disabled || input.readOnly || this.numericStepDisabled(direction)) return;\n\n const previous = input.value;\n if (direction > 0) input.stepUp();\n else input.stepDown();\n input.focus({ preventScroll: true });\n if (input.value === previous) return;\n\n this.value = input.value;\n this.dsChange.emit(this.value);\n };\n\n private renderNumericStepper(inactive: boolean) {\n const incrementDisabled = inactive || this.readOnly || this.numericStepDisabled(1);\n const decrementDisabled = inactive || this.readOnly || this.numericStepDisabled(-1);\n\n return (\n <span class=\"input-control__number-stepper\">\n <button\n type=\"button\"\n class=\"input-control__number-step input-control__number-step--increment ds-focus-ring-inset ds-interaction-fill\"\n disabled={incrementDisabled}\n tabIndex={-1}\n aria-hidden=\"true\"\n onClick={() => this.handleNumericStep(1)}\n >\n <ds-icon\n class=\"input-control__number-step-icon ds-interaction-fill__content\"\n name=\"ChevronUp\"\n size=\"xs\"\n color=\"inherit\"\n />\n </button>\n <button\n type=\"button\"\n class=\"input-control__number-step input-control__number-step--decrement ds-focus-ring-inset ds-interaction-fill\"\n disabled={decrementDisabled}\n tabIndex={-1}\n aria-hidden=\"true\"\n onClick={() => this.handleNumericStep(-1)}\n >\n <ds-icon\n class=\"input-control__number-step-icon ds-interaction-fill__content\"\n name=\"ChevronDown\"\n size=\"xs\"\n color=\"inherit\"\n />\n </button>\n </span>\n );\n }\n\n render() {\n const inputId = this.inputId ?? this.generatedId;\n const inactive = this.isInactive || this.disabled || this.formDisabled;\n const filled = this.value.length > 0;\n const dirty = this.value !== this.initialValue;\n const showClear = this.type === 'search' && filled && !inactive && !this.readOnly;\n const showError = this.error && Boolean(this.errorMessage);\n const textVariant = CONTROL_TEXT_VARIANT[this.size];\n const iconSize = ICON_SIZE[this.size];\n const numeric = this.type === 'number';\n\n const describedBy =\n [this.ariaDescribedby, showError ? this.errorId : undefined].filter(Boolean).join(' ') ||\n undefined;\n\n return (\n <Host\n class={{\n 'input-host': true,\n 'ds-field-stack': true,\n 'ds-control-inactive': inactive,\n [`ds-control--${this.size}`]: true,\n ...controlWidthClass(this.width),\n }}\n data-disabled={inactive ? '' : undefined}\n data-readonly={this.readOnly ? '' : undefined}\n data-required={this.required ? '' : undefined}\n data-invalid={this.error ? '' : undefined}\n data-filled={filled ? '' : undefined}\n data-focused={this.focused ? '' : undefined}\n data-dirty={dirty ? '' : undefined}\n data-touched={this.touched ? '' : undefined}\n >\n <div\n class={{\n 'input-control': true,\n 'input-control--number': numeric,\n 'input-control--align-start': this.textAlign === 'start',\n 'input-control--align-end': this.textAlign === 'end',\n 'ds-control-frame': true,\n 'input-control--bordered': this.hasBorder,\n 'input-control--error': this.hasBorder && this.error,\n 'ds-interaction-fill': true,\n [`ds-control--${this.size}`]: true,\n }}\n >\n {numeric && this.textAlign === 'end' && this.renderNumericStepper(inactive)}\n {this.icon && (\n <span\n class=\"input-control__prefix ds-control-icon-box ds-interaction-fill__content\"\n aria-hidden=\"true\"\n >\n <ds-icon name={this.icon} size={iconSize} color=\"inherit\" />\n </span>\n )}\n <input\n ref={element => {\n this.inputEl = element;\n }}\n type={this.type}\n id={inputId}\n value={this.value}\n placeholder={this.placeholder}\n min={numeric ? this.min : undefined}\n max={numeric ? this.max : undefined}\n step={numeric ? this.step : undefined}\n disabled={inactive}\n readOnly={this.readOnly}\n required={this.required}\n autoFocus={this.autoFocus}\n autoComplete={this.autoComplete}\n inputMode={this.inputMode || undefined}\n enterKeyHint={this.enterKeyHint || undefined}\n class={`native-input native-input--align-${this.textAlign} ds-control-label-box ds-text--${textVariant.replace('text-', '')} ds-text--regular ds-interaction-fill__content`}\n aria-label={this.ariaLabel}\n aria-labelledby={this.ariaLabelledby}\n aria-describedby={describedBy}\n aria-invalid={this.error ? 'true' : undefined}\n onInput={this.handleInput}\n onFocus={this.handleFocus}\n onBlur={this.handleBlur}\n />\n <span\n class={{\n 'input-control__suffix': true,\n 'ds-control-icon-box': true,\n 'input-control__suffix--empty': !this.hasSuffix,\n }}\n >\n <slot name=\"suffix\" />\n </span>\n {showClear && (\n <ds-button-unfilled\n class=\"input-control__clear\"\n variant=\"icon\"\n size={CLEAR_BUTTON_SIZE[this.size]}\n icon=\"CrossCircle\"\n hasBorder={false}\n rounded\n ariaLabel={this.clearLabel}\n onDsClick={this.handleClear}\n />\n )}\n {numeric && this.textAlign === 'start' && this.renderNumericStepper(inactive)}\n </div>\n {showError && (\n <ds-text\n class=\"error-text\"\n as=\"div\"\n variant=\"text-body-small\"\n color=\"negative\"\n textId={this.errorId}\n role=\"alert\"\n >\n {this.errorMessage}\n </ds-text>\n )}\n </Host>\n );\n }\n}\n",
723
+ "content": "import {\n AttachInternals,\n Component,\n Prop,\n State,\n Event,\n EventEmitter,\n Element,\n Method,\n Watch,\n h,\n Host,\n} from '@stencil/core';\nimport {\n controlWidthClass,\n CONTROL_TEXT_VARIANT,\n DEFAULT_REQUIRED_MESSAGE,\n restoreStringFormState,\n setFormControlValue,\n setRequiredValidity,\n type ControlWidth,\n} from '../../utils';\n\nexport type InputType = 'text' | 'email' | 'tel' | 'url' | 'search' | 'password' | 'number';\nexport type InputSize = 'lg' | 'md' | 'sm' | 'xs';\nexport type InputWidth = ControlWidth;\nexport type InputTextAlign = 'start' | 'end';\n\nconst ICON_SIZE: Record<InputSize, 'lg' | 'md' | 'sm' | 'xs'> = {\n lg: 'lg',\n md: 'md',\n sm: 'sm',\n xs: 'xs',\n};\n\nconst CLEAR_BUTTON_SIZE: Record<InputSize, 'md' | 'sm' | 'xs'> = {\n lg: 'md',\n md: 'sm',\n sm: 'xs',\n xs: 'xs',\n};\n\nlet idCounter = 0;\n\n@Component({\n tag: 'ds-input',\n styleUrl: 'Input.css',\n scoped: true,\n formAssociated: true,\n})\nexport class Input {\n @Element() el!: HTMLElement;\n @AttachInternals() internals!: ElementInternals;\n\n private generatedId = `ds-input-${++idCounter}`;\n private errorId = `${this.generatedId}-error`;\n\n @Prop({ mutable: true }) value: string = '';\n @Prop({ reflect: true }) name: string | undefined;\n @Prop({ reflect: true }) form: string | undefined;\n @Prop({ reflect: true }) disabled: boolean = false;\n /** Keeps the value focusable and submittable while preventing edits. */\n @Prop({ reflect: true }) readOnly: boolean = false;\n @Prop({ reflect: true }) required: boolean = false;\n @Prop() requiredMessage: string = DEFAULT_REQUIRED_MESSAGE;\n @Prop() clearLabel: string = 'Clear';\n @Prop() placeholder: string | undefined;\n @Prop() type: InputType = 'text';\n /** Minimum accepted value when type is number. */\n @Prop() min: number | undefined;\n /** Maximum accepted value when type is number. */\n @Prop() max: number | undefined;\n /** Numeric increment used by native stepping and constraint validation. */\n @Prop() step: number | undefined;\n /** Align the editable value; number steppers follow the same inline edge. */\n @Prop() textAlign: InputTextAlign = 'start';\n /** Native browser autofill hint. */\n @Prop({ attribute: 'autocomplete' }) autoComplete: string | undefined;\n /** Preferred virtual keyboard without changing the value semantics. */\n @Prop({ attribute: 'inputmode' }) inputMode: string = '';\n /** Preferred virtual-keyboard action label. */\n @Prop({ attribute: 'enterkeyhint' }) enterKeyHint: string = '';\n /** Control density. */\n @Prop() size: InputSize = 'md';\n /** Width fit — fill the parent (default) or hug the available content. */\n @Prop() width: InputWidth = 'fill';\n /** Show the standard inset border, including focused and invalid strokes. */\n @Prop() hasBorder: boolean = true;\n /** Show the standard hover and pressed fill when the field is not embedded in interactive chrome. */\n @Prop() hasInteractionFill: boolean = true;\n /** Optional leading icon name. */\n @Prop() icon: string | undefined;\n @Prop() isInactive: boolean = false;\n @Prop() autoFocus: boolean = false;\n @Prop() error: boolean = false;\n @Prop() errorMessage: string | undefined;\n /** Associates the internal input with an external <label>. */\n @Prop() inputId: string | undefined;\n @Prop({ attribute: 'aria-label' }) ariaLabel: string | null = null;\n @Prop({ attribute: 'aria-labelledby' }) ariaLabelledby: string | undefined;\n @Prop({ attribute: 'aria-describedby' }) ariaDescribedby: string | undefined;\n /** Identifies the results or popup controlled by the editable field. */\n @Prop({ attribute: 'aria-controls' }) ariaControls: string | undefined;\n /** Identifies the active descendant while focus remains in the editable field. */\n @Prop({ attribute: 'aria-activedescendant' }) ariaActiveDescendant: string | undefined;\n\n @Event() dsChange!: EventEmitter<string>;\n @Event() dsClear!: EventEmitter<void>;\n\n private initialValue = '';\n private inputEl?: HTMLInputElement;\n @State() private formDisabled = false;\n @State() private hasSuffix = false;\n @State() private focused = false;\n @State() private touched = false;\n\n componentWillLoad() {\n this.initialValue = this.value;\n this.hasSuffix = Boolean(this.el.querySelector('[slot=\"suffix\"]'));\n this.syncFormValue();\n }\n\n componentDidRender() {\n const hasSuffix = Boolean(this.el.querySelector('[slot=\"suffix\"]'));\n if (hasSuffix !== this.hasSuffix) this.hasSuffix = hasSuffix;\n }\n\n @Watch('value')\n @Watch('disabled')\n @Watch('isInactive')\n @Watch('required')\n syncFormValue() {\n const inactive = this.isInactive || this.disabled || this.formDisabled;\n setFormControlValue(this.internals, this.value, { inactive });\n const missing = this.required && !inactive && this.value.length === 0;\n setRequiredValidity(this.internals, missing, this.requiredMessage);\n }\n\n formDisabledCallback(disabled: boolean) {\n this.formDisabled = disabled;\n this.syncFormValue();\n }\n\n formResetCallback() {\n this.value = this.initialValue;\n }\n\n formStateRestoreCallback(state: string | File | FormData | null) {\n this.value = restoreStringFormState(state);\n }\n\n @Method()\n async setFocus() {\n this.inputEl?.focus();\n }\n\n private handleInput = (e: Event) => {\n this.value = (e.target as HTMLInputElement).value;\n this.dsChange.emit(this.value);\n };\n\n private handleFocus = () => {\n this.focused = true;\n };\n\n private handleBlur = () => {\n this.focused = false;\n this.touched = true;\n };\n\n private handleClear = () => {\n this.value = '';\n this.dsChange.emit('');\n this.dsClear.emit();\n this.inputEl?.focus();\n };\n\n private numericStepDisabled(direction: 1 | -1): boolean {\n if (this.value.trim() === '') return false;\n const value = Number(this.value);\n if (!Number.isFinite(value)) return false;\n if (direction > 0 && this.max !== undefined) return value >= this.max;\n if (direction < 0 && this.min !== undefined) return value <= this.min;\n return false;\n }\n\n private handleNumericStep = (direction: 1 | -1) => {\n const input = this.inputEl;\n if (!input || input.disabled || input.readOnly || this.numericStepDisabled(direction)) return;\n\n const previous = input.value;\n if (direction > 0) input.stepUp();\n else input.stepDown();\n input.focus({ preventScroll: true });\n if (input.value === previous) return;\n\n this.value = input.value;\n this.dsChange.emit(this.value);\n };\n\n private renderNumericStepper(inactive: boolean) {\n const incrementDisabled = inactive || this.readOnly || this.numericStepDisabled(1);\n const decrementDisabled = inactive || this.readOnly || this.numericStepDisabled(-1);\n\n return (\n <span class=\"input-control__number-stepper\">\n <button\n type=\"button\"\n class=\"input-control__number-step input-control__number-step--increment ds-focus-ring-inset ds-interaction-fill\"\n disabled={incrementDisabled}\n tabIndex={-1}\n aria-hidden=\"true\"\n onClick={() => this.handleNumericStep(1)}\n >\n <ds-icon\n class=\"input-control__number-step-icon ds-interaction-fill__content\"\n name=\"ChevronUp\"\n size=\"xs\"\n color=\"inherit\"\n />\n </button>\n <button\n type=\"button\"\n class=\"input-control__number-step input-control__number-step--decrement ds-focus-ring-inset ds-interaction-fill\"\n disabled={decrementDisabled}\n tabIndex={-1}\n aria-hidden=\"true\"\n onClick={() => this.handleNumericStep(-1)}\n >\n <ds-icon\n class=\"input-control__number-step-icon ds-interaction-fill__content\"\n name=\"ChevronDown\"\n size=\"xs\"\n color=\"inherit\"\n />\n </button>\n </span>\n );\n }\n\n render() {\n const inputId = this.inputId ?? this.generatedId;\n const inactive = this.isInactive || this.disabled || this.formDisabled;\n const filled = this.value.length > 0;\n const dirty = this.value !== this.initialValue;\n const showClear = this.type === 'search' && filled && !inactive && !this.readOnly;\n const showError = this.error && Boolean(this.errorMessage);\n const textVariant = CONTROL_TEXT_VARIANT[this.size];\n const iconSize = ICON_SIZE[this.size];\n const numeric = this.type === 'number';\n const resolvedAutoComplete = this.autoComplete ?? (this.type === 'search' ? 'off' : undefined);\n\n const describedBy =\n [this.ariaDescribedby, showError ? this.errorId : undefined].filter(Boolean).join(' ') ||\n undefined;\n\n return (\n <Host\n class={{\n 'input-host': true,\n 'ds-field-stack': true,\n 'ds-control-inactive': inactive,\n [`ds-control--${this.size}`]: true,\n ...controlWidthClass(this.width),\n }}\n data-disabled={inactive ? '' : undefined}\n data-readonly={this.readOnly ? '' : undefined}\n data-required={this.required ? '' : undefined}\n data-invalid={this.error ? '' : undefined}\n data-filled={filled ? '' : undefined}\n data-focused={this.focused ? '' : undefined}\n data-dirty={dirty ? '' : undefined}\n data-touched={this.touched ? '' : undefined}\n >\n <div\n class={{\n 'input-control': true,\n 'input-control--number': numeric,\n 'input-control--align-start': this.textAlign === 'start',\n 'input-control--align-end': this.textAlign === 'end',\n 'ds-control-frame': true,\n 'input-control--bordered': this.hasBorder,\n 'input-control--error': this.hasBorder && this.error,\n 'ds-interaction-fill': this.hasInteractionFill,\n [`ds-control--${this.size}`]: true,\n }}\n >\n {numeric && this.textAlign === 'end' && this.renderNumericStepper(inactive)}\n {this.icon && (\n <span\n class=\"input-control__prefix ds-control-icon-box ds-interaction-fill__content\"\n aria-hidden=\"true\"\n >\n <ds-icon name={this.icon} size={iconSize} color=\"inherit\" />\n </span>\n )}\n <input\n ref={element => {\n this.inputEl = element;\n }}\n type={this.type}\n id={inputId}\n value={this.value}\n placeholder={this.placeholder}\n min={numeric ? this.min : undefined}\n max={numeric ? this.max : undefined}\n step={numeric ? this.step : undefined}\n disabled={inactive}\n readOnly={this.readOnly}\n required={this.required}\n autoFocus={this.autoFocus}\n autoComplete={resolvedAutoComplete}\n autoCapitalize={this.type === 'search' ? 'none' : undefined}\n autoCorrect={this.type === 'search' ? 'off' : undefined}\n spellcheck={this.type === 'search' ? false : undefined}\n inputMode={this.inputMode || undefined}\n enterKeyHint={this.enterKeyHint || undefined}\n class={`native-input native-input--align-${this.textAlign} ds-control-label-box ds-text--${textVariant.replace('text-', '')} ds-text--regular ds-interaction-fill__content`}\n aria-label={this.ariaLabel}\n aria-labelledby={this.ariaLabelledby}\n aria-describedby={describedBy}\n aria-controls={this.ariaControls}\n aria-activedescendant={this.ariaActiveDescendant}\n aria-invalid={this.error ? 'true' : undefined}\n onInput={this.handleInput}\n onFocus={this.handleFocus}\n onBlur={this.handleBlur}\n />\n <span\n class={{\n 'input-control__suffix': true,\n 'ds-control-icon-box': true,\n 'input-control__suffix--empty': !this.hasSuffix,\n }}\n >\n <slot name=\"suffix\" />\n </span>\n {showClear && (\n <ds-button-unfilled\n class=\"input-control__clear\"\n variant=\"icon\"\n size={CLEAR_BUTTON_SIZE[this.size]}\n icon=\"CrossCircle\"\n hasBorder={false}\n rounded\n ariaLabel={this.clearLabel}\n onDsClick={this.handleClear}\n />\n )}\n {numeric && this.textAlign === 'start' && this.renderNumericStepper(inactive)}\n </div>\n {showError && (\n <ds-text\n class=\"error-text\"\n as=\"div\"\n variant=\"text-body-small\"\n color=\"negative\"\n textId={this.errorId}\n role=\"alert\"\n >\n {this.errorMessage}\n </ds-text>\n )}\n </Host>\n );\n }\n}\n",
672
724
  "type": "registry:ui"
673
725
  }
674
726
  ]
@@ -368,25 +368,24 @@
368
368
  },
369
369
  "dependencies": [
370
370
  "@ds-mo/ui",
371
- "@ds-mo/tokens",
372
- "@ds-mo/icons"
371
+ "@ds-mo/tokens"
373
372
  ],
374
373
  "registryDependencies": [
375
374
  "button-unfilled",
376
375
  "divider",
377
- "icon",
376
+ "input",
378
377
  "text",
379
378
  "tooltip"
380
379
  ],
381
380
  "files": [
382
381
  {
383
382
  "path": "src/wc/components/PanelToolSearch/PanelToolSearch.css",
384
- "content": "@import '../../utils/control-density.css';\n@import '../../utils/chrome-layout.css';\n@import '../../utils/search-control.css';\n@import '../../utils/typography.css';\n\n:host {\n display: block;\n flex: 0 0 var(--dimension-size-600);\n width: 100%;\n min-width: 0;\n height: var(--dimension-size-600);\n box-sizing: border-box;\n background: transparent;\n}\n\n.panel-tool-search {\n position: relative;\n width: 100%;\n height: 100%;\n background: transparent;\n}\n\n.panel-tool-search::after {\n content: '';\n position: absolute;\n inset: auto 0 0;\n height: var(--dimension-stroke-width-012);\n background-color: var(--color-border-tertiary);\n pointer-events: none;\n}\n\n.select-search {\n flex: 1 1 auto;\n width: auto;\n min-width: 0;\n height: var(--dimension-size-400);\n padding: 0;\n}\n\n.select-search::after {\n display: none;\n}\n\n.panel-tool-search__filter-group {\n display: flex;\n flex: 0 0 auto;\n align-items: center;\n gap: var(--dimension-space-100);\n}\n\n.panel-tool-search__divider,\n.panel-tool-search__filter {\n flex: 0 0 auto;\n}\n",
383
+ "content": "@import '../../utils/control-density.css';\n@import '../../utils/chrome-layout.css';\n@import '../../utils/search-control.css';\n\n:host {\n display: block;\n flex: 0 0 var(--dimension-size-600);\n width: 100%;\n min-width: 0;\n height: var(--dimension-size-600);\n box-sizing: border-box;\n background: transparent;\n}\n\n.panel-tool-search {\n position: relative;\n width: 100%;\n height: 100%;\n background: transparent;\n}\n\n.panel-tool-search::after {\n content: '';\n position: absolute;\n inset: auto 0 0;\n height: var(--dimension-stroke-width-012);\n background-color: var(--color-border-tertiary);\n pointer-events: none;\n}\n\n.select-search {\n flex: 1 1 auto;\n width: auto;\n min-width: 0;\n height: var(--dimension-size-400);\n padding: 0;\n}\n\n.panel-tool-search__filter-group {\n display: flex;\n flex: 0 0 auto;\n align-items: center;\n gap: var(--dimension-space-100);\n}\n\n.panel-tool-search__divider,\n.panel-tool-search__filter {\n flex: 0 0 auto;\n}\n",
385
384
  "type": "registry:ui"
386
385
  },
387
386
  {
388
387
  "path": "src/wc/components/PanelToolSearch/PanelToolSearch.tsx",
389
- "content": "import { Component, Element, Event, EventEmitter, h, Host, Method, Prop } from '@stencil/core';\nimport { ChoiceSearch } from '../../utils/choice-list-parts';\n\n@Component({\n tag: 'ds-panel-tool-search',\n styleUrl: 'PanelToolSearch.css',\n scoped: true,\n})\nexport class PanelToolSearch {\n @Element() el!: HTMLElement;\n\n /** Current search query. */\n @Prop({ mutable: true }) value: string = '';\n /** Search guidance shown while the query is empty. */\n @Prop() placeholder: string = 'Search';\n /** Accessible name for the search field. */\n @Prop({ attribute: 'aria-label' }) ariaLabel: string = 'Search';\n /** Optional ID of the results region filtered by this search. */\n @Prop() controls: string | undefined;\n /** Prevents search interaction while keeping the row visible. */\n @Prop() isInactive: boolean = false;\n /** Show the optional trailing filter-menu trigger. */\n @Prop() showFilter: boolean = false;\n /** Accessible name for the filter-menu trigger. */\n @Prop() filterAriaLabel: string = 'Filter';\n /** Stable id placed on the filter trigger for ds-menu anchoring. */\n @Prop() filterTriggerId: string = '';\n /** Id of the menu controlled by the filter trigger. */\n @Prop() filterControls: string | undefined;\n /** Whether the controlled filter menu is open. */\n @Prop() filterExpanded: boolean = false;\n /** Promote the trigger foreground when one or more filters are applied. */\n @Prop() filterActive: boolean = false;\n\n @Event() dsChange!: EventEmitter<string>;\n @Event() dsClear!: EventEmitter<void>;\n @Event() dsFilterToggle!: EventEmitter<MouseEvent>;\n\n componentDidRender() {\n const input = this.el.querySelector('input');\n if (input && input.value !== this.value) input.value = this.value;\n }\n\n @Method()\n async setFocus() {\n this.el.querySelector('input')?.focus();\n }\n\n @Method()\n async focusFilterTrigger() {\n const trigger = this.el.querySelector('ds-button-unfilled.panel-tool-search__filter') as\n | (HTMLElement & { setFocus?: () => Promise<void> })\n | null;\n await trigger?.setFocus?.();\n }\n\n private handleChange = (value: string) => {\n this.value = value;\n this.dsChange.emit(value);\n };\n\n render() {\n return (\n <Host>\n <div class=\"panel-tool-search ds-chrome-row ds-chrome-space--md\">\n <ChoiceSearch\n value={this.value}\n placeholder={this.placeholder}\n ariaLabel={this.ariaLabel}\n controls={this.controls}\n disabled={this.isInactive}\n inputRef={() => undefined}\n clearLabel=\"Clear\"\n onValueChange={this.handleChange}\n onClear={() => this.dsClear.emit()}\n onKeyDown={() => undefined}\n />\n {this.showFilter ? (\n <div class=\"panel-tool-search__filter-group\">\n <ds-divider\n class=\"panel-tool-search__divider\"\n orientation=\"vertical\"\n length=\"var(--dimension-size-200)\"\n />\n <ds-tooltip label={this.filterAriaLabel} side=\"bottom\" size=\"sm\">\n <ds-button-unfilled\n id={this.filterTriggerId || undefined}\n class=\"panel-tool-search__filter\"\n variant=\"icon\"\n icon=\"Filters\"\n size=\"md\"\n aria-label={this.filterAriaLabel}\n haspopup=\"menu\"\n controls={this.filterControls}\n expanded={this.filterExpanded}\n isActive={this.filterActive}\n isInactive={this.isInactive}\n activeFill={false}\n hasBorder={false}\n onDsChange={(event: CustomEvent<boolean>) => {\n event.stopPropagation();\n }}\n onDsClick={(event: CustomEvent<MouseEvent>) => {\n event.stopPropagation();\n this.dsFilterToggle.emit(event.detail);\n }}\n />\n </ds-tooltip>\n </div>\n ) : null}\n </div>\n </Host>\n );\n }\n}\n",
388
+ "content": "import { Component, Element, Event, EventEmitter, h, Host, Method, Prop } from '@stencil/core';\nimport { ChoiceSearch } from '../../utils/choice-list-parts';\n\n@Component({\n tag: 'ds-panel-tool-search',\n styleUrl: 'PanelToolSearch.css',\n scoped: true,\n})\nexport class PanelToolSearch {\n @Element() el!: HTMLElement;\n\n /** Current search query. */\n @Prop({ mutable: true }) value: string = '';\n /** Search guidance shown while the query is empty. */\n @Prop() placeholder: string = 'Search';\n /** Accessible name for the search field. */\n @Prop({ attribute: 'aria-label' }) ariaLabel: string = 'Search';\n /** Optional ID of the results region filtered by this search. */\n @Prop() controls: string | undefined;\n /** Prevents search interaction while keeping the row visible. */\n @Prop() isInactive: boolean = false;\n /** Show the optional trailing filter-menu trigger. */\n @Prop() showFilter: boolean = false;\n /** Accessible name for the filter-menu trigger. */\n @Prop() filterAriaLabel: string = 'Filter';\n /** Stable id placed on the filter trigger for ds-menu anchoring. */\n @Prop() filterTriggerId: string = '';\n /** Id of the menu controlled by the filter trigger. */\n @Prop() filterControls: string | undefined;\n /** Whether the controlled filter menu is open. */\n @Prop() filterExpanded: boolean = false;\n /** Promote the trigger foreground when one or more filters are applied. */\n @Prop() filterActive: boolean = false;\n\n @Event() dsChange!: EventEmitter<string>;\n @Event() dsClear!: EventEmitter<void>;\n @Event() dsFilterToggle!: EventEmitter<MouseEvent>;\n\n componentDidRender() {\n const input = this.el.querySelector('input');\n if (input && input.value !== this.value) input.value = this.value;\n }\n\n @Method()\n async setFocus() {\n this.el.querySelector('input')?.focus();\n }\n\n @Method()\n async focusFilterTrigger() {\n const trigger = this.el.querySelector('ds-button-unfilled.panel-tool-search__filter') as\n | (HTMLElement & { setFocus?: () => Promise<void> })\n | null;\n await trigger?.setFocus?.();\n }\n\n private handleChange = (value: string) => {\n this.value = value;\n this.dsChange.emit(value);\n };\n\n render() {\n return (\n <Host>\n <div class=\"panel-tool-search ds-chrome-row ds-chrome-space--md\">\n <ChoiceSearch\n hasFocusBoundary={false}\n hasInteractionFill={false}\n value={this.value}\n placeholder={this.placeholder}\n ariaLabel={this.ariaLabel}\n controls={this.controls}\n disabled={this.isInactive}\n inputRef={() => undefined}\n clearLabel=\"Clear\"\n onValueChange={this.handleChange}\n onClear={() => this.dsClear.emit()}\n onKeyDown={() => undefined}\n />\n {this.showFilter ? (\n <div class=\"panel-tool-search__filter-group\">\n <ds-divider\n class=\"panel-tool-search__divider\"\n orientation=\"vertical\"\n length=\"var(--dimension-size-200)\"\n />\n <ds-tooltip label={this.filterAriaLabel} side=\"bottom\" size=\"sm\">\n <ds-button-unfilled\n id={this.filterTriggerId || undefined}\n class=\"panel-tool-search__filter\"\n variant=\"icon\"\n icon=\"Filters\"\n size=\"md\"\n aria-label={this.filterAriaLabel}\n haspopup=\"menu\"\n controls={this.filterControls}\n expanded={this.filterExpanded}\n isActive={this.filterActive}\n isInactive={this.isInactive}\n activeFill={false}\n hasBorder={false}\n onDsChange={(event: CustomEvent<boolean>) => {\n event.stopPropagation();\n }}\n onDsClick={(event: CustomEvent<MouseEvent>) => {\n event.stopPropagation();\n this.dsFilterToggle.emit(event.detail);\n }}\n />\n </ds-tooltip>\n </div>\n ) : null}\n </div>\n </Host>\n );\n }\n}\n",
390
389
  "type": "registry:ui"
391
390
  }
392
391
  ]