@ds-mo/ui 15.11.1 → 15.12.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 (409) hide show
  1. package/dist/.package-ready.json +1 -1
  2. package/dist/agent-patterns.json +1 -1
  3. package/dist/agent.json +114 -18
  4. package/dist/angular/ds-card-action-center.d.ts +1 -1
  5. package/dist/angular/ds-card-action-center.js +3 -3
  6. package/dist/angular/ds-card-chart.d.ts +1 -1
  7. package/dist/angular/ds-card-chart.js +3 -3
  8. package/dist/angular/ds-card-navigation.d.ts +1 -1
  9. package/dist/angular/ds-card-navigation.js +3 -3
  10. package/dist/angular/ds-card-setting.d.ts +1 -1
  11. package/dist/angular/ds-card-setting.js +3 -3
  12. package/dist/angular/ds-card-settings-scope.d.ts +1 -1
  13. package/dist/angular/ds-card-settings-scope.js +3 -3
  14. package/dist/angular/ds-field.d.ts +1 -1
  15. package/dist/angular/ds-field.js +3 -3
  16. package/dist/angular/ds-inline-banner-settings.d.ts +1 -1
  17. package/dist/angular/ds-inline-banner-settings.js +3 -3
  18. package/dist/angular/ds-pagination.d.ts +1 -1
  19. package/dist/angular/ds-pagination.js +3 -3
  20. package/dist/angular/ds-radio.d.ts +1 -1
  21. package/dist/angular/ds-radio.js +3 -3
  22. package/dist/angular/ds-setting-row-radio.d.ts +1 -1
  23. package/dist/angular/ds-setting-row-radio.js +3 -3
  24. package/dist/angular/ds-setting-row-toggle.d.ts +1 -1
  25. package/dist/angular/ds-setting-row-toggle.js +3 -3
  26. package/dist/angular/ds-skeleton.d.ts +1 -1
  27. package/dist/angular/ds-skeleton.js +3 -3
  28. package/dist/components/THIRD-PARTY-NOTICES +1 -1
  29. package/dist/components/bundled-dependencies.json +1 -1
  30. package/dist/components/ds-agent-activity.js +1 -1
  31. package/dist/components/ds-agent-questionnaire.js +1 -1
  32. package/dist/components/ds-agent-response.js +1 -1
  33. package/dist/components/ds-agent-response.js.map +1 -1
  34. package/dist/components/ds-agent-source-list.js +1 -1
  35. package/dist/components/ds-agent-tool-call.js +1 -1
  36. package/dist/components/ds-attachment-list.js +1 -1
  37. package/dist/components/ds-badge.js +1 -1
  38. package/dist/components/ds-banner.js +1 -1
  39. package/dist/components/ds-bar-action.js +1 -1
  40. package/dist/components/ds-bar-nav.js +1 -1
  41. package/dist/components/ds-bar-page-title.js +1 -1
  42. package/dist/components/ds-bar-title.js +1 -1
  43. package/dist/components/ds-bar-workflow.js +1 -1
  44. package/dist/components/ds-breadcrumb.js +1 -1
  45. package/dist/components/ds-button-filled.js +1 -1
  46. package/dist/components/ds-button-inverted.js +1 -1
  47. package/dist/components/ds-button-unfilled.js +1 -1
  48. package/dist/components/ds-calendar.js +1 -1
  49. package/dist/components/ds-card-action-center.js +1 -1
  50. package/dist/components/ds-card-action-center.js.map +1 -1
  51. package/dist/components/ds-card-chart.js +1 -1
  52. package/dist/components/ds-card-chart.js.map +1 -1
  53. package/dist/components/ds-card-navigation.js +1 -1
  54. package/dist/components/ds-card-navigation.js.map +1 -1
  55. package/dist/components/ds-card-overview.js +1 -1
  56. package/dist/components/ds-card-overview.js.map +1 -1
  57. package/dist/components/ds-card-setting.js +1 -1
  58. package/dist/components/ds-card-setting.js.map +1 -1
  59. package/dist/components/ds-card-settings-scope.js +1 -1
  60. package/dist/components/ds-card-settings-scope.js.map +1 -1
  61. package/dist/components/ds-chart-legend.js +1 -1
  62. package/dist/components/ds-chart.js +1 -1
  63. package/dist/components/ds-checkbox-group.js +1 -1
  64. package/dist/components/ds-checkbox.js +1 -1
  65. package/dist/components/ds-chip.js +1 -1
  66. package/dist/components/ds-code-block.js +1 -1
  67. package/dist/components/ds-conversation-list-item.js +1 -1
  68. package/dist/components/ds-conversation-list-section.js +1 -1
  69. package/dist/components/ds-conversation-list.js +1 -1
  70. package/dist/components/ds-data-customize.js +1 -1
  71. package/dist/components/ds-data-customize.js.map +1 -1
  72. package/dist/components/ds-data-filter.js +1 -1
  73. package/dist/components/ds-data-group.js +1 -1
  74. package/dist/components/ds-data-preferences.js +1 -1
  75. package/dist/components/ds-data-saved-views.js +1 -1
  76. package/dist/components/ds-data-saved-views.js.map +1 -1
  77. package/dist/components/ds-data-search.js +1 -1
  78. package/dist/components/ds-data-sort.js +1 -1
  79. package/dist/components/ds-data-toolbar.js +1 -1
  80. package/dist/components/ds-divider.js +1 -1
  81. package/dist/components/ds-empty-state.js +1 -1
  82. package/dist/components/ds-field.js +1 -1
  83. package/dist/components/ds-filter-menu.js +1 -1
  84. package/dist/components/ds-inline-banner-settings.js +1 -1
  85. package/dist/components/ds-inline-banner-settings.js.map +1 -1
  86. package/dist/components/ds-input-date.js +1 -1
  87. package/dist/components/ds-input-time.js +1 -1
  88. package/dist/components/ds-input.js +1 -1
  89. package/dist/components/ds-map-cluster-marker.js +1 -1
  90. package/dist/components/ds-map-entity-marker.js +1 -1
  91. package/dist/components/ds-map-marker.js +1 -1
  92. package/dist/components/ds-markdown.js +1 -1
  93. package/dist/components/ds-menu.js +1 -1
  94. package/dist/components/ds-message-actions.js +1 -1
  95. package/dist/components/ds-message-bubble.js +1 -1
  96. package/dist/components/ds-message-composer.js +1 -1
  97. package/dist/components/ds-message-scroller.js +1 -1
  98. package/dist/components/ds-message.js +1 -1
  99. package/dist/components/ds-mobile-bar-nav.js +1 -1
  100. package/dist/components/ds-mobile-header.js +1 -1
  101. package/dist/components/ds-mobile-section-switcher.js +1 -1
  102. package/dist/components/ds-mobile-sheet-nav.js +1 -1
  103. package/dist/components/ds-modal.js +1 -1
  104. package/dist/components/ds-navigation-tab-group.js +1 -1
  105. package/dist/components/ds-pagination.js +1 -1
  106. package/dist/components/ds-panel-nav.js +1 -1
  107. package/dist/components/ds-panel-sub-nav.js +1 -1
  108. package/dist/components/ds-panel-tool-header.js +1 -1
  109. package/dist/components/ds-panel-tool-search.js +1 -1
  110. package/dist/components/ds-panel-tools.js +1 -1
  111. package/dist/components/ds-paper-texture.js +1 -1
  112. package/dist/components/ds-radio-tile.js +1 -1
  113. package/dist/components/ds-radio.js +1 -1
  114. package/dist/components/ds-score.js +1 -1
  115. package/dist/components/ds-scroll-overlay.js +1 -1
  116. package/dist/components/ds-select-toggle.js +1 -1
  117. package/dist/components/ds-select.js +1 -1
  118. package/dist/components/ds-setting-row-checkbox.js +1 -1
  119. package/dist/components/ds-setting-row-radio.js +1 -1
  120. package/dist/components/ds-setting-row-radio.js.map +1 -1
  121. package/dist/components/ds-setting-row-toggle.js +1 -1
  122. package/dist/components/ds-setting-row-toggle.js.map +1 -1
  123. package/dist/components/ds-shell-app.js +1 -1
  124. package/dist/components/ds-shell-app.js.map +1 -1
  125. package/dist/components/ds-shell-page.js +1 -1
  126. package/dist/components/ds-shell-tools.js +1 -1
  127. package/dist/components/ds-skeleton.js +1 -1
  128. package/dist/components/ds-slider.js +1 -1
  129. package/dist/components/ds-swatch-picker.js +1 -1
  130. package/dist/components/ds-switch.js +1 -1
  131. package/dist/components/ds-tab-group.js +1 -1
  132. package/dist/components/ds-table.js +1 -1
  133. package/dist/components/ds-table.js.map +1 -1
  134. package/dist/components/ds-tag.js +1 -1
  135. package/dist/components/ds-text.js +1 -1
  136. package/dist/components/ds-textarea.js +1 -1
  137. package/dist/components/ds-time-picker.js +1 -1
  138. package/dist/components/ds-toast.js +1 -1
  139. package/dist/components/ds-tooltip-chart.js +1 -1
  140. package/dist/components/ds-tooltip.js +1 -1
  141. package/dist/components/ds-typing-indicator.js +1 -1
  142. package/dist/components/{p-6QYDIPd1.js → p-3dG9v5Aw.js} +2 -2
  143. package/dist/components/{p-DwFnt0W0.js → p-5PReYMiY.js} +2 -2
  144. package/dist/components/{p-CzTJAO2J.js → p-8fddX3V3.js} +2 -2
  145. package/dist/components/{p-Cw1ljgW1.js → p-9u2WDF0J.js} +2 -2
  146. package/dist/components/{p-M9pOLcyK.js → p-B-ChwMFE.js} +2 -2
  147. package/dist/components/{p-y2Sdv9M3.js → p-BAIYOobl.js} +2 -2
  148. package/dist/components/{p-DKG26pp5.js → p-BIMW5_Z7.js} +2 -2
  149. package/dist/components/p-BMI0F08u.js +2 -0
  150. package/dist/components/{p-B5rN3slq.js.map → p-BMI0F08u.js.map} +1 -1
  151. package/dist/components/p-BV8sNEVP.js +2 -0
  152. package/dist/components/p-BV8sNEVP.js.map +1 -0
  153. package/dist/components/p-BVUdtuog.js +2 -0
  154. package/dist/components/p-BVUdtuog.js.map +1 -0
  155. package/dist/components/{p-CgYDQSLW.js → p-BYo1-6b5.js} +2 -2
  156. package/dist/components/{p-S5QCVAdH.js → p-BZbJkJpG.js} +2 -2
  157. package/dist/components/{p-D2rASHHq.js → p-BcYzHn1E.js} +2 -2
  158. package/dist/components/{p-0EpjqRWc.js → p-BfRAVR40.js} +2 -2
  159. package/dist/components/p-BnE9MeXS.js +2 -0
  160. package/dist/components/{p-CEB8RFih.js.map → p-BnE9MeXS.js.map} +1 -1
  161. package/dist/components/p-BoFK9lmP.js +2 -0
  162. package/dist/components/p-BoFK9lmP.js.map +1 -0
  163. package/dist/components/{p-BBZz2Dvg.js → p-BoWpIl_m.js} +2 -2
  164. package/dist/components/{p-DixX2_Bd.js → p-BpPHCF63.js} +2 -2
  165. package/dist/components/p-BpssHpam.js +2 -0
  166. package/dist/components/p-BpssHpam.js.map +1 -0
  167. package/dist/components/{p-DfwvHxYi.js → p-By_jYvHp.js} +2 -2
  168. package/dist/components/p-C5HGwzy9.js +2 -0
  169. package/dist/components/{p-Ba-dSshd.js.map → p-C5HGwzy9.js.map} +1 -1
  170. package/dist/components/{p-D4r6oWyQ.js → p-C860ilDn.js} +2 -2
  171. package/dist/components/{p-DGDF4NMV.js → p-CEHhx4VQ.js} +2 -2
  172. package/dist/components/{p-BqIRExej.js → p-CL0FpMKo.js} +2 -2
  173. package/dist/components/{p-CEm0AoDR.js → p-CQnjpuMX.js} +2 -2
  174. package/dist/components/{p-B9Q7fXxW.js → p-CUG4EkKn.js} +2 -2
  175. package/dist/components/{p-D-cZ6cRI.js → p-CYmz92EF.js} +2 -2
  176. package/dist/components/{p-DfzXyVoM.js → p-CbP9ASmI.js} +2 -2
  177. package/dist/components/{p-DvMCOJwc.js → p-CbPGO7vl.js} +2 -2
  178. package/dist/components/{p-DfphSI9S.js → p-CdMIA5hz.js} +2 -2
  179. package/dist/components/{p-Cxk1A7Sx.js → p-CeaIWw1Q.js} +2 -2
  180. package/dist/components/{p-CW-7vLUB.js → p-Cfqvxxs2.js} +2 -2
  181. package/dist/components/{p-CsPqGA8B.js → p-CpqLGzv4.js} +2 -2
  182. package/dist/components/{p-DKg181YU.js → p-DFR9hqDU.js} +2 -2
  183. package/dist/components/p-DKZP3jCY.js +2 -0
  184. package/dist/components/p-DKZP3jCY.js.map +1 -0
  185. package/dist/components/{p-CTAF7SkL.js → p-DMPn_dt7.js} +2 -2
  186. package/dist/components/{p-CYRTkP1A.js → p-DYruK9cb.js} +2 -2
  187. package/dist/components/{p-CqfYCn-e.js → p-DiUaIJ91.js} +2 -2
  188. package/dist/components/{p-OFJpWJcN.js → p-DimFbKZH.js} +2 -2
  189. package/dist/components/p-DmyU1fd-.js +2 -0
  190. package/dist/components/p-DmyU1fd-.js.map +1 -0
  191. package/dist/components/{p-BkajUPiA.js → p-DuhJ49iN.js} +2 -2
  192. package/dist/components/{p-CqW2eyiF.js → p-E0RqkUNq.js} +2 -2
  193. package/dist/components/{p-D_iZPukF.js → p-G6r6yYg8.js} +2 -2
  194. package/dist/components/p-HNktxWtF.js +2 -0
  195. package/dist/components/p-HNktxWtF.js.map +1 -0
  196. package/dist/components/{p-87FjWil8.js → p-IQdLCfJJ.js} +2 -2
  197. package/dist/components/{p-CAARHqjE.js → p-KTaiJztz.js} +2 -2
  198. package/dist/components/{p-BM-UYlIS.js → p-N-2CZze7.js} +2 -2
  199. package/dist/components/{p-Ch00yccW.js → p-Nx52go85.js} +2 -2
  200. package/dist/components/{p-CaNMVLhm.js → p-WEffoQQD.js} +2 -2
  201. package/dist/components/{p-DDawngok.js → p-XKt6j1UN.js} +2 -2
  202. package/dist/components/{p-CeXf9-X3.js → p-mSCnWLhL.js} +2 -2
  203. package/dist/components/{p-C8D853vs.js → p-nakO4viw.js} +2 -2
  204. package/dist/components/{p-BC9xYdJD.js → p-pkJ3X3s7.js} +2 -2
  205. package/dist/components/{p-BNnw_O4e.js → p-r_e6_0nP.js} +2 -2
  206. package/dist/components/p-zsWHUNJ9.js +2 -0
  207. package/dist/components/p-zsWHUNJ9.js.map +1 -0
  208. package/dist/docs/components.json +642 -22
  209. package/dist/lint/index.js +1 -1
  210. package/dist/mcp-data/registry/agent-activity.json +2 -2
  211. package/dist/mcp-data/registry/agent-questionnaire.json +2 -2
  212. package/dist/mcp-data/registry/agent-response.json +2 -2
  213. package/dist/mcp-data/registry/agent-source-list.json +2 -2
  214. package/dist/mcp-data/registry/agent-tool-call.json +2 -2
  215. package/dist/mcp-data/registry/attachment-list.json +2 -2
  216. package/dist/mcp-data/registry/avatar.json +2 -2
  217. package/dist/mcp-data/registry/badge.json +2 -2
  218. package/dist/mcp-data/registry/banner.json +2 -2
  219. package/dist/mcp-data/registry/bar-action.json +2 -2
  220. package/dist/mcp-data/registry/bar-nav.json +2 -2
  221. package/dist/mcp-data/registry/bar-page-title.json +2 -2
  222. package/dist/mcp-data/registry/bar-title.json +2 -2
  223. package/dist/mcp-data/registry/bar-workflow.json +2 -2
  224. package/dist/mcp-data/registry/breadcrumb.json +2 -2
  225. package/dist/mcp-data/registry/button-filled.json +2 -2
  226. package/dist/mcp-data/registry/button-inverted.json +2 -2
  227. package/dist/mcp-data/registry/button-unfilled.json +2 -2
  228. package/dist/mcp-data/registry/calendar.json +2 -2
  229. package/dist/mcp-data/registry/card-action-center.json +25 -5
  230. package/dist/mcp-data/registry/card-chart.json +25 -5
  231. package/dist/mcp-data/registry/card-navigation.json +25 -5
  232. package/dist/mcp-data/registry/card-overview.json +4 -4
  233. package/dist/mcp-data/registry/card-setting.json +25 -5
  234. package/dist/mcp-data/registry/card-settings-scope.json +24 -4
  235. package/dist/mcp-data/registry/chart-legend.json +2 -2
  236. package/dist/mcp-data/registry/chart.json +2 -2
  237. package/dist/mcp-data/registry/checkbox-group.json +2 -2
  238. package/dist/mcp-data/registry/checkbox.json +2 -2
  239. package/dist/mcp-data/registry/chip.json +2 -2
  240. package/dist/mcp-data/registry/code-block.json +2 -2
  241. package/dist/mcp-data/registry/conversation-list-item.json +2 -2
  242. package/dist/mcp-data/registry/conversation-list-section.json +2 -2
  243. package/dist/mcp-data/registry/conversation-list.json +2 -2
  244. package/dist/mcp-data/registry/data-customize.json +2 -2
  245. package/dist/mcp-data/registry/data-filter.json +2 -2
  246. package/dist/mcp-data/registry/data-group.json +2 -2
  247. package/dist/mcp-data/registry/data-preferences.json +2 -2
  248. package/dist/mcp-data/registry/data-saved-views.json +2 -2
  249. package/dist/mcp-data/registry/data-search.json +2 -2
  250. package/dist/mcp-data/registry/data-sort.json +2 -2
  251. package/dist/mcp-data/registry/data-toolbar.json +2 -2
  252. package/dist/mcp-data/registry/divider.json +2 -2
  253. package/dist/mcp-data/registry/empty-state.json +2 -2
  254. package/dist/mcp-data/registry/field.json +24 -4
  255. package/dist/mcp-data/registry/filter-menu.json +2 -2
  256. package/dist/mcp-data/registry/icon.json +2 -2
  257. package/dist/mcp-data/registry/inline-banner-settings.json +24 -4
  258. package/dist/mcp-data/registry/input-date.json +3 -3
  259. package/dist/mcp-data/registry/input-time.json +3 -3
  260. package/dist/mcp-data/registry/input.json +2 -2
  261. package/dist/mcp-data/registry/loader.json +2 -2
  262. package/dist/mcp-data/registry/map-cluster-marker.json +2 -2
  263. package/dist/mcp-data/registry/map-entity-marker.json +2 -2
  264. package/dist/mcp-data/registry/map-marker.json +2 -2
  265. package/dist/mcp-data/registry/markdown.json +2 -2
  266. package/dist/mcp-data/registry/menu.json +2 -2
  267. package/dist/mcp-data/registry/message-actions.json +2 -2
  268. package/dist/mcp-data/registry/message-bubble.json +2 -2
  269. package/dist/mcp-data/registry/message-composer.json +2 -2
  270. package/dist/mcp-data/registry/message-scroller.json +2 -2
  271. package/dist/mcp-data/registry/message.json +2 -2
  272. package/dist/mcp-data/registry/mobile-bar-nav.json +2 -2
  273. package/dist/mcp-data/registry/mobile-header.json +2 -2
  274. package/dist/mcp-data/registry/mobile-section-switcher.json +2 -2
  275. package/dist/mcp-data/registry/mobile-sheet-nav.json +2 -2
  276. package/dist/mcp-data/registry/modal.json +2 -2
  277. package/dist/mcp-data/registry/navigation-tab-group.json +2 -2
  278. package/dist/mcp-data/registry/pagination.json +24 -4
  279. package/dist/mcp-data/registry/panel-nav.json +2 -2
  280. package/dist/mcp-data/registry/panel-sub-nav.json +2 -2
  281. package/dist/mcp-data/registry/panel-tool-header.json +2 -2
  282. package/dist/mcp-data/registry/panel-tool-search.json +2 -2
  283. package/dist/mcp-data/registry/panel-tools.json +2 -2
  284. package/dist/mcp-data/registry/paper-texture.json +2 -2
  285. package/dist/mcp-data/registry/radio-tile.json +2 -2
  286. package/dist/mcp-data/registry/radio.json +24 -4
  287. package/dist/mcp-data/registry/registry.json +115 -19
  288. package/dist/mcp-data/registry/score.json +2 -2
  289. package/dist/mcp-data/registry/scroll-overlay.json +2 -2
  290. package/dist/mcp-data/registry/select-toggle.json +2 -2
  291. package/dist/mcp-data/registry/select.json +2 -2
  292. package/dist/mcp-data/registry/setting-row-checkbox.json +2 -2
  293. package/dist/mcp-data/registry/setting-row-radio.json +24 -4
  294. package/dist/mcp-data/registry/setting-row-toggle.json +25 -5
  295. package/dist/mcp-data/registry/shell-app.json +5 -4
  296. package/dist/mcp-data/registry/shell-page.json +2 -2
  297. package/dist/mcp-data/registry/shell-tools.json +2 -2
  298. package/dist/mcp-data/registry/skeleton.json +102 -10
  299. package/dist/mcp-data/registry/slider.json +2 -2
  300. package/dist/mcp-data/registry/swatch-picker.json +2 -2
  301. package/dist/mcp-data/registry/switch.json +2 -2
  302. package/dist/mcp-data/registry/tab-group.json +2 -2
  303. package/dist/mcp-data/registry/table.json +19 -8
  304. package/dist/mcp-data/registry/tag.json +2 -2
  305. package/dist/mcp-data/registry/text.json +2 -2
  306. package/dist/mcp-data/registry/textarea.json +2 -2
  307. package/dist/mcp-data/registry/time-picker.json +2 -2
  308. package/dist/mcp-data/registry/toast.json +2 -2
  309. package/dist/mcp-data/registry/tooltip-chart.json +2 -2
  310. package/dist/mcp-data/registry/tooltip.json +2 -2
  311. package/dist/mcp-data/registry/typing-indicator.json +2 -2
  312. package/dist/types/components/CardActionCenter/CardActionCenter.d.ts +2 -0
  313. package/dist/types/components/CardChart/CardChart.d.ts +2 -0
  314. package/dist/types/components/CardNavigation/CardNavigation.d.ts +2 -0
  315. package/dist/types/components/CardSetting/CardSetting.d.ts +2 -0
  316. package/dist/types/components/CardSettingsScope/CardSettingsScope.d.ts +2 -0
  317. package/dist/types/components/Field/Field.d.ts +3 -0
  318. package/dist/types/components/InlineBannerSettings/InlineBannerSettings.d.ts +2 -0
  319. package/dist/types/components/InputDate/InputDate.d.ts +5 -6
  320. package/dist/types/components/InputTime/InputTime.d.ts +5 -6
  321. package/dist/types/components/Pagination/Pagination.d.ts +3 -0
  322. package/dist/types/components/Radio/Radio.d.ts +2 -0
  323. package/dist/types/components/SettingRowRadio/SettingRowRadio.d.ts +2 -0
  324. package/dist/types/components/SettingRowToggle/SettingRowToggle.d.ts +2 -0
  325. package/dist/types/components/Skeleton/Skeleton.d.ts +13 -1
  326. package/dist/types/components/Skeleton/index.d.ts +1 -1
  327. package/dist/types/components/Table/Table.d.ts +6 -49
  328. package/dist/types/components/Table/table-caption-controller.d.ts +54 -0
  329. package/dist/types/components/Table/table-cell-editor.d.ts +1 -1
  330. package/dist/types/components/Table/table-editing-controller.d.ts +37 -0
  331. package/dist/types/components.d.ts +169 -4
  332. package/dist/types/utils/picker-popup-controller.d.ts +24 -0
  333. package/dist/types/utils/select-controller.d.ts +1 -0
  334. package/dist/vue/ds-card-action-center.js +1 -0
  335. package/dist/vue/ds-card-chart.js +1 -0
  336. package/dist/vue/ds-card-navigation.js +1 -0
  337. package/dist/vue/ds-card-setting.js +1 -0
  338. package/dist/vue/ds-card-settings-scope.js +1 -0
  339. package/dist/vue/ds-field.js +2 -1
  340. package/dist/vue/ds-inline-banner-settings.js +2 -1
  341. package/dist/vue/ds-pagination.js +1 -0
  342. package/dist/vue/ds-radio.js +1 -0
  343. package/dist/vue/ds-setting-row-radio.js +2 -1
  344. package/dist/vue/ds-setting-row-toggle.js +1 -0
  345. package/dist/vue/ds-skeleton.js +4 -0
  346. package/package.json +6 -6
  347. package/dist/components/p-B5rN3slq.js +0 -2
  348. package/dist/components/p-BT6xQogY.js +0 -2
  349. package/dist/components/p-BT6xQogY.js.map +0 -1
  350. package/dist/components/p-Ba-dSshd.js +0 -2
  351. package/dist/components/p-CEB8RFih.js +0 -2
  352. package/dist/components/p-CMrHRjjH.js +0 -2
  353. package/dist/components/p-CMrHRjjH.js.map +0 -1
  354. package/dist/components/p-CPNA8raE.js +0 -2
  355. package/dist/components/p-CPNA8raE.js.map +0 -1
  356. package/dist/components/p-Cnzry0_v.js +0 -2
  357. package/dist/components/p-Cnzry0_v.js.map +0 -1
  358. package/dist/components/p-Djkk338n.js +0 -2
  359. package/dist/components/p-Djkk338n.js.map +0 -1
  360. package/dist/components/p-hWKa8Jn8.js +0 -2
  361. package/dist/components/p-hWKa8Jn8.js.map +0 -1
  362. package/dist/components/p-xCqqM1Rg.js +0 -2
  363. package/dist/components/p-xCqqM1Rg.js.map +0 -1
  364. package/dist/types/utils/cartesian-chart-layout.d.ts +0 -13
  365. package/dist/types/utils/chart-viewport-controller.d.ts +0 -21
  366. /package/dist/components/{p-6QYDIPd1.js.map → p-3dG9v5Aw.js.map} +0 -0
  367. /package/dist/components/{p-DwFnt0W0.js.map → p-5PReYMiY.js.map} +0 -0
  368. /package/dist/components/{p-CzTJAO2J.js.map → p-8fddX3V3.js.map} +0 -0
  369. /package/dist/components/{p-Cw1ljgW1.js.map → p-9u2WDF0J.js.map} +0 -0
  370. /package/dist/components/{p-M9pOLcyK.js.map → p-B-ChwMFE.js.map} +0 -0
  371. /package/dist/components/{p-y2Sdv9M3.js.map → p-BAIYOobl.js.map} +0 -0
  372. /package/dist/components/{p-DKG26pp5.js.map → p-BIMW5_Z7.js.map} +0 -0
  373. /package/dist/components/{p-CgYDQSLW.js.map → p-BYo1-6b5.js.map} +0 -0
  374. /package/dist/components/{p-S5QCVAdH.js.map → p-BZbJkJpG.js.map} +0 -0
  375. /package/dist/components/{p-D2rASHHq.js.map → p-BcYzHn1E.js.map} +0 -0
  376. /package/dist/components/{p-0EpjqRWc.js.map → p-BfRAVR40.js.map} +0 -0
  377. /package/dist/components/{p-BBZz2Dvg.js.map → p-BoWpIl_m.js.map} +0 -0
  378. /package/dist/components/{p-DixX2_Bd.js.map → p-BpPHCF63.js.map} +0 -0
  379. /package/dist/components/{p-DfwvHxYi.js.map → p-By_jYvHp.js.map} +0 -0
  380. /package/dist/components/{p-D4r6oWyQ.js.map → p-C860ilDn.js.map} +0 -0
  381. /package/dist/components/{p-DGDF4NMV.js.map → p-CEHhx4VQ.js.map} +0 -0
  382. /package/dist/components/{p-BqIRExej.js.map → p-CL0FpMKo.js.map} +0 -0
  383. /package/dist/components/{p-CEm0AoDR.js.map → p-CQnjpuMX.js.map} +0 -0
  384. /package/dist/components/{p-B9Q7fXxW.js.map → p-CUG4EkKn.js.map} +0 -0
  385. /package/dist/components/{p-D-cZ6cRI.js.map → p-CYmz92EF.js.map} +0 -0
  386. /package/dist/components/{p-DfzXyVoM.js.map → p-CbP9ASmI.js.map} +0 -0
  387. /package/dist/components/{p-DvMCOJwc.js.map → p-CbPGO7vl.js.map} +0 -0
  388. /package/dist/components/{p-DfphSI9S.js.map → p-CdMIA5hz.js.map} +0 -0
  389. /package/dist/components/{p-Cxk1A7Sx.js.map → p-CeaIWw1Q.js.map} +0 -0
  390. /package/dist/components/{p-CW-7vLUB.js.map → p-Cfqvxxs2.js.map} +0 -0
  391. /package/dist/components/{p-CsPqGA8B.js.map → p-CpqLGzv4.js.map} +0 -0
  392. /package/dist/components/{p-DKg181YU.js.map → p-DFR9hqDU.js.map} +0 -0
  393. /package/dist/components/{p-CTAF7SkL.js.map → p-DMPn_dt7.js.map} +0 -0
  394. /package/dist/components/{p-CYRTkP1A.js.map → p-DYruK9cb.js.map} +0 -0
  395. /package/dist/components/{p-CqfYCn-e.js.map → p-DiUaIJ91.js.map} +0 -0
  396. /package/dist/components/{p-OFJpWJcN.js.map → p-DimFbKZH.js.map} +0 -0
  397. /package/dist/components/{p-BkajUPiA.js.map → p-DuhJ49iN.js.map} +0 -0
  398. /package/dist/components/{p-CqW2eyiF.js.map → p-E0RqkUNq.js.map} +0 -0
  399. /package/dist/components/{p-D_iZPukF.js.map → p-G6r6yYg8.js.map} +0 -0
  400. /package/dist/components/{p-87FjWil8.js.map → p-IQdLCfJJ.js.map} +0 -0
  401. /package/dist/components/{p-CAARHqjE.js.map → p-KTaiJztz.js.map} +0 -0
  402. /package/dist/components/{p-BM-UYlIS.js.map → p-N-2CZze7.js.map} +0 -0
  403. /package/dist/components/{p-Ch00yccW.js.map → p-Nx52go85.js.map} +0 -0
  404. /package/dist/components/{p-CaNMVLhm.js.map → p-WEffoQQD.js.map} +0 -0
  405. /package/dist/components/{p-DDawngok.js.map → p-XKt6j1UN.js.map} +0 -0
  406. /package/dist/components/{p-CeXf9-X3.js.map → p-mSCnWLhL.js.map} +0 -0
  407. /package/dist/components/{p-C8D853vs.js.map → p-nakO4viw.js.map} +0 -0
  408. /package/dist/components/{p-BC9xYdJD.js.map → p-pkJ3X3s7.js.map} +0 -0
  409. /package/dist/components/{p-BNnw_O4e.js.map → p-r_e6_0nP.js.map} +0 -0
