@adia-ai/web-components 0.8.40 → 0.8.41

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 (378) hide show
  1. package/CHANGELOG.md +50 -3
  2. package/MIGRATION.md +1042 -16
  3. package/README.md +25 -30
  4. package/USAGE.md +26 -0
  5. package/bin/audit-template-children.mjs +556 -0
  6. package/components/accordion/accordion-item.a2ui.json +4 -0
  7. package/components/accordion/accordion-item.yaml +2 -0
  8. package/components/accordion/accordion.a2ui.json +4 -0
  9. package/components/accordion/accordion.yaml +2 -0
  10. package/components/action-list/action-item.a2ui.json +24 -2
  11. package/components/action-list/action-item.yaml +28 -3
  12. package/components/action-list/action-list.a2ui.json +6 -1
  13. package/components/action-list/action-list.class.js +52 -11
  14. package/components/action-list/action-list.css +43 -3
  15. package/components/action-list/action-list.d.ts +4 -2
  16. package/components/action-list/action-list.yaml +5 -0
  17. package/components/adia-mark/adia-mark.a2ui.json +1 -0
  18. package/components/adia-wordmark/adia-wordmark.a2ui.json +1 -0
  19. package/components/agent-artifact/agent-artifact.a2ui.json +1 -0
  20. package/components/agent-feedback-bar/agent-feedback-bar.a2ui.json +6 -5
  21. package/components/agent-feedback-bar/agent-feedback-bar.yaml +6 -2
  22. package/components/agent-questions/agent-questions.a2ui.json +1 -0
  23. package/components/agent-reasoning/agent-reasoning.a2ui.json +6 -5
  24. package/components/agent-reasoning/agent-reasoning.yaml +6 -2
  25. package/components/agent-suggestions/agent-suggestions.a2ui.json +11 -2
  26. package/components/agent-suggestions/agent-suggestions.class.js +2 -1
  27. package/components/agent-suggestions/agent-suggestions.d.ts +4 -4
  28. package/components/agent-suggestions/agent-suggestions.yaml +4 -2
  29. package/components/agent-trace/agent-trace.a2ui.json +6 -5
  30. package/components/agent-trace/agent-trace.yaml +6 -2
  31. package/components/alert/alert.a2ui.json +1 -0
  32. package/components/alert/alert.css +1 -1
  33. package/components/anchor-bar/anchor-bar.a2ui.json +1 -0
  34. package/components/aside/aside.a2ui.json +1 -0
  35. package/components/avatar/avatar-group.a2ui.json +7 -1
  36. package/components/avatar/avatar-group.yaml +1 -0
  37. package/components/avatar/avatar.a2ui.json +12 -11
  38. package/components/avatar/avatar.d.ts +1 -1
  39. package/components/avatar/avatar.yaml +4 -4
  40. package/components/badge/badge.a2ui.json +1 -0
  41. package/components/block/block.a2ui.json +1 -0
  42. package/components/blockquote/blockquote.a2ui.json +1 -0
  43. package/components/breadcrumb/breadcrumb.a2ui.json +1 -0
  44. package/components/button/button.a2ui.json +1 -3
  45. package/components/button/button.yaml +1 -3
  46. package/components/calendar-grid/calendar-grid.a2ui.json +1 -0
  47. package/components/calendar-grid/calendar-grid.class.js +2 -1
  48. package/components/calendar-picker/calendar-picker.a2ui.json +143 -24
  49. package/components/calendar-picker/calendar-picker.class.js +490 -197
  50. package/components/calendar-picker/calendar-picker.css +120 -171
  51. package/components/calendar-picker/calendar-picker.yaml +225 -47
  52. package/components/canvas/canvas.a2ui.json +6 -5
  53. package/components/canvas/canvas.d.ts +37 -0
  54. package/components/canvas/canvas.js +72 -3
  55. package/components/canvas/canvas.yaml +6 -2
  56. package/components/card/card.a2ui.json +25 -2
  57. package/components/card/card.class.js +3 -0
  58. package/components/card/card.css +31 -1
  59. package/components/card/card.d.ts +2 -2
  60. package/components/card/card.examples.md +3 -3
  61. package/components/card/card.yaml +28 -4
  62. package/components/chart/chart.a2ui.json +9 -4
  63. package/components/chart/chart.class.js +6 -6
  64. package/components/chart/chart.css +6 -4
  65. package/components/chart/chart.d.ts +1 -1
  66. package/components/chart/chart.yaml +5 -3
  67. package/components/chart-legend/chart-legend.a2ui.json +1 -0
  68. package/components/chat-thread/chat-input.a2ui.json +1 -0
  69. package/components/chat-thread/chat-thread.a2ui.json +10 -9
  70. package/components/chat-thread/chat-thread.yaml +13 -20
  71. package/components/check/check.a2ui.json +10 -9
  72. package/components/check/check.yaml +4 -4
  73. package/components/code/code.a2ui.json +1 -0
  74. package/components/col/col.a2ui.json +1 -0
  75. package/components/color-input/color-input.a2ui.json +1 -0
  76. package/components/color-picker/color-picker.a2ui.json +1 -0
  77. package/components/combobox/combobox.a2ui.json +3 -2
  78. package/components/combobox/combobox.yaml +2 -2
  79. package/components/command/command.a2ui.json +12 -10
  80. package/components/command/command.class.js +3 -2
  81. package/components/command/command.yaml +17 -4
  82. package/components/context-menu/context-menu.a2ui.json +1 -0
  83. package/components/date-range-picker/date-range-picker.a2ui.json +2 -1
  84. package/components/date-range-picker/date-range-picker.yaml +1 -1
  85. package/components/datetime-picker/datetime-picker.a2ui.json +15 -108
  86. package/components/datetime-picker/datetime-picker.class.js +37 -690
  87. package/components/datetime-picker/datetime-picker.css +11 -183
  88. package/components/datetime-picker/datetime-picker.d.ts +4 -5
  89. package/components/datetime-picker/datetime-picker.yaml +44 -135
  90. package/components/demo-toggle/demo-toggle.a2ui.json +1 -0
  91. package/components/demo-toggle/demo-toggle.css +1 -1
  92. package/components/description-list/description-list.a2ui.json +1 -0
  93. package/components/display-field/display-field.a2ui.json +1 -0
  94. package/components/divider/divider.a2ui.json +1 -0
  95. package/components/drawer/drawer.a2ui.json +1 -3
  96. package/components/drawer/drawer.css +1 -1
  97. package/components/drawer/drawer.yaml +0 -2
  98. package/components/drilldown/drilldown.a2ui.json +22 -20
  99. package/components/drilldown/drilldown.class.js +4 -3
  100. package/components/drilldown/drilldown.css +6 -6
  101. package/components/drilldown/drilldown.yaml +40 -9
  102. package/components/embed/embed.a2ui.json +6 -5
  103. package/components/embed/embed.yaml +2 -2
  104. package/components/empty-state/empty-state.a2ui.json +1 -0
  105. package/components/feed/feed-item.a2ui.json +25 -5
  106. package/components/feed/feed-item.yaml +28 -7
  107. package/components/feed/feed.a2ui.json +9 -2
  108. package/components/feed/feed.class.js +19 -12
  109. package/components/feed/feed.css +8 -8
  110. package/components/feed/feed.yaml +14 -1
  111. package/components/field/field.a2ui.json +1 -0
  112. package/components/field/field.examples.md +1 -1
  113. package/components/fields/fields.a2ui.json +1 -0
  114. package/components/fields/fields.examples.md +1 -1
  115. package/components/footer/footer.a2ui.json +1 -0
  116. package/components/frame/frame.a2ui.json +1 -0
  117. package/components/grid/grid.a2ui.json +1 -0
  118. package/components/header/header.a2ui.json +3 -2
  119. package/components/header/header.yaml +3 -3
  120. package/components/heatmap/heatmap.a2ui.json +2 -1
  121. package/components/heatmap/heatmap.class.js +1 -1
  122. package/components/heatmap/heatmap.css +4 -4
  123. package/components/heatmap/heatmap.yaml +1 -1
  124. package/components/icon/icon.a2ui.json +1 -0
  125. package/components/image/image.a2ui.json +28 -14
  126. package/components/image/image.class.js +38 -23
  127. package/components/image/image.css +18 -8
  128. package/components/image/image.d.ts +2 -2
  129. package/components/image/image.examples.md +3 -3
  130. package/components/image/image.yaml +23 -7
  131. package/components/inline-edit/inline-edit.a2ui.json +1 -0
  132. package/components/inline-message/inline-message.a2ui.json +3 -1
  133. package/components/inline-message/inline-message.class.js +3 -1
  134. package/components/inline-message/inline-message.d.ts +2 -2
  135. package/components/inline-message/inline-message.yaml +2 -1
  136. package/components/input/input.a2ui.json +66 -16
  137. package/components/input/input.class.js +64 -7
  138. package/components/input/input.css +14 -14
  139. package/components/input/input.d.ts +9 -4
  140. package/components/input/input.yaml +83 -10
  141. package/components/inspector/inspector.a2ui.json +1 -0
  142. package/components/integration-card/integration-card.a2ui.json +1 -0
  143. package/components/kbd/kbd.a2ui.json +1 -0
  144. package/components/link/link.a2ui.json +2 -1
  145. package/components/link/link.yaml +1 -1
  146. package/components/list/list-item.a2ui.json +9 -0
  147. package/components/list/list-item.yaml +12 -0
  148. package/components/list/list.a2ui.json +9 -3
  149. package/components/list/list.class.js +14 -1
  150. package/components/list/list.css +12 -1
  151. package/components/list/list.d.ts +7 -5
  152. package/components/list/list.yaml +16 -6
  153. package/components/list-window/list-window.a2ui.json +1 -0
  154. package/components/list-window/list-window.class.js +2 -1
  155. package/components/loading-overlay/loading-overlay.a2ui.json +1 -0
  156. package/components/mark/mark.a2ui.json +2 -1
  157. package/components/mark/mark.yaml +1 -1
  158. package/components/menu/menu-divider.a2ui.json +1 -0
  159. package/components/menu/menu-item.a2ui.json +3 -1
  160. package/components/menu/menu-item.yaml +6 -0
  161. package/components/menu/menu-label.a2ui.json +1 -0
  162. package/components/menu/menu.a2ui.json +3 -2
  163. package/components/menu/menu.class.js +2 -2
  164. package/components/menu/menu.d.ts +2 -2
  165. package/components/menu/menu.yaml +3 -3
  166. package/components/modal/modal.a2ui.json +1 -0
  167. package/components/nav/nav.a2ui.json +1 -0
  168. package/components/nav/nav.class.js +14 -3
  169. package/components/nav-group/nav-group.a2ui.json +1 -0
  170. package/components/nav-group/nav-group.class.js +3 -1
  171. package/components/nav-item/nav-item.a2ui.json +1 -0
  172. package/components/noodles/noodles.a2ui.json +1 -0
  173. package/components/noodles/noodles.class.js +5 -1
  174. package/components/number-format/number-format.a2ui.json +1 -0
  175. package/components/option-card/option-card.a2ui.json +1 -0
  176. package/components/otp-input/otp-input.a2ui.json +3 -2
  177. package/components/otp-input/otp-input.yaml +9 -2
  178. package/components/page/page.a2ui.json +13 -0
  179. package/components/page/page.d.ts +1 -1
  180. package/components/page/page.yaml +1 -0
  181. package/components/pagination/pagination.a2ui.json +1 -0
  182. package/components/pagination/pagination.class.js +3 -2
  183. package/components/pane/pane.a2ui.json +6 -0
  184. package/components/pane/pane.class.js +3 -3
  185. package/components/pane/pane.css +2 -2
  186. package/components/pane/pane.yaml +3 -0
  187. package/components/password-strength/password-strength.a2ui.json +1 -0
  188. package/components/pipeline-status/pipeline-status.a2ui.json +1 -0
  189. package/components/popover/popover.a2ui.json +7 -6
  190. package/components/popover/popover.class.js +2 -2
  191. package/components/popover/popover.d.ts +2 -2
  192. package/components/popover/popover.yaml +4 -4
  193. package/components/preview/preview.a2ui.json +1 -0
  194. package/components/preview/preview.class.js +5 -1
  195. package/components/progress/progress.a2ui.json +47 -24
  196. package/components/progress/progress.class.js +66 -11
  197. package/components/progress/progress.css +44 -26
  198. package/components/progress/progress.d.ts +7 -5
  199. package/components/progress/progress.examples.md +2 -2
  200. package/components/progress/progress.yaml +235 -53
  201. package/components/progress-row/progress-row.a2ui.json +16 -12
  202. package/components/progress-row/progress-row.d.ts +2 -2
  203. package/components/progress-row/progress-row.examples.md +2 -14
  204. package/components/progress-row/progress-row.yaml +28 -36
  205. package/components/qr-code/qr-code.a2ui.json +3 -2
  206. package/components/qr-code/qr-code.class.js +4 -4
  207. package/components/qr-code/qr-code.css +1 -1
  208. package/components/qr-code/qr-code.yaml +5 -3
  209. package/components/radio/radio.a2ui.json +8 -7
  210. package/components/radio/radio.class.js +8 -0
  211. package/components/radio/radio.yaml +3 -3
  212. package/components/radio-group/radio-group.a2ui.json +5 -3
  213. package/components/radio-group/radio-group.class.js +11 -0
  214. package/components/radio-group/radio-group.yaml +7 -1
  215. package/components/range/range.a2ui.json +6 -0
  216. package/components/range/range.class.js +2 -2
  217. package/components/range/range.css +2 -2
  218. package/components/range/range.yaml +3 -0
  219. package/components/rating/rating.a2ui.json +1 -0
  220. package/components/relative-time/relative-time.a2ui.json +1 -0
  221. package/components/richtext/richtext.a2ui.json +2 -1
  222. package/components/richtext/richtext.yaml +1 -1
  223. package/components/row/row.a2ui.json +1 -0
  224. package/components/search/search.a2ui.json +1 -0
  225. package/components/search/search.class.js +4 -1
  226. package/components/section/section.a2ui.json +1 -0
  227. package/components/segment/segment.a2ui.json +21 -10
  228. package/components/segment/segment.css +15 -0
  229. package/components/segment/segment.d.ts +2 -1
  230. package/components/segment/segment.yaml +20 -13
  231. package/components/segmented/segmented.a2ui.json +36 -7
  232. package/components/segmented/segmented.class.js +113 -22
  233. package/components/segmented/segmented.css +3 -0
  234. package/components/segmented/segmented.d.ts +3 -1
  235. package/components/segmented/segmented.yaml +80 -8
  236. package/components/select/select.a2ui.json +18 -13
  237. package/components/select/select.class.js +61 -37
  238. package/components/select/select.css +15 -13
  239. package/components/select/select.yaml +18 -7
  240. package/components/skeleton/skeleton.a2ui.json +8 -7
  241. package/components/skeleton/skeleton.class.js +8 -7
  242. package/components/skeleton/skeleton.css +21 -6
  243. package/components/skeleton/skeleton.d.ts +2 -2
  244. package/components/skeleton/skeleton.examples.md +2 -2
  245. package/components/skeleton/skeleton.yaml +3 -2
  246. package/components/skip-nav/skip-nav.a2ui.json +1 -0
  247. package/components/slider/slider.a2ui.json +6 -0
  248. package/components/slider/slider.class.js +20 -3
  249. package/components/slider/slider.css +2 -2
  250. package/components/slider/slider.yaml +3 -0
  251. package/components/spinner/spinner.a2ui.json +1 -0
  252. package/components/stack/stack.a2ui.json +1 -0
  253. package/components/stat/stat.a2ui.json +1 -0
  254. package/components/stat/stat.js +2 -2
  255. package/components/step-progress/step-progress.a2ui.json +1 -0
  256. package/components/step-progress/step-progress.yaml +1 -1
  257. package/components/stepper/stepper-item.a2ui.json +7 -3
  258. package/components/stepper/stepper-item.yaml +15 -5
  259. package/components/stepper/stepper.a2ui.json +5 -1
  260. package/components/stepper/stepper.class.js +31 -16
  261. package/components/stepper/stepper.d.ts +1 -1
  262. package/components/stepper/stepper.yaml +4 -2
  263. package/components/stream/stream.a2ui.json +1 -0
  264. package/components/swatch/swatch.a2ui.json +1 -0
  265. package/components/swiper/swiper.a2ui.json +1 -0
  266. package/components/swiper/swiper.class.js +5 -1
  267. package/components/switch/switch.a2ui.json +12 -11
  268. package/components/switch/switch.css +1 -1
  269. package/components/switch/switch.yaml +6 -6
  270. package/components/table/table.a2ui.json +1 -0
  271. package/components/table/table.class.js +14 -12
  272. package/components/table/table.css +11 -9
  273. package/components/table-toolbar/table-toolbar.a2ui.json +1 -0
  274. package/components/table-toolbar/table-toolbar.class.js +38 -19
  275. package/components/table-toolbar/table-toolbar.css +1 -1
  276. package/components/tabs/tab.a2ui.json +9 -0
  277. package/components/tabs/tab.js +4 -0
  278. package/components/tabs/tab.yaml +15 -0
  279. package/components/tabs/tabs.a2ui.json +9 -4
  280. package/components/tabs/tabs.class.js +13 -1
  281. package/components/tabs/tabs.css +8 -0
  282. package/components/tabs/tabs.d.ts +2 -0
  283. package/components/tabs/tabs.yaml +9 -2
  284. package/components/tag/tag.a2ui.json +1 -0
  285. package/components/tags-input/tags-input.a2ui.json +22 -17
  286. package/components/tags-input/tags-input.class.js +13 -11
  287. package/components/tags-input/tags-input.css +10 -6
  288. package/components/tags-input/tags-input.d.ts +16 -7
  289. package/components/tags-input/tags-input.examples.md +2 -2
  290. package/components/tags-input/tags-input.yaml +25 -8
  291. package/components/text/text.a2ui.json +6 -5
  292. package/components/text/text.css +10 -5
  293. package/components/text/text.d.ts +2 -2
  294. package/components/text/text.yaml +9 -4
  295. package/components/textarea/textarea.a2ui.json +2 -1
  296. package/components/textarea/textarea.yaml +1 -1
  297. package/components/theme-provider/theme-provider.a2ui.json +2 -1
  298. package/components/theme-provider/theme-provider.d.ts +5 -3
  299. package/components/theme-provider/theme-provider.yaml +5 -3
  300. package/components/time-picker/time-picker.a2ui.json +1 -0
  301. package/components/time-picker/time-picker.class.js +4 -2
  302. package/components/timeline/timeline-item.a2ui.json +26 -3
  303. package/components/timeline/timeline-item.yaml +22 -7
  304. package/components/timeline/timeline.a2ui.json +4 -0
  305. package/components/timeline/timeline.class.js +29 -18
  306. package/components/timeline/timeline.d.ts +3 -3
  307. package/components/timeline/timeline.yaml +2 -0
  308. package/components/toast/toast.a2ui.json +10 -3
  309. package/components/toast/toast.yaml +20 -13
  310. package/components/toc/toc.a2ui.json +1 -0
  311. package/components/toggle-group/toggle-group.a2ui.json +7 -3
  312. package/components/toggle-group/toggle-group.class.js +40 -1
  313. package/components/toggle-group/toggle-group.css +6 -1
  314. package/components/toggle-group/toggle-group.d.ts +2 -2
  315. package/components/toggle-group/toggle-group.yaml +21 -12
  316. package/components/toggle-group/toggle-option.a2ui.json +7 -3
  317. package/components/toggle-group/toggle-option.yaml +13 -7
  318. package/components/toggle-scheme/toggle-scheme.a2ui.json +2 -1
  319. package/components/toggle-scheme/toggle-scheme.yaml +1 -1
  320. package/components/toolbar/toolbar-group.a2ui.json +1 -0
  321. package/components/toolbar/toolbar.a2ui.json +1 -0
  322. package/components/toolbar/toolbar.class.js +3 -0
  323. package/components/tooltip/tooltip.a2ui.json +1 -0
  324. package/components/tour/tour-step.a2ui.json +4 -0
  325. package/components/tour/tour-step.yaml +2 -0
  326. package/components/tour/tour.a2ui.json +4 -0
  327. package/components/tour/tour.yaml +2 -0
  328. package/components/tree/tree-item.a2ui.json +5 -0
  329. package/components/tree/tree-item.yaml +3 -0
  330. package/components/tree/tree.a2ui.json +4 -0
  331. package/components/tree/tree.class.js +2 -1
  332. package/components/tree/tree.yaml +2 -0
  333. package/components/upload/upload.a2ui.json +8 -1
  334. package/components/upload/upload.class.js +35 -5
  335. package/components/upload/upload.css +28 -0
  336. package/components/upload/upload.d.ts +16 -0
  337. package/components/upload/upload.yaml +27 -7
  338. package/components/visually-hidden/visually-hidden.a2ui.json +1 -0
  339. package/core/dom.d.ts +11 -0
  340. package/core/dom.js +34 -0
  341. package/core/form.js +7 -0
  342. package/core/index.d.ts +1 -0
  343. package/core/index.js +1 -0
  344. package/core/responsive.js +16 -4
  345. package/core/template.js +2 -1
  346. package/custom-elements.json +437 -489
  347. package/dist/host.min.css +1 -1
  348. package/dist/host.sheet.js +1 -1
  349. package/dist/theme-provider.min.js +5 -5
  350. package/dist/web-components.min.css +1 -1
  351. package/dist/web-components.min.js +91 -104
  352. package/dist/web-components.sheet.js +1 -1
  353. package/package.json +4 -2
  354. package/patterns/conversion-funnel/conversion-funnel.examples.html +15 -15
  355. package/patterns/inline-dialog/inline-dialog.examples.html +2 -2
  356. package/patterns/inline-dialog/inline-dialog.html +4 -0
  357. package/patterns/timezone-selector/timezone-selector.examples.html +1 -1
  358. package/patterns/timezone-selector/timezone-selector.html +2 -2
  359. package/styles/api/text.css +7 -0
  360. package/traits/_catalog.json +129 -41
  361. package/traits/anchor-positioning/anchor-positioning.js +1 -0
  362. package/traits/announcer/announcer.js +1 -0
  363. package/traits/arrow-grid-nav/arrow-grid-nav.js +1 -0
  364. package/traits/attention-pulse/attention-pulse.js +1 -0
  365. package/traits/count-up/count-up.js +1 -0
  366. package/traits/define.js +78 -0
  367. package/traits/focus-restore/focus-restore.js +2 -1
  368. package/traits/haptic-feedback/haptic-feedback.js +1 -0
  369. package/traits/input-mask/input-mask.js +1 -0
  370. package/traits/intersection-observer/intersection-observer.js +1 -0
  371. package/traits/layout-animation/layout-animation.js +1 -0
  372. package/traits/noise-texture/noise-texture.js +1 -0
  373. package/traits/resize-observer/resize-observer.js +1 -0
  374. package/traits/scroll-progress/scroll-progress.js +1 -0
  375. package/traits/snap-to-grid/snap-to-grid.js +1 -0
  376. package/traits/sound-feedback/sound-feedback.js +1 -0
  377. package/traits/spring-animate/spring-animate.js +1 -0
  378. package/traits/validation/validation.js +1 -0
@@ -4,23 +4,31 @@ tag: calendar-picker-ui
4
4
  status: stable
5
5
  component: CalendarPicker
6
6
  category: input
7
- version: 1
7
+ version: 2
8
8
  description: >-
9
- Date picker with trigger button and popover calendar grid.
10
- Form-associated input emitting ISO date string via change events;
11
- supports min/max and disabled-date masks. Use for single-date input in
12
- forms; for date ranges compose two pickers or use a dedicated range
13
- component.
9
+ Date (and, per `[precision]`, date+time) picker with trigger button and
10
+ popover panel. Form-associated input emitting an ISO date (or, when
11
+ `precision` is `minute`/`second`, ISO datetime) string via change events;
12
+ supports min/max and disabled-date masks. Use for single-date or
13
+ single-datetime input in forms; for date ranges use
14
+ <date-range-picker-ui> instead of composing two calendar-picker
15
+ instances. gh#1372 (#1363 C3c) folded <datetime-picker-ui>'s surface into
16
+ this widened `precision` axis — see the deprecated
17
+ <datetime-picker-ui> alias.
14
18
  # Per ADR-0027 — primitives that programmatically create other primitives
15
19
  # in their render() do NOT auto-import them. Consumer (or demo shell) must
16
20
  # explicitly import each composed primitive.