@@ -49,6 +49,7 @@
49
49
  "Do not use placeholder text as the only label. Keep label text concise and put format or consequence guidance in description."
50
50
  ],
51
51
  "states": [
52
+ "Loading masks field copy and the slotted control in place. The control remains mounted with its value, native form association, and accessible label intact; the field is inert until loading ends.",
52
53
  "The visible label is optional. Omit it when a nearby heading already names the field; Field still associates description and error text with the slotted control.",
53
54
  "Label, control, description, and error content follow the shared 4px vertical field flow without changing the slotted control's width or semantics. When the slotted control is borderless, description and error copy inset to that control's text origin instead of the resting bordered edge.",
54
55
  "Field exposes data-focused, data-filled, data-dirty, data-touched, data-invalid, data-disabled, and data-required hooks while the slotted control remains the source of value and interaction behavior.",
@@ -132,6 +133,15 @@
132
133
  "mutable": false,
133
134
  "description": "Explicit ID for the slotted control; generated when omitted."
134
135
  },
136
+ "isLoading": {
137
+ "type": "boolean",
138
+ "resolvedType": "boolean",
139
+ "attribute": "is-loading",
140
+ "default": "false",
141
+ "required": false,
142
+ "mutable": false,
143
+ "description": "Masks field copy and its mounted control while preserving layout and form state."
144
+ },
135
145
  "label": {
136
146
  "type": "string",
137
147
  "resolvedType": "string | undefined",
@@ -179,6 +189,15 @@
179
189
  "mutable": false,
180
190
  "description": "Explicit ID for the slotted control; generated when omitted."
181
191
  },
192
+ "isLoading": {
193
+ "type": "boolean",
194
+ "resolvedType": "boolean",
195
+ "attribute": "is-loading",
196
+ "default": "false",
197
+ "required": false,
198
+ "mutable": false,
199
+ "description": "Masks field copy and its mounted control while preserving layout and form state."
200
+ },
182
201
  "label": {
183
202
  "type": "string",
184
203
  "resolvedType": "string | undefined",
@@ -218,8 +237,8 @@
218
237
  },