17
21
  composes:
18
- - button-ui # day cells + month nav (gh issue 276 wave 4)
22
+ - calendar-grid-ui # popover's day-grid substrate (gh#1371, #1363 C3a) — button-ui day cells + month nav live inside it
23
+ - time-picker-ui # the time pane (gh#1372) — composed only when [precision] is minute/second
24
+ - divider-ui # pane separator (gh#1372) — composed only when [precision] is minute/second
25
+
19
26
  props:
20
27
  name:
21
28
  description: Form field name
22
29
  type: string
23
30
  default: ''
31
+ reflect: true
24
32
  required:
25
33
  description: Required for validation
26
34
  type: boolean
@@ -31,24 +39,59 @@ props:
31
39
  type: boolean
32
40
  default: false
33
41
  reflect: true
42
+ readonly:
43
+ description: Blocks edits; the trigger stays keyboard-focusable for screen-reader inspection but the popover does not open. #1363 C3d convergence — inherited from the shared form-element base, now with real behavior wired.
44
+ type: boolean
45
+ default: false
46
+ reflect: true
34
47
  format:
35
- description: Display format for the selected date
48
+ description: Display format for the trigger text. `short`, e.g. `Jan 1, 2026` (+ ` 14:30` when `precision` is minute/second); `long`, e.g. `January 1, 2026`; `iso`, the raw ISO string.
36
49
  type: string
37
50
  default: short
38
51
  enum:
39
52
  - short
40
53
  - long
41
54
  - iso
42
- label:
43
- description: Label text displayed above the trigger
44
- type: string
45
- default: ''
46
55
  max:
47
- description: Maximum selectable date in ISO format (YYYY-MM-DD)
56
+ description: Maximum selectable date (ISO `YYYY-MM-DD`), or datetime (ISO `YYYY-MM-DDTHH:mm[:ss]`) when `precision` is minute/second.
48
57
  type: string
49
58
  default: ''
59
+ reflect: true
50
60
  min:
51
- description: Minimum selectable date in ISO format (YYYY-MM-DD)
61
+ description: Minimum selectable date (ISO `YYYY-MM-DD`), or datetime (ISO `YYYY-MM-DDTHH:mm[:ss]`) when `precision` is minute/second.
62
+ type: string
63
+ default: ''
64
+ reflect: true
65
+ precision:
66
+ description: Mode axis (gh#1372, #1363 C3c). `date` (default) is a date-only picker — the composed calendar-grid-ui alone. `minute`/`second` additionally compose a <time-picker-ui> pane (separated by a <divider-ui>); `value` becomes a full ISO 8601 datetime string ("YYYY-MM-DDTHH:mm" or with seconds) and `hour-cycle`/`step`/`locale` become active.
67
+ type: string
68
+ default: date
69
+ enum:
70
+ - date
71
+ - minute
72
+ - second
73
+ reflect: true
74
+ step:
75
+ description: Per-Arrow-keypress increment in seconds for the time pane. Active only when `precision` is minute/second. 60 = minute precision (default), 900 = 15-minute, 1 = second precision.
76
+ type: number
77
+ default: 60
78
+ reflect: true
79
+ hourcycle:
80
+ description: |
81
+ Hour cycle for the time pane. Active only when `precision` is
82
+ minute/second. Empty (default) derives from the document locale.
83
+ `h12` forces a 12-hour cycle with an AM/PM (meridiem) segment; `h23`
84
+ forces 24-hour cycle.
85
+ type: string
86
+ default: ''
87
+ enum:
88
+ - ''
89
+ - h12
90
+ - h23
91
+ reflect: true
92
+ attribute: hour-cycle
93
+ locale:
94
+ description: BCP-47 locale tag used to derive hour-cycle when `hour-cycle` is empty. Active only when `precision` is minute/second. Falls back to `<html lang>` then to browser default.
52
95
  type: string
53
96
  default: ''
54
97
  open:
@@ -61,7 +104,7 @@ props:
61
104
  type: string
62
105
  default: Select date...
63
106
  value:
64
- description: Selected date (ISO string)
107
+ description: Selected date (ISO string), or datetime (ISO `YYYY-MM-DDTHH:mm[:ss]`) when `precision` is minute/second.
65
108
  type: string
66
109
  default: ''
67
110
  placement:
@@ -80,73 +123,208 @@ props:
80
123
  - bottom-end
81
124
  events:
82
125
  change:
83
- description: Fired when a date is selected
126
+ description: Fired when a value commits (date picked, or — when `precision` is minute/second — date picked + time edited, or Apply clicked in an explicit-commit footer).
127
+ input:
128
+ description: Fired during partial selection (date picked but time still pending, or vice versa — meaningful only when `precision` is minute/second).
129
+ detail:
130
+ value: string
131
+ open:
132
+ description: Popover opened (user clicked the trigger, pressed Enter/Space, or Apply/Cancel in a footer closed then reopened).
133
+ detail:
134
+ trigger: string
135
+ close:
136
+ description: Popover closed (without commit, or after commit).
137
+ detail:
138
+ reason: string
139
+ invalid:
140
+ description: A constraint failed (out of range, or — when `precision` is minute/second — a parse error).
141
+ detail:
142
+ value: string
143
+ reason: string
84
144
  slots:
85
- calendar:
86
- description: Popover container for the month grid
87
- label:
88
- description: Label element above the trigger
145
+ popover:
146
+ description: >-
147
+ Popover container for the calendar pane(s) (gh#1461; renamed from the
148
+ yaml's prior `calendar` key, which matched no real slot="…" attribute
149
+ — render() stamps this element as slot="popover").
89
150
  trigger:
90
151
  description: Combobox button that opens the calendar popover
152
+ footer:
153
+ description: Optional Apply/Cancel buttons for explicit-commit flows. Spans the pane(s) below the calendar (+ time, when `precision` is minute/second).
91
154
  states:
92
155
  - name: idle
93
156
  description: Default, ready for interaction.
94
157
  - name: disabled
95
158
  description: Non-interactive; dimmed.
96
159
  attribute: disabled
160
+ - name: readonly
161
+ description: Read-only; trigger keyboard-focusable but popover does not open.
162
+ attribute: readonly
97
163
  traits: []
98
- tokens: {}
164
+ tokens:
165
+ --calendar-picker-popover-gap:
166
+ description: Gap between the calendar pane and the time pane. Only visible when `precision` is minute/second.
167
+ default: var(--a-space-3)
168
+ --calendar-picker-divider:
169
+ description: Pane divider color. Only visible when `precision` is minute/second.
170
+ default: var(--md-sys-color-neutral-outline-variant)
99
171
  requiredIcons:
100
172
  - calendar
101
- - caret-left
102
- - caret-right
103
173
  a2ui:
104
174
  rules:
105
175
  - rule: 'Form-associated date input. Trigger button + popover calendar grid; emits ISO date string via change events.'
106
176
  reason: 'Standard date-picker contract.'
107
- - rule: 'Use for single-date input. For date ranges compose two pickers or use a dedicated range component.'
177
+ - rule: 'Use for single-date input. For date ranges use <date-range-picker-ui> instead of composing two calendar-picker instances.'
108
178
  reason: 'Single-value scope.'
109
179
  - rule: 'min/max attributes constrain selectable range; disabled-dates accepts a function or date list.'
110
180
  reason: 'Constraint knobs.'
111
- anti_patterns: []
181
+ - rule: 'Set `precision: "minute"` or `precision: "second"` for combined date+time selection — composes a time pane alongside the calendar grid. `value` MUST then be ISO 8601 datetime ("YYYY-MM-DDTHH:mm" or with seconds) OR empty string; a date-only or time-only string fires `invalid`.'
182
+ reason: 'Widened mode axis (gh#1372, #1363 C3c) — folds what <datetime-picker-ui> used to be its own primitive for.'
183
+ - rule: '`hour-cycle`/`step`/`locale` are only meaningful when `precision` is minute/second.'
184
+ reason: 'Time-pane-only knobs.'
185
+ - rule: 'Do NOT wrap in `<field-ui label>` AND also expect a bare `label` attribute on `<calendar-picker-ui>` to render — the picker has no first-class label; use `<field-ui label="…">` (siblings all follow this convention).'
186
+ reason: 'Label delegates to field-ui (#1363 C3d).'
187
+ anti_patterns:
188
+ - wrong: |
189
+ {"component": "CalendarPicker", "precision": "minute", "value": "2026-05-24"}
190
+ why: |
191
+ `value` is a date-only string but `precision` is "minute" — no time
192
+ component. The contract requires a full ISO 8601 datetime including
193
+ the `T` and time segment when `precision` isn't "date".
194
+ fix: |
195
+ {"component": "CalendarPicker", "precision": "minute", "value": "2026-05-24T00:00"}
196
+ - wrong: |
197
+ {"component": "CalendarPicker", "label": "Date"}
198
+ why: |
199
+ `label` is not a first-class prop on CalendarPicker (#1363 C3d) —
200
+ siblings all delegate the field label to `<field-ui label>`.
201
+ fix: |
202
+ {"component": "Field", "label": "Date", "children": ["cal"]}
112
203
  examples:
113
204
  - name: date-picker
114
- description: Date and time picker form with calendar picker and time selects.
205
+ description: Event form with a name field and a date picker, wrapped in Field for its label per #1363 C3d (CalendarPicker has no first-class `label`).
115
206
  a2ui: "[\n {\n \"id\": \"root\",\n \"component\": \"Card\",\n \"children\": [\n \"sec\"\n ]\n },\n {\n\
116
207
  \ \"id\": \"sec\",\n \"component\": \"Section\",\n \"children\": [\n \"col\"\n ]\n },\n {\n \"id\"\
117
- : \"col\",\n \"component\": \"Column\",\n \"children\": [\n \"name\",\n \"cal\",\n \"btn\"\n ],\n\
208
+ : \"col\",\n \"component\": \"Column\",\n \"children\": [\n \"name\",\n \"field\",\n \"btn\"\n ],\n\
118
209
  \ \"gap\": \"4\"\n },\n {\n \"id\": \"name\",\n \"component\": \"Input\",\n \"label\": \"Event Name\"\n\
119
- \ },\n {\n \"id\": \"cal\",\n \"component\": \"CalendarPicker\",\n \"label\": \"Date\"\n },\n {\n \"id\"\
210
+ \ },\n {\n \"id\": \"field\",\n \"component\": \"Field\",\n \"label\": \"Date\",\n \"children\": [\n \"\
211
+ cal\"\n ]\n },\n {\n \"id\": \"cal\",\n \"component\": \"CalendarPicker\"\n },\n {\n \"id\"\
120
212
  : \"btn\",\n \"component\": \"Button\",\n \"text\": \"Schedule\",\n \"variant\": \"primary\"\n }\n]"
121
- - name: date-range-picker
122
- description: Date range selection form with start/end calendar pickers, quick-pick badges, and apply button.
123
- a2ui: "[\n {\n \"id\": \"root\",\n \"component\": \"Card\",\n \"children\": [\n \"hdr\",\n \"sec\",\n\
124
- \ \"ftr\"\n ]\n },\n {\n \"id\": \"hdr\",\n \"component\": \"Header\",\n \"children\": [\n \"\
125
- title\"\n ]\n },\n {\n \"id\": \"title\",\n \"component\": \"Text\",\n \"slot\": \"heading\",\n \"textContent\"\
126
- : \"Select Dates\",\n \"variant\": \"section\"\n },\n {\n \"id\": \"sec\",\n \"component\": \"Section\",\n\
127
- \ \"children\": [\n \"fields\"\n ]\n },\n {\n \"id\": \"fields\",\n \"component\": \"Column\",\n \
128
- \ \"children\": [\n \"calendars-row\",\n \"quick-picks\"\n ],\n \"gap\": \"4\"\n },\n {\n \"id\"\
129
- : \"calendars-row\",\n \"component\": \"Row\",\n \"children\": [\n \"start-cal\",\n \"end-cal\"\n ],\n\
130
- \ \"gap\": \"3\"\n },\n {\n \"id\": \"start-cal\",\n \"component\": \"CalendarPicker\",\n \"label\": \"\
131
- Start Date\",\n \"name\": \"startDate\"\n },\n {\n \"id\": \"end-cal\",\n \"component\": \"CalendarPicker\"\
132
- ,\n \"label\": \"End Date\",\n \"name\": \"endDate\"\n },\n {\n \"id\": \"quick-picks\",\n \"component\"\
133
- : \"Row\",\n \"children\": [\n \"pick-today\",\n \"pick-week\",\n \"pick-month\",\n \"pick-quarter\"\
134
- \n ],\n \"gap\": \"2\"\n },\n {\n \"id\": \"pick-today\",\n \"component\": \"Badge\",\n \"textContent\"\
135
- : \"Today\"\n },\n {\n \"id\": \"pick-week\",\n \"component\": \"Badge\",\n \"textContent\": \"This Week\"\n\
136
- \ },\n {\n \"id\": \"pick-month\",\n \"component\": \"Badge\",\n \"textContent\": \"This Month\"\n },\n {\n\
137
- \ \"id\": \"pick-quarter\",\n \"component\": \"Badge\",\n \"textContent\": \"This Quarter\"\n },\n {\n \"\
138
- id\": \"ftr\",\n \"component\": \"Footer\",\n \"children\": [\n \"apply-btn\"\n ]\n },\n {\n \"id\"\
139
- : \"apply-btn\",\n \"component\": \"Button\",\n \"text\": \"Apply\",\n \"variant\": \"primary\"\n }\n]"
213
+ - name: datetime-picker
214
+ description: Combined date+time selection via precision the mode gh#1372 folded in from the former <datetime-picker-ui>.
215
+ a2ui: |
216
+ [
217
+ {
218
+ "id": "field",
219
+ "component": "Field",
220
+ "label": "Appointment",
221
+ "children": ["dt"]
222
+ },
223
+ {
224
+ "id": "dt",
225
+ "component": "CalendarPicker",
226
+ "name": "appointment",
227
+ "precision": "minute",
228
+ "min": "2026-01-01T00:00",
229
+ "max": "2026-12-31T23:59"
230
+ }
231
+ ]
232
+ - name: constrained-date
233
+ description: Single-date picker constrained to a future booking window via min/max, paired with a submit button.
234
+ a2ui: >-
235
+ [
236
+ {
237
+ "id": "root",
238
+ "component": "Card",
239
+ "children": [
240
+ "sec"
241
+ ]
242
+ },
243
+ {
244
+ "id": "sec",
245
+ "component": "Section",
246
+ "children": [
247
+ "col"
248
+ ]
249
+ },
250
+ {
251
+ "id": "col",
252
+ "component": "Column",
253
+ "children": [
254
+ "field",
255
+ "btn"
256
+ ],
257
+ "gap": "4"
258
+ },
259
+ {
260
+ "id": "field",
261
+ "component": "Field",
262
+ "label": "Check-in date",
263
+ "children": [
264
+ "cal"
265
+ ]
266
+ },
267
+ {
268
+ "id": "cal",
269
+ "component": "CalendarPicker",
270
+ "name": "checkin",
271
+ "min": "2026-08-16",
272
+ "max": "2026-12-31"
273
+ },
274
+ {
275
+ "id": "btn",
276
+ "component": "Button",
277
+ "text": "Reserve",
278
+ "variant": "primary"
279
+ }
280
+ ]
281
+ - name: second-precision
282
+ description: Log-cursor picker with second precision — gh#1372's fold of the former datetime-picker second-precision example.
283
+ a2ui: |
284
+ [
285
+ {
286
+ "id": "dt",
287
+ "component": "CalendarPicker",
288
+ "name": "log-cursor",
289
+ "precision": "second",
290
+ "step": 1,
291
+ "value": "2026-05-24T14:30:45"
292
+ }
293
+ ]
140
294
  keywords:
141
295
  - calendarpicker
142
296
  - calendar-picker
143
297
  - calendar
144
298
  - picker
299
+ - datetimepicker
300
+ - datetime-picker
301
+ - datetime
302
+ - date-time
303
+ - dateandtime
304
+ - appointment
305
+ - schedule
306
+ - timestamp
145
307
  synonyms:
146
308
  tags:
147
309
  - DateTimeInput
148
310
  - DatePicker
311
+ - DateTimePicker
312
+ - DatetimeInput
313
+ - Timestamp
314
+ datetime:
315
+ - date-time
316
+ - timestamp
317
+ - appointment
318
+ - schedule
319
+ appointment:
320
+ - datetime
321
+ - meeting
322
+ - schedule
149
323
  related:
150
324
  - input
151
325
  - button
152
326
  - badge
327
+ - date-range-picker
328
+ - time-picker
329
+ - field
330
+ - popover
@@ -46,16 +46,17 @@
46
46
  "canvas"
47
47
  ],