219
238
  "peerDependencies": {
220
239
  "required": [
221
- "@ds-mo/tokens ^8.0.0",
222
- "@ds-mo/icons ^8.1.1"
240
+ "@ds-mo/tokens ^8.0.1",
241
+ "@ds-mo/icons ^8.1.2"
223
242
  ],
224
243
  "frameworks": "Custom Elements; React 18/19 wrappers; Vue 3 wrappers; Angular 19-22 standalone adapters."
225
244
  }
@@ -230,17 +249,18 @@
230
249
  "@ds-mo/tokens"
231
250
  ],
232
251
  "registryDependencies": [
252
+ "skeleton",
233
253
  "text"
234
254
  ],
235
255
  "files": [
236
256
  {
237
257
  "path": "src/wc/components/Field/Field.css",
238
- "content": "@import '../../utils/text-field-support.css';\n@import '../../utils/control-density.css';\n@import '../../utils/field-stack.css';\n\n:host {\n display: block;\n}\n\n.field__control {\n display: flex;\n min-width: 0;\n}\n\n.field__control > * {\n width: 100%;\n}\n",
258
+ "content": "@import '../../utils/text-field-support.css';\n@import '../../utils/control-density.css';\n@import '../../utils/field-stack.css';\n\n:host {\n display: block;\n}\n\n.field__control {\n position: relative;\n display: flex;\n min-width: 0;\n}\n\n.field__control > * {\n width: 100%;\n}\n\n.field__label,\n.field__description,\n.field__error,\n.text-field-count {\n position: relative;\n}\n\n.field__copy-source--loading,\n:host(.field--loading) .field__control > :not(slot):not(.field__control-skeleton) {\n visibility: hidden;\n}\n\n.field__copy-skeleton {\n position: absolute;\n inset-inline-start: 0;\n inset-block-start: 0;\n max-inline-size: 100%;\n}\n\n.field__label .field__copy-skeleton {\n inline-size: min(100%, calc(var(--dimension-size-800) * 2));\n}\n\n.field__control-skeleton {\n position: absolute;\n inset: 0;\n inline-size: 100%;\n block-size: 100%;\n}\n",
239
259
  "type": "registry:ui"
240
260
  },
241
261
  {
242
262
  "path": "src/wc/components/Field/Field.tsx",
243
- "content": "import { Component, Element, Prop, State, Watch, h, Host } from '@stencil/core';\n\ninterface FieldControl extends HTMLElement {\n value?: string | string[];\n tokens?: string[];\n tokenized?: boolean;\n inputId?: string;\n error?: boolean;\n disabled?: boolean;\n isInactive?: boolean;\n required?: boolean;\n hasBorder?: boolean;\n size?: string;\n setFocus?: () => Promise<void> | void;\n}\n\ninterface AuthoredAria {\n labelledby: string[];\n describedby: string[];\n}\n\nlet fieldCounter = 0;\n\nconst tokens = (value: string | null | undefined): string[] =>\n value?.split(/\\s+/).filter(Boolean) ?? [];\n\nconst uniqueTokens = (...groups: string[][]): string[] => [...new Set(groups.flat())];\n\nconst CONTROL_SIZES = ['lg', 'md', 'sm', 'xs'] as const;\ntype FieldControlSize = (typeof CONTROL_SIZES)[number];\n\nconst readControlSize = (control: FieldControl): FieldControlSize =>\n CONTROL_SIZES.includes(control.size as FieldControlSize)\n ? (control.size as FieldControlSize)\n : 'md';\n\n@Component({\n tag: 'ds-field',\n styleUrl: 'Field.css',\n scoped: true,\n})\nexport class Field {\n @Element() el!: HTMLElement;\n\n /** Visible label for the slotted control. Omit when a nearby heading already names the field. */\n @Prop() label?: string;\n /** Explicit ID for the slotted control; generated when omitted. */\n @Prop() fieldId: string | undefined;\n /** Optional guidance associated with the slotted control while no visible error is shown. */\n @Prop() description: string | undefined;\n /** Invalid visual and accessible state forwarded to supported ds controls. */\n @Prop() error: boolean = false;\n /** Visible error associated with the slotted control while error is true. */\n @Prop() errorMessage: string | undefined;\n\n @State() private constraintMessage = '';\n @State() private characterCount: string | undefined;\n @State() private characterLimit: string | undefined;\n @State() private focused = false;\n @State() private filled = false;\n @State() private dirty = false;\n @State() private touched = false;\n @State() private controlDisabled = false;\n @State() private controlRequired = false;\n @State() private controlBorderless = false;\n @State() private controlSize: 'lg' | 'md' | 'sm' | 'xs' = 'md';\n /** Bumped to let Stencil relocate a control added after the initial render. */\n @State() private slotRevision = 0;\n\n private readonly generatedId = `ds-field-${++fieldCounter}`;\n private controlContainer?: HTMLDivElement;\n private control?: FieldControl;\n private initialValue = '';\n private authoredAria = new WeakMap<FieldControl, AuthoredAria>();\n private childObserver?: MutationObserver;\n private controlAttrObserver?: MutationObserver;\n private didLoad = false;\n\n connectedCallback() {\n if (this.didLoad) this.observeLateControls();\n }\n\n disconnectedCallback() {\n this.childObserver?.disconnect();\n this.childObserver = undefined;\n this.controlAttrObserver?.disconnect();\n this.controlAttrObserver = undefined;\n }\n\n componentDidLoad() {\n this.syncControl();\n this.didLoad = true;\n this.observeLateControls();\n requestAnimationFrame(() => this.syncControl());\n }\n\n componentDidRender() {\n this.syncControl();\n }\n\n @Watch('fieldId')\n @Watch('label')\n @Watch('description')\n @Watch('error')\n @Watch('errorMessage')\n onFieldContractChange() {\n this.syncControl();\n }\n\n private get hasLabel(): boolean {\n return Boolean(this.label?.trim());\n }\n\n private get controlId(): string {\n return this.fieldId || this.generatedId;\n }\n\n private get labelId(): string {\n return `${this.controlId}-label`;\n }\n\n private get descriptionId(): string {\n return `${this.controlId}-description`;\n }\n\n private get errorId(): string {\n return `${this.controlId}-error`;\n }\n\n private get renderedDescription(): boolean {\n return Boolean(this.description) && !this.renderedError;\n }\n\n private get renderedError(): boolean {\n return Boolean(this.visibleError);\n }\n\n private get visibleError(): string {\n return this.error && this.errorMessage ? this.errorMessage : this.constraintMessage;\n }\n\n private readValue(control: FieldControl): string {\n if (control.tokenized)\n return [...(control.tokens ?? []), String(control.value ?? '')]\n .filter(Boolean)\n .join('\\u001f');\n const value = control.value;\n return Array.isArray(value) ? value.join('\\u001f') : String(value ?? '');\n }\n\n private updateControlAttribute(control: FieldControl, name: string, value: string | undefined) {\n if (value === undefined) {\n if (control.hasAttribute(name)) control.removeAttribute(name);\n return;\n }\n if (control.getAttribute(name) !== value) control.setAttribute(name, value);\n }\n\n private findControl(): FieldControl | undefined {\n return this.controlContainer?.querySelector<FieldControl>(':scope > :not(slot)') ?? undefined;\n }\n\n private observeLateControls() {\n if (this.childObserver || typeof MutationObserver === 'undefined') return;\n this.childObserver = new MutationObserver(records => {\n const addedControl = records.some(record =>\n Array.from(record.addedNodes).some(node => node.nodeType === 1)\n );\n if (addedControl) this.slotRevision++;\n });\n this.childObserver.observe(this.el, { childList: true });\n }\n\n private syncControl = () => {\n const control = this.findControl();\n if (!control) return;\n\n if (control !== this.control) {\n this.control = control;\n this.initialValue = this.readValue(control);\n this.authoredAria.set(control, {\n labelledby: tokens(control.getAttribute('aria-labelledby')),\n describedby: tokens(control.getAttribute('aria-describedby')),\n });\n this.observeControlAttributes(control);\n }\n\n this.constraintMessage = control.getAttribute('data-constraint-message') ?? '';\n this.characterCount = control.getAttribute('data-character-count') ?? undefined;\n this.characterLimit = control.getAttribute('data-character-limit') ?? undefined;\n\n const isDsControl = control.tagName.startsWith('DS-');\n if (isDsControl && 'inputId' in control) control.inputId = this.controlId;\n else this.updateControlAttribute(control, 'id', this.controlId);\n\n const authored = this.authoredAria.get(control) ?? { labelledby: [], describedby: [] };\n const labelledby = uniqueTokens(authored.labelledby, this.hasLabel ? [this.labelId] : []).join(\n ' '\n );\n const describedby = uniqueTokens(\n authored.describedby,\n this.renderedDescription ? [this.descriptionId] : [],\n this.renderedError ? [this.errorId] : [],\n this.characterCount !== undefined ? [`${this.controlId}-count`] : []\n ).join(' ');\n\n this.updateControlAttribute(control, 'aria-labelledby', labelledby || undefined);\n this.updateControlAttribute(control, 'aria-describedby', describedby || undefined);\n this.updateControlAttribute(control, 'aria-invalid', this.error ? 'true' : undefined);\n\n if (isDsControl && 'error' in control && control.error !== this.error)\n control.error = this.error;\n\n const value = this.readValue(control);\n this.filled = value.length > 0;\n this.dirty = value !== this.initialValue;\n this.controlDisabled = Boolean(\n control.disabled || control.isInactive || control.hasAttribute('disabled')\n );\n this.controlRequired = Boolean(control.required || control.hasAttribute('required'));\n this.controlBorderless = control.hasBorder === false;\n this.controlSize = readControlSize(control);\n };\n\n private observeControlAttributes(control: FieldControl) {\n this.controlAttrObserver?.disconnect();\n this.controlAttrObserver = new MutationObserver(() => this.syncControl());\n this.controlAttrObserver.observe(control, {\n attributes: true,\n attributeFilter: [\n 'has-border',\n 'size',\n 'class',\n 'data-constraint-message',\n 'data-character-count',\n 'data-character-limit',\n ],\n });\n }\n\n private handleLabelClick = (event: MouseEvent) => {\n if (!this.control?.tagName.startsWith('DS-')) return;\n event.preventDefault();\n this.control.setFocus?.();\n };\n\n private handleFocusIn = () => {\n this.focused = true;\n };\n\n private handleFocusOut = (event: FocusEvent) => {\n if (event.relatedTarget instanceof Node && this.el.contains(event.relatedTarget)) return;\n this.focused = false;\n this.touched = true;\n };\n\n private handleValueChange = () => {\n this.syncControl();\n };\n\n render() {\n return (\n <Host\n data-focused={this.focused ? '' : undefined}\n data-filled={this.filled ? '' : undefined}\n data-dirty={this.dirty ? '' : undefined}\n data-touched={this.touched ? '' : undefined}\n data-invalid={this.error || this.constraintMessage ? '' : undefined}\n data-disabled={this.controlDisabled ? '' : undefined}\n data-required={this.controlRequired ? '' : undefined}\n onFocusin={this.handleFocusIn}\n onFocusout={this.handleFocusOut}\n onInput={this.handleValueChange}\n onChange={this.handleValueChange}\n onDsChange={this.handleValueChange}\n onDsTokensChange={this.handleValueChange}\n >\n <div\n class={{\n field: true,\n 'ds-field-stack': true,\n 'ds-field-stack--supporting-inset': this.controlBorderless,\n [`ds-control--${this.controlSize}`]: true,\n }}\n >\n {this.hasLabel ? (\n <ds-text\n class=\"field__label\"\n as=\"label\"\n variant=\"text-body-small\"\n color=\"primary\"\n emphasis\n for={this.controlId}\n textId={this.labelId}\n onClick={this.handleLabelClick}\n >\n {this.label}\n </ds-text>\n ) : null}\n <div class=\"field__control\" ref={el => (this.controlContainer = el)}>\n <slot onSlotchange={this.syncControl} />\n </div>\n {(this.renderedDescription ||\n this.renderedError ||\n this.characterCount !== undefined) && (\n <div class=\"text-field-support\">\n {this.renderedDescription && (\n <ds-text\n class=\"field__description\"\n as=\"div\"\n variant=\"text-body-small\"\n color=\"secondary\"\n textId={this.descriptionId}\n >\n {this.description}\n </ds-text>\n )}\n {this.renderedError && (\n <ds-text\n class=\"field__error\"\n as=\"div\"\n variant=\"text-body-small\"\n color=\"negative\"\n textId={this.errorId}\n role=\"alert\"\n >\n {this.visibleError}\n </ds-text>\n )}\n {this.characterCount !== undefined && (\n <ds-text\n class=\"text-field-count\"\n as=\"span\"\n variant=\"text-body-small\"\n color={this.error || this.constraintMessage ? 'negative' : 'secondary'}\n textId={`${this.controlId}-count`}\n >\n {this.characterCount}/{this.characterLimit}\n </ds-text>\n )}\n </div>\n )}\n </div>\n </Host>\n );\n }\n}\n",
263
+ "content": "import { Component, Element, Prop, State, Watch, h, Host } from '@stencil/core';\n\ninterface FieldControl extends HTMLElement {\n value?: string | string[];\n tokens?: string[];\n tokenized?: boolean;\n inputId?: string;\n error?: boolean;\n disabled?: boolean;\n isInactive?: boolean;\n required?: boolean;\n hasBorder?: boolean;\n size?: string;\n setFocus?: () => Promise<void> | void;\n}\n\ninterface AuthoredAria {\n labelledby: string[];\n describedby: string[];\n}\n\nlet fieldCounter = 0;\n\nconst tokens = (value: string | null | undefined): string[] =>\n value?.split(/\\s+/).filter(Boolean) ?? [];\n\nconst uniqueTokens = (...groups: string[][]): string[] => [...new Set(groups.flat())];\n\nconst CONTROL_SIZES = ['lg', 'md', 'sm', 'xs'] as const;\ntype FieldControlSize = (typeof CONTROL_SIZES)[number];\n\nconst readControlSize = (control: FieldControl): FieldControlSize =>\n CONTROL_SIZES.includes(control.size as FieldControlSize)\n ? (control.size as FieldControlSize)\n : 'md';\n\n@Component({\n tag: 'ds-field',\n styleUrl: 'Field.css',\n scoped: true,\n})\nexport class Field {\n @Element() el!: HTMLElement;\n\n /** Visible label for the slotted control. Omit when a nearby heading already names the field. */\n @Prop() label?: string;\n /** Explicit ID for the slotted control; generated when omitted. */\n @Prop() fieldId: string | undefined;\n /** Optional guidance associated with the slotted control while no visible error is shown. */\n @Prop() description: string | undefined;\n /** Invalid visual and accessible state forwarded to supported ds controls. */\n @Prop() error: boolean = false;\n /** Visible error associated with the slotted control while error is true. */\n @Prop() errorMessage: string | undefined;\n /** Masks field copy and its mounted control while preserving layout and form state. */\n @Prop() isLoading: boolean = false;\n\n @State() private constraintMessage = '';\n @State() private characterCount: string | undefined;\n @State() private characterLimit: string | undefined;\n @State() private focused = false;\n @State() private filled = false;\n @State() private dirty = false;\n @State() private touched = false;\n @State() private controlDisabled = false;\n @State() private controlRequired = false;\n @State() private controlBorderless = false;\n @State() private controlSize: 'lg' | 'md' | 'sm' | 'xs' = 'md';\n /** Bumped to let Stencil relocate a control added after the initial render. */\n @State() private slotRevision = 0;\n\n private readonly generatedId = `ds-field-${++fieldCounter}`;\n private controlContainer?: HTMLDivElement;\n private control?: FieldControl;\n private initialValue = '';\n private authoredAria = new WeakMap<FieldControl, AuthoredAria>();\n private childObserver?: MutationObserver;\n private controlAttrObserver?: MutationObserver;\n private didLoad = false;\n\n connectedCallback() {\n if (this.didLoad) this.observeLateControls();\n }\n\n disconnectedCallback() {\n this.childObserver?.disconnect();\n this.childObserver = undefined;\n this.controlAttrObserver?.disconnect();\n this.controlAttrObserver = undefined;\n }\n\n componentDidLoad() {\n this.syncControl();\n this.didLoad = true;\n this.observeLateControls();\n requestAnimationFrame(() => this.syncControl());\n }\n\n componentDidRender() {\n this.syncControl();\n }\n\n @Watch('fieldId')\n @Watch('label')\n @Watch('description')\n @Watch('error')\n @Watch('errorMessage')\n onFieldContractChange() {\n this.syncControl();\n }\n\n private get hasLabel(): boolean {\n return Boolean(this.label?.trim());\n }\n\n private get controlId(): string {\n return this.fieldId || this.generatedId;\n }\n\n private get labelId(): string {\n return `${this.controlId}-label`;\n }\n\n private get descriptionId(): string {\n return `${this.controlId}-description`;\n }\n\n private get errorId(): string {\n return `${this.controlId}-error`;\n }\n\n private get renderedDescription(): boolean {\n return Boolean(this.description) && !this.renderedError;\n }\n\n private get renderedError(): boolean {\n return Boolean(this.visibleError);\n }\n\n private get visibleError(): string {\n return this.error && this.errorMessage ? this.errorMessage : this.constraintMessage;\n }\n\n private readValue(control: FieldControl): string {\n if (control.tokenized)\n return [...(control.tokens ?? []), String(control.value ?? '')]\n .filter(Boolean)\n .join('\\u001f');\n const value = control.value;\n return Array.isArray(value) ? value.join('\\u001f') : String(value ?? '');\n }\n\n private updateControlAttribute(control: FieldControl, name: string, value: string | undefined) {\n if (value === undefined) {\n if (control.hasAttribute(name)) control.removeAttribute(name);\n return;\n }\n if (control.getAttribute(name) !== value) control.setAttribute(name, value);\n }\n\n private findControl(): FieldControl | undefined {\n return (\n this.controlContainer?.querySelector<FieldControl>(\n ':scope > :not(slot):not(.field__control-skeleton)'\n ) ?? undefined\n );\n }\n\n private observeLateControls() {\n if (this.childObserver || typeof MutationObserver === 'undefined') return;\n this.childObserver = new MutationObserver(records => {\n const addedControl = records.some(record =>\n Array.from(record.addedNodes).some(node => node.nodeType === 1)\n );\n if (addedControl) this.slotRevision++;\n });\n this.childObserver.observe(this.el, { childList: true });\n }\n\n private syncControl = () => {\n const control = this.findControl();\n if (!control) return;\n\n if (control !== this.control) {\n this.control = control;\n this.initialValue = this.readValue(control);\n this.authoredAria.set(control, {\n labelledby: tokens(control.getAttribute('aria-labelledby')),\n describedby: tokens(control.getAttribute('aria-describedby')),\n });\n this.observeControlAttributes(control);\n }\n\n this.constraintMessage = control.getAttribute('data-constraint-message') ?? '';\n this.characterCount = control.getAttribute('data-character-count') ?? undefined;\n this.characterLimit = control.getAttribute('data-character-limit') ?? undefined;\n\n const isDsControl = control.tagName.startsWith('DS-');\n if (isDsControl && 'inputId' in control) control.inputId = this.controlId;\n else this.updateControlAttribute(control, 'id', this.controlId);\n\n const authored = this.authoredAria.get(control) ?? { labelledby: [], describedby: [] };\n const labelledby = uniqueTokens(authored.labelledby, this.hasLabel ? [this.labelId] : []).join(\n ' '\n );\n const describedby = uniqueTokens(\n authored.describedby,\n this.renderedDescription ? [this.descriptionId] : [],\n this.renderedError ? [this.errorId] : [],\n this.characterCount !== undefined ? [`${this.controlId}-count`] : []\n ).join(' ');\n\n this.updateControlAttribute(control, 'aria-labelledby', labelledby || undefined);\n this.updateControlAttribute(control, 'aria-describedby', describedby || undefined);\n this.updateControlAttribute(control, 'aria-invalid', this.error ? 'true' : undefined);\n\n if (isDsControl && 'error' in control && control.error !== this.error)\n control.error = this.error;\n\n const value = this.readValue(control);\n this.filled = value.length > 0;\n this.dirty = value !== this.initialValue;\n this.controlDisabled = Boolean(\n control.disabled || control.isInactive || control.hasAttribute('disabled')\n );\n this.controlRequired = Boolean(control.required || control.hasAttribute('required'));\n this.controlBorderless = control.hasBorder === false;\n this.controlSize = readControlSize(control);\n };\n\n private observeControlAttributes(control: FieldControl) {\n this.controlAttrObserver?.disconnect();\n this.controlAttrObserver = new MutationObserver(() => this.syncControl());\n this.controlAttrObserver.observe(control, {\n attributes: true,\n attributeFilter: [\n 'has-border',\n 'size',\n 'class',\n 'data-constraint-message',\n 'data-character-count',\n 'data-character-limit',\n ],\n });\n }\n\n private handleLabelClick = (event: MouseEvent) => {\n if (this.isLoading) return;\n if (!this.control?.tagName.startsWith('DS-')) return;\n event.preventDefault();\n this.control.setFocus?.();\n };\n\n private handleFocusIn = () => {\n this.focused = true;\n };\n\n private handleFocusOut = (event: FocusEvent) => {\n if (event.relatedTarget instanceof Node && this.el.contains(event.relatedTarget)) return;\n this.focused = false;\n this.touched = true;\n };\n\n private handleValueChange = () => {\n this.syncControl();\n };\n\n private renderCopy(value: string | undefined) {\n return [\n <span class={{ 'field__copy-source': true, 'field__copy-source--loading': this.isLoading }}>\n {value}\n </span>,\n this.isLoading && <ds-skeleton class=\"field__copy-skeleton\" textVariant=\"text-body-small\" />,\n ];\n }\n\n render() {\n return (\n <Host\n class={{ 'field--loading': this.isLoading }}\n aria-busy={this.isLoading ? 'true' : undefined}\n inert={this.isLoading}\n data-focused={this.focused ? '' : undefined}\n data-filled={this.filled ? '' : undefined}\n data-dirty={this.dirty ? '' : undefined}\n data-touched={this.touched ? '' : undefined}\n data-invalid={this.error || this.constraintMessage ? '' : undefined}\n data-disabled={this.controlDisabled ? '' : undefined}\n data-required={this.controlRequired ? '' : undefined}\n onFocusin={this.handleFocusIn}\n onFocusout={this.handleFocusOut}\n onInput={this.handleValueChange}\n onChange={this.handleValueChange}\n onDsChange={this.handleValueChange}\n onDsTokensChange={this.handleValueChange}\n >\n <div\n class={{\n field: true,\n 'ds-field-stack': true,\n 'ds-field-stack--supporting-inset': this.controlBorderless,\n [`ds-control--${this.controlSize}`]: true,\n }}\n >\n {this.hasLabel ? (\n <ds-text\n class=\"field__label\"\n as=\"label\"\n variant=\"text-body-small\"\n color=\"primary\"\n emphasis\n for={this.controlId}\n textId={this.labelId}\n onClick={this.handleLabelClick}\n >\n {this.renderCopy(this.label)}\n </ds-text>\n ) : null}\n <div class=\"field__control\" ref={el => (this.controlContainer = el)}>\n <slot onSlotchange={this.syncControl} />\n {this.isLoading && (\n <ds-skeleton\n class=\"field__control-skeleton\"\n variant=\"control\"\n controlAppearance={this.controlBorderless ? 'borderless' : 'outlined'}\n controlContent={this.control?.localName === 'ds-select' ? 'label-icon' : 'label'}\n controlSize={this.controlSize}\n />\n )}\n </div>\n {(this.renderedDescription ||\n this.renderedError ||\n this.characterCount !== undefined) && (\n <div class=\"text-field-support\">\n {this.renderedDescription && (\n <ds-text\n class=\"field__description\"\n as=\"div\"\n variant=\"text-body-small\"\n color=\"secondary\"\n textId={this.descriptionId}\n >\n {this.renderCopy(this.description)}\n </ds-text>\n )}\n {this.renderedError && (\n <ds-text\n class=\"field__error\"\n as=\"div\"\n variant=\"text-body-small\"\n color=\"negative\"\n textId={this.errorId}\n role=\"alert\"\n >\n {this.renderCopy(this.visibleError)}\n </ds-text>\n )}\n {this.characterCount !== undefined && (\n <ds-text\n class=\"text-field-count\"\n as=\"span\"\n variant=\"text-body-small\"\n color={this.error || this.constraintMessage ? 'negative' : 'secondary'}\n textId={`${this.controlId}-count`}\n >\n {this.renderCopy(`${this.characterCount}/${this.characterLimit}`)}\n </ds-text>\n )}\n </div>\n )}\n </div>\n </Host>\n );\n }\n}\n",
244
264
  "type": "registry:ui"
245
265
  }
246
266
  ]