48
48
  "name": "UICanvas",
49
+ "parts": {
50
+ "default": {
51
+ "description": "Template-owned anatomy, not a light-DOM insertion point (gh#1454). render() appends its own `<a2ui-root>` rendering surface; the runtime owns all rendered content (a2ui rule below: \"Do not place static children inside\"). No consumer content is captured or preserved."
52
+ }
53
+ },
49
54
  "related": [
50
55
  "A2uiRoot",
51
56
  "GenRoot",
52
57
  "EditorCanvas"
53
58
  ],
54
- "slots": {
55
- "default": {
56
- "description": "Default slot — primary child content."
57
- }
58
- },
59
+ "slots": {},
59
60
  "states": [
60
61
  {
61
62
  "description": "Default, ready for interaction.",
@@ -29,9 +29,46 @@ export class UICanvas extends UIElement {
29
29
  /** Process an array of A2UI messages in order. */
30
30
  processAll(messages: unknown[]): void;
31
31
 
32
+ /**
33
+ * Transactionally replace the rendered doc — passthrough to
34
+ * `<a2ui-root>#replaceDoc` (spec-a2ui-surface-lifecycle.md, ADR-0061,
35
+ * gh#1364): an existing surface regenerates through a lifecycle bracket
36
+ * (old content stays visible, no blank frame) instead of reset()+replay.
37
+ */
38
+ replaceDoc(messages: unknown[]): void;
39
+
32
40
  /** Clear the canvas surface — discards all components. */
33
41
  reset(): void;
34
42
 
43
+ /**
44
+ * Begin a regeneration bracket — passthrough to the wrapped
45
+ * `<a2ui-root>`'s renderer (spec-a2ui-surface-lifecycle.md, gh#1364).
46
+ * Returns the generationId, or null (no-op: root not ready yet, or
47
+ * `surfaceId` is missing/synthetic).
48
+ */
49
+ beginSurfaceUpdate(surfaceId: string, opts?: {
50
+ generationId?: string;
51
+ reason?: 'refine' | 'revalidate' | 'regenerate';
52
+ mode?: 'replace' | 'patch';
53
+ }): string | null;
54
+
55
+ /** Apply messages to a bracketed (buffers) or live (applies immediately) surface. */
56
+ applyTo(surfaceId: string, messages: unknown): void;
57
+
58
+ /**
59
+ * Commit the in-flight generation opened by `beginSurfaceUpdate`.
60
+ * Returns false when there was nothing to commit or the generationId
61
+ * was superseded (ignored, not an error).
62
+ */
63
+ commitSurfaceUpdate(surfaceId: string, generationId?: string): Promise<boolean>;
64
+
65
+ /**
66
+ * Abort the in-flight generation — prior content (if any) stays visible
67
+ * as error-stale. Returns false when there was nothing to abort or the
68
+ * generationId was superseded.
69
+ */
70
+ abortSurfaceUpdate(surfaceId: string, generationId?: string, error?: Record<string, unknown>): boolean;
71
+
35
72
  /** Return the formatted innerHTML of the internal `<a2ui-root>`. */
36
73
  getHTML(): string;
37
74
 
@@ -179,11 +179,69 @@ export class UICanvas extends UIElement {
179
179
  });
180
180
  }
181
181
 
182
+ /**
183
+ * Transactionally replace the rendered doc — passthrough to
184
+ * `<a2ui-root>#replaceDoc` (spec-a2ui-surface-lifecycle.md, ADR-0061,
185
+ * gh#1364): an existing surface regenerates through a lifecycle bracket
186
+ * (old content stays visible, no blank frame) instead of `reset()` +
187
+ * re-process. Degrades to reset()+processAll on a root that predates
188
+ * gh#1364 (FEEDBACK-81's lazy load means an older cached module is
189
+ * possible).
190
+ */
191
+ replaceDoc(messages) {
192
+ this.#whenRoot((root) => {
193
+ if (typeof root.replaceDoc === 'function') {
194
+ root.replaceDoc(messages);
195
+ } else {
196
+ root.reset();
197
+ for (const msg of messages || []) root.process(msg);
198
+ }
199
+ });
200
+ }
201
+
182
202
  /** Reset the canvas. */
183
203
  reset() {
184
204
  this.#whenRoot((root) => root.reset());
185
205
  }
186
206
 
207
+ // ── Surface lifecycle passthroughs (spec-a2ui-surface-lifecycle.md,
208
+ // ADR-0061, gh#1364) — a caller that wants to bracket ITS OWN async
209
+ // generation call (open before the await, commit/abort after) needs the
210
+ // generationId back synchronously, so these skip the `#whenRoot`
211
+ // deferred-queue path `process`/`processAll`/`replaceDoc` use and read
212
+ // `this.#rootEl.renderer` directly. Each degrades to a safe no-op
213
+ // (null / false) when the root isn't upgraded yet or predates gh#1364 —
214
+ // same shape as the renderer's own missing/synthetic-surface no-ops.
215
+
216
+ /** Begin a regeneration bracket. Returns the generationId, or null (no-op). */
217
+ beginSurfaceUpdate(surfaceId, opts) {
218
+ const renderer = this.#rootEl?.renderer;
219
+ return typeof renderer?.beginSurfaceUpdate === 'function'
220
+ ? renderer.beginSurfaceUpdate(surfaceId, opts)
221
+ : null;
222
+ }
223
+
224
+ /** Apply messages to a bracketed (or live, unbracketed) surface. */
225
+ applyTo(surfaceId, messages) {
226
+ this.#rootEl?.renderer?.applyTo?.(surfaceId, messages);
227
+ }
228
+
229
+ /** Commit the in-flight generation. Returns false on no-op (nothing to commit / stale generationId). */
230
+ commitSurfaceUpdate(surfaceId, generationId) {
231
+ const renderer = this.#rootEl?.renderer;
232
+ return typeof renderer?.commitSurfaceUpdate === 'function'
233
+ ? renderer.commitSurfaceUpdate(surfaceId, generationId)
234
+ : false;
235
+ }
236
+
237
+ /** Abort the in-flight generation — prior content (if any) stays visible as error-stale. */
238
+ abortSurfaceUpdate(surfaceId, generationId, error) {
239
+ const renderer = this.#rootEl?.renderer;
240
+ return typeof renderer?.abortSurfaceUpdate === 'function'
241
+ ? renderer.abortSurfaceUpdate(surfaceId, generationId, error)
242
+ : false;
243
+ }
244
+
187
245
  /** Return formatted innerHTML of the a2ui-root. */