@@ -899,8 +899,8 @@
899
899
  "complexPropertyNote": "Assign these non-primitive values as JavaScript properties: anchor, boundary, filters, matchModes, values.",
900
900
  "peerDependencies": {
901
901
  "required": [
902
- "@ds-mo/tokens ^8.0.0",
903
- "@ds-mo/icons ^8.1.1"
902
+ "@ds-mo/tokens ^8.0.1",
903
+ "@ds-mo/icons ^8.1.2"
904
904
  ],
905
905
  "frameworks": "Custom Elements; React 18/19 wrappers; Vue 3 wrappers; Angular 19-22 standalone adapters."
906
906
  }
@@ -221,8 +221,8 @@
221
221
  },
222
222
  "peerDependencies": {
223
223
  "required": [
224
- "@ds-mo/tokens ^8.0.0",
225
- "@ds-mo/icons ^8.1.1"
224
+ "@ds-mo/tokens ^8.0.1",
225
+ "@ds-mo/icons ^8.1.2"
226
226
  ],
227
227
  "frameworks": "Custom Elements; React 18/19 wrappers; Vue 3 wrappers; Angular 19-22 standalone adapters."
228
228
  }
@@ -48,7 +48,8 @@
48
48
  "states": [
49
49
  "The description renders verbatim in every state in which the owning settings card projects the component.",
50
50
  "The component has no internal visibility, editing, or dismissal state; the owning settings card controls whether it is present.",
51
- "The content height is intrinsic: the banner contributes 8px block padding and its inner content container contributes 4px block padding. A single body-small line is 24px inside that container (4px + 16px line-height + 4px), followed by the tertiary bottom boundary."
51
+ "The content height is intrinsic: the banner contributes 8px block padding and its inner content container contributes 4px block padding. A single body-small line is 24px inside that container (4px + 16px line-height + 4px), followed by the tertiary bottom boundary.",
52
+ "isLoading replaces the copy with a wrapping text skeleton inside the original banner geometry."
52
53
  ],
53
54
  "responsiveBehavior": [
54
55
  "The component fills the available inline size and lets body-small copy wrap naturally.",
@@ -100,6 +101,15 @@
100
101
  "required": true,
101
102
  "mutable": false,
102
103
  "description": "Authored informational copy rendered without transformation."
104
+ },
105
+ "isLoading": {
106
+ "type": "boolean",
107
+ "resolvedType": "boolean",
108
+ "attribute": "is-loading",
109
+ "default": "false",
110
+ "required": false,
111
+ "mutable": false,
112
+ "description": "Keep the informational row footprint while its copy is loading."
103
113
  }
104
114
  },
105
115
  "events": [],
@@ -114,6 +124,15 @@
114
124
  "required": true,
115
125
  "mutable": false,
116
126
  "description": "Authored informational copy rendered without transformation."
127
+ },
128
+ "isLoading": {
129
+ "type": "boolean",
130
+ "resolvedType": "boolean",
131
+ "attribute": "is-loading",
132
+ "default": "false",
133
+ "required": false,
134
+ "mutable": false,
135
+ "description": "Keep the informational row footprint while its copy is loading."
117
136
  }
118
137
  },
119
138
  "events": [],
@@ -146,8 +165,8 @@
146
165
  },
147
166
  "peerDependencies": {
148
167
  "required": [
149
- "@ds-mo/tokens ^8.0.0",
150
- "@ds-mo/icons ^8.1.1"
168
+ "@ds-mo/tokens ^8.0.1",
169
+ "@ds-mo/icons ^8.1.2"
151
170
  ],
152
171
  "frameworks": "Custom Elements; React 18/19 wrappers; Vue 3 wrappers; Angular 19-22 standalone adapters."
153
172
  }
@@ -158,6 +177,7 @@
158
177
  "@ds-mo/tokens"
159
178
  ],
160
179
  "registryDependencies": [
180
+ "skeleton",
161
181
  "text"
162
182
  ],
163
183
  "files": [
@@ -168,7 +188,7 @@
168
188
  },
169
189
  {
170
190
  "path": "src/wc/components/InlineBannerSettings/InlineBannerSettings.tsx",
171
- "content": "import { Component, h, Host, Prop } from '@stencil/core';\n\n@Component({\n tag: 'ds-inline-banner-settings',\n styleUrl: 'InlineBannerSettings.css',\n scoped: true,\n})\nexport class InlineBannerSettings {\n /** Authored informational copy rendered without transformation. */\n @Prop() description!: string;\n\n render() {\n return (\n <Host>\n {/* eslint-disable-next-line compomo/prefer-direct-ds-text -- This structural layer owns the banner's inner padding separately from the ds-text balance padding. */}\n <div class=\"inline-banner-settings__content\">\n <ds-text\n class=\"inline-banner-settings__description\"\n as=\"p\"\n variant=\"text-body-small\"\n color=\"secondary\"\n >\n {this.description}\n </ds-text>\n </div>\n </Host>\n );\n }\n}\n",
191
+ "content": "import { Component, h, Host, Prop } from '@stencil/core';\n\n@Component({\n tag: 'ds-inline-banner-settings',\n styleUrl: 'InlineBannerSettings.css',\n scoped: true,\n})\nexport class InlineBannerSettings {\n /** Authored informational copy rendered without transformation. */\n @Prop() description!: string;\n /** Keep the informational row footprint while its copy is loading. */\n @Prop() isLoading: boolean = false;\n\n render() {\n return (\n <Host aria-busy={this.isLoading ? 'true' : undefined}>\n <div class=\"inline-banner-settings__content\">\n <ds-skeleton preserveLayout isLoading={this.isLoading} textVariant=\"text-body-small\">\n <ds-text\n class=\"inline-banner-settings__description\"\n as=\"p\"\n variant=\"text-body-small\"\n color=\"secondary\"\n >\n {this.description}\n </ds-text>\n </ds-skeleton>\n </div>\n </Host>\n );\n }\n}\n",
172
192
  "type": "registry:ui"
173
193
  }
174
194
  ]
@@ -532,8 +532,8 @@
532
532
  },
533
533
  "peerDependencies": {
534
534
  "required": [
535
- "@ds-mo/tokens ^8.0.0",
536
- "@ds-mo/icons ^8.1.1"
535
+ "@ds-mo/tokens ^8.0.1",
536
+ "@ds-mo/icons ^8.1.2"
537
537
  ],
538
538
  "frameworks": "Custom Elements; React 18/19 wrappers; Vue 3 wrappers; Angular 19-22 standalone adapters."
539
539
  }
@@ -556,7 +556,7 @@
556
556
  },
557
557
  {
558
558
  "path": "src/wc/components/InputDate/InputDate.tsx",
559
- "content": "import {\n AttachInternals,\n Component,\n Element,\n Prop,\n State,\n Event,\n EventEmitter,\n Listen,\n Method,\n Watch,\n h,\n Host,\n} from '@stencil/core';\nimport {\n controlWidthClass,\n CONTROL_TEXT_VARIANT,\n DEFAULT_REQUIRED_MESSAGE,\n formatIsoCalendarDateLabel,\n isIsoCalendarDate,\n parseLooseCalendarDate,\n resolveChoicePopupAlignOffset,\n resolveCssLengthPx,\n resolveMotionTimeMs,\n restoreStringFormState,\n setFormControlValue,\n TOKEN_DEFAULTS,\n type ControlSize,\n type ControlWidth,\n} from '../../utils';\nimport { AnchoredPositionController } from '../../utils/anchored-position-controller';\nimport { AnchoredOverlayInteractionController } from '../../utils/anchored-overlay-interaction-controller';\nimport { resolveAnchoredOverlayBoundaryRect } from '../../utils/anchored-overlay-boundary';\n\nexport type InputDateSize = ControlSize;\nexport type InputDateWidth = ControlWidth;\n\nlet idCounter = 0;\n\nconst INVALID_DATE_MESSAGE = 'Enter a valid date.';\nconst DATE_BEFORE_MIN_MESSAGE = 'Date is before the minimum allowed date.';\nconst DATE_AFTER_MAX_MESSAGE = 'Date is after the maximum allowed date.';\n\n@Component({\n tag: 'ds-input-date',\n styleUrl: 'InputDate.css',\n scoped: true,\n formAssociated: true,\n})\nexport class InputDate {\n @Element() el!: HTMLElement;\n @AttachInternals() internals!: ElementInternals;\n\n private generatedId = `ds-input-date-${++idCounter}`;\n private errorId = `${this.generatedId}-error`;\n private popupId = `${this.generatedId}-popup`;\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 @Prop({ reflect: true }) readOnly: boolean = false;\n @Prop({ reflect: true }) required: boolean = false;\n @Prop() requiredMessage: string = DEFAULT_REQUIRED_MESSAGE;\n @Prop() min: string | undefined;\n @Prop() max: string | undefined;\n @Prop() size: InputDateSize = 'md';\n @Prop() width: InputDateWidth = 'fill';\n @Prop() hasBorder: boolean = true;\n @Prop() hasInteractionFill: boolean = true;\n @Prop() isInactive: boolean = false;\n @Prop() autoFocus: boolean = false;\n @Prop() error: boolean = false;\n @Prop() errorMessage: string | undefined;\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\n private initialValue = '';\n private inputEl?: HTMLInputElement;\n private controlEl?: HTMLElement;\n private calendarButton?: HTMLDsButtonUnfilledElement;\n private closeTimer: ReturnType<typeof setTimeout> | null = null;\n @State() private formDisabled = false;\n @State() private focused = false;\n @State() private touched = false;\n @State() private draftText = '';\n @State() private open = false;\n @State() private shouldRender = false;\n @State() private closing = false;\n @State() private positionReady = false;\n @State() private pos = { x: 0, y: 0 };\n\n private readonly position = new AnchoredPositionController({\n getAnchor: () => this.controlEl ?? null,\n getPopup: () => this.el.querySelector<HTMLElement>('.input-date-popup'),\n getOwnerDocument: () => this.el.ownerDocument,\n measure: (anchor, popup) => {\n if (!this.open) return null;\n const sectionInsetPx = resolveCssLengthPx(TOKEN_DEFAULTS.space050, TOKEN_DEFAULTS.space050);\n return {\n anchorRect: anchor.getBoundingClientRect(),\n popupWidth: popup.offsetWidth || this.popupFallbackWidth,\n popupHeight: popup.offsetHeight || this.popupFallbackHeight,\n side: 'bottom',\n align: 'end',\n sideOffsetPx: resolveCssLengthPx(TOKEN_DEFAULTS.space050, TOKEN_DEFAULTS.space050),\n alignOffsetPx: resolveChoicePopupAlignOffset({\n align: 'end',\n alignOffsetPx: 0,\n sectionInsetPx,\n anchorAlignment: 'popup-frame',\n }),\n viewportPadPx: resolveCssLengthPx(TOKEN_DEFAULTS.space050, TOKEN_DEFAULTS.space050),\n viewportWidth: window.innerWidth,\n viewportHeight: window.innerHeight,\n collisionRect: resolveAnchoredOverlayBoundaryRect(anchor),\n };\n },\n apply: ({ x, y }) => {\n this.pos = { x, y };\n },\n onReady: () => {\n this.positionReady = true;\n },\n liveUpdate: 'double-frame',\n observeResize: true,\n topLayer: true,\n });\n private readonly interaction = new AnchoredOverlayInteractionController({\n getAnchor: () => this.controlEl ?? null,\n getPopup: () => this.el.querySelector<HTMLElement>('.input-date-popup'),\n getOwnerDocument: () => this.el.ownerDocument,\n onOutsideActivation: () => this.closePicker(false),\n });\n\n private get popupFallbackWidth(): number {\n return resolveCssLengthPx(TOKEN_DEFAULTS.menuWidthXs, TOKEN_DEFAULTS.menuWidthXs);\n }\n\n private get popupFallbackHeight(): number {\n return resolveCssLengthPx(TOKEN_DEFAULTS.menuFallbackHeight, TOKEN_DEFAULTS.menuFallbackHeight);\n }\n\n private get formInactive(): boolean {\n return this.isInactive || this.disabled || this.formDisabled;\n }\n\n private get pickerInactive(): boolean {\n return this.formInactive || this.readOnly;\n }\n\n private get hasConstraintError(): boolean {\n if (!this.value) return false;\n if (!isIsoCalendarDate(this.value)) return true;\n if (this.min && isIsoCalendarDate(this.min) && this.value < this.min) return true;\n if (this.max && isIsoCalendarDate(this.max) && this.value > this.max) return true;\n return false;\n }\n\n private get isInvalid(): boolean {\n return (\n this.error ||\n (!this.formInactive &&\n ((this.required && this.value.length === 0) || this.hasConstraintError))\n );\n }\n\n componentWillLoad() {\n this.initialValue = this.value;\n this.syncFormValue();\n }\n\n disconnectedCallback() {\n this.teardownListeners();\n this.open = false;\n this.shouldRender = false;\n this.closing = false;\n this.positionReady = false;\n this.focused = false;\n }\n\n @Watch('value')\n @Watch('required')\n @Watch('requiredMessage')\n @Watch('min')\n @Watch('max')\n syncFormValue() {\n const inactive = this.formInactive;\n setFormControlValue(this.internals, this.value, { inactive });\n const flags: ValidityStateFlags = {};\n let message = '';\n if (!inactive) {\n if (this.required && this.value.length === 0) {\n flags.valueMissing = true;\n message = this.requiredMessage;\n } else if (this.value && !isIsoCalendarDate(this.value)) {\n flags.badInput = true;\n message = INVALID_DATE_MESSAGE;\n } else if (this.value && this.min && isIsoCalendarDate(this.min) && this.value < this.min) {\n flags.rangeUnderflow = true;\n message = DATE_BEFORE_MIN_MESSAGE;\n } else if (this.value && this.max && isIsoCalendarDate(this.max) && this.value > this.max) {\n flags.rangeOverflow = true;\n message = DATE_AFTER_MAX_MESSAGE;\n }\n }\n this.internals.setValidity(flags, message);\n }\n\n @Watch('disabled')\n @Watch('isInactive')\n @Watch('readOnly')\n onInteractionStateChange() {\n this.syncFormValue();\n if (this.pickerInactive && this.shouldRender) this.closePicker(false);\n }\n\n formDisabledCallback(disabled: boolean) {\n this.formDisabled = disabled;\n this.onInteractionStateChange();\n }\n\n formResetCallback() {\n this.value = this.initialValue;\n this.draftText = this.displayValue;\n }\n\n formStateRestoreCallback(state: string | File | FormData | null) {\n this.value = restoreStringFormState(state);\n this.draftText = this.displayValue;\n }\n\n @Method()\n async setFocus() {\n this.inputEl?.focus();\n }\n\n @Listen('keydown')\n handleHostKeyDown(event: KeyboardEvent) {\n if (!this.shouldRender || this.closing) return;\n if (event.key === 'Escape') {\n event.preventDefault();\n this.closePicker('button');\n return;\n }\n if (event.key !== 'Tab') return;\n const popup = this.el.querySelector<HTMLElement>('.input-date-popup');\n if (!popup || !event.composedPath().includes(popup)) return;\n if (!this.interaction.tabLeavesPopup(event)) return;\n event.preventDefault();\n this.closePicker(false);\n this.interaction.moveFocusAfterTab(event.shiftKey);\n }\n\n private get displayValue(): string {\n return formatIsoCalendarDateLabel(this.value);\n }\n\n private parseDraft(text: string): string | null {\n const trimmed = text.trim();\n if (!trimmed) return '';\n const iso = parseLooseCalendarDate(trimmed);\n if (!iso) return null;\n if (this.min && isIsoCalendarDate(this.min) && iso < this.min) return null;\n if (this.max && isIsoCalendarDate(this.max) && iso > this.max) return null;\n return iso;\n }\n\n private commitIso(iso: string, emit = true) {\n if (this.value !== iso) {\n this.value = iso;\n if (emit) this.dsChange.emit(iso);\n }\n this.draftText = formatIsoCalendarDateLabel(iso);\n }\n\n private teardownListeners() {\n this.position.unobserve();\n this.interaction.disconnect();\n if (this.closeTimer) {\n clearTimeout(this.closeTimer);\n this.closeTimer = null;\n }\n }\n\n private openPicker() {\n const inactive = this.isInactive || this.disabled || this.formDisabled || this.readOnly;\n if (inactive || this.open || !this.el.isConnected) return;\n this.shouldRender = true;\n this.closing = false;\n this.positionReady = false;\n this.open = true;\n this.teardownListeners();\n this.interaction.connect();\n this.position.observe();\n this.position.schedule();\n }\n\n private closePicker(restore: 'input' | 'button' | false) {\n if (!this.shouldRender || this.closing) return;\n this.open = false;\n this.position.cancel();\n this.closing = true;\n this.interaction.disconnect();\n this.position.unobserve();\n if (restore === 'input') this.inputEl?.focus();\n if (restore === 'button') void this.calendarButton?.setFocus();\n const duration = resolveMotionTimeMs(\n TOKEN_DEFAULTS.motionShort2,\n TOKEN_DEFAULTS.animationDurationShort3\n );\n if (duration <= 0) {\n this.finishClose();\n return;\n }\n this.closeTimer = setTimeout(() => this.finishClose(), duration);\n }\n\n private finishClose() {\n const popup = this.el.querySelector<HTMLElement>('.input-date-popup');\n if (popup?.matches(':popover-open')) popup.hidePopover();\n this.shouldRender = false;\n this.closing = false;\n this.closeTimer = null;\n }\n\n private togglePicker = () => {\n if (this.isInactive || this.disabled || this.formDisabled || this.readOnly) return;\n if (this.open) this.closePicker('button');\n else this.openPicker();\n };\n\n private handleInput = (event: Event) => {\n if (this.pickerInactive) return;\n this.draftText = (event.target as HTMLInputElement).value;\n const parsed = this.parseDraft(this.draftText);\n if (parsed === null) return;\n this.commitIso(parsed);\n };\n\n private handleFocus = () => {\n this.draftText = this.displayValue || this.value;\n this.focused = true;\n };\n\n private handleBlur = () => {\n this.focused = false;\n this.touched = true;\n if (this.pickerInactive) {\n this.draftText = this.displayValue;\n return;\n }\n const parsed = this.parseDraft(this.draftText);\n if (parsed === null) {\n this.draftText = this.displayValue;\n return;\n }\n this.commitIso(parsed);\n };\n\n private handleCalendarChange = (event: CustomEvent<string>) => {\n event.stopPropagation();\n if (this.pickerInactive) return;\n const parsed = this.parseDraft(event.detail);\n if (parsed === null) return;\n this.commitIso(parsed);\n this.closePicker('input');\n };\n\n render() {\n const inputId = this.inputId ?? this.generatedId;\n const inactive = this.formInactive;\n const pickerInactive = this.pickerInactive;\n const filled = this.value.length > 0;\n const dirty = this.value !== this.initialValue;\n const showError = this.error && Boolean(this.errorMessage);\n const textVariant = CONTROL_TEXT_VARIANT[this.size];\n const textClass = `ds-text--${textVariant.replace('text-', '')}`;\n const describedBy =\n [this.ariaDescribedby, showError ? this.errorId : undefined].filter(Boolean).join(' ') ||\n undefined;\n const popupStyle = {\n position: 'fixed',\n left: '0',\n top: '0',\n transform: `translate(${Math.round(this.pos.x)}px, ${Math.round(this.pos.y)}px)`,\n zIndex: 'var(--dimension-z-index-floating)',\n visibility: this.positionReady ? 'visible' : 'hidden',\n };\n\n return (\n <Host\n class={{\n 'input-host': true,\n 'ds-field-stack': true,\n 'ds-field-stack--supporting-inset': !this.hasBorder,\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.isInvalid ? '' : 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 ref={element => {\n this.controlEl = element;\n }}\n class={{\n 'input-control': true,\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 <input\n ref={element => {\n this.inputEl = element;\n }}\n type=\"text\"\n id={inputId}\n value={this.focused ? this.draftText : this.displayValue}\n disabled={inactive}\n readOnly={this.readOnly}\n required={this.required}\n autoFocus={this.autoFocus}\n autoComplete=\"off\"\n spellcheck={false}\n class={{\n 'native-input': true,\n 'native-input--align-start': true,\n 'ds-control-label-box': true,\n [textClass]: true,\n 'ds-text--regular': true,\n }}\n aria-label={this.ariaLabel}\n aria-labelledby={this.ariaLabelledby}\n aria-describedby={describedBy}\n aria-invalid={this.isInvalid ? 'true' : undefined}\n onInput={this.handleInput}\n onFocus={this.handleFocus}\n onBlur={this.handleBlur}\n />\n <ds-button-unfilled\n ref={element => {\n this.calendarButton = element as HTMLDsButtonUnfilledElement | undefined;\n }}\n class=\"input-control__datetime-action\"\n variant=\"icon\"\n size={this.size}\n icon=\"Calendar\"\n hasBorder={false}\n isInset\n isInactive={pickerInactive}\n ariaLabel=\"Choose date\"\n haspopup=\"dialog\"\n expanded={this.open}\n surfaceOpen={this.open || this.closing}\n controls={this.open ? this.popupId : undefined}\n onDsClick={this.togglePicker}\n />\n </div>\n {this.shouldRender ? (\n <div\n id={this.popupId}\n popover=\"manual\"\n class={{\n 'input-date-popup': true,\n 'ds-choice-popup': true,\n 'ds-choice-popup--closing': this.closing,\n 'ds-chrome-column': true,\n 'ds-chrome-space--sm': true,\n }}\n style={popupStyle}\n role=\"dialog\"\n aria-label=\"Choose date\"\n >\n <ds-calendar\n selectionMode=\"single\"\n value={this.value}\n min={this.min}\n max={this.max}\n isInactive={pickerInactive}\n autoFocus\n onDsChange={this.handleCalendarChange}\n />\n </div>\n ) : null}\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",
559
+ "content": "import {\n AttachInternals,\n Component,\n Element,\n Prop,\n State,\n Event,\n EventEmitter,\n Listen,\n Method,\n Watch,\n h,\n Host,\n} from '@stencil/core';\nimport {\n controlWidthClass,\n CONTROL_TEXT_VARIANT,\n DEFAULT_REQUIRED_MESSAGE,\n formatIsoCalendarDateLabel,\n isIsoCalendarDate,\n parseLooseCalendarDate,\n resolveChoicePopupAlignOffset,\n resolveCssLengthPx,\n restoreStringFormState,\n setFormControlValue,\n TOKEN_DEFAULTS,\n type ControlSize,\n type ControlWidth,\n} from '../../utils';\nimport { AnchoredPositionController } from '../../utils/anchored-position-controller';\nimport { AnchoredOverlayInteractionController } from '../../utils/anchored-overlay-interaction-controller';\nimport { resolveAnchoredOverlayBoundaryRect } from '../../utils/anchored-overlay-boundary';\nimport { PickerPopupController, type PickerPopupPhase } from '../../utils/picker-popup-controller';\n\nexport type InputDateSize = ControlSize;\nexport type InputDateWidth = ControlWidth;\n\nlet idCounter = 0;\n\nconst INVALID_DATE_MESSAGE = 'Enter a valid date.';\nconst DATE_BEFORE_MIN_MESSAGE = 'Date is before the minimum allowed date.';\nconst DATE_AFTER_MAX_MESSAGE = 'Date is after the maximum allowed date.';\n\n@Component({\n tag: 'ds-input-date',\n styleUrl: 'InputDate.css',\n scoped: true,\n formAssociated: true,\n})\nexport class InputDate {\n @Element() el!: HTMLElement;\n @AttachInternals() internals!: ElementInternals;\n\n private generatedId = `ds-input-date-${++idCounter}`;\n private errorId = `${this.generatedId}-error`;\n private popupId = `${this.generatedId}-popup`;\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 @Prop({ reflect: true }) readOnly: boolean = false;\n @Prop({ reflect: true }) required: boolean = false;\n @Prop() requiredMessage: string = DEFAULT_REQUIRED_MESSAGE;\n @Prop() min: string | undefined;\n @Prop() max: string | undefined;\n @Prop() size: InputDateSize = 'md';\n @Prop() width: InputDateWidth = 'fill';\n @Prop() hasBorder: boolean = true;\n @Prop() hasInteractionFill: boolean = true;\n @Prop() isInactive: boolean = false;\n @Prop() autoFocus: boolean = false;\n @Prop() error: boolean = false;\n @Prop() errorMessage: string | undefined;\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\n private initialValue = '';\n private inputEl?: HTMLInputElement;\n private controlEl?: HTMLElement;\n private calendarButton?: HTMLDsButtonUnfilledElement;\n @State() private formDisabled = false;\n @State() private focused = false;\n @State() private touched = false;\n @State() private draftText = '';\n @State() private popupPhase: PickerPopupPhase = 'closed';\n @State() private positionReady = false;\n @State() private pos = { x: 0, y: 0 };\n\n private readonly position = new AnchoredPositionController({\n getAnchor: () => this.controlEl ?? null,\n getPopup: () => this.el.querySelector<HTMLElement>('.input-date-popup'),\n getOwnerDocument: () => this.el.ownerDocument,\n measure: (anchor, popup) => {\n if (!this.open) return null;\n const sectionInsetPx = resolveCssLengthPx(TOKEN_DEFAULTS.space050, TOKEN_DEFAULTS.space050);\n return {\n anchorRect: anchor.getBoundingClientRect(),\n popupWidth: popup.offsetWidth || this.popupFallbackWidth,\n popupHeight: popup.offsetHeight || this.popupFallbackHeight,\n side: 'bottom',\n align: 'end',\n sideOffsetPx: resolveCssLengthPx(TOKEN_DEFAULTS.space050, TOKEN_DEFAULTS.space050),\n alignOffsetPx: resolveChoicePopupAlignOffset({\n align: 'end',\n alignOffsetPx: 0,\n sectionInsetPx,\n anchorAlignment: 'popup-frame',\n }),\n viewportPadPx: resolveCssLengthPx(TOKEN_DEFAULTS.space050, TOKEN_DEFAULTS.space050),\n viewportWidth: window.innerWidth,\n viewportHeight: window.innerHeight,\n collisionRect: resolveAnchoredOverlayBoundaryRect(anchor),\n };\n },\n apply: ({ x, y }) => {\n this.pos = { x, y };\n },\n onReady: () => {\n this.positionReady = true;\n },\n liveUpdate: 'double-frame',\n observeResize: true,\n topLayer: true,\n });\n private readonly interaction = new AnchoredOverlayInteractionController({\n getAnchor: () => this.controlEl ?? null,\n getPopup: () => this.el.querySelector<HTMLElement>('.input-date-popup'),\n getOwnerDocument: () => this.el.ownerDocument,\n onOutsideActivation: () => this.closePicker(false),\n });\n private readonly pickerPopup = new PickerPopupController({\n position: this.position,\n interaction: this.interaction,\n getPopup: () => this.el.querySelector<HTMLElement>('.input-date-popup'),\n onPhaseChange: phase => {\n this.popupPhase = phase;\n },\n });\n\n private get open(): boolean {\n return this.popupPhase === 'open';\n }\n\n private get shouldRender(): boolean {\n return this.popupPhase !== 'closed';\n }\n\n private get closing(): boolean {\n return this.popupPhase === 'closing';\n }\n\n private get popupFallbackWidth(): number {\n return resolveCssLengthPx(TOKEN_DEFAULTS.menuWidthXs, TOKEN_DEFAULTS.menuWidthXs);\n }\n\n private get popupFallbackHeight(): number {\n return resolveCssLengthPx(TOKEN_DEFAULTS.menuFallbackHeight, TOKEN_DEFAULTS.menuFallbackHeight);\n }\n\n private get formInactive(): boolean {\n return this.isInactive || this.disabled || this.formDisabled;\n }\n\n private get pickerInactive(): boolean {\n return this.formInactive || this.readOnly;\n }\n\n private get hasConstraintError(): boolean {\n if (!this.value) return false;\n if (!isIsoCalendarDate(this.value)) return true;\n if (this.min && isIsoCalendarDate(this.min) && this.value < this.min) return true;\n if (this.max && isIsoCalendarDate(this.max) && this.value > this.max) return true;\n return false;\n }\n\n private get isInvalid(): boolean {\n return (\n this.error ||\n (!this.formInactive &&\n ((this.required && this.value.length === 0) || this.hasConstraintError))\n );\n }\n\n componentWillLoad() {\n this.initialValue = this.value;\n this.syncFormValue();\n }\n\n disconnectedCallback() {\n this.pickerPopup.disconnect();\n this.positionReady = false;\n this.focused = false;\n }\n\n @Watch('value')\n @Watch('required')\n @Watch('requiredMessage')\n @Watch('min')\n @Watch('max')\n syncFormValue() {\n const inactive = this.formInactive;\n setFormControlValue(this.internals, this.value, { inactive });\n const flags: ValidityStateFlags = {};\n let message = '';\n if (!inactive) {\n if (this.required && this.value.length === 0) {\n flags.valueMissing = true;\n message = this.requiredMessage;\n } else if (this.value && !isIsoCalendarDate(this.value)) {\n flags.badInput = true;\n message = INVALID_DATE_MESSAGE;\n } else if (this.value && this.min && isIsoCalendarDate(this.min) && this.value < this.min) {\n flags.rangeUnderflow = true;\n message = DATE_BEFORE_MIN_MESSAGE;\n } else if (this.value && this.max && isIsoCalendarDate(this.max) && this.value > this.max) {\n flags.rangeOverflow = true;\n message = DATE_AFTER_MAX_MESSAGE;\n }\n }\n this.internals.setValidity(flags, message);\n }\n\n @Watch('disabled')\n @Watch('isInactive')\n @Watch('readOnly')\n onInteractionStateChange() {\n this.syncFormValue();\n if (this.pickerInactive && this.shouldRender) this.closePicker(false);\n }\n\n formDisabledCallback(disabled: boolean) {\n this.formDisabled = disabled;\n this.onInteractionStateChange();\n }\n\n formResetCallback() {\n this.value = this.initialValue;\n this.draftText = this.displayValue;\n }\n\n formStateRestoreCallback(state: string | File | FormData | null) {\n this.value = restoreStringFormState(state);\n this.draftText = this.displayValue;\n }\n\n @Method()\n async setFocus() {\n this.inputEl?.focus();\n }\n\n @Listen('keydown')\n handleHostKeyDown(event: KeyboardEvent) {\n if (!this.shouldRender || this.closing) return;\n if (event.key === 'Escape') {\n event.preventDefault();\n this.closePicker('button');\n return;\n }\n if (event.key !== 'Tab') return;\n const popup = this.el.querySelector<HTMLElement>('.input-date-popup');\n if (!popup || !event.composedPath().includes(popup)) return;\n if (!this.interaction.tabLeavesPopup(event)) return;\n event.preventDefault();\n this.closePicker(false);\n this.interaction.moveFocusAfterTab(event.shiftKey);\n }\n\n private get displayValue(): string {\n return formatIsoCalendarDateLabel(this.value);\n }\n\n private parseDraft(text: string): string | null {\n const trimmed = text.trim();\n if (!trimmed) return '';\n const iso = parseLooseCalendarDate(trimmed);\n if (!iso) return null;\n if (this.min && isIsoCalendarDate(this.min) && iso < this.min) return null;\n if (this.max && isIsoCalendarDate(this.max) && iso > this.max) return null;\n return iso;\n }\n\n private commitIso(iso: string, emit = true) {\n if (this.value !== iso) {\n this.value = iso;\n if (emit) this.dsChange.emit(iso);\n }\n this.draftText = formatIsoCalendarDateLabel(iso);\n }\n\n private openPicker() {\n if (this.pickerInactive || this.open || !this.el.isConnected) return;\n this.positionReady = false;\n this.pickerPopup.open();\n }\n\n private closePicker(restore: 'input' | 'button' | false) {\n this.pickerPopup.close(() => {\n if (restore === 'input') this.inputEl?.focus();\n if (restore === 'button') void this.calendarButton?.setFocus();\n });\n }\n\n private togglePicker = () => {\n if (this.pickerInactive) return;\n if (this.open) this.closePicker('button');\n else this.openPicker();\n };\n\n private handleInput = (event: Event) => {\n if (this.pickerInactive) return;\n this.draftText = (event.target as HTMLInputElement).value;\n const parsed = this.parseDraft(this.draftText);\n if (parsed === null) return;\n this.commitIso(parsed);\n };\n\n private handleFocus = () => {\n this.draftText = this.displayValue || this.value;\n this.focused = true;\n };\n\n private handleBlur = () => {\n this.focused = false;\n this.touched = true;\n if (this.pickerInactive) {\n this.draftText = this.displayValue;\n return;\n }\n const parsed = this.parseDraft(this.draftText);\n if (parsed === null) {\n this.draftText = this.displayValue;\n return;\n }\n this.commitIso(parsed);\n };\n\n private handleCalendarChange = (event: CustomEvent<string>) => {\n event.stopPropagation();\n if (this.pickerInactive) return;\n const parsed = this.parseDraft(event.detail);\n if (parsed === null) return;\n this.commitIso(parsed);\n this.closePicker('input');\n };\n\n render() {\n const inputId = this.inputId ?? this.generatedId;\n const inactive = this.formInactive;\n const pickerInactive = this.pickerInactive;\n const filled = this.value.length > 0;\n const dirty = this.value !== this.initialValue;\n const showError = this.error && Boolean(this.errorMessage);\n const textVariant = CONTROL_TEXT_VARIANT[this.size];\n const textClass = `ds-text--${textVariant.replace('text-', '')}`;\n const describedBy =\n [this.ariaDescribedby, showError ? this.errorId : undefined].filter(Boolean).join(' ') ||\n undefined;\n const popupStyle = {\n position: 'fixed',\n left: '0',\n top: '0',\n transform: `translate(${Math.round(this.pos.x)}px, ${Math.round(this.pos.y)}px)`,\n zIndex: 'var(--dimension-z-index-floating)',\n visibility: this.positionReady ? 'visible' : 'hidden',\n };\n\n return (\n <Host\n class={{\n 'input-host': true,\n 'ds-field-stack': true,\n 'ds-field-stack--supporting-inset': !this.hasBorder,\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.isInvalid ? '' : 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 ref={element => {\n this.controlEl = element;\n }}\n class={{\n 'input-control': true,\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 <input\n ref={element => {\n this.inputEl = element;\n }}\n type=\"text\"\n id={inputId}\n value={this.focused ? this.draftText : this.displayValue}\n disabled={inactive}\n readOnly={this.readOnly}\n required={this.required}\n autoFocus={this.autoFocus}\n autoComplete=\"off\"\n spellcheck={false}\n class={{\n 'native-input': true,\n 'native-input--align-start': true,\n 'ds-control-label-box': true,\n [textClass]: true,\n 'ds-text--regular': true,\n }}\n aria-label={this.ariaLabel}\n aria-labelledby={this.ariaLabelledby}\n aria-describedby={describedBy}\n aria-invalid={this.isInvalid ? 'true' : undefined}\n onInput={this.handleInput}\n onFocus={this.handleFocus}\n onBlur={this.handleBlur}\n />\n <ds-button-unfilled\n ref={element => {\n this.calendarButton = element as HTMLDsButtonUnfilledElement | undefined;\n }}\n class=\"input-control__datetime-action\"\n variant=\"icon\"\n size={this.size}\n icon=\"Calendar\"\n hasBorder={false}\n isInset\n isInactive={pickerInactive}\n ariaLabel=\"Choose date\"\n haspopup=\"dialog\"\n expanded={this.open}\n surfaceOpen={this.open || this.closing}\n controls={this.open ? this.popupId : undefined}\n onDsClick={this.togglePicker}\n />\n </div>\n {this.shouldRender ? (\n <div\n id={this.popupId}\n popover=\"manual\"\n class={{\n 'input-date-popup': true,\n 'ds-choice-popup': true,\n 'ds-choice-popup--closing': this.closing,\n 'ds-chrome-column': true,\n 'ds-chrome-space--sm': true,\n }}\n style={popupStyle}\n role=\"dialog\"\n aria-label=\"Choose date\"\n >\n <ds-calendar\n selectionMode=\"single\"\n value={this.value}\n min={this.min}\n max={this.max}\n isInactive={pickerInactive}\n autoFocus\n onDsChange={this.handleCalendarChange}\n />\n </div>\n ) : null}\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",
560
560
  "type": "registry:ui"
561
561
  }