188
246
  getHTML() {
189
247
  return this.#rootEl?.innerHTML ?? '';
@@ -219,12 +277,23 @@ export class UICanvas extends UIElement {
219
277
  get historyLength() { return this.#history.length; }
220
278
  get historyIndex() { return this.#historyIndex; }
221
279
 
280
+ // Surface lifecycle (spec-a2ui-surface-lifecycle.md, ADR-0061, gh#1364):
281
+ // history stepping replays through <a2ui-root>#replaceDoc — a
282
+ // transactional per-surface regeneration bracket — instead of
283
+ // reset()+replay, so back()/forward() no longer flash a blank frame
284
+ // between versions. `replaceDoc` degrades to an ordinary process() loop
285
+ // on a root that predates gh#1364 (feature-detected — FEEDBACK-81's lazy
286
+ // <a2ui-root> load means an older cached module is possible).
222
287
  #restoreVersion() {
223
288
  const messages = this.#history[this.#historyIndex];
224
289
  this.#whenRoot((root) => {
225
- root.reset();
226
- if (messages) {
227
- for (const msg of messages) root.process(msg);
290
+ if (typeof root.replaceDoc === 'function') {
291
+ root.replaceDoc(messages || []);
292
+ } else {
293
+ root.reset();
294
+ if (messages) {
295
+ for (const msg of messages) root.process(msg);
296
+ }
228
297
  }
229
298
  });
230
299
  }
@@ -32,9 +32,13 @@ props:
32
32
  events:
33
33
  canvas-interaction:
34
34
  description: Fired on canvas interactions (focus, blur, pointer events). Dispatched at canvas.js:50 + :167.
35
- slots:
35
+ parts:
36
36
  default:
37
- description: Default slot — primary child content.
37
+ description: >-
38
+ Template-owned anatomy, not a light-DOM insertion point (gh#1454).
39
+ render() appends its own `<a2ui-root>` rendering surface; the runtime
40
+ owns all rendered content (a2ui rule below: "Do not place static
41
+ children inside"). No consumer content is captured or preserved.
38
42
  states:
39
43
  - name: idle
40
44
  description: Default, ready for interaction.
@@ -33,9 +33,31 @@
33
33
  "default": 1
34
34
  },
35
35
  "padding": {
36
- "description": "Interior padding scale (overrides --card-padding). Accepts the named scale (none/xs/sm/md/lg/xl) or a numeric rung (\"1\"…\"16\").",
36
+ "description": "Interior padding scale overrides --card-inset (the header/section/footer inset token) for the whole card. Accepts the named scale (none/xs/sm/md/lg/xl — the parametric --a-padding-* tokens, same vocabulary as block-ui's [padding]) or a literal space rung (\"0\"/\"1\"…\"10\"/\"12\"/\"16\", mapped to --a-space-N). Empty (default) defers to the ambient --card-inset (context/[size]-driven) — unchanged behavior for the many existing cards that never set this attribute.",
37
37
  "type": "string",
38
- "default": "md"
38
+ "enum": [
39
+ "",
40
+ "none",
41
+ "xs",
42
+ "sm",
43
+ "md",
44
+ "lg",
45
+ "xl",
46
+ "0",
47
+ "1",
48
+ "2",
49
+ "3",
50
+ "4",
51
+ "5",
52
+ "6",
53
+ "7",
54
+ "8",
55
+ "9",
56
+ "10",
57
+ "12",
58
+ "16"
59
+ ],
60
+ "default": ""
39
61
  },
40
62
  "raw": {
41
63
  "description": "Strips background, border, and shadow. Parent owns the surface. Content structure still applies.",
@@ -103,6 +125,7 @@
103
125
  "responsive"
104
126
  ],
105
127
  "name": "UICard",
128
+ "parts": {},
106
129
  "related": [
107
130
  "avatar",
108
131
  "input",
@@ -31,6 +31,8 @@
31
31
  * Attributes:
32
32
  * variant — "default" | "outlined" | "filled" | "ghost"
33
33
  * size — "sm" | "md" | "lg" (controls padding + font scale)
34
+ * padding — "" | none|xs|sm|md|lg|xl | "0"…"10"|"12"|"16" (overrides
35
+ * --card-inset; empty = ambient/[size]-driven, unchanged)
34
36
  * elevation — 0-3 (shadow depth)
35
37
  * raw — strips all chrome (border, bg, shadow, padding)
36
38
  * draggable — enables drag handle + cursor:grab; wires the draggable trait
@@ -43,6 +45,7 @@ export class UICard extends UIElement {
43
45
  static properties = {
44
46
  variant: { type: String, default: 'default', reflect: true },
45
47
  size: { type: String, default: '', reflect: true },
48
+ padding: { type: String, default: '', reflect: true },
46
49
  elevation: { type: Number, default: 1, reflect: true },
47
50
  raw: { type: Boolean, default: false, reflect: true },
48
51
  draggable: { type: Boolean, default: false, reflect: true },
@@ -120,6 +120,36 @@
120
120
  :scope[elevation="2"] { --card-shadow: var(--card-shadow-2); }
121
121
  :scope[elevation="3"] { --card-shadow: var(--card-shadow-3); }
122
122
 
123
+ /* ═══════ Padding — token override (gh#1416) ═══════
124
+ Overrides --card-inset (the header/section/footer inset token) for
125
+ the whole card. Named scale mirrors block-ui's own [padding] contract
126
+ + the global [padding] attribute API (api/sizing.css) — same
127
+ --a-padding-{xs..xl} tokens, so <card-ui padding="md"> == [padding="md"].
128
+ Literal rungs are the same k-independent --a-space-N set as the
129
+ universal [gap]/[padding] attribute (api/sizing.css). Unset (empty)
130
+ keeps the ambient --card-inset (context/[size]-driven) — this section
131
+ only fires when an author writes the attribute explicitly, so the many
132
+ existing cards that never set [padding] are unaffected. */
133
+ :scope[padding="none"] { --card-inset: 0; }
134
+ :scope[padding="xs"] { --card-inset: var(--a-padding-xs); }
135
+ :scope[padding="sm"] { --card-inset: var(--a-padding-sm); }
136
+ :scope[padding="md"] { --card-inset: var(--a-padding-md); }
137
+ :scope[padding="lg"] { --card-inset: var(--a-padding-lg); }
138
+ :scope[padding="xl"] { --card-inset: var(--a-padding-xl); }
139
+ :scope[padding="0"] { --card-inset: 0; }
140
+ :scope[padding="1"] { --card-inset: var(--a-space-1); }
141
+ :scope[padding="2"] { --card-inset: var(--a-space-2); }
142
+ :scope[padding="3"] { --card-inset: var(--a-space-3); }
143
+ :scope[padding="4"] { --card-inset: var(--a-space-4); }
144
+ :scope[padding="5"] { --card-inset: var(--a-space-5); }
145
+ :scope[padding="6"] { --card-inset: var(--a-space-6); }
146
+ :scope[padding="7"] { --card-inset: var(--a-space-7); }
147
+ :scope[padding="8"] { --card-inset: var(--a-space-8); }
148
+ :scope[padding="9"] { --card-inset: var(--a-space-9); }
149
+ :scope[padding="10"] { --card-inset: var(--a-space-10); }
150
+ :scope[padding="12"] { --card-inset: var(--a-space-12); }
151
+ :scope[padding="16"] { --card-inset: var(--a-space-16); }
152
+
123
153
  /* ═══════ Loading ═══════ */
124
154
 
125
155
  :scope[loading] {
@@ -194,7 +224,7 @@
194
224
  align-items: center;
195
225
  }
196
226
 
197
- & > header[padding] {
227
+ & > header[padded] {
198
228
  margin: 0;
199
229
  padding: var(--card-inset);
200
230
  background: var(--card-bg-padded);
@@ -17,8 +17,8 @@ export class UICard extends UIElement {
17
17
  draggable: boolean;
18
18
  /** Shadow depth 0-3 */
19
19
  elevation: 0 | 1 | 2 | 3;
20
- /** Interior padding scale (overrides --card-padding). Accepts the named scale (none/xs/sm/md/lg/xl) or a numeric rung ("1"…"16"). */
21
- padding: string;
20
+ /** Interior padding scale overrides --card-inset (the header/section/footer inset token) for the whole card. Accepts the named scale (none/xs/sm/md/lg/xl — the parametric --a-padding-* tokens, same vocabulary as block-ui's [padding]) or a literal space rung ("0"/"1"…"10"/"12"/"16", mapped to --a-space-N). Empty (default) defers to the ambient --card-inset (context/[size]-driven) — unchanged behavior for the many existing cards that never set this attribute. */
21
+ padding: '' | 'none' | 'xs' | 'sm' | 'md' | 'lg' | 'xl' | '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9' | '10' | '12' | '16';
22
22
  /** Strips background, border, and shadow. Parent owns the surface. Content structure still applies. */
23
23
  raw: boolean;
24
24
  /** Card scale. Controls inset, radius, gap, and font sizes. Default (empty) = md. */