562
562
  ]
@@ -570,8 +570,8 @@
570
570
  },
571
571
  "peerDependencies": {
572
572
  "required": [
573
- "@ds-mo/tokens ^8.0.0",
574
- "@ds-mo/icons ^8.1.1"
573
+ "@ds-mo/tokens ^8.0.1",
574
+ "@ds-mo/icons ^8.1.2"
575
575
  ],
576
576
  "frameworks": "Custom Elements; React 18/19 wrappers; Vue 3 wrappers; Angular 19-22 standalone adapters."
577
577
  }
@@ -594,7 +594,7 @@
594
594
  },
595
595
  {
596
596
  "path": "src/wc/components/InputTime/InputTime.tsx",
597
- "content": "import {\n AttachInternals,\n Component,\n Element,\n Prop,\n State,\n Event,\n EventEmitter,\n Listen,\n Method,\n Watch,\n h,\n Host,\n} from '@stencil/core';\nimport {\n controlWidthClass,\n CONTROL_TEXT_VARIANT,\n DEFAULT_REQUIRED_MESSAGE,\n formatClockTimeLabel,\n isClockTime,\n isClockTimeStepAligned,\n parseLooseClockTime,\n resolveChoicePopupAlignOffset,\n resolveCssLengthPx,\n resolveMotionTimeMs,\n restoreStringFormState,\n setFormControlValue,\n TOKEN_DEFAULTS,\n type ControlSize,\n type ControlWidth,\n} from '../../utils';\nimport { AnchoredPositionController } from '../../utils/anchored-position-controller';\nimport { AnchoredOverlayInteractionController } from '../../utils/anchored-overlay-interaction-controller';\nimport { resolveAnchoredOverlayBoundaryRect } from '../../utils/anchored-overlay-boundary';\n\nexport type InputTimeSize = ControlSize;\nexport type InputTimeWidth = ControlWidth;\n\nlet idCounter = 0;\n\nconst INVALID_TIME_MESSAGE = 'Enter a valid time.';\nconst TIME_BEFORE_MIN_MESSAGE = 'Time is before the minimum allowed time.';\nconst TIME_AFTER_MAX_MESSAGE = 'Time is after the maximum allowed time.';\nconst TIME_STEP_MESSAGE = 'Time does not match the allowed interval.';\n\n@Component({\n tag: 'ds-input-time',\n styleUrl: 'InputTime.css',\n scoped: true,\n formAssociated: true,\n})\nexport class InputTime {\n @Element() el!: HTMLElement;\n @AttachInternals() internals!: ElementInternals;\n\n private generatedId = `ds-input-time-${++idCounter}`;\n private errorId = `${this.generatedId}-error`;\n private popupId = `${this.generatedId}-popup`;\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 @Prop({ reflect: true }) readOnly: boolean = false;\n @Prop({ reflect: true }) required: boolean = false;\n @Prop() requiredMessage: string = DEFAULT_REQUIRED_MESSAGE;\n /** Native time step in seconds. Defaults to minutes (`60`). */\n @Prop() step: string | number = 60;\n /** Display format; submitted values remain HH:MM in either format. */\n @Prop() hourFormat: '12' | '24' = '12';\n @Prop() min: string | undefined;\n @Prop() max: string | undefined;\n @Prop() size: InputTimeSize = 'md';\n @Prop() width: InputTimeWidth = 'fill';\n @Prop() hasBorder: boolean = true;\n @Prop() hasInteractionFill: boolean = true;\n @Prop() isInactive: boolean = false;\n @Prop() autoFocus: boolean = false;\n @Prop() error: boolean = false;\n @Prop() errorMessage: string | undefined;\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\n private initialValue = '';\n private inputEl?: HTMLInputElement;\n private controlEl?: HTMLElement;\n private clockButton?: HTMLDsButtonUnfilledElement;\n private closeTimer: ReturnType<typeof setTimeout> | null = null;\n @State() private formDisabled = false;\n @State() private focused = false;\n @State() private touched = false;\n @State() private draftText = '';\n @State() private open = false;\n @State() private shouldRender = false;\n @State() private closing = false;\n @State() private positionReady = false;\n @State() private pos = { x: 0, y: 0 };\n\n private readonly position = new AnchoredPositionController({\n getAnchor: () => this.controlEl ?? null,\n getPopup: () => this.el.querySelector<HTMLElement>('.input-time-popup'),\n getOwnerDocument: () => this.el.ownerDocument,\n measure: (anchor, popup) => {\n if (!this.open) return null;\n const sectionInsetPx = resolveCssLengthPx(TOKEN_DEFAULTS.space050, TOKEN_DEFAULTS.space050);\n return {\n anchorRect: anchor.getBoundingClientRect(),\n popupWidth: popup.offsetWidth || this.popupFallbackWidth,\n popupHeight: popup.offsetHeight || this.popupFallbackHeight,\n side: 'bottom',\n align: 'end',\n sideOffsetPx: resolveCssLengthPx(TOKEN_DEFAULTS.space050, TOKEN_DEFAULTS.space050),\n alignOffsetPx: resolveChoicePopupAlignOffset({\n align: 'end',\n alignOffsetPx: 0,\n sectionInsetPx,\n anchorAlignment: 'popup-frame',\n }),\n viewportPadPx: resolveCssLengthPx(TOKEN_DEFAULTS.space050, TOKEN_DEFAULTS.space050),\n viewportWidth: window.innerWidth,\n viewportHeight: window.innerHeight,\n collisionRect: resolveAnchoredOverlayBoundaryRect(anchor),\n };\n },\n apply: ({ x, y }) => {\n this.pos = { x, y };\n },\n onReady: () => {\n this.positionReady = true;\n },\n liveUpdate: 'double-frame',\n observeResize: true,\n topLayer: true,\n });\n private readonly interaction = new AnchoredOverlayInteractionController({\n getAnchor: () => this.controlEl ?? null,\n getPopup: () => this.el.querySelector<HTMLElement>('.input-time-popup'),\n getOwnerDocument: () => this.el.ownerDocument,\n onOutsideActivation: () => this.closePicker(false),\n });\n\n private get popupFallbackWidth(): number {\n return resolveCssLengthPx(TOKEN_DEFAULTS.menuWidthXs, TOKEN_DEFAULTS.menuWidthXs);\n }\n\n private get popupFallbackHeight(): number {\n return resolveCssLengthPx(TOKEN_DEFAULTS.menuFallbackHeight, TOKEN_DEFAULTS.menuFallbackHeight);\n }\n\n private get formInactive(): boolean {\n return this.isInactive || this.disabled || this.formDisabled;\n }\n\n private get pickerInactive(): boolean {\n return this.formInactive || this.readOnly;\n }\n\n private get hasConstraintError(): boolean {\n if (!this.value) return false;\n if (!isClockTime(this.value)) return true;\n if (this.min && isClockTime(this.min) && this.value < this.min) return true;\n if (this.max && isClockTime(this.max) && this.value > this.max) return true;\n return !isClockTimeStepAligned(this.value, this.step, this.min);\n }\n\n private get isInvalid(): boolean {\n return (\n this.error ||\n (!this.formInactive &&\n ((this.required && this.value.length === 0) || this.hasConstraintError))\n );\n }\n\n componentWillLoad() {\n this.initialValue = this.value;\n this.syncFormValue();\n }\n\n disconnectedCallback() {\n this.teardownListeners();\n this.open = false;\n this.shouldRender = false;\n this.closing = false;\n this.positionReady = false;\n this.focused = false;\n }\n\n @Watch('hourFormat')\n onHourFormatChange() {\n this.draftText = this.displayValue;\n }\n\n @Watch('value')\n @Watch('required')\n @Watch('requiredMessage')\n @Watch('min')\n @Watch('max')\n @Watch('step')\n syncFormValue() {\n const inactive = this.formInactive;\n setFormControlValue(this.internals, this.value, { inactive });\n const flags: ValidityStateFlags = {};\n let message = '';\n if (!inactive) {\n if (this.required && this.value.length === 0) {\n flags.valueMissing = true;\n message = this.requiredMessage;\n } else if (this.value && !isClockTime(this.value)) {\n flags.badInput = true;\n message = INVALID_TIME_MESSAGE;\n } else if (this.value && this.min && isClockTime(this.min) && this.value < this.min) {\n flags.rangeUnderflow = true;\n message = TIME_BEFORE_MIN_MESSAGE;\n } else if (this.value && this.max && isClockTime(this.max) && this.value > this.max) {\n flags.rangeOverflow = true;\n message = TIME_AFTER_MAX_MESSAGE;\n } else if (this.value && !isClockTimeStepAligned(this.value, this.step, this.min)) {\n flags.stepMismatch = true;\n message = TIME_STEP_MESSAGE;\n }\n }\n this.internals.setValidity(flags, message);\n }\n\n @Watch('disabled')\n @Watch('isInactive')\n @Watch('readOnly')\n onInteractionStateChange() {\n this.syncFormValue();\n if (this.pickerInactive && this.shouldRender) this.closePicker(false);\n }\n\n formDisabledCallback(disabled: boolean) {\n this.formDisabled = disabled;\n this.onInteractionStateChange();\n }\n\n formResetCallback() {\n this.value = this.initialValue;\n this.draftText = this.displayValue;\n }\n\n formStateRestoreCallback(state: string | File | FormData | null) {\n this.value = restoreStringFormState(state);\n this.draftText = this.displayValue;\n }\n\n @Method()\n async setFocus() {\n this.inputEl?.focus();\n }\n\n @Listen('keydown')\n handleHostKeyDown(event: KeyboardEvent) {\n if (!this.shouldRender || this.closing) return;\n if (event.key === 'Escape') {\n event.preventDefault();\n this.closePicker('button');\n return;\n }\n if (event.key !== 'Tab') return;\n const popup = this.el.querySelector<HTMLElement>('.input-time-popup');\n if (!popup || !event.composedPath().includes(popup)) return;\n if (!this.interaction.tabLeavesPopup(event)) return;\n event.preventDefault();\n this.closePicker(false);\n this.interaction.moveFocusAfterTab(event.shiftKey);\n }\n\n private get displayValue(): string {\n return this.hourFormat === '24' ? this.value : formatClockTimeLabel(this.value);\n }\n\n private parseDraft(text: string): string | null {\n const trimmed = text.trim();\n if (!trimmed) return '';\n const iso = parseLooseClockTime(trimmed);\n if (!iso) return null;\n if (this.min && isClockTime(this.min) && iso < this.min) return null;\n if (this.max && isClockTime(this.max) && iso > this.max) return null;\n if (!isClockTimeStepAligned(iso, this.step, this.min)) return null;\n return iso;\n }\n\n private commitIso(iso: string, emit = true) {\n if (this.value !== iso) {\n this.value = iso;\n if (emit) this.dsChange.emit(iso);\n }\n this.draftText = this.hourFormat === '24' ? iso : formatClockTimeLabel(iso);\n }\n\n private teardownListeners() {\n this.position.unobserve();\n this.interaction.disconnect();\n if (this.closeTimer) {\n clearTimeout(this.closeTimer);\n this.closeTimer = null;\n }\n }\n\n private openPicker() {\n const inactive = this.isInactive || this.disabled || this.formDisabled || this.readOnly;\n if (inactive || this.open || !this.el.isConnected) return;\n this.shouldRender = true;\n this.closing = false;\n this.positionReady = false;\n this.open = true;\n this.teardownListeners();\n this.interaction.connect();\n this.position.observe();\n this.position.schedule();\n }\n\n private closePicker(restore: 'input' | 'button' | false) {\n if (!this.shouldRender || this.closing) return;\n this.open = false;\n this.position.cancel();\n this.closing = true;\n this.interaction.disconnect();\n this.position.unobserve();\n if (restore === 'input') this.inputEl?.focus();\n if (restore === 'button') void this.clockButton?.setFocus();\n const duration = resolveMotionTimeMs(\n TOKEN_DEFAULTS.motionShort2,\n TOKEN_DEFAULTS.animationDurationShort3\n );\n if (duration <= 0) {\n this.finishClose();\n return;\n }\n this.closeTimer = setTimeout(() => this.finishClose(), duration);\n }\n\n private finishClose() {\n const popup = this.el.querySelector<HTMLElement>('.input-time-popup');\n if (popup?.matches(':popover-open')) popup.hidePopover();\n this.shouldRender = false;\n this.closing = false;\n this.closeTimer = null;\n }\n\n private togglePicker = () => {\n if (this.isInactive || this.disabled || this.formDisabled || this.readOnly) return;\n if (this.open) this.closePicker('button');\n else this.openPicker();\n };\n\n private handleInput = (event: Event) => {\n if (this.pickerInactive) return;\n this.draftText = (event.target as HTMLInputElement).value;\n const parsed = this.parseDraft(this.draftText);\n if (parsed === null) return;\n this.commitIso(parsed);\n };\n\n private handleFocus = () => {\n this.draftText = this.displayValue || this.value;\n this.focused = true;\n };\n\n private handleBlur = () => {\n this.focused = false;\n this.touched = true;\n if (this.pickerInactive) {\n this.draftText = this.displayValue;\n return;\n }\n const parsed = this.parseDraft(this.draftText);\n if (parsed === null) {\n this.draftText = this.displayValue;\n return;\n }\n this.commitIso(parsed);\n };\n\n private handleTimeChange = (event: CustomEvent<string>) => {\n event.stopPropagation();\n if (this.pickerInactive) return;\n const parsed = this.parseDraft(event.detail);\n if (parsed === null) return;\n this.commitIso(parsed);\n };\n\n render() {\n const inputId = this.inputId ?? this.generatedId;\n const inactive = this.formInactive;\n const pickerInactive = this.pickerInactive;\n const filled = this.value.length > 0;\n const dirty = this.value !== this.initialValue;\n const showError = this.error && Boolean(this.errorMessage);\n const textVariant = CONTROL_TEXT_VARIANT[this.size];\n const textClass = `ds-text--${textVariant.replace('text-', '')}`;\n const describedBy =\n [this.ariaDescribedby, showError ? this.errorId : undefined].filter(Boolean).join(' ') ||\n undefined;\n const popupStyle = {\n position: 'fixed',\n left: '0',\n top: '0',\n transform: `translate(${Math.round(this.pos.x)}px, ${Math.round(this.pos.y)}px)`,\n zIndex: 'var(--dimension-z-index-floating)',\n visibility: this.positionReady ? 'visible' : 'hidden',\n };\n\n return (\n <Host\n class={{\n 'input-host': true,\n 'ds-field-stack': true,\n 'ds-field-stack--supporting-inset': !this.hasBorder,\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.isInvalid ? '' : 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 ref={element => {\n this.controlEl = element;\n }}\n class={{\n 'input-control': true,\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 <input\n ref={element => {\n this.inputEl = element;\n }}\n type=\"text\"\n id={inputId}\n value={this.focused ? this.draftText : this.displayValue}\n disabled={inactive}\n readOnly={this.readOnly}\n required={this.required}\n autoFocus={this.autoFocus}\n autoComplete=\"off\"\n spellcheck={false}\n class={{\n 'native-input': true,\n 'native-input--align-start': true,\n 'ds-control-label-box': true,\n [textClass]: true,\n 'ds-text--regular': true,\n }}\n aria-label={this.ariaLabel}\n aria-labelledby={this.ariaLabelledby}\n aria-describedby={describedBy}\n aria-invalid={this.isInvalid ? 'true' : undefined}\n onInput={this.handleInput}\n onFocus={this.handleFocus}\n onBlur={this.handleBlur}\n />\n <ds-button-unfilled\n ref={element => {\n this.clockButton = element as HTMLDsButtonUnfilledElement | undefined;\n }}\n class=\"input-control__datetime-action\"\n variant=\"icon\"\n size={this.size}\n icon=\"Clock\"\n hasBorder={false}\n isInset\n isInactive={pickerInactive}\n ariaLabel=\"Choose time\"\n haspopup=\"dialog\"\n expanded={this.open}\n surfaceOpen={this.open || this.closing}\n controls={this.open ? this.popupId : undefined}\n onDsClick={this.togglePicker}\n />\n </div>\n {this.shouldRender ? (\n <div\n id={this.popupId}\n popover=\"manual\"\n class={{\n 'input-time-popup': true,\n 'ds-choice-popup': true,\n 'ds-choice-popup--closing': this.closing,\n 'ds-chrome-column': true,\n 'ds-chrome-space--sm': true,\n }}\n style={popupStyle}\n role=\"dialog\"\n aria-label=\"Choose time\"\n >\n <ds-time-picker\n hourFormat={this.hourFormat}\n value={this.value}\n min={this.min}\n max={this.max}\n step={this.step}\n isInactive={pickerInactive}\n autoFocus\n onDsChange={this.handleTimeChange}\n />\n </div>\n ) : null}\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",
597
+ "content": "import {\n AttachInternals,\n Component,\n Element,\n Prop,\n State,\n Event,\n EventEmitter,\n Listen,\n Method,\n Watch,\n h,\n Host,\n} from '@stencil/core';\nimport {\n controlWidthClass,\n CONTROL_TEXT_VARIANT,\n DEFAULT_REQUIRED_MESSAGE,\n formatClockTimeLabel,\n isClockTime,\n isClockTimeStepAligned,\n parseLooseClockTime,\n resolveChoicePopupAlignOffset,\n resolveCssLengthPx,\n restoreStringFormState,\n setFormControlValue,\n TOKEN_DEFAULTS,\n type ControlSize,\n type ControlWidth,\n} from '../../utils';\nimport { AnchoredPositionController } from '../../utils/anchored-position-controller';\nimport { AnchoredOverlayInteractionController } from '../../utils/anchored-overlay-interaction-controller';\nimport { resolveAnchoredOverlayBoundaryRect } from '../../utils/anchored-overlay-boundary';\nimport { PickerPopupController, type PickerPopupPhase } from '../../utils/picker-popup-controller';\n\nexport type InputTimeSize = ControlSize;\nexport type InputTimeWidth = ControlWidth;\n\nlet idCounter = 0;\n\nconst INVALID_TIME_MESSAGE = 'Enter a valid time.';\nconst TIME_BEFORE_MIN_MESSAGE = 'Time is before the minimum allowed time.';\nconst TIME_AFTER_MAX_MESSAGE = 'Time is after the maximum allowed time.';\nconst TIME_STEP_MESSAGE = 'Time does not match the allowed interval.';\n\n@Component({\n tag: 'ds-input-time',\n styleUrl: 'InputTime.css',\n scoped: true,\n formAssociated: true,\n})\nexport class InputTime {\n @Element() el!: HTMLElement;\n @AttachInternals() internals!: ElementInternals;\n\n private generatedId = `ds-input-time-${++idCounter}`;\n private errorId = `${this.generatedId}-error`;\n private popupId = `${this.generatedId}-popup`;\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 @Prop({ reflect: true }) readOnly: boolean = false;\n @Prop({ reflect: true }) required: boolean = false;\n @Prop() requiredMessage: string = DEFAULT_REQUIRED_MESSAGE;\n /** Native time step in seconds. Defaults to minutes (`60`). */\n @Prop() step: string | number = 60;\n /** Display format; submitted values remain HH:MM in either format. */\n @Prop() hourFormat: '12' | '24' = '12';\n @Prop() min: string | undefined;\n @Prop() max: string | undefined;\n @Prop() size: InputTimeSize = 'md';\n @Prop() width: InputTimeWidth = 'fill';\n @Prop() hasBorder: boolean = true;\n @Prop() hasInteractionFill: boolean = true;\n @Prop() isInactive: boolean = false;\n @Prop() autoFocus: boolean = false;\n @Prop() error: boolean = false;\n @Prop() errorMessage: string | undefined;\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\n private initialValue = '';\n private inputEl?: HTMLInputElement;\n private controlEl?: HTMLElement;\n private clockButton?: HTMLDsButtonUnfilledElement;\n @State() private formDisabled = false;\n @State() private focused = false;\n @State() private touched = false;\n @State() private draftText = '';\n @State() private popupPhase: PickerPopupPhase = 'closed';\n @State() private positionReady = false;\n @State() private pos = { x: 0, y: 0 };\n\n private readonly position = new AnchoredPositionController({\n getAnchor: () => this.controlEl ?? null,\n getPopup: () => this.el.querySelector<HTMLElement>('.input-time-popup'),\n getOwnerDocument: () => this.el.ownerDocument,\n measure: (anchor, popup) => {\n if (!this.open) return null;\n const sectionInsetPx = resolveCssLengthPx(TOKEN_DEFAULTS.space050, TOKEN_DEFAULTS.space050);\n return {\n anchorRect: anchor.getBoundingClientRect(),\n popupWidth: popup.offsetWidth || this.popupFallbackWidth,\n popupHeight: popup.offsetHeight || this.popupFallbackHeight,\n side: 'bottom',\n align: 'end',\n sideOffsetPx: resolveCssLengthPx(TOKEN_DEFAULTS.space050, TOKEN_DEFAULTS.space050),\n alignOffsetPx: resolveChoicePopupAlignOffset({\n align: 'end',\n alignOffsetPx: 0,\n sectionInsetPx,\n anchorAlignment: 'popup-frame',\n }),\n viewportPadPx: resolveCssLengthPx(TOKEN_DEFAULTS.space050, TOKEN_DEFAULTS.space050),\n viewportWidth: window.innerWidth,\n viewportHeight: window.innerHeight,\n collisionRect: resolveAnchoredOverlayBoundaryRect(anchor),\n };\n },\n apply: ({ x, y }) => {\n this.pos = { x, y };\n },\n onReady: () => {\n this.positionReady = true;\n },\n liveUpdate: 'double-frame',\n observeResize: true,\n topLayer: true,\n });\n private readonly interaction = new AnchoredOverlayInteractionController({\n getAnchor: () => this.controlEl ?? null,\n getPopup: () => this.el.querySelector<HTMLElement>('.input-time-popup'),\n getOwnerDocument: () => this.el.ownerDocument,\n onOutsideActivation: () => this.closePicker(false),\n });\n private readonly pickerPopup = new PickerPopupController({\n position: this.position,\n interaction: this.interaction,\n getPopup: () => this.el.querySelector<HTMLElement>('.input-time-popup'),\n onPhaseChange: phase => {\n this.popupPhase = phase;\n },\n });\n\n private get open(): boolean {\n return this.popupPhase === 'open';\n }\n\n private get shouldRender(): boolean {\n return this.popupPhase !== 'closed';\n }\n\n private get closing(): boolean {\n return this.popupPhase === 'closing';\n }\n\n private get popupFallbackWidth(): number {\n return resolveCssLengthPx(TOKEN_DEFAULTS.menuWidthXs, TOKEN_DEFAULTS.menuWidthXs);\n }\n\n private get popupFallbackHeight(): number {\n return resolveCssLengthPx(TOKEN_DEFAULTS.menuFallbackHeight, TOKEN_DEFAULTS.menuFallbackHeight);\n }\n\n private get formInactive(): boolean {\n return this.isInactive || this.disabled || this.formDisabled;\n }\n\n private get pickerInactive(): boolean {\n return this.formInactive || this.readOnly;\n }\n\n private get hasConstraintError(): boolean {\n if (!this.value) return false;\n if (!isClockTime(this.value)) return true;\n if (this.min && isClockTime(this.min) && this.value < this.min) return true;\n if (this.max && isClockTime(this.max) && this.value > this.max) return true;\n return !isClockTimeStepAligned(this.value, this.step, this.min);\n }\n\n private get isInvalid(): boolean {\n return (\n this.error ||\n (!this.formInactive &&\n ((this.required && this.value.length === 0) || this.hasConstraintError))\n );\n }\n\n componentWillLoad() {\n this.initialValue = this.value;\n this.syncFormValue();\n }\n\n disconnectedCallback() {\n this.pickerPopup.disconnect();\n this.positionReady = false;\n this.focused = false;\n }\n\n @Watch('hourFormat')\n onHourFormatChange() {\n this.draftText = this.displayValue;\n }\n\n @Watch('value')\n @Watch('required')\n @Watch('requiredMessage')\n @Watch('min')\n @Watch('max')\n @Watch('step')\n syncFormValue() {\n const inactive = this.formInactive;\n setFormControlValue(this.internals, this.value, { inactive });\n const flags: ValidityStateFlags = {};\n let message = '';\n if (!inactive) {\n if (this.required && this.value.length === 0) {\n flags.valueMissing = true;\n message = this.requiredMessage;\n } else if (this.value && !isClockTime(this.value)) {\n flags.badInput = true;\n message = INVALID_TIME_MESSAGE;\n } else if (this.value && this.min && isClockTime(this.min) && this.value < this.min) {\n flags.rangeUnderflow = true;\n message = TIME_BEFORE_MIN_MESSAGE;\n } else if (this.value && this.max && isClockTime(this.max) && this.value > this.max) {\n flags.rangeOverflow = true;\n message = TIME_AFTER_MAX_MESSAGE;\n } else if (this.value && !isClockTimeStepAligned(this.value, this.step, this.min)) {\n flags.stepMismatch = true;\n message = TIME_STEP_MESSAGE;\n }\n }\n this.internals.setValidity(flags, message);\n }\n\n @Watch('disabled')\n @Watch('isInactive')\n @Watch('readOnly')\n onInteractionStateChange() {\n this.syncFormValue();\n if (this.pickerInactive && this.shouldRender) this.closePicker(false);\n }\n\n formDisabledCallback(disabled: boolean) {\n this.formDisabled = disabled;\n this.onInteractionStateChange();\n }\n\n formResetCallback() {\n this.value = this.initialValue;\n this.draftText = this.displayValue;\n }\n\n formStateRestoreCallback(state: string | File | FormData | null) {\n this.value = restoreStringFormState(state);\n this.draftText = this.displayValue;\n }\n\n @Method()\n async setFocus() {\n this.inputEl?.focus();\n }\n\n @Listen('keydown')\n handleHostKeyDown(event: KeyboardEvent) {\n if (!this.shouldRender || this.closing) return;\n if (event.key === 'Escape') {\n event.preventDefault();\n this.closePicker('button');\n return;\n }\n if (event.key !== 'Tab') return;\n const popup = this.el.querySelector<HTMLElement>('.input-time-popup');\n if (!popup || !event.composedPath().includes(popup)) return;\n if (!this.interaction.tabLeavesPopup(event)) return;\n event.preventDefault();\n this.closePicker(false);\n this.interaction.moveFocusAfterTab(event.shiftKey);\n }\n\n private get displayValue(): string {\n return this.hourFormat === '24' ? this.value : formatClockTimeLabel(this.value);\n }\n\n private parseDraft(text: string): string | null {\n const trimmed = text.trim();\n if (!trimmed) return '';\n const iso = parseLooseClockTime(trimmed);\n if (!iso) return null;\n if (this.min && isClockTime(this.min) && iso < this.min) return null;\n if (this.max && isClockTime(this.max) && iso > this.max) return null;\n if (!isClockTimeStepAligned(iso, this.step, this.min)) return null;\n return iso;\n }\n\n private commitIso(iso: string, emit = true) {\n if (this.value !== iso) {\n this.value = iso;\n if (emit) this.dsChange.emit(iso);\n }\n this.draftText = this.hourFormat === '24' ? iso : formatClockTimeLabel(iso);\n }\n\n private openPicker() {\n if (this.pickerInactive || this.open || !this.el.isConnected) return;\n this.positionReady = false;\n this.pickerPopup.open();\n }\n\n private closePicker(restore: 'input' | 'button' | false) {\n this.pickerPopup.close(() => {\n if (restore === 'input') this.inputEl?.focus();\n if (restore === 'button') void this.clockButton?.setFocus();\n });\n }\n\n private togglePicker = () => {\n if (this.pickerInactive) return;\n if (this.open) this.closePicker('button');\n else this.openPicker();\n };\n\n private handleInput = (event: Event) => {\n if (this.pickerInactive) return;\n this.draftText = (event.target as HTMLInputElement).value;\n const parsed = this.parseDraft(this.draftText);\n if (parsed === null) return;\n this.commitIso(parsed);\n };\n\n private handleFocus = () => {\n this.draftText = this.displayValue || this.value;\n this.focused = true;\n };\n\n private handleBlur = () => {\n this.focused = false;\n this.touched = true;\n if (this.pickerInactive) {\n this.draftText = this.displayValue;\n return;\n }\n const parsed = this.parseDraft(this.draftText);\n if (parsed === null) {\n this.draftText = this.displayValue;\n return;\n }\n this.commitIso(parsed);\n };\n\n private handleTimeChange = (event: CustomEvent<string>) => {\n event.stopPropagation();\n if (this.pickerInactive) return;\n const parsed = this.parseDraft(event.detail);\n if (parsed === null) return;\n this.commitIso(parsed);\n };\n\n render() {\n const inputId = this.inputId ?? this.generatedId;\n const inactive = this.formInactive;\n const pickerInactive = this.pickerInactive;\n const filled = this.value.length > 0;\n const dirty = this.value !== this.initialValue;\n const showError = this.error && Boolean(this.errorMessage);\n const textVariant = CONTROL_TEXT_VARIANT[this.size];\n const textClass = `ds-text--${textVariant.replace('text-', '')}`;\n const describedBy =\n [this.ariaDescribedby, showError ? this.errorId : undefined].filter(Boolean).join(' ') ||\n undefined;\n const popupStyle = {\n position: 'fixed',\n left: '0',\n top: '0',\n transform: `translate(${Math.round(this.pos.x)}px, ${Math.round(this.pos.y)}px)`,\n zIndex: 'var(--dimension-z-index-floating)',\n visibility: this.positionReady ? 'visible' : 'hidden',\n };\n\n return (\n <Host\n class={{\n 'input-host': true,\n 'ds-field-stack': true,\n 'ds-field-stack--supporting-inset': !this.hasBorder,\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.isInvalid ? '' : 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 ref={element => {\n this.controlEl = element;\n }}\n class={{\n 'input-control': true,\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 <input\n ref={element => {\n this.inputEl = element;\n }}\n type=\"text\"\n id={inputId}\n value={this.focused ? this.draftText : this.displayValue}\n disabled={inactive}\n readOnly={this.readOnly}\n required={this.required}\n autoFocus={this.autoFocus}\n autoComplete=\"off\"\n spellcheck={false}\n class={{\n 'native-input': true,\n 'native-input--align-start': true,\n 'ds-control-label-box': true,\n [textClass]: true,\n 'ds-text--regular': true,\n }}\n aria-label={this.ariaLabel}\n aria-labelledby={this.ariaLabelledby}\n aria-describedby={describedBy}\n aria-invalid={this.isInvalid ? 'true' : undefined}\n onInput={this.handleInput}\n onFocus={this.handleFocus}\n onBlur={this.handleBlur}\n />\n <ds-button-unfilled\n ref={element => {\n this.clockButton = element as HTMLDsButtonUnfilledElement | undefined;\n }}\n class=\"input-control__datetime-action\"\n variant=\"icon\"\n size={this.size}\n icon=\"Clock\"\n hasBorder={false}\n isInset\n isInactive={pickerInactive}\n ariaLabel=\"Choose time\"\n haspopup=\"dialog\"\n expanded={this.open}\n surfaceOpen={this.open || this.closing}\n controls={this.open ? this.popupId : undefined}\n onDsClick={this.togglePicker}\n />\n </div>\n {this.shouldRender ? (\n <div\n id={this.popupId}\n popover=\"manual\"\n class={{\n 'input-time-popup': true,\n 'ds-choice-popup': true,\n 'ds-choice-popup--closing': this.closing,\n 'ds-chrome-column': true,\n 'ds-chrome-space--sm': true,\n }}\n style={popupStyle}\n role=\"dialog\"\n aria-label=\"Choose time\"\n >\n <ds-time-picker\n hourFormat={this.hourFormat}\n value={this.value}\n min={this.min}\n max={this.max}\n step={this.step}\n isInactive={pickerInactive}\n autoFocus\n onDsChange={this.handleTimeChange}\n />\n </div>\n ) : null}\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",
598
598
  "type": "registry:ui"
599
599
  }
600
600
  ]
@@ -1037,8 +1037,8 @@
1037
1037
  "complexPropertyNote": "Assign these non-primitive values as JavaScript properties: suggestions, tokens.",
1038
1038
  "peerDependencies": {
1039
1039
  "required": [
1040
- "@ds-mo/tokens ^8.0.0",
1041
- "@ds-mo/icons ^8.1.1"
1040
+ "@ds-mo/tokens ^8.0.1",
1041
+ "@ds-mo/icons ^8.1.2"
1042
1042
  ],
1043
1043
  "frameworks": "Custom Elements; React 18/19 wrappers; Vue 3 wrappers; Angular 19-22 standalone adapters."
1044
1044
  }
@@ -191,8 +191,8 @@
191
191
  },
192
192
  "peerDependencies": {
193
193
  "required": [
194
- "@ds-mo/tokens ^8.0.0",
195
- "@ds-mo/icons ^8.1.1"
194
+ "@ds-mo/tokens ^8.0.1",
195
+ "@ds-mo/icons ^8.1.2"
196
196
  ],
197
197
  "frameworks": "Custom Elements; React 18/19 wrappers; Vue 3 wrappers; Angular 19-22 standalone adapters."
198
198
  }
@@ -241,8 +241,8 @@
241
241
  },
242
242
  "peerDependencies": {
243
243
  "required": [
244
- "@ds-mo/tokens ^8.0.0",
245
- "@ds-mo/icons ^8.1.1"
244
+ "@ds-mo/tokens ^8.0.1",
245
+ "@ds-mo/icons ^8.1.2"
246
246
  ],
247
247
  "frameworks": "Custom Elements; React 18/19 wrappers; Vue 3 wrappers; Angular 19-22 standalone adapters."
248
248
  }
@@ -297,8 +297,8 @@
297
297
  },
298
298
  "peerDependencies": {
299
299
  "required": [
300
- "@ds-mo/tokens ^8.0.0",
301
- "@ds-mo/icons ^8.1.1"
300
+ "@ds-mo/tokens ^8.0.1",
301
+ "@ds-mo/icons ^8.1.2"
302
302
  ],
303
303
  "frameworks": "Custom Elements; React 18/19 wrappers; Vue 3 wrappers; Angular 19-22 standalone adapters."
304
304
  }
@@ -257,8 +257,8 @@
257
257
  },
258
258
  "peerDependencies": {
259
259
  "required": [
260
- "@ds-mo/tokens ^8.0.0",
261
- "@ds-mo/icons ^8.1.1"
260
+ "@ds-mo/tokens ^8.0.1",
261
+ "@ds-mo/icons ^8.1.2"
262
262
  ],
263
263
  "frameworks": "Custom Elements; React 18/19 wrappers; Vue 3 wrappers; Angular 19-22 standalone adapters."
264
264
  }
@@ -138,8 +138,8 @@
138
138
  },
139
139
  "peerDependencies": {
140
140
  "required": [
141
- "@ds-mo/tokens ^8.0.0",
142
- "@ds-mo/icons ^8.1.1"
141
+ "@ds-mo/tokens ^8.0.1",
142
+ "@ds-mo/icons ^8.1.2"
143
143
  ],
144
144
  "frameworks": "Custom Elements; React 18/19 wrappers; Vue 3 wrappers; Angular 19-22 standalone adapters."
145
145
  }
@@ -581,8 +581,8 @@
581
581
  "complexPropertyNote": "Assign these non-primitive values as JavaScript properties: anchor, boundary, items, sections.",
582
582
  "peerDependencies": {
583
583
  "required": [
584
- "@ds-mo/tokens ^8.0.0",
585
- "@ds-mo/icons ^8.1.1"
584
+ "@ds-mo/tokens ^8.0.1",
585
+ "@ds-mo/icons ^8.1.2"
586
586
  ],
587
587
  "frameworks": "Custom Elements; React 18/19 wrappers; Vue 3 wrappers; Angular 19-22 standalone adapters."
588
588
  }
@@ -167,8 +167,8 @@
167
167
  },
168
168
  "peerDependencies": {
169
169
  "required": [
170
- "@ds-mo/tokens ^8.0.0",
171
- "@ds-mo/icons ^8.1.1"
170
+ "@ds-mo/tokens ^8.0.1",
171
+ "@ds-mo/icons ^8.1.2"
172
172
  ],
173
173
  "frameworks": "Custom Elements; React 18/19 wrappers; Vue 3 wrappers; Angular 19-22 standalone adapters."
174
174
  }
@@ -127,8 +127,8 @@
127
127
  },
128
128
  "peerDependencies": {
129
129
  "required": [
130
- "@ds-mo/tokens ^8.0.0",
131
- "@ds-mo/icons ^8.1.1"
130
+ "@ds-mo/tokens ^8.0.1",
131
+ "@ds-mo/icons ^8.1.2"
132
132
  ],
133
133
  "frameworks": "Custom Elements; React 18/19 wrappers; Vue 3 wrappers; Angular 19-22 standalone adapters."
134
134
  }
@@ -285,8 +285,8 @@
285
285
  },
286
286
  "peerDependencies": {
287
287
  "required": [
288
- "@ds-mo/tokens ^8.0.0",
289
- "@ds-mo/icons ^8.1.1"
288
+ "@ds-mo/tokens ^8.0.1",
289
+ "@ds-mo/icons ^8.1.2"
290
290
  ],
291
291
  "frameworks": "Custom Elements; React 18/19 wrappers; Vue 3 wrappers; Angular 19-22 standalone adapters."
292
292
  }
@@ -212,8 +212,8 @@
212
212
  },
213
213
  "peerDependencies": {
214
214
  "required": [
215
- "@ds-mo/tokens ^8.0.0",
216
- "@ds-mo/icons ^8.1.1"
215
+ "@ds-mo/tokens ^8.0.1",
216
+ "@ds-mo/icons ^8.1.2"
217
217
  ],
218
218
  "frameworks": "Custom Elements; React 18/19 wrappers; Vue 3 wrappers; Angular 19-22 standalone adapters."
219
219
  }
@@ -259,8 +259,8 @@
259
259
  },
260
260
  "peerDependencies": {
261
261
  "required": [
262
- "@ds-mo/tokens ^8.0.0",
263
- "@ds-mo/icons ^8.1.1"
262
+ "@ds-mo/tokens ^8.0.1",
263
+ "@ds-mo/icons ^8.1.2"
264
264
  ],
265
265
  "frameworks": "Custom Elements; React 18/19 wrappers; Vue 3 wrappers; Angular 19-22 standalone adapters."
266
266
  }
@@ -429,8 +429,8 @@
429
429
  "complexPropertyNote": "Assign these non-primitive values as JavaScript properties: currentArea.",
430
430
  "peerDependencies": {
431
431
  "required": [
432
- "@ds-mo/tokens ^8.0.0",
433
- "@ds-mo/icons ^8.1.1"
432
+ "@ds-mo/tokens ^8.0.1",
433
+ "@ds-mo/icons ^8.1.2"
434
434
  ],
435
435
  "frameworks": "Custom Elements; React 18/19 wrappers; Vue 3 wrappers; Angular 19-22 standalone adapters."
436
436
  }
@@ -368,8 +368,8 @@
368
368
  "complexPropertyNote": "Assign these non-primitive values as JavaScript properties: sections, subsections.",
369
369
  "peerDependencies": {
370
370
  "required": [
371
- "@ds-mo/tokens ^8.0.0",
372
- "@ds-mo/icons ^8.1.1"
371
+ "@ds-mo/tokens ^8.0.1",
372
+ "@ds-mo/icons ^8.1.2"
373
373
  ],
374
374
  "frameworks": "Custom Elements; React 18/19 wrappers; Vue 3 wrappers; Angular 19-22 standalone adapters."
375
375
  